mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
Attribute turn metrics to the models used during the turn (#44656)
## Why Turn completion metrics used session-level telemetry, which could label usage with the wrong model after a model switch. A turn can also include compaction and responses from different models, so a single token total cannot attribute usage correctly. ## What changed - Accumulate token usage by model using each response's resolved step settings, and emit one histogram sample per model and token type per turn. - Preserve zero-valued samples when no usage is reported, without adding a sample for an unused selected model when only compaction ran. - Use turn telemetry for tool-call, memory, network-proxy, and running-process metrics. ## Testing Add regression tests for model switches, step-level model changes, compaction followed by a response or an aborted turn, and turns without responses. Verify repeated requests aggregate into one sample per model and earlier session usage is excluded. GitOrigin-RevId: 03ab1dcde7da0b16b3a500a9a05e4c86583ee585
This commit is contained in:
committed by
copyberry
parent
8570091e14
commit
c8a8295e79
@@ -3,6 +3,7 @@ mod auto_compact_window;
|
||||
mod service;
|
||||
mod session;
|
||||
mod turn;
|
||||
mod turn_token_usage;
|
||||
|
||||
pub(crate) use crate::tools::ExecutedToolCalls;
|
||||
pub(crate) use additional_context::AdditionalContextStore;
|
||||
@@ -18,3 +19,4 @@ pub(crate) use turn::PendingRequestPermissions;
|
||||
pub(crate) use turn::RunningTask;
|
||||
pub(crate) use turn::TaskKind;
|
||||
pub(crate) use turn::TurnState;
|
||||
pub(crate) use turn_token_usage::TurnTokenUsage;
|
||||
|
||||
@@ -17,6 +17,7 @@ use codex_sandboxing::policy_transforms::merge_permission_profiles;
|
||||
use rmcp::model::RequestId;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use super::TurnTokenUsage;
|
||||
use crate::agent::control::AgentExecutionGuard;
|
||||
use crate::mcp_tool_call::McpToolApprovalMetadata;
|
||||
use crate::session::TurnInputQueue;
|
||||
@@ -101,6 +102,7 @@ pub(crate) struct TurnState {
|
||||
pub(crate) tool_calls: u64,
|
||||
pub(crate) has_memory_citation: bool,
|
||||
pub(crate) token_usage_at_turn_start: TokenUsage,
|
||||
pub(crate) token_usage_by_model: TurnTokenUsage,
|
||||
/// The last step captured for execution or selected from a speculative fallback.
|
||||
/// Remains absent until a step is captured; standalone local compaction has no step.
|
||||
pub(crate) last_known_step_context: Option<Arc<StepContext>>,
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
//! Turn token metrics grouped by the model that actually produced each response.
|
||||
//! Multiple responses from one model contribute a single histogram sample per turn.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use codex_otel::SessionTelemetry;
|
||||
use codex_otel::TURN_TOKEN_USAGE_METRIC;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct TurnTokenUsage {
|
||||
by_model: BTreeMap<String, (SessionTelemetry, TokenUsage)>,
|
||||
}
|
||||
|
||||
impl TurnTokenUsage {
|
||||
pub(crate) fn record(&mut self, model: &str, telemetry: SessionTelemetry, usage: &TokenUsage) {
|
||||
let (_, total) = self
|
||||
.by_model
|
||||
.entry(model.to_owned())
|
||||
.or_insert_with(|| (telemetry, TokenUsage::default()));
|
||||
total.add_assign(usage);
|
||||
}
|
||||
|
||||
pub(crate) fn emit(self, fallback: &SessionTelemetry, tmp_mem: (&str, &str)) {
|
||||
let mut usage = self.by_model.into_values().collect::<Vec<_>>();
|
||||
// Preserve zero-valued completion samples for turns without reported usage.
|
||||
// Do not create a sample for the selected model if only compaction ran.
|
||||
if usage.is_empty() {
|
||||
usage.push((fallback.clone(), TokenUsage::default()));
|
||||
}
|
||||
for (telemetry, usage) in usage {
|
||||
for (token_type, value) in [
|
||||
("total", usage.total_tokens),
|
||||
("input", usage.input_tokens),
|
||||
("cached_input", usage.cached_input()),
|
||||
("cache_write_input", usage.cache_write_input_tokens),
|
||||
("output", usage.output_tokens),
|
||||
("reasoning_output", usage.reasoning_output_tokens),
|
||||
] {
|
||||
telemetry.histogram(
|
||||
TURN_TOKEN_USAGE_METRIC,
|
||||
value.max(0),
|
||||
&[("token_type", token_type), tmp_mem],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user