Add turn start timestamp to turn metadata (#19473)

## Why
- Without change: MCP tool calls receive
`_meta["x-codex-turn-metadata"]` with `session_id` and `turn_id`.
- Issue: MCP servers may want the turn start timestamp to measure
internal latency relative to turn start.

## What Changed
- With change: turn metadata now includes `turn_started_at_unix_ms`,
which is propagated to MCP tool calls in
`_meta["x-codex-turn-metadata"]`.

## Verification
- `codex-rs/core/src/mcp_tool_call_tests.rs`
- `codex-rs/core/src/turn_metadata_tests.rs`
- `codex-rs/core/src/turn_timing_tests.rs`
- `codex-rs/core/tests/responses_headers.rs`
- `codex-rs/core/tests/suite/search_tool.rs`
This commit is contained in:
mchen-oai
2026-04-28 09:36:59 -07:00
committed by GitHub
parent 4e0cf945b7
commit ccec84b148
8 changed files with 210 additions and 12 deletions

View File

@@ -434,6 +434,14 @@ async fn responses_stream_includes_turn_metadata_header_for_git_workspace_e2e()
!initial_turn_id.is_empty(),
"turn_id should not be empty in x-codex-turn-metadata"
);
let initial_turn_started_at_unix_ms = initial_parsed
.get("turn_started_at_unix_ms")
.and_then(serde_json::Value::as_i64)
.expect("turn_started_at_unix_ms should be present");
assert!(
initial_turn_started_at_unix_ms > 0,
"turn_started_at_unix_ms should be positive"
);
assert_eq!(
initial_parsed
.get("sandbox")
@@ -537,6 +545,22 @@ async fn responses_stream_includes_turn_metadata_header_for_git_workspace_e2e()
.get("turn_id")
.and_then(serde_json::Value::as_str)
.expect("second turn_id should be present");
let first_turn_started_at_unix_ms = first_parsed
.get("turn_started_at_unix_ms")
.and_then(serde_json::Value::as_i64)
.expect("first turn_started_at_unix_ms should be present");
let second_turn_started_at_unix_ms = second_parsed
.get("turn_started_at_unix_ms")
.and_then(serde_json::Value::as_i64)
.expect("second turn_started_at_unix_ms should be present");
assert!(
first_turn_started_at_unix_ms > 0,
"first turn_started_at_unix_ms should be positive"
);
assert_eq!(
first_turn_started_at_unix_ms, second_turn_started_at_unix_ms,
"requests in the same turn should share turn_started_at_unix_ms"
);
assert_eq!(
first_parsed
.get("thread_source")

View File

@@ -604,6 +604,27 @@ async fn tool_search_returns_deferred_tools_without_follow_up_tool_injection() -
.is_some_and(|turn_id| !turn_id.is_empty()),
"apps tools/call should include turn metadata turn_id: {apps_tool_call:?}"
);
let mcp_turn_started_at_unix_ms = apps_tool_call
.pointer("/params/_meta/x-codex-turn-metadata/turn_started_at_unix_ms")
.and_then(Value::as_i64)
.expect("apps tools/call should include turn_started_at_unix_ms");
assert!(
mcp_turn_started_at_unix_ms > 0,
"apps tools/call should include a positive turn_started_at_unix_ms: {apps_tool_call:?}"
);
let first_request_turn_metadata: Value = serde_json::from_str(
&requests[0]
.header("x-codex-turn-metadata")
.expect("first response request should include turn metadata"),
)
.expect("first response request turn metadata should be valid JSON");
assert_eq!(
first_request_turn_metadata
.get("turn_started_at_unix_ms")
.and_then(Value::as_i64),
Some(mcp_turn_started_at_unix_ms)
);
let first_request_body = requests[0].body_json();
let first_request_tools = tool_names(&first_request_body);