1use std::{
2 fmt::{Debug, Formatter},
3 time::Duration,
4};
5
6use serde_json::Value;
7
8use crate::error::{Error, ErrorKind, Result};
9
10#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
12pub enum ReasoningEffort {
13 None,
15 Minimal,
17 Low,
19 Medium,
21 High,
23 #[default]
25 XHigh,
26 Max,
28}
29
30impl ReasoningEffort {
31 pub const fn as_str(self) -> &'static str {
33 match self {
34 Self::None => "none",
35 Self::Minimal => "minimal",
36 Self::Low => "low",
37 Self::Medium => "medium",
38 Self::High => "high",
39 Self::XHigh => "xhigh",
40 Self::Max => "max",
41 }
42 }
43}
44
45#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
47pub enum ImageMediaType {
48 Png,
50 Jpeg,
52 Webp,
54 Gif,
56}
57
58impl ImageMediaType {
59 pub const fn mime_type(self) -> &'static str {
61 match self {
62 Self::Png => "image/png",
63 Self::Jpeg => "image/jpeg",
64 Self::Webp => "image/webp",
65 Self::Gif => "image/gif",
66 }
67 }
68}
69
70#[derive(Clone, Eq, PartialEq)]
72pub struct ImageInput {
73 media_type: ImageMediaType,
74 bytes: Vec<u8>,
75}
76
77impl ImageInput {
78 pub fn new(media_type: ImageMediaType, bytes: impl Into<Vec<u8>>) -> Result<Self> {
80 let bytes = bytes.into();
81 if bytes.is_empty() {
82 return Err(Error::new(
83 ErrorKind::InvalidInput,
84 "Codex image input must not be empty",
85 ));
86 }
87 Ok(Self { media_type, bytes })
88 }
89
90 pub const fn media_type(&self) -> ImageMediaType {
92 self.media_type
93 }
94
95 pub fn bytes(&self) -> &[u8] {
97 &self.bytes
98 }
99}
100
101impl Debug for ImageInput {
102 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
103 formatter
104 .debug_struct("ImageInput")
105 .field("media_type", &self.media_type)
106 .field("byte_len", &self.bytes.len())
107 .finish()
108 }
109}
110
111#[derive(Clone, Debug, PartialEq)]
113pub struct ImageTurnRequest {
114 pub prompt: String,
116 pub model: String,
118 pub images: Vec<ImageInput>,
120 pub reasoning_effort: ReasoningEffort,
122 pub timeout: Duration,
124}
125
126impl ImageTurnRequest {
127 pub fn new(
129 prompt: impl Into<String>,
130 model: impl Into<String>,
131 images: Vec<ImageInput>,
132 ) -> Self {
133 Self {
134 prompt: prompt.into(),
135 model: model.into(),
136 images,
137 reasoning_effort: ReasoningEffort::XHigh,
138 timeout: Duration::from_secs(30 * 60),
139 }
140 }
141}
142
143#[derive(Clone, Debug, PartialEq)]
145pub struct DynamicTool {
146 pub name: String,
148 pub description: String,
150 pub input_schema: Value,
152}
153
154impl DynamicTool {
155 pub fn new(
157 name: impl Into<String>,
158 description: impl Into<String>,
159 input_schema: Value,
160 ) -> Self {
161 Self {
162 name: name.into(),
163 description: description.into(),
164 input_schema,
165 }
166 }
167}
168
169#[derive(Clone, Debug, PartialEq)]
171pub struct AgentRequest {
172 pub input: String,
174 pub model: String,
176 pub reasoning_effort: ReasoningEffort,
178 pub previous_thread_id: Option<String>,
180 pub tools: Vec<DynamicTool>,
182 pub ephemeral: bool,
184 pub timeout: Duration,
186}
187
188impl AgentRequest {
189 pub fn new(input: impl Into<String>, model: impl Into<String>) -> Self {
191 Self {
192 input: input.into(),
193 model: model.into(),
194 reasoning_effort: ReasoningEffort::XHigh,
195 previous_thread_id: None,
196 tools: Vec::new(),
197 ephemeral: false,
198 timeout: Duration::from_secs(30 * 60),
199 }
200 }
201}
202
203#[derive(Clone, Debug, PartialEq)]
205pub struct DynamicToolCall {
206 pub call_id: String,
208 pub tool: String,
210 pub arguments: Value,
212}
213
214#[derive(Clone, Debug, Eq, PartialEq)]
216pub struct ToolResult {
217 pub success: bool,
219 pub text: String,
221}
222
223impl ToolResult {
224 pub fn success(text: impl Into<String>) -> Self {
226 Self {
227 success: true,
228 text: text.into(),
229 }
230 }
231
232 pub fn failure(text: impl Into<String>) -> Self {
234 Self {
235 success: false,
236 text: text.into(),
237 }
238 }
239}
240
241#[derive(Clone, Debug, Default, Eq, PartialEq)]
243pub struct TokenUsage {
244 pub input_tokens: u64,
246 pub output_tokens: u64,
248 pub cached_input_tokens: u64,
250 pub reasoning_output_tokens: u64,
252 pub last_input_tokens: Option<u64>,
254 pub last_output_tokens: Option<u64>,
256}
257
258#[derive(Clone, Debug, Eq, PartialEq)]
260pub struct CompletedTurn {
261 pub thread_id: String,
263 pub turn_id: String,
265 pub answer: String,
267 pub usage: Option<TokenUsage>,
269}
270
271#[derive(Clone, Debug, PartialEq)]
273pub enum AgentEvent {
274 ProviderInput(String),
276 UsageUpdated(TokenUsage),
281 ToolCall(DynamicToolCall),
283 Completed(CompletedTurn),
285}