1use crate::{CacheRetention, ThinkingLevel};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::fmt;
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
15pub struct ProviderOptions {
16 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub anthropic: Option<AnthropicOptions>,
19
20 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub openai: Option<OpenAiOptions>,
23
24 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub google: Option<GoogleOptions>,
27
28 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub openai_compatible: Option<OpenAiCompatibleOptions>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct AnthropicOptions {
36 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub thinking_type: Option<String>,
41
42 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub thinking_budget: Option<usize>,
45
46 #[serde(default, skip_serializing_if = "Option::is_none")]
49 pub effort: Option<String>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct OpenAiOptions {
55 #[serde(default, skip_serializing_if = "Option::is_none")]
57 pub store: Option<bool>,
58
59 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub reasoning_effort: Option<String>,
62
63 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub reasoning_summary: Option<String>,
66
67 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub include_encrypted_reasoning: Option<bool>,
70
71 #[serde(default, skip_serializing_if = "Option::is_none")]
73 pub text_verbosity: Option<String>,
74
75 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub prompt_cache_key: Option<String>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct GoogleOptions {
83 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub include_thoughts: Option<bool>,
86
87 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub thinking_level: Option<String>,
90
91 #[serde(default, skip_serializing_if = "Option::is_none")]
93 pub thinking_budget: Option<usize>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct OpenAiCompatibleOptions {
99 #[serde(default, skip_serializing_if = "Option::is_none")]
101 pub reasoning_effort: Option<String>,
102
103 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub enable_thinking: Option<bool>,
106
107 #[serde(default, skip_serializing_if = "Option::is_none")]
109 pub cache_control: Option<String>,
110}
111
112#[derive(Clone, Default, Serialize, Deserialize)]
114pub struct StreamOptions {
115 #[serde(default)]
117 pub temperature: Option<f64>,
118
119 #[serde(default)]
121 pub max_tokens: Option<usize>,
122
123 #[serde(skip)]
126 pub api_key: Option<String>,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub cache_retention: Option<CacheRetention>,
131
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub session_id: Option<String>,
135
136 #[serde(default)]
138 pub headers: HashMap<String, String>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub thinking_level: Option<ThinkingLevel>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub thinking_budgets: Option<ThinkingBudgets>,
147
148 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub provider_options: Option<ProviderOptions>,
156}
157
158impl fmt::Debug for StreamOptions {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 f.debug_struct("StreamOptions")
161 .field("temperature", &self.temperature)
162 .field("max_tokens", &self.max_tokens)
163 .field("api_key", &self.api_key.as_ref().map(|_| "[REDACTED]"))
164 .field("cache_retention", &self.cache_retention)
165 .field("session_id", &self.session_id)
166 .field("headers", &self.headers)
167 .field("thinking_level", &self.thinking_level)
168 .field("thinking_budgets", &self.thinking_budgets)
169 .field("provider_options", &self.provider_options)
170 .finish()
171 }
172}
173
174impl StreamOptions {
175 pub fn new() -> Self {
177 Self::default()
178 }
179
180 pub fn temperature(mut self, temp: f64) -> Self {
182 self.temperature = Some(temp);
183 self
184 }
185
186 pub fn max_tokens(mut self, tokens: usize) -> Self {
188 self.max_tokens = Some(tokens);
189 self
190 }
191
192 pub fn api_key(mut self, key: impl Into<String>) -> Self {
194 self.api_key = Some(key.into());
195 self
196 }
197
198 pub fn cache_retention(mut self, retention: CacheRetention) -> Self {
200 self.cache_retention = Some(retention);
201 self
202 }
203
204 pub fn session_id(mut self, id: impl Into<String>) -> Self {
206 self.session_id = Some(id.into());
207 self
208 }
209
210 pub fn thinking_level(mut self, level: ThinkingLevel) -> Self {
212 self.thinking_level = Some(level);
213 self
214 }
215}
216
217#[derive(Debug, Clone, Default, Serialize, Deserialize)]
219pub struct ThinkingBudgets {
220 #[serde(default)]
221 pub minimal: Option<usize>,
222 #[serde(default)]
223 pub low: Option<usize>,
224 #[serde(default)]
225 pub medium: Option<usize>,
226 #[serde(default)]
227 pub high: Option<usize>,
228}
229
230impl ThinkingBudgets {
231 pub fn new() -> Self {
232 Self::default()
233 }
234
235 pub fn minimal(mut self, tokens: usize) -> Self {
236 self.minimal = Some(tokens);
237 self
238 }
239
240 pub fn low(mut self, tokens: usize) -> Self {
241 self.low = Some(tokens);
242 self
243 }
244
245 pub fn medium(mut self, tokens: usize) -> Self {
246 self.medium = Some(tokens);
247 self
248 }
249
250 pub fn high(mut self, tokens: usize) -> Self {
251 self.high = Some(tokens);
252 self
253 }
254}