diff --git a/codex-rs/core/src/tasks/mod.rs b/codex-rs/core/src/tasks/mod.rs index b2f110486c..b91e28319b 100644 --- a/codex-rs/core/src/tasks/mod.rs +++ b/codex-rs/core/src/tasks/mod.rs @@ -186,11 +186,12 @@ impl Session { let ctx = Arc::clone(&turn_context); let task_for_run = Arc::clone(&task); let task_cancellation_token = cancellation_token.child_token(); - // Task-owned turn spans keep a core-owned span open for the - // full task lifecycle after the submission dispatch span ends. + // Task-owned turn spans keep a core-owned parent span open for the + // full turn lifecycle after the submission dispatch span ends. let task_span = info_span!( "turn", otel.name = span_name, + conversation.id = %self.conversation_id, thread.id = %self.conversation_id, turn.id = %turn_context.sub_id, model = %turn_context.model_info.slug, diff --git a/codex-rs/core/tests/suite/otel.rs b/codex-rs/core/tests/suite/otel.rs index 4fadee0770..08b90c5bf1 100644 --- a/codex-rs/core/tests/suite/otel.rs +++ b/codex-rs/core/tests/suite/otel.rs @@ -747,7 +747,12 @@ async fn responses_request_span_records_turn_correlation_fields() { lines .iter() .find(|line| { - line.contains("responses_http.request{") + line.contains("turn{otel.name=\"session_task.turn\"") + && line.contains("conversation.id=") + && line.contains("thread.id=") + && line.contains("turn.id=") + && line.contains("model=") + && line.contains("responses_http.request{") && line.contains("otel.kind=\"client\"") && line.contains("transport=\"responses_http\"") && line.contains("conversation.id=") @@ -756,7 +761,10 @@ async fn responses_request_span_records_turn_correlation_fields() { }) .map(|_| Ok(())) .unwrap_or_else(|| { - Err("missing responses_http.request span with correlation fields".to_string()) + Err( + "missing responses_http.request span nested under session_task.turn" + .to_string(), + ) }) }); } diff --git a/codex-rs/core/tests/suite/rmcp_client.rs b/codex-rs/core/tests/suite/rmcp_client.rs index 337d4d69b3..0f31222923 100644 --- a/codex-rs/core/tests/suite/rmcp_client.rs +++ b/codex-rs/core/tests/suite/rmcp_client.rs @@ -194,7 +194,12 @@ async fn stdio_server_round_trip() -> anyhow::Result<()> { lines .iter() .find(|line| { - line.contains("mcp.tools.call{") + line.contains("turn{otel.name=\"session_task.turn\"") + && line.contains("conversation.id=") + && line.contains("thread.id=") + && line.contains("turn.id=") + && line.contains("model=") + && line.contains("mcp.tools.call{") && line.contains("otel.kind=\"client\"") && line.contains("rpc.system=\"jsonrpc\"") && line.contains("rpc.method=\"tools/call\"") @@ -205,7 +210,9 @@ async fn stdio_server_round_trip() -> anyhow::Result<()> { && line.contains("turn.id=") }) .map(|_| Ok(())) - .unwrap_or_else(|| Err("missing mcp.tools.call span with MCP fields".to_string())) + .unwrap_or_else(|| { + Err("missing mcp.tools.call span nested under session_task.turn".to_string()) + }) }); server.verify().await;