use serde::Deserialize;
use super::ExtraFields;
#[derive(Debug, Clone, Deserialize)]
pub struct CodexLine {
#[serde(default)]
pub timestamp: Option<String>,
#[serde(flatten)]
pub record: CodexRecord,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CodexRecord {
SessionMeta {
payload: SessionMeta,
},
TurnContext {
payload: TurnContext,
},
ResponseItem {
payload: ResponseItem,
},
EventMsg {
payload: EventMsg,
},
Compacted {
#[serde(default)]
payload: serde_json::Value,
},
#[serde(other)]
Unknown,
}
impl CodexRecord {
pub fn tag(&self) -> Option<&'static str> {
Some(match self {
CodexRecord::SessionMeta { .. } => "session_meta",
CodexRecord::TurnContext { .. } => "turn_context",
CodexRecord::ResponseItem { .. } => "response_item",
CodexRecord::EventMsg { .. } => "event_msg",
CodexRecord::Compacted { .. } => "compacted",
CodexRecord::Unknown => return None,
})
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct SessionMeta {
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub cwd: Option<String>,
#[serde(default)]
pub base_instructions: Option<serde_json::Value>,
#[serde(default)]
pub model_provider: Option<String>,
#[serde(flatten)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Deserialize)]
pub struct TurnContext {
#[serde(default)]
pub model: Option<String>,
#[serde(default)]
pub cwd: Option<String>,
#[serde(flatten)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ResponseItem {
Message {
role: String,
#[serde(default)]
content: Vec<super::ContentBlock>,
#[serde(flatten)]
extra: ExtraFields,
},
FunctionCall {
name: String,
#[serde(default)]
arguments: String,
call_id: String,
#[serde(flatten)]
extra: ExtraFields,
},
FunctionCallOutput {
call_id: String,
#[serde(default)]
output: serde_json::Value,
#[serde(flatten)]
extra: ExtraFields,
},
CustomToolCall {
#[serde(default)]
name: Option<String>,
#[serde(default)]
input: serde_json::Value,
#[serde(default)]
call_id: Option<String>,
#[serde(flatten)]
extra: ExtraFields,
},
CustomToolCallOutput {
#[serde(default)]
call_id: Option<String>,
#[serde(default)]
output: serde_json::Value,
#[serde(flatten)]
extra: ExtraFields,
},
Reasoning {
#[serde(flatten)]
extra: ExtraFields,
},
WebSearchCall {
#[serde(flatten)]
extra: ExtraFields,
},
ToolSearchCall {
#[serde(flatten)]
extra: ExtraFields,
},
ToolSearchOutput {
#[serde(flatten)]
extra: ExtraFields,
},
ImageGenerationCall {
#[serde(flatten)]
extra: ExtraFields,
},
#[serde(other)]
Unknown,
}
impl ResponseItem {
pub fn tag(&self) -> Option<&'static str> {
Some(match self {
ResponseItem::Message { .. } => "message",
ResponseItem::FunctionCall { .. } => "function_call",
ResponseItem::FunctionCallOutput { .. } => "function_call_output",
ResponseItem::CustomToolCall { .. } => "custom_tool_call",
ResponseItem::CustomToolCallOutput { .. } => "custom_tool_call_output",
ResponseItem::Reasoning { .. } => "reasoning",
ResponseItem::WebSearchCall { .. } => "web_search_call",
ResponseItem::ToolSearchCall { .. } => "tool_search_call",
ResponseItem::ToolSearchOutput { .. } => "tool_search_output",
ResponseItem::ImageGenerationCall { .. } => "image_generation_call",
ResponseItem::Unknown => return None,
})
}
pub fn is_normalized(&self) -> bool {
matches!(
self,
ResponseItem::Message { .. }
| ResponseItem::FunctionCall { .. }
| ResponseItem::FunctionCallOutput { .. }
| ResponseItem::CustomToolCall { .. }
| ResponseItem::CustomToolCallOutput { .. }
| ResponseItem::ToolSearchCall { .. }
| ResponseItem::ToolSearchOutput { .. }
| ResponseItem::WebSearchCall { .. }
| ResponseItem::ImageGenerationCall { .. }
)
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct EventMsg {
#[serde(rename = "type", default)]
pub kind: Option<String>,
#[serde(flatten)]
pub extra: ExtraFields,
}