mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(otel, core): record turn TTFT and TTFM metrics in codex-core (#13630)
### Summary This adds turn-level latency metrics for the first model output and the first completed agent message. - `codex.turn.ttft.duration_ms` starts at turn start and records on the first output signal we see from the model. That includes normal assistant text, reasoning deltas, and non-text outputs like tool-call items. - `codex.turn.ttfm.duration_ms` also starts at turn start, but it records when the first agent message finishes streaming rather than when its first delta arrives. ### Implementation notes The timing is tracked in codex-core, not app-server, so the definition stays consistent across CLI, TUI, and app-server clients. I reused the existing turn lifecycle boundary that already drives `codex.turn.e2e_duration_ms`, stored the turn start timestamp in turn state, and record each metric once per turn. I also wired the new metric names into the OTEL runtime metrics summary so they show up in the same in-memory/debug snapshot path as the existing timing metrics.
This commit is contained in:
committed by
GitHub
Unverified
parent
6c98a59dbd
commit
3449e00bc9
@@ -290,6 +290,9 @@ use crate::tools::sandboxing::ApprovalStore;
|
||||
use crate::tools::spec::ToolsConfig;
|
||||
use crate::tools::spec::ToolsConfigParams;
|
||||
use crate::turn_diff_tracker::TurnDiffTracker;
|
||||
use crate::turn_timing::TurnTimingState;
|
||||
use crate::turn_timing::record_turn_ttfm_metric;
|
||||
use crate::turn_timing::record_turn_ttft_metric;
|
||||
use crate::unified_exec::UnifiedExecProcessManager;
|
||||
use crate::util::backoff;
|
||||
use crate::windows_sandbox::WindowsSandboxLevelExt;
|
||||
@@ -694,6 +697,7 @@ pub(crate) struct TurnContext {
|
||||
pub(crate) dynamic_tools: Vec<DynamicToolSpec>,
|
||||
pub(crate) turn_metadata_state: Arc<TurnMetadataState>,
|
||||
pub(crate) turn_skills: TurnSkillsContext,
|
||||
pub(crate) turn_timing_state: Arc<TurnTimingState>,
|
||||
}
|
||||
impl TurnContext {
|
||||
pub(crate) fn model_context_window(&self) -> Option<i64> {
|
||||
@@ -783,6 +787,7 @@ impl TurnContext {
|
||||
dynamic_tools: self.dynamic_tools.clone(),
|
||||
turn_metadata_state: self.turn_metadata_state.clone(),
|
||||
turn_skills: self.turn_skills.clone(),
|
||||
turn_timing_state: Arc::clone(&self.turn_timing_state),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,6 +1170,7 @@ impl Session {
|
||||
dynamic_tools: session_configuration.dynamic_tools.clone(),
|
||||
turn_metadata_state,
|
||||
turn_skills: TurnSkillsContext::new(skills_outcome),
|
||||
turn_timing_state: Arc::new(TurnTimingState::default()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2488,6 +2494,7 @@ impl Session {
|
||||
turn_context: &TurnContext,
|
||||
item: TurnItem,
|
||||
) {
|
||||
record_turn_ttfm_metric(turn_context, &item).await;
|
||||
self.send_event(
|
||||
turn_context,
|
||||
EventMsg::ItemCompleted(ItemCompletedEvent {
|
||||
@@ -4988,6 +4995,7 @@ async fn spawn_review_thread(
|
||||
truncation_policy: model_info.truncation_policy.into(),
|
||||
turn_metadata_state,
|
||||
turn_skills: TurnSkillsContext::new(parent_turn_context.turn_skills.outcome.clone()),
|
||||
turn_timing_state: Arc::new(TurnTimingState::default()),
|
||||
};
|
||||
|
||||
// Seed the child task with the review prompt as the initial user message.
|
||||
@@ -6583,6 +6591,7 @@ async fn try_run_sampling_request(
|
||||
sess.services
|
||||
.otel_manager
|
||||
.record_responses(&handle_responses, &event);
|
||||
record_turn_ttft_metric(&turn_context, &event).await;
|
||||
|
||||
match event {
|
||||
ResponseEvent::Created => {}
|
||||
|
||||
Reference in New Issue
Block a user