mirror of
https://github.com/openai/codex.git
synced 2026-11-03 08:22:30 +00:00
Report code mode host request durations (#41452)
## Why Code mode wall time should measure the host operation itself, without including client-side response delays or idle time between requests. ## What changed - Measure each execute, wait, and terminate request in the code mode host. - Carry the duration through the stdio and gRPC protocols and use it for model-visible wall time. - Emit a structured `codex.code_mode.host_timing` event correlated with the conversation, turn, tool call, and cell. ## Testing - Cover successful and failed execution timing, delayed response reads, repeated waits, termination, and missing cells across stdio and gRPC. - Verify timing survives protocol serialization and is reflected in app-server model output and structured telemetry. GitOrigin-RevId: d24af30c3fc5820521b4beba1f9970714dad6482
This commit is contained in:
1 parent
75388bf321
commit
48e22a5fa0
34 files changed
+1398
-259
No files matched your search
@@ -109,6 +109,9 @@ impl CodeModeExecuteHandler {
|
||||
.initial_response()
|
||||
.await
|
||||
.map_err(FunctionCallError::RespondToModel)?;
|
||||
if let Some(code_mode_host_duration) = response.code_mode_host_duration() {
|
||||
telemetry.record_code_mode_host_duration(code_mode_host_duration);
|
||||
}
|
||||
// Record the raw runtime boundary. The model-visible custom-tool output
|
||||
// is produced by `handle_runtime_response` and later linked through
|
||||
// `CodeCell.output_item_ids` in the reduced trace.
|
||||
@@ -131,7 +134,10 @@ impl CodeModeExecuteHandler {
|
||||
});
|
||||
}
|
||||
exec.session.services.elicitations.wait_until_clear().await;
|
||||
handle_runtime_response(&exec, response, args.max_output_tokens, started_at)
|
||||
let wall_time = response
|
||||
.code_mode_host_duration()
|
||||
.unwrap_or_else(|| started_at.elapsed());
|
||||
handle_runtime_response(&exec, response, args.max_output_tokens, wall_time)
|
||||
.await
|
||||
.map_err(FunctionCallError::RespondToModel)
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ pub(super) async fn handle_runtime_response(
|
||||
exec: &ExecContext,
|
||||
response: RuntimeResponse,
|
||||
max_output_tokens: Option<usize>,
|
||||
started_at: std::time::Instant,
|
||||
wall_time: Duration,
|
||||
) -> Result<FunctionToolOutput, String> {
|
||||
let script_status = format_script_status(&response);
|
||||
|
||||
@@ -260,14 +260,14 @@ pub(super) async fn handle_runtime_response(
|
||||
let mut content_items = into_function_call_output_content_items(content_items);
|
||||
sanitize_runtime_image_detail(exec.turn.as_ref(), &mut content_items);
|
||||
content_items = truncate_code_mode_result(content_items, max_output_tokens);
|
||||
prepend_script_status(&mut content_items, &script_status, started_at.elapsed());
|
||||
prepend_script_status(&mut content_items, &script_status, wall_time);
|
||||
Ok(FunctionToolOutput::from_content(content_items, Some(true)))
|
||||
}
|
||||
RuntimeResponse::Terminated { content_items, .. } => {
|
||||
let mut content_items = into_function_call_output_content_items(content_items);
|
||||
sanitize_runtime_image_detail(exec.turn.as_ref(), &mut content_items);
|
||||
content_items = truncate_code_mode_result(content_items, max_output_tokens);
|
||||
prepend_script_status(&mut content_items, &script_status, started_at.elapsed());
|
||||
prepend_script_status(&mut content_items, &script_status, wall_time);
|
||||
Ok(FunctionToolOutput::from_content(content_items, Some(true)))
|
||||
}
|
||||
RuntimeResponse::Result {
|
||||
@@ -284,7 +284,7 @@ pub(super) async fn handle_runtime_response(
|
||||
});
|
||||
}
|
||||
content_items = truncate_code_mode_result(content_items, max_output_tokens);
|
||||
prepend_script_status(&mut content_items, &script_status, started_at.elapsed());
|
||||
prepend_script_status(&mut content_items, &script_status, wall_time);
|
||||
Ok(FunctionToolOutput::from_content(
|
||||
content_items,
|
||||
Some(success),
|
||||
|
||||
@@ -3,6 +3,7 @@ use codex_analytics::CodeModeToolCallFact;
|
||||
use codex_analytics::CodeModeToolCallStatus;
|
||||
use codex_analytics::TurnAnalyticsMetadata;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
pub(super) struct CodeModeToolCallGuard {
|
||||
analytics: AnalyticsEventsClient,
|
||||
@@ -45,6 +46,27 @@ impl CodeModeToolCallGuard {
|
||||
CodeModeToolCallStatus::Failed
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) fn record_code_mode_host_duration(&self, duration: Duration) {
|
||||
let Ok(code_mode_host_duration_ns) = u64::try_from(duration.as_nanos()) else {
|
||||
return;
|
||||
};
|
||||
// Bridge joins this record to the outer tool-completion event. Emit it
|
||||
// before the handler returns so consumers never need another timeout.
|
||||
tracing::info!(
|
||||
target: "codex_code_mode::timing",
|
||||
{
|
||||
event.name = "codex.code_mode.host_timing",
|
||||
conversation_id = %self.thread_id,
|
||||
turn_id = %self.turn_id,
|
||||
call_id = %self.call_id,
|
||||
cell_id = self.cell_id.as_deref(),
|
||||
tool_name = self.tool_name,
|
||||
code_mode_host_duration_ns,
|
||||
},
|
||||
"code-mode host operation completed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CodeModeToolCallGuard {
|
||||
|
||||
@@ -94,6 +94,7 @@ impl CodeModeWaitHandler {
|
||||
})?;
|
||||
let exec = ExecContext { session, turn };
|
||||
let started_at = std::time::Instant::now();
|
||||
telemetry.cell_id = Some(args.cell_id.clone());
|
||||
let cell_id = codex_code_mode::CellId::new(args.cell_id);
|
||||
let wait_response = if args.terminate {
|
||||
exec.session
|
||||
@@ -152,8 +153,14 @@ impl CodeModeWaitHandler {
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(code_mode_host_duration) = wait_response.code_mode_host_duration() {
|
||||
telemetry.record_code_mode_host_duration(code_mode_host_duration);
|
||||
}
|
||||
exec.session.services.elicitations.wait_until_clear().await;
|
||||
handle_runtime_response(&exec, wait_response.into(), args.max_tokens, started_at)
|
||||
let wall_time = wait_response
|
||||
.code_mode_host_duration()
|
||||
.unwrap_or_else(|| started_at.elapsed());
|
||||
handle_runtime_response(&exec, wait_response.into(), args.max_tokens, wall_time)
|
||||
.await
|
||||
.map_err(FunctionCallError::RespondToModel)
|
||||
.map(boxed_tool_output)
|
||||
|
||||
Reference in new issue
Block a user