[codex-analytics] add protocol-native turn timestamps (#16638)

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16638).
* #16870
* #16706
* #16659
* #16641
* #16640
* __->__ #16638
This commit is contained in:
rhan-oai
2026-04-06 16:22:59 -07:00
committed by GitHub
parent e88c2cf4d7
commit 756c45ec61
58 changed files with 1134 additions and 36 deletions

View File

@@ -1864,11 +1864,23 @@ pub struct ContextCompactedEvent;
pub struct TurnCompleteEvent {
pub turn_id: String,
pub last_agent_message: Option<String>,
/// Unix timestamp (in seconds) when the turn completed.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null", optional)]
pub completed_at: Option<i64>,
/// Duration between turn start and completion in milliseconds, if known.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null", optional)]
pub duration_ms: Option<i64>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
pub struct TurnStartedEvent {
pub turn_id: String,
/// Unix timestamp (in seconds) when the turn started.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null", optional)]
pub started_at: Option<i64>,
// TODO(aibrahim): make this not optional
pub model_context_window: Option<i64>,
#[serde(default)]
@@ -3375,6 +3387,14 @@ pub struct Chunk {
pub struct TurnAbortedEvent {
pub turn_id: Option<String>,
pub reason: TurnAbortReason,
/// Unix timestamp (in seconds) when the turn was aborted.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null", optional)]
pub completed_at: Option<i64>,
/// Duration between turn start and abort in milliseconds, if known.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null", optional)]
pub duration_ms: Option<i64>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
@@ -4543,7 +4563,9 @@ mod tests {
}))?;
match event {
EventMsg::TurnAborted(TurnAbortedEvent { turn_id, reason }) => {
EventMsg::TurnAborted(TurnAbortedEvent {
turn_id, reason, ..
}) => {
assert_eq!(turn_id, None);
assert_eq!(reason, TurnAbortReason::Interrupted);
}