Skip to main content

codex_relay/
types.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4// ── Responses API (inbound from Codex CLI) ──────────────────────────────────
5
6#[derive(Debug, Deserialize)]
7pub struct ResponsesRequest {
8    pub model: String,
9    pub input: ResponsesInput,
10    #[serde(default)]
11    pub previous_response_id: Option<String>,
12    #[serde(default)]
13    pub tools: Vec<Value>,
14    #[serde(default)]
15    pub stream: bool,
16    #[serde(default)]
17    pub temperature: Option<f64>,
18    #[serde(default)]
19    pub max_output_tokens: Option<u32>,
20    /// Responses API system prompt field (some clients use `system`, others `instructions`)
21    #[serde(default)]
22    pub system: Option<String>,
23    #[serde(default)]
24    pub instructions: Option<String>,
25}
26
27#[derive(Debug, Deserialize)]
28#[serde(untagged)]
29pub enum ResponsesInput {
30    Text(String),
31    /// Each item may be a user/assistant message OR a function_call_output result.
32    /// Using Value here lets us handle both without a brittle fixed schema.
33    Messages(Vec<Value>),
34}
35
36#[derive(Debug, Deserialize, Clone, Serialize)]
37pub struct ContentPart {
38    #[serde(rename = "type")]
39    pub kind: String,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub text: Option<String>,
42}
43
44#[derive(Debug, Serialize)]
45pub struct ResponsesResponse {
46    pub id: String,
47    pub object: &'static str,
48    pub model: String,
49    pub output: Vec<ResponsesOutputItem>,
50    pub usage: ResponsesUsage,
51}
52
53#[derive(Debug, Serialize)]
54pub struct ResponsesOutputItem {
55    #[serde(rename = "type")]
56    pub kind: String,
57    pub role: String,
58    pub content: Vec<ContentPart>,
59}
60
61#[derive(Debug, Serialize, Default)]
62pub struct ResponsesUsage {
63    pub input_tokens: u32,
64    pub output_tokens: u32,
65    pub total_tokens: u32,
66}
67
68// ── Chat Completions (outbound to provider) ──────────────────────────────────
69
70#[derive(Debug, Serialize)]
71pub struct ChatRequest {
72    pub model: String,
73    pub messages: Vec<ChatMessage>,
74    #[serde(skip_serializing_if = "Vec::is_empty")]
75    pub tools: Vec<Value>,
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub temperature: Option<f64>,
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub max_tokens: Option<u32>,
80    pub stream: bool,
81}
82
83#[derive(Debug, Serialize, Deserialize, Clone)]
84pub struct ChatMessage {
85    pub role: String,
86    pub content: Option<String>,
87    /// Reasoning/thinking content emitted by models like kimi-k2.6.
88    /// Must be round-tripped back when replaying tool call history.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub reasoning_content: Option<String>,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub tool_calls: Option<Vec<Value>>,
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub tool_call_id: Option<String>,
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub name: Option<String>,
97}
98
99#[derive(Debug, Deserialize)]
100pub struct ChatResponse {
101    pub choices: Vec<ChatChoice>,
102    #[serde(default)]
103    pub usage: Option<ChatUsage>,
104}
105
106#[derive(Debug, Deserialize)]
107pub struct ChatChoice {
108    pub message: ChatMessage,
109}
110
111#[derive(Debug, Deserialize)]
112pub struct ChatUsage {
113    pub prompt_tokens: u32,
114    pub completion_tokens: u32,
115    pub total_tokens: u32,
116}
117
118// ── SSE streaming types ───────────────────────────────────────────────────────
119
120#[derive(Debug, Deserialize)]
121pub struct ChatStreamChunk {
122    pub choices: Vec<ChatStreamChoice>,
123    #[serde(default)]
124    #[allow(dead_code)]
125    pub usage: Option<ChatUsage>,
126}
127
128#[derive(Debug, Deserialize)]
129pub struct ChatStreamChoice {
130    pub delta: ChatDelta,
131    #[allow(dead_code)]
132    pub finish_reason: Option<String>,
133}
134
135#[derive(Debug, Deserialize, Default)]
136pub struct ChatDelta {
137    #[allow(dead_code)]
138    pub role: Option<String>,
139    pub content: Option<String>,
140    #[serde(default)]
141    pub reasoning_content: Option<String>,
142    #[serde(default)]
143    pub tool_calls: Option<Vec<DeltaToolCall>>,
144}
145
146#[derive(Debug, Deserialize, Default)]
147pub struct DeltaToolCall {
148    pub index: usize,
149    #[serde(default)]
150    pub id: Option<String>,
151    #[serde(default)]
152    pub function: Option<DeltaFunction>,
153}
154
155#[derive(Debug, Deserialize, Default)]
156pub struct DeltaFunction {
157    #[serde(default)]
158    pub name: Option<String>,
159    #[serde(default)]
160    pub arguments: Option<String>,
161}