codex_rollout_trace/
code_cell.rs1use std::sync::Arc;
9
10use codex_code_mode::RuntimeResponse;
11use serde::Serialize;
12use tracing::warn;
13
14use crate::model::AgentThreadId;
15use crate::model::CodeCellRuntimeStatus;
16use crate::model::CodexTurnId;
17use crate::model::ModelVisibleCallId;
18use crate::payload::RawPayloadKind;
19use crate::payload::RawPayloadRef;
20use crate::raw_event::RawTraceEventContext;
21use crate::raw_event::RawTraceEventPayload;
22use crate::writer::TraceWriter;
23
24#[derive(Clone, Debug)]
26pub struct CodeCellTraceContext {
27 state: CodeCellTraceContextState,
28}
29
30#[derive(Clone, Debug)]
31enum CodeCellTraceContextState {
32 Disabled,
33 Enabled(EnabledCodeCellTraceContext),
34}
35
36#[derive(Clone, Debug)]
37struct EnabledCodeCellTraceContext {
38 writer: Arc<TraceWriter>,
39 thread_id: AgentThreadId,
40 codex_turn_id: CodexTurnId,
41 runtime_cell_id: String,
42}
43
44#[derive(Serialize)]
51struct CodeCellResponseTracePayload<'a> {
52 response: &'a RuntimeResponse,
53}
54
55impl CodeCellTraceContext {
56 pub(crate) fn disabled() -> Self {
58 Self {
59 state: CodeCellTraceContextState::Disabled,
60 }
61 }
62
63 pub(crate) fn enabled(
65 writer: Arc<TraceWriter>,
66 thread_id: impl Into<AgentThreadId>,
67 codex_turn_id: impl Into<CodexTurnId>,
68 runtime_cell_id: impl Into<String>,
69 ) -> Self {
70 Self {
71 state: CodeCellTraceContextState::Enabled(EnabledCodeCellTraceContext {
72 writer,
73 thread_id: thread_id.into(),
74 codex_turn_id: codex_turn_id.into(),
75 runtime_cell_id: runtime_cell_id.into(),
76 }),
77 }
78 }
79
80 pub fn record_started(
82 &self,
83 model_visible_call_id: impl Into<ModelVisibleCallId>,
84 source_js: impl Into<String>,
85 ) {
86 let CodeCellTraceContextState::Enabled(context) = &self.state else {
87 return;
88 };
89 append_with_context_best_effort(
90 context,
91 RawTraceEventPayload::CodeCellStarted {
92 runtime_cell_id: context.runtime_cell_id.clone(),
93 model_visible_call_id: model_visible_call_id.into(),
94 source_js: source_js.into(),
95 },
96 );
97 }
98
99 pub fn record_initial_response(&self, response: &RuntimeResponse) {
106 let CodeCellTraceContextState::Enabled(context) = &self.state else {
107 return;
108 };
109 append_with_context_best_effort(
110 context,
111 RawTraceEventPayload::CodeCellInitialResponse {
112 runtime_cell_id: context.runtime_cell_id.clone(),
113 status: code_cell_status_for_runtime_response(response),
114 response_payload: code_cell_response_payload(context, response),
115 },
116 );
117 }
118
119 pub fn record_ended(&self, response: &RuntimeResponse) {
121 let CodeCellTraceContextState::Enabled(context) = &self.state else {
122 return;
123 };
124 append_with_context_best_effort(
125 context,
126 RawTraceEventPayload::CodeCellEnded {
127 runtime_cell_id: context.runtime_cell_id.clone(),
128 status: code_cell_status_for_runtime_response(response),
129 response_payload: code_cell_response_payload(context, response),
130 },
131 );
132 }
133}
134
135fn code_cell_status_for_runtime_response(response: &RuntimeResponse) -> CodeCellRuntimeStatus {
136 match response {
137 RuntimeResponse::Yielded { .. } => CodeCellRuntimeStatus::Yielded,
138 RuntimeResponse::Terminated { .. } => CodeCellRuntimeStatus::Terminated,
139 RuntimeResponse::Result { error_text, .. } => {
140 if error_text.is_some() {
141 CodeCellRuntimeStatus::Failed
142 } else {
143 CodeCellRuntimeStatus::Completed
144 }
145 }
146 }
147}
148
149fn code_cell_response_payload(
150 context: &EnabledCodeCellTraceContext,
151 response: &RuntimeResponse,
152) -> Option<RawPayloadRef> {
153 write_json_payload_best_effort(
154 &context.writer,
155 RawPayloadKind::ToolResult,
156 &CodeCellResponseTracePayload { response },
157 )
158}
159
160fn write_json_payload_best_effort(
161 writer: &TraceWriter,
162 kind: RawPayloadKind,
163 payload: &impl Serialize,
164) -> Option<RawPayloadRef> {
165 match writer.write_json_payload(kind, payload) {
166 Ok(payload_ref) => Some(payload_ref),
167 Err(err) => {
168 warn!("failed to write rollout trace payload: {err:#}");
169 None
170 }
171 }
172}
173
174fn append_with_context_best_effort(
175 context: &EnabledCodeCellTraceContext,
176 payload: RawTraceEventPayload,
177) {
178 let event_context = RawTraceEventContext {
179 thread_id: Some(context.thread_id.clone()),
180 codex_turn_id: Some(context.codex_turn_id.clone()),
181 };
182 if let Err(err) = context.writer.append_with_context(event_context, payload) {
183 warn!("failed to append rollout trace event: {err:#}");
184 }
185}