mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
Add session id to Codex analytics events
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -746,6 +746,7 @@ fn compaction_event_serializes_expected_shape() {
|
||||
},
|
||||
sample_app_server_client_metadata(),
|
||||
sample_runtime_metadata(),
|
||||
"session-1".to_string(),
|
||||
Some("user"),
|
||||
/*subagent_source*/ None,
|
||||
/*parent_thread_id*/ None,
|
||||
@@ -759,6 +760,7 @@ fn compaction_event_serializes_expected_shape() {
|
||||
json!({
|
||||
"event_type": "codex_compaction_event",
|
||||
"event_params": {
|
||||
"session_id": "session-1",
|
||||
"thread_id": "thread-1",
|
||||
"turn_id": "turn-1",
|
||||
"app_server_client": {
|
||||
@@ -829,6 +831,7 @@ fn thread_initialized_event_serializes_expected_shape() {
|
||||
let event = TrackEventRequest::ThreadInitialized(ThreadInitializedEvent {
|
||||
event_type: "codex_thread_initialized",
|
||||
event_params: ThreadInitializedEventParams {
|
||||
session_id: "session-0".to_string(),
|
||||
thread_id: "thread-0".to_string(),
|
||||
app_server_client: CodexAppServerClientMetadata {
|
||||
product_client_id: DEFAULT_ORIGINATOR.to_string(),
|
||||
@@ -860,6 +863,7 @@ fn thread_initialized_event_serializes_expected_shape() {
|
||||
json!({
|
||||
"event_type": "codex_thread_initialized",
|
||||
"event_params": {
|
||||
"session_id": "session-0",
|
||||
"thread_id": "thread-0",
|
||||
"app_server_client": {
|
||||
"product_client_id": DEFAULT_ORIGINATOR,
|
||||
@@ -1249,6 +1253,10 @@ async fn guardian_review_event_ingests_custom_fact_with_optional_target_item() {
|
||||
let payload = serde_json::to_value(&events).expect("serialize events");
|
||||
assert_eq!(payload.as_array().expect("events array").len(), 1);
|
||||
assert_eq!(payload[0]["event_type"], "codex_guardian_review");
|
||||
assert_eq!(
|
||||
payload[0]["event_params"]["session_id"],
|
||||
"session-thread-guardian"
|
||||
);
|
||||
assert_eq!(payload[0]["event_params"]["thread_id"], "thread-guardian");
|
||||
assert_eq!(payload[0]["event_params"]["turn_id"], "turn-guardian");
|
||||
assert_eq!(payload[0]["event_params"]["review_id"], "review-guardian");
|
||||
@@ -1295,6 +1303,7 @@ async fn guardian_review_event_ingests_custom_fact_with_optional_target_item() {
|
||||
fn subagent_thread_started_review_serializes_expected_shape() {
|
||||
let event = TrackEventRequest::ThreadInitialized(subagent_thread_started_event_request(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-review".to_string(),
|
||||
parent_thread_id: None,
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
@@ -1338,6 +1347,7 @@ fn subagent_thread_started_thread_spawn_serializes_parent_thread_id() {
|
||||
.expect("valid thread id");
|
||||
let event = TrackEventRequest::ThreadInitialized(subagent_thread_started_event_request(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-spawn".to_string(),
|
||||
parent_thread_id: None,
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
@@ -1369,6 +1379,7 @@ fn subagent_thread_started_thread_spawn_serializes_parent_thread_id() {
|
||||
fn subagent_thread_started_memory_consolidation_serializes_expected_shape() {
|
||||
let event = TrackEventRequest::ThreadInitialized(subagent_thread_started_event_request(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-memory".to_string(),
|
||||
parent_thread_id: None,
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
@@ -1394,6 +1405,7 @@ fn subagent_thread_started_memory_consolidation_serializes_expected_shape() {
|
||||
fn subagent_thread_started_other_serializes_expected_shape() {
|
||||
let event = TrackEventRequest::ThreadInitialized(subagent_thread_started_event_request(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-guardian".to_string(),
|
||||
parent_thread_id: None,
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
@@ -1415,6 +1427,7 @@ fn subagent_thread_started_other_serializes_expected_shape() {
|
||||
fn subagent_thread_started_other_serializes_explicit_parent_thread_id() {
|
||||
let event = TrackEventRequest::ThreadInitialized(subagent_thread_started_event_request(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-guardian".to_string(),
|
||||
parent_thread_id: Some("parent-thread-guardian".to_string()),
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
@@ -1444,6 +1457,7 @@ async fn subagent_thread_started_publishes_without_initialize() {
|
||||
.ingest(
|
||||
AnalyticsFact::Custom(CustomAnalyticsFact::SubAgentThreadStarted(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-review".to_string(),
|
||||
parent_thread_id: None,
|
||||
product_client_id: "codex-tui".to_string(),
|
||||
@@ -1517,6 +1531,7 @@ async fn subagent_thread_started_inherits_parent_connection_for_new_thread() {
|
||||
.ingest(
|
||||
AnalyticsFact::Custom(CustomAnalyticsFact::SubAgentThreadStarted(
|
||||
SubAgentThreadStartedInput {
|
||||
session_id: "session-root".to_string(),
|
||||
thread_id: "thread-review".to_string(),
|
||||
parent_thread_id: None,
|
||||
product_client_id: "parent-client".to_string(),
|
||||
@@ -1968,6 +1983,7 @@ fn turn_event_serializes_expected_shape() {
|
||||
let event = TrackEventRequest::TurnEvent(Box::new(CodexTurnEventRequest {
|
||||
event_type: "codex_turn_event",
|
||||
event_params: crate::events::CodexTurnEventParams {
|
||||
session_id: "session-2".to_string(),
|
||||
thread_id: "thread-2".to_string(),
|
||||
turn_id: "turn-2".to_string(),
|
||||
app_server_client: sample_app_server_client_metadata(),
|
||||
@@ -2018,6 +2034,7 @@ fn turn_event_serializes_expected_shape() {
|
||||
r#"{
|
||||
"event_type": "codex_turn_event",
|
||||
"event_params": {
|
||||
"session_id": "session-2",
|
||||
"thread_id": "thread-2",
|
||||
"turn_id": "turn-2",
|
||||
"submission_type": null,
|
||||
|
||||
@@ -105,6 +105,7 @@ pub(crate) struct CodexRuntimeMetadata {
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct ThreadInitializedEventParams {
|
||||
pub(crate) session_id: String,
|
||||
pub(crate) thread_id: String,
|
||||
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
||||
pub(crate) runtime: CodexRuntimeMetadata,
|
||||
@@ -378,6 +379,7 @@ impl GuardianReviewAnalyticsResult {
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct GuardianReviewEventPayload {
|
||||
pub(crate) session_id: String,
|
||||
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
||||
pub(crate) runtime: CodexRuntimeMetadata,
|
||||
#[serde(flatten)]
|
||||
@@ -425,6 +427,7 @@ pub(crate) struct CodexHookRunEventRequest {
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct CodexCompactionEventParams {
|
||||
pub(crate) session_id: String,
|
||||
pub(crate) thread_id: String,
|
||||
pub(crate) turn_id: String,
|
||||
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
||||
@@ -454,6 +457,7 @@ pub(crate) struct CodexCompactionEventRequest {
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct CodexTurnEventParams {
|
||||
pub(crate) session_id: String,
|
||||
pub(crate) thread_id: String,
|
||||
pub(crate) turn_id: String,
|
||||
// TODO(rhan-oai): Populate once queued/default submission type is plumbed from
|
||||
@@ -510,6 +514,7 @@ pub(crate) struct CodexTurnEventRequest {
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct CodexTurnSteerEventParams {
|
||||
pub(crate) session_id: String,
|
||||
pub(crate) thread_id: String,
|
||||
pub(crate) expected_turn_id: Option<String>,
|
||||
pub(crate) accepted_turn_id: Option<String>,
|
||||
@@ -618,11 +623,13 @@ pub(crate) fn codex_compaction_event_params(
|
||||
input: CodexCompactionEvent,
|
||||
app_server_client: CodexAppServerClientMetadata,
|
||||
runtime: CodexRuntimeMetadata,
|
||||
session_id: String,
|
||||
thread_source: Option<&'static str>,
|
||||
subagent_source: Option<String>,
|
||||
parent_thread_id: Option<String>,
|
||||
) -> CodexCompactionEventParams {
|
||||
CodexCompactionEventParams {
|
||||
session_id,
|
||||
thread_id: input.thread_id,
|
||||
turn_id: input.turn_id,
|
||||
app_server_client,
|
||||
@@ -711,6 +718,7 @@ pub(crate) fn subagent_thread_started_event_request(
|
||||
input: SubAgentThreadStartedInput,
|
||||
) -> ThreadInitializedEvent {
|
||||
let event_params = ThreadInitializedEventParams {
|
||||
session_id: input.session_id,
|
||||
thread_id: input.thread_id,
|
||||
app_server_client: CodexAppServerClientMetadata {
|
||||
product_client_id: input.product_client_id,
|
||||
|
||||
@@ -191,6 +191,7 @@ pub struct AppInvocation {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubAgentThreadStartedInput {
|
||||
pub session_id: String,
|
||||
pub thread_id: String,
|
||||
pub parent_thread_id: Option<String>,
|
||||
pub product_client_id: String,
|
||||
|
||||
@@ -147,6 +147,7 @@ enum MissingAnalyticsContext {
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ThreadMetadataState {
|
||||
session_id: String,
|
||||
thread_source: Option<&'static str>,
|
||||
initialization_mode: ThreadInitializationMode,
|
||||
subagent_source: Option<String>,
|
||||
@@ -155,6 +156,7 @@ struct ThreadMetadataState {
|
||||
|
||||
impl ThreadMetadataState {
|
||||
fn from_thread_metadata(
|
||||
session_id: String,
|
||||
session_source: &SessionSource,
|
||||
initialization_mode: ThreadInitializationMode,
|
||||
) -> Self {
|
||||
@@ -172,6 +174,7 @@ impl ThreadMetadataState {
|
||||
| SessionSource::Unknown => (None, None),
|
||||
};
|
||||
Self {
|
||||
session_id,
|
||||
thread_source: session_source.thread_source_name(),
|
||||
initialization_mode,
|
||||
subagent_source,
|
||||
@@ -348,6 +351,7 @@ impl AnalyticsReducer {
|
||||
thread_state
|
||||
.metadata
|
||||
.get_or_insert_with(|| ThreadMetadataState {
|
||||
session_id: input.session_id.clone(),
|
||||
thread_source: Some("subagent"),
|
||||
initialization_mode: ThreadInitializationMode::New,
|
||||
subagent_source: Some(subagent_source_name(&input.subagent_source)),
|
||||
@@ -366,8 +370,8 @@ impl AnalyticsReducer {
|
||||
input: GuardianReviewEventParams,
|
||||
out: &mut Vec<TrackEventRequest>,
|
||||
) {
|
||||
let Some(connection_state) =
|
||||
self.thread_connection_or_warn(AnalyticsDropSite::guardian(&input))
|
||||
let Some((connection_state, thread_metadata)) =
|
||||
self.thread_context_or_warn(AnalyticsDropSite::guardian(&input))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -375,6 +379,7 @@ impl AnalyticsReducer {
|
||||
GuardianReviewEventRequest {
|
||||
event_type: "codex_guardian_review",
|
||||
event_params: GuardianReviewEventPayload {
|
||||
session_id: thread_metadata.session_id.clone(),
|
||||
app_server_client: connection_state.app_server_client.clone(),
|
||||
runtime: connection_state.runtime.clone(),
|
||||
guardian_review: input,
|
||||
@@ -573,6 +578,7 @@ impl AnalyticsReducer {
|
||||
connection_id,
|
||||
response.thread,
|
||||
response.model,
|
||||
response.session_id,
|
||||
ThreadInitializationMode::New,
|
||||
out,
|
||||
);
|
||||
@@ -582,6 +588,7 @@ impl AnalyticsReducer {
|
||||
connection_id,
|
||||
response.thread,
|
||||
response.model,
|
||||
response.session_id,
|
||||
ThreadInitializationMode::Resumed,
|
||||
out,
|
||||
);
|
||||
@@ -589,8 +596,9 @@ impl AnalyticsReducer {
|
||||
ClientResponse::ThreadFork { response, .. } => {
|
||||
self.emit_thread_initialized(
|
||||
connection_id,
|
||||
response.thread,
|
||||
response.thread.clone(),
|
||||
response.model,
|
||||
response.thread.id,
|
||||
ThreadInitializationMode::Forked,
|
||||
out,
|
||||
);
|
||||
@@ -744,6 +752,7 @@ impl AnalyticsReducer {
|
||||
connection_id: u64,
|
||||
thread: codex_app_server_protocol::Thread,
|
||||
model: String,
|
||||
session_id: String,
|
||||
initialization_mode: ThreadInitializationMode,
|
||||
out: &mut Vec<TrackEventRequest>,
|
||||
) {
|
||||
@@ -752,8 +761,11 @@ impl AnalyticsReducer {
|
||||
let Some(connection_state) = self.connections.get(&connection_id) else {
|
||||
return;
|
||||
};
|
||||
let thread_metadata =
|
||||
ThreadMetadataState::from_thread_metadata(&thread_source, initialization_mode);
|
||||
let thread_metadata = ThreadMetadataState::from_thread_metadata(
|
||||
session_id.clone(),
|
||||
&thread_source,
|
||||
initialization_mode,
|
||||
);
|
||||
self.threads.insert(
|
||||
thread_id.clone(),
|
||||
ThreadAnalyticsState {
|
||||
@@ -765,6 +777,7 @@ impl AnalyticsReducer {
|
||||
ThreadInitializedEvent {
|
||||
event_type: "codex_thread_initialized",
|
||||
event_params: ThreadInitializedEventParams {
|
||||
session_id,
|
||||
thread_id,
|
||||
app_server_client: connection_state.app_server_client.clone(),
|
||||
runtime: connection_state.runtime.clone(),
|
||||
@@ -793,6 +806,7 @@ impl AnalyticsReducer {
|
||||
input,
|
||||
connection_state.app_server_client.clone(),
|
||||
connection_state.runtime.clone(),
|
||||
thread_metadata.session_id.clone(),
|
||||
thread_metadata.thread_source,
|
||||
thread_metadata.subagent_source.clone(),
|
||||
thread_metadata.parent_thread_id.clone(),
|
||||
@@ -850,6 +864,7 @@ impl AnalyticsReducer {
|
||||
out.push(TrackEventRequest::TurnSteer(CodexTurnSteerEventRequest {
|
||||
event_type: "codex_turn_steer_event",
|
||||
event_params: CodexTurnSteerEventParams {
|
||||
session_id: thread_metadata.session_id.clone(),
|
||||
thread_id: pending_request.thread_id,
|
||||
expected_turn_id: Some(pending_request.expected_turn_id),
|
||||
accepted_turn_id,
|
||||
@@ -1015,6 +1030,7 @@ fn codex_turn_event_params(
|
||||
} = resolved_config;
|
||||
let token_usage = turn_state.token_usage.clone();
|
||||
CodexTurnEventParams {
|
||||
session_id: thread_metadata.session_id.clone(),
|
||||
thread_id,
|
||||
turn_id,
|
||||
app_server_client,
|
||||
|
||||
@@ -291,6 +291,7 @@ impl AgentControl {
|
||||
.services
|
||||
.analytics_events_client,
|
||||
client_metadata,
|
||||
self.session_id,
|
||||
new_thread.thread_id,
|
||||
/*parent_thread_id*/ None,
|
||||
thread_config,
|
||||
|
||||
@@ -109,6 +109,7 @@ pub(crate) async fn run_codex_thread_interactive(
|
||||
emit_subagent_session_started(
|
||||
&parent_session.services.analytics_events_client,
|
||||
client_metadata,
|
||||
parent_session.services.agent_control.session_id(),
|
||||
codex.session.conversation_id,
|
||||
Some(parent_session.conversation_id),
|
||||
thread_config,
|
||||
|
||||
@@ -3256,6 +3256,7 @@ impl Session {
|
||||
pub(crate) fn emit_subagent_session_started(
|
||||
analytics_events_client: &AnalyticsEventsClient,
|
||||
client_metadata: AppServerClientMetadata,
|
||||
session_id: codex_protocol::SessionId,
|
||||
thread_id: ThreadId,
|
||||
parent_thread_id: Option<ThreadId>,
|
||||
thread_config: ThreadConfigSnapshot,
|
||||
@@ -3274,6 +3275,7 @@ pub(crate) fn emit_subagent_session_started(
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
analytics_events_client.track_subagent_thread_started(SubAgentThreadStartedInput {
|
||||
session_id: session_id.to_string(),
|
||||
thread_id: thread_id.to_string(),
|
||||
parent_thread_id: parent_thread_id.map(|thread_id| thread_id.to_string()),
|
||||
product_client_id: client_name.clone(),
|
||||
|
||||
Reference in New Issue
Block a user