diff --git a/codex-rs/core/src/responses_retry.rs b/codex-rs/core/src/responses_retry.rs index 048a68bfc9..6a4214609c 100644 --- a/codex-rs/core/src/responses_retry.rs +++ b/codex-rs/core/src/responses_retry.rs @@ -54,6 +54,7 @@ pub(crate) struct ExhaustedResponseRetry { /// Returns `Ok(())` when the caller should retry the request loop, or the original error when /// it is terminal or the retry budget is exhausted. +#[tracing::instrument(level = "trace", skip_all, fields(request = ?request))] pub(crate) async fn handle_response_stream_error( retry_state: &mut ResponsesStreamRetryState, max_retries: u64, diff --git a/codex-rs/core/src/session/startup_prewarm.rs b/codex-rs/core/src/session/startup_prewarm.rs index 554e69e178..31dcf07cf8 100644 --- a/codex-rs/core/src/session/startup_prewarm.rs +++ b/codex-rs/core/src/session/startup_prewarm.rs @@ -286,6 +286,7 @@ impl Session { )); } + #[tracing::instrument(level = "trace", skip_all)] pub(crate) async fn consume_startup_prewarm_for_regular_turn( &self, cancellation_token: &CancellationToken, diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index 65cbd64a18..6f2e622367 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::collections::HashSet; use std::sync::Arc; use std::sync::atomic::Ordering; +use std::time::Instant; use crate::client::ModelClientSession; use crate::client_common::Prompt; @@ -2418,6 +2419,7 @@ async fn emit_streamed_assistant_text_delta( } /// Flush buffered assistant text parser state when an assistant message item ends. +#[instrument(level = "trace", skip_all)] async fn flush_assistant_text_segments_for_item( sess: &Session, turn_context: &TurnContext, @@ -2430,6 +2432,7 @@ async fn flush_assistant_text_segments_for_item( } /// Flush any remaining buffered assistant text parser state at response completion. +#[instrument(level = "trace", skip_all)] async fn flush_assistant_text_segments_all( sess: &Session, turn_context: &TurnContext, @@ -2815,14 +2818,21 @@ async fn try_run_sampling_request( gen_ai.usage.output_tokens = field::Empty, codex.usage.reasoning_output_tokens = field::Empty, codex.usage.total_tokens = field::Empty, + codex.response.receive_wait_ms = field::Empty, ); + let receive_started = Instant::now(); let event = stream .next() .instrument(trace_span!(parent: &handle_responses, "receiving")) .or_cancel(&preempt) .or_cancel(&cancellation_token) .await; + // Split the existing iteration span without adding another span per streamed delta. + handle_responses.record( + "codex.response.receive_wait_ms", + receive_started.elapsed().as_secs_f64() * 1000.0, + ); // Account for an already-received terminal error even if cancellation raced it. // Cancellation still stops ordinary stream events before they can run tools. let event = match event { diff --git a/codex-rs/core/src/tasks/lifecycle.rs b/codex-rs/core/src/tasks/lifecycle.rs index 07a2c850a8..9fab93cd10 100644 --- a/codex-rs/core/src/tasks/lifecycle.rs +++ b/codex-rs/core/src/tasks/lifecycle.rs @@ -13,6 +13,7 @@ use crate::session::session::Session; use crate::session::turn_context::TurnContext; impl Session { + #[tracing::instrument(level = "trace", skip_all, fields(turn_id = %turn_context.sub_id, phase = ?phase))] pub(super) async fn emit_turn_start_lifecycle( self: &Arc, turn_context: &TurnContext,