1use super::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
4#[serde(rename_all = "kebab-case")]
5#[value(rename_all = "kebab-case")]
6pub enum BackendKind {
7 Auto,
8 #[serde(rename = "deepseek-chat")]
9 #[value(name = "deepseek-chat")]
10 DeepSeekChat,
11 FireworksChat,
12 #[serde(rename = "openai-responses")]
13 #[value(name = "openai-responses")]
14 OpenAiResponses,
15 #[serde(rename = "chatgpt-codex-responses")]
16 #[value(name = "chatgpt-codex-responses")]
17 ChatGptCodexResponses,
18}
19
20impl BackendKind {
21 pub fn as_str(self) -> &'static str {
22 match self {
23 Self::Auto => "auto",
24 Self::DeepSeekChat => "deepseek-chat",
25 Self::FireworksChat => "fireworks-chat",
26 Self::OpenAiResponses => "openai-responses",
27 Self::ChatGptCodexResponses => "chatgpt-codex-responses",
28 }
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub enum ReasoningEffort {
34 None,
35 Minimal,
36 Low,
37 Medium,
38 High,
39 Xhigh,
40 Custom(String),
42}
43
44impl ReasoningEffort {
45 pub fn as_str(&self) -> &str {
46 match self {
47 Self::None => "none",
48 Self::Minimal => "minimal",
49 Self::Low => "low",
50 Self::Medium => "medium",
51 Self::High => "high",
52 Self::Xhigh => "xhigh",
53 Self::Custom(s) => s.as_str(),
54 }
55 }
56}
57
58impl std::fmt::Display for ReasoningEffort {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 f.write_str(self.as_str())
61 }
62}
63
64impl std::str::FromStr for ReasoningEffort {
65 type Err = String;
66 fn from_str(s: &str) -> Result<Self, Self::Err> {
67 match s {
68 "none" => Ok(Self::None),
69 "minimal" => Ok(Self::Minimal),
70 "low" => Ok(Self::Low),
71 "medium" => Ok(Self::Medium),
72 "high" => Ok(Self::High),
73 "xhigh" => Ok(Self::Xhigh),
74 "" => Err("reasoning effort must not be empty".to_string()),
75 other => Ok(Self::Custom(other.to_string())),
76 }
77 }
78}
79
80impl serde::Serialize for ReasoningEffort {
81 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
82 serializer.serialize_str(self.as_str())
83 }
84}
85
86impl<'de> serde::Deserialize<'de> for ReasoningEffort {
87 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
88 let s = String::deserialize(deserializer)?;
89 s.parse().map_err(serde::de::Error::custom)
90 }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94#[serde(rename_all = "lowercase")]
95pub enum ReasoningSummary {
96 Auto,
97 Concise,
98 Detailed,
99}
100
101impl ReasoningSummary {
102 pub fn as_str(&self) -> &str {
103 match self {
104 Self::Auto => "auto",
105 Self::Concise => "concise",
106 Self::Detailed => "detailed",
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(rename_all = "snake_case")]
113pub enum ReasoningContext {
114 CurrentTurn,
115 AllTurns,
116}
117
118impl ReasoningContext {
119 pub fn as_str(&self) -> &str {
120 match self {
121 Self::CurrentTurn => "current_turn",
122 Self::AllTurns => "all_turns",
123 }
124 }
125}
126
127#[derive(Debug, Clone, Default)]
128pub struct ClientOverrides {
129 pub base_url: Option<String>,
130 pub model: Option<String>,
131 pub backend: Option<BackendKind>,
132 pub reasoning_effort: Option<ReasoningEffort>,
133 pub reasoning_summary: Option<ReasoningSummary>,
134 pub reasoning_context: Option<ReasoningContext>,
135 pub api_key_env: Option<String>,
136 pub api_key: Option<String>,
137}
138
139pub struct TextCompletion {
140 pub content: String,
141 pub usage: Usage,
142}
143
144#[derive(Debug, Clone)]
145pub struct AssistantTurn {
146 pub content: Option<String>,
147 pub reasoning_text: Option<String>,
148 pub reasoning_details: Option<Value>,
149 pub tool_calls: Option<Vec<ToolCall>>,
150}
151
152#[derive(Debug, Clone)]
153pub struct ModelTurnResponse {
154 pub assistant: AssistantTurn,
155 pub finish_reason: Option<String>,
156 pub usage: Usage,
157}