1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum ThinkingLevel {
9 Off,
11 Minimal,
13 Low,
15 Medium,
17 High,
19 XHigh,
21}
22
23impl Default for ThinkingLevel {
24 fn default() -> Self {
25 ThinkingLevel::Off
26 }
27}
28
29impl std::fmt::Display for ThinkingLevel {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 ThinkingLevel::Off => write!(f, "off"),
33 ThinkingLevel::Minimal => write!(f, "minimal"),
34 ThinkingLevel::Low => write!(f, "low"),
35 ThinkingLevel::Medium => write!(f, "medium"),
36 ThinkingLevel::High => write!(f, "high"),
37 ThinkingLevel::XHigh => write!(f, "xhigh"),
38 }
39 }
40}
41
42impl From<&str> for ThinkingLevel {
43 fn from(s: &str) -> Self {
44 match s.to_lowercase().as_str() {
45 "off" => ThinkingLevel::Off,
46 "minimal" => ThinkingLevel::Minimal,
47 "low" => ThinkingLevel::Low,
48 "medium" => ThinkingLevel::Medium,
49 "high" => ThinkingLevel::High,
50 "xhigh" => ThinkingLevel::XHigh,
51 _ => ThinkingLevel::Off,
52 }
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct ThinkingConfig {
59 pub level: ThinkingLevel,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub budget_tokens: Option<u32>,
64}
65
66impl Default for ThinkingConfig {
67 fn default() -> Self {
68 Self {
69 level: ThinkingLevel::Off,
70 budget_tokens: None,
71 }
72 }
73}
74
75impl ThinkingConfig {
76 pub fn new(level: ThinkingLevel) -> Self {
78 Self {
79 level,
80 budget_tokens: None,
81 }
82 }
83
84 pub fn with_budget(level: ThinkingLevel, budget_tokens: u32) -> Self {
86 Self {
87 level,
88 budget_tokens: Some(budget_tokens),
89 }
90 }
91
92 pub fn default_budget(level: ThinkingLevel) -> u32 {
94 match level {
95 ThinkingLevel::Off => 0,
96 ThinkingLevel::Minimal => 128,
97 ThinkingLevel::Low => 512,
98 ThinkingLevel::Medium => 1024,
99 ThinkingLevel::High => 2048,
100 ThinkingLevel::XHigh => 4096,
101 }
102 }
103}
104
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
107pub struct OpenAIThinkingOptions {
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub reasoning_effort: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub reasoning_summary: Option<String>,
114}
115
116impl OpenAIThinkingOptions {
117 pub fn from_level(level: ThinkingLevel) -> Self {
119 let effort = match level {
120 ThinkingLevel::Off => None,
121 ThinkingLevel::Minimal => Some("minimal".to_string()),
122 ThinkingLevel::Low => Some("low".to_string()),
123 ThinkingLevel::Medium => Some("medium".to_string()),
124 ThinkingLevel::High => Some("high".to_string()),
125 ThinkingLevel::XHigh => Some("xhigh".to_string()),
126 };
127
128 Self {
129 reasoning_effort: effort,
130 reasoning_summary: None,
131 }
132 }
133}
134
135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
137pub struct AnthropicThinkingOptions {
138 pub thinking_enabled: bool,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub budget_tokens: Option<u32>,
143 #[serde(default)]
145 pub adaptive: bool,
146}
147
148impl AnthropicThinkingOptions {
149 pub fn from_config(config: &ThinkingConfig) -> Self {
151 Self {
152 thinking_enabled: config.level != ThinkingLevel::Off,
153 budget_tokens: config.budget_tokens.or_else(|| {
154 if config.level == ThinkingLevel::Off {
155 None
156 } else {
157 Some(ThinkingConfig::default_budget(config.level))
158 }
159 }),
160 adaptive: false,
161 }
162 }
163
164 pub fn adaptive(budget_tokens: Option<u32>) -> Self {
166 Self {
167 thinking_enabled: true,
168 budget_tokens,
169 adaptive: true,
170 }
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
176pub struct GoogleThinkingOptions {
177 pub enabled: bool,
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub budget_tokens: Option<u32>,
182}
183
184impl GoogleThinkingOptions {
185 pub fn from_config(config: &ThinkingConfig) -> Self {
187 Self {
188 enabled: config.level != ThinkingLevel::Off,
189 budget_tokens: config.budget_tokens,
190 }
191 }
192}