mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
[codex-analytics] add item lifecycle timing (#20514)
## Why Tool families already disagree on what their existing `duration` fields mean, so lifecycle latency should live on the shared item envelope instead of being inferred from per-tool execution fields. Carrying that envelope through app-server notifications gives downstream consumers one reusable timing signal without pretending every tool has the same execution semantics. ## What changed - Adds `started_at_ms` to core `ItemStartedEvent` values and `completed_at_ms` to core `ItemCompletedEvent` values. - Populates those timestamps in the shared session lifecycle emitters, so protocol-native items get timing without each producer tracking its own clock state. - Exposes `startedAtMs` on app-server `item/started` notifications and `completedAtMs` on `item/completed` notifications. - Maps the lifecycle timestamps through the app-server boundary while leaving legacy-converted notifications nullable when no lifecycle timestamp exists. - Regenerates the app-server JSON schema and TypeScript fixtures for the notification-envelope change and updates downstream fixtures that construct those notifications directly. - Extends the existing web-search and image-generation integration flows to assert the new lifecycle timestamps on the native item events. ## Verification - `cargo check -p codex-protocol -p codex-core -p codex-app-server-protocol -p codex-app-server -p codex-tui -p codex-exec -p codex-app-server-client` - `cargo test -p codex-core --test all web_search_item_is_emitted` - `cargo test -p codex-core --test all image_generation_call_event_is_emitted` - `cargo test -p codex-app-server-protocol` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/20514). * #18748 * #18747 * #17090 * #17089 * __->__ #20514
This commit is contained in:
@@ -20,6 +20,7 @@ fn failed_turn_does_not_overwrite_output_last_message_file() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ fn command_execution_started_and_completed_translate_to_thread_events() {
|
||||
item: command_item,
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
assert_eq!(
|
||||
started,
|
||||
@@ -216,6 +217,7 @@ fn command_execution_started_and_completed_translate_to_thread_events() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
assert_eq!(
|
||||
@@ -250,6 +252,7 @@ fn empty_reasoning_items_are_ignored() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -274,6 +277,7 @@ fn unsupported_items_do_not_consume_synthetic_ids() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -295,6 +299,7 @@ fn unsupported_items_do_not_consume_synthetic_ids() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -327,6 +332,7 @@ fn reasoning_items_emit_summary_not_raw_content() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -362,6 +368,7 @@ fn web_search_completion_preserves_query_and_action() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -399,6 +406,7 @@ fn web_search_start_and_completion_reuse_item_id() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
|
||||
let completed = processor.collect_thread_events(ServerNotification::ItemCompleted(
|
||||
@@ -413,6 +421,7 @@ fn web_search_start_and_completion_reuse_item_id() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -472,6 +481,7 @@ fn mcp_tool_call_begin_and_end_emit_item_events() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
let completed = processor.collect_thread_events(ServerNotification::ItemCompleted(
|
||||
ItemCompletedNotification {
|
||||
@@ -492,6 +502,7 @@ fn mcp_tool_call_begin_and_end_emit_item_events() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -559,6 +570,7 @@ fn mcp_tool_call_failure_sets_failed_status() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -604,6 +616,7 @@ fn mcp_tool_call_defaults_arguments_and_preserves_structured_content() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
let completed = processor.collect_thread_events(ServerNotification::ItemCompleted(
|
||||
ItemCompletedNotification {
|
||||
@@ -627,6 +640,7 @@ fn mcp_tool_call_defaults_arguments_and_preserves_structured_content() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -695,6 +709,7 @@ fn collab_spawn_begin_and_end_emit_item_events() {
|
||||
},
|
||||
thread_id: "thread-parent".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
let completed = processor.collect_thread_events(ServerNotification::ItemCompleted(
|
||||
ItemCompletedNotification {
|
||||
@@ -717,6 +732,7 @@ fn collab_spawn_begin_and_end_emit_item_events() {
|
||||
},
|
||||
thread_id: "thread-parent".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -795,6 +811,7 @@ fn file_change_completion_maps_change_kinds() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -845,6 +862,7 @@ fn file_change_declined_maps_to_failed_status() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -882,6 +900,7 @@ fn agent_message_item_updates_final_message() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -916,6 +935,7 @@ fn agent_message_item_started_is_ignored() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
|
||||
assert_eq!(
|
||||
@@ -940,6 +960,7 @@ fn reasoning_item_completed_uses_synthetic_id() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -1296,6 +1317,7 @@ fn turn_completion_reconciles_started_items_from_turn_items() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
started_at_ms: 0,
|
||||
}));
|
||||
assert_eq!(
|
||||
started,
|
||||
@@ -1378,6 +1400,7 @@ fn turn_completion_overwrites_stale_final_message_from_turn_items() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -1426,6 +1449,7 @@ fn turn_completion_preserves_streamed_final_message_when_turn_items_are_empty()
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
@@ -1470,6 +1494,7 @@ fn failed_turn_clears_stale_final_message() {
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user