Skip to main content

codex_rollout_trace/model/
conversation.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use crate::payload::RawPayloadId;
5
6use super::AgentPath;
7use super::AgentThreadId;
8use super::CodeCellId;
9use super::CodexTurnId;
10use super::CompactionId;
11use super::ConversationItemId;
12use super::EdgeId;
13use super::InferenceCallId;
14use super::ModelVisibleCallId;
15use super::ToolCallId;
16use super::session::ExecutionWindow;
17
18/// One logical transcript item or transcript boundary.
19///
20/// The reducer builds conversation items primarily from inference request and
21/// response payloads. Runtime objects can be listed in `produced_by`, but they
22/// must not rewrite what the item body says the model saw. Structural items,
23/// such as compaction markers, live in the same ordered list so conversation
24/// views can show where the live history changed.
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26pub struct ConversationItem {
27    pub item_id: ConversationItemId,
28    pub thread_id: AgentThreadId,
29    /// Runtime activation that first introduced this item locally, when known.
30    pub codex_turn_id: Option<CodexTurnId>,
31    pub first_seen_at_unix_ms: i64,
32    pub role: ConversationRole,
33    /// Codex channel for assistant/tool content, when the item is channel-specific.
34    pub channel: Option<ConversationChannel>,
35    pub kind: ConversationItemKind,
36    /// Routing metadata carried by a Responses `agent_message` item.
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    pub agent_message: Option<AgentMessageMetadata>,
39    pub body: ConversationBody,
40    /// Protocol/model `call_id` for function/custom tool call and output items.
41    pub call_id: Option<ModelVisibleCallId>,
42    /// Runtime or control-plane objects that caused this conversation item to exist.
43    pub produced_by: Vec<ProducerRef>,
44}
45
46/// Sender and destination identities attached to a model-visible agent message.
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48pub struct AgentMessageMetadata {
49    /// Agent path that authored the message.
50    pub author: AgentPath,
51    /// Agent path that received the message.
52    pub recipient: AgentPath,
53}
54
55/// Model-visible role assigned to a conversation item.
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
57#[serde(rename_all = "snake_case")]
58pub enum ConversationRole {
59    System,
60    Developer,
61    User,
62    Assistant,
63    Tool,
64}
65
66/// Codex channel for model-visible content.
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(rename_all = "snake_case")]
69pub enum ConversationChannel {
70    Analysis,
71    Commentary,
72    Final,
73    /// Remote compaction summaries are reintroduced as assistant summary-channel content.
74    Summary,
75}
76
77/// Responses item category after normalization into the reduced transcript.
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79#[serde(rename_all = "snake_case")]
80pub enum ConversationItemKind {
81    Message,
82    Reasoning,
83    FunctionCall,
84    FunctionCallOutput,
85    CustomToolCall,
86    CustomToolCallOutput,
87    /// Structural marker inserted where live history was replaced by compaction.
88    CompactionMarker,
89}
90
91/// Ordered content parts for a reduced conversation item.
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct ConversationBody {
94    /// Renderable model-visible parts. Raw payload refs are used when the bytes
95    /// are too large or too structured for the normal conversation path.
96    pub parts: Vec<ConversationPart>,
97}
98
99/// One model-visible part inside a conversation item.
100#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
101#[serde(rename_all = "snake_case", tag = "type")]
102pub enum ConversationPart {
103    Text {
104        text: String,
105    },
106    /// A model-provided summary of content whose full form may also be present.
107    ///
108    /// Reasoning summaries are not interchangeable with raw reasoning text:
109    /// both can be present in one payload, and replay/debug tooling needs to
110    /// preserve which representation the model actually returned.
111    Summary {
112        text: String,
113    },
114    /// Opaque model-visible content that is intentionally not decoded here.
115    ///
116    /// Reasoning can be carried as `encrypted_content` with no readable text.
117    /// Keeping that blob inline makes it part of item identity, unlike a raw
118    /// payload reference whose ID changes every time the same item is replayed
119    /// in a later inference request.
120    Encoded {
121        label: String,
122        value: String,
123    },
124    /// Small JSON-ish body represented by a summary plus a raw ref.
125    Json {
126        summary: String,
127        raw_payload_id: RawPayloadId,
128    },
129    Code {
130        language: String,
131        source: String,
132    },
133    /// Large or uncommon payload that should be lazy-loaded from details UI.
134    PayloadRef {
135        label: String,
136        raw_payload_id: RawPayloadId,
137    },
138}
139
140/// Explanation for where a conversation item came from.
141///
142/// This is deliberately plural at the call site: a function output can be both
143/// model-visible conversation and the product of a runtime tool call.
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145#[serde(rename_all = "snake_case", tag = "type")]
146pub enum ProducerRef {
147    UserInput,
148    Inference { inference_call_id: InferenceCallId },
149    Tool { tool_call_id: ToolCallId },
150    CodeCell { code_cell_id: CodeCellId },
151    InteractionEdge { edge_id: EdgeId },
152    Compaction { compaction_id: CompactionId },
153    Harness,
154}
155
156/// One outbound inference request and its response metadata.
157///
158/// Full upstream request/response bodies live behind raw payload refs. The
159/// request/response item ID lists are the reduced, model-visible snapshot.
160#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
161pub struct InferenceCall {
162    pub inference_call_id: InferenceCallId,
163    pub thread_id: AgentThreadId,
164    pub codex_turn_id: CodexTurnId,
165    pub execution: ExecutionWindow,
166    pub model: String,
167    pub provider_name: String,
168    /// Responses API response id, used by follow-up `previous_response_id` requests.
169    pub response_id: Option<String>,
170    /// Request id returned by HTTP/proxy/engine infrastructure.
171    pub upstream_request_id: Option<String>,
172    /// Complete ordered input snapshot sent with this request.
173    pub request_item_ids: Vec<ConversationItemId>,
174    /// Ordered output items produced by this response.
175    pub response_item_ids: Vec<ConversationItemId>,
176    /// Runtime tool calls whose model-visible call item came from this response.
177    pub tool_call_ids_started_by_response: Vec<ToolCallId>,
178    pub usage: Option<TokenUsage>,
179    pub raw_request_payload_id: RawPayloadId,
180    /// Full upstream response payload. `None` while running or after pre-stream failures.
181    pub raw_response_payload_id: Option<RawPayloadId>,
182}
183
184/// Token usage summary for one inference call.
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
186pub struct TokenUsage {
187    pub input_tokens: u64,
188    pub cached_input_tokens: u64,
189    #[serde(default)]
190    pub cache_write_input_tokens: u64,
191    pub output_tokens: u64,
192    pub reasoning_output_tokens: u64,
193}