mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +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:
committed by
copyberry
parent
75388bf321
commit
48e22a5fa0
@@ -463,6 +463,7 @@ fn host_to_client_v1_variants_are_pinned() {
|
||||
request_id(/*value*/ 3),
|
||||
HostResponse::WaitCompleted {
|
||||
outcome: WireWaitOutcome::LiveCell(WireRuntimeResponse::Yielded {
|
||||
code_mode_host_duration_ns: 0,
|
||||
cell_id: cell_id("cell-1"),
|
||||
content_items: content_items(),
|
||||
}),
|
||||
@@ -474,6 +475,7 @@ fn host_to_client_v1_variants_are_pinned() {
|
||||
"Yielded": {
|
||||
"cell_id": "cell-1",
|
||||
"content_items": content_items_json(),
|
||||
"code_mode_host_duration_ns": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -483,6 +485,7 @@ fn host_to_client_v1_variants_are_pinned() {
|
||||
request_id(/*value*/ 4),
|
||||
HostResponse::WaitCompleted {
|
||||
outcome: WireWaitOutcome::MissingCell(WireRuntimeResponse::Result {
|
||||
code_mode_host_duration_ns: 0,
|
||||
cell_id: cell_id("missing-cell"),
|
||||
content_items: Vec::new(),
|
||||
error_text: Some("cell not found".to_string()),
|
||||
@@ -496,6 +499,7 @@ fn host_to_client_v1_variants_are_pinned() {
|
||||
"cell_id": "missing-cell",
|
||||
"content_items": [],
|
||||
"error_text": "cell not found",
|
||||
"code_mode_host_duration_ns": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -540,6 +544,7 @@ fn host_to_client_v1_variants_are_pinned() {
|
||||
id: request_id(/*value*/ 7),
|
||||
result: WireResult::Ok {
|
||||
value: WireRuntimeResponse::Terminated {
|
||||
code_mode_host_duration_ns: 0,
|
||||
cell_id: cell_id("cell-1"),
|
||||
content_items: Vec::new(),
|
||||
},
|
||||
@@ -551,7 +556,11 @@ fn host_to_client_v1_variants_are_pinned() {
|
||||
"result": {
|
||||
"status": "ok",
|
||||
"value": {
|
||||
"Terminated": { "cell_id": "cell-1", "content_items": [] },
|
||||
"Terminated": {
|
||||
"cell_id": "cell-1",
|
||||
"content_items": [],
|
||||
"code_mode_host_duration_ns": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -798,6 +807,7 @@ fn every_nested_v1_object_rejects_unknown_fields() {
|
||||
"Yielded": {
|
||||
"cell_id": "cell-1",
|
||||
"content_items": [],
|
||||
"code_mode_host_duration_ns": 0,
|
||||
"unexpected": true,
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::num::TryFromIntError;
|
||||
use std::time::Duration;
|
||||
|
||||
use codex_protocol::ToolName;
|
||||
use serde::Deserialize;
|
||||
@@ -12,6 +13,7 @@ use crate::CodeModeToolKind;
|
||||
use crate::ExecuteRequest;
|
||||
use crate::FunctionCallOutputContentItem;
|
||||
use crate::ImageDetail;
|
||||
use crate::MissingCodeModeHostDuration;
|
||||
use crate::RuntimeResponse;
|
||||
use crate::ToolDefinition;
|
||||
use crate::WaitOutcome;
|
||||
@@ -312,51 +314,81 @@ impl From<WireContentItem> for FunctionCallOutputContentItem {
|
||||
}
|
||||
|
||||
/// Runtime output returned over the V1 host connection.
|
||||
///
|
||||
/// Host time is required and covers this request, not the cell lifetime. The
|
||||
/// app-server and host run at the same version; no negotiation is needed.
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum WireRuntimeResponse {
|
||||
Yielded {
|
||||
cell_id: WireCellId,
|
||||
content_items: Vec<WireContentItem>,
|
||||
code_mode_host_duration_ns: u64,
|
||||
},
|
||||
Terminated {
|
||||
cell_id: WireCellId,
|
||||
content_items: Vec<WireContentItem>,
|
||||
code_mode_host_duration_ns: u64,
|
||||
},
|
||||
Result {
|
||||
cell_id: WireCellId,
|
||||
content_items: Vec<WireContentItem>,
|
||||
error_text: Option<String>,
|
||||
code_mode_host_duration_ns: u64,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<RuntimeResponse> for WireRuntimeResponse {
|
||||
fn from(value: RuntimeResponse) -> Self {
|
||||
match value {
|
||||
impl TryFrom<RuntimeResponse> for WireRuntimeResponse {
|
||||
type Error = MissingCodeModeHostDuration;
|
||||
|
||||
/// Preserves the response's timing; the host handler must record it first.
|
||||
fn try_from(value: RuntimeResponse) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
RuntimeResponse::Yielded {
|
||||
cell_id,
|
||||
content_items,
|
||||
} => Self::Yielded {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
},
|
||||
code_mode_host_duration,
|
||||
} => {
|
||||
let code_mode_host_duration =
|
||||
code_mode_host_duration.ok_or(MissingCodeModeHostDuration)?;
|
||||
Self::Yielded {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
code_mode_host_duration_ns: u64::try_from(code_mode_host_duration.as_nanos())
|
||||
.unwrap_or(u64::MAX),
|
||||
}
|
||||
}
|
||||
RuntimeResponse::Terminated {
|
||||
cell_id,
|
||||
content_items,
|
||||
} => Self::Terminated {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
},
|
||||
code_mode_host_duration,
|
||||
} => {
|
||||
let code_mode_host_duration =
|
||||
code_mode_host_duration.ok_or(MissingCodeModeHostDuration)?;
|
||||
Self::Terminated {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
code_mode_host_duration_ns: u64::try_from(code_mode_host_duration.as_nanos())
|
||||
.unwrap_or(u64::MAX),
|
||||
}
|
||||
}
|
||||
RuntimeResponse::Result {
|
||||
cell_id,
|
||||
content_items,
|
||||
error_text,
|
||||
} => Self::Result {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
error_text,
|
||||
},
|
||||
}
|
||||
code_mode_host_duration,
|
||||
} => {
|
||||
let code_mode_host_duration =
|
||||
code_mode_host_duration.ok_or(MissingCodeModeHostDuration)?;
|
||||
Self::Result {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
error_text,
|
||||
code_mode_host_duration_ns: u64::try_from(code_mode_host_duration.as_nanos())
|
||||
.unwrap_or(u64::MAX),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,25 +398,31 @@ impl From<WireRuntimeResponse> for RuntimeResponse {
|
||||
WireRuntimeResponse::Yielded {
|
||||
cell_id,
|
||||
content_items,
|
||||
code_mode_host_duration_ns,
|
||||
} => Self::Yielded {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
code_mode_host_duration: Some(Duration::from_nanos(code_mode_host_duration_ns)),
|
||||
},
|
||||
WireRuntimeResponse::Terminated {
|
||||
cell_id,
|
||||
content_items,
|
||||
code_mode_host_duration_ns,
|
||||
} => Self::Terminated {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
code_mode_host_duration: Some(Duration::from_nanos(code_mode_host_duration_ns)),
|
||||
},
|
||||
WireRuntimeResponse::Result {
|
||||
cell_id,
|
||||
content_items,
|
||||
error_text,
|
||||
code_mode_host_duration_ns,
|
||||
} => Self::Result {
|
||||
cell_id: cell_id.into(),
|
||||
content_items: content_items.into_iter().map(Into::into).collect(),
|
||||
error_text,
|
||||
code_mode_host_duration: Some(Duration::from_nanos(code_mode_host_duration_ns)),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -398,12 +436,14 @@ pub enum WireWaitOutcome {
|
||||
MissingCell(WireRuntimeResponse),
|
||||
}
|
||||
|
||||
impl From<WaitOutcome> for WireWaitOutcome {
|
||||
fn from(value: WaitOutcome) -> Self {
|
||||
match value {
|
||||
WaitOutcome::LiveCell(response) => Self::LiveCell(response.into()),
|
||||
WaitOutcome::MissingCell(response) => Self::MissingCell(response.into()),
|
||||
}
|
||||
impl TryFrom<WaitOutcome> for WireWaitOutcome {
|
||||
type Error = MissingCodeModeHostDuration;
|
||||
|
||||
fn try_from(value: WaitOutcome) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
WaitOutcome::LiveCell(response) => Self::LiveCell(response.try_into()?),
|
||||
WaitOutcome::MissingCell(response) => Self::MissingCell(response.try_into()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user