1use crate::config::types::{ReasoningEffortLevel, VerbosityLevel};
2use serde::{Deserialize, Serialize};
3use serde_json::{Value, json};
4use std::sync::Arc;
5
6use super::{Message, ToolDefinition};
7
8#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(rename_all = "snake_case")]
10pub enum PromptCacheProfile {
11 BudgetContinuation,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
15#[serde(rename_all = "snake_case")]
16pub enum AnthropicThinkingModeOverride {
17 #[default]
18 Inherit,
19 Disabled,
20 Adaptive,
21 ManualBudget(u32),
22}
23
24#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
25#[serde(rename_all = "snake_case")]
26pub enum AnthropicThinkingDisplayOverride {
27 #[default]
28 Inherit,
29 Summarized,
30 Omitted,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
34#[serde(rename_all = "snake_case")]
35pub enum AnthropicOptionalStringOverride {
36 #[default]
37 Inherit,
38 Omit,
39 Explicit(String),
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
43#[serde(rename_all = "snake_case")]
44pub enum AnthropicOptionalU32Override {
45 #[default]
46 Inherit,
47 Omit,
48 Explicit(u32),
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
52pub struct AnthropicRequestOverrides {
53 #[serde(default)]
54 pub thinking_mode: AnthropicThinkingModeOverride,
55 #[serde(default)]
56 pub thinking_display: AnthropicThinkingDisplayOverride,
57 #[serde(default)]
58 pub effort: AnthropicOptionalStringOverride,
59 #[serde(default)]
60 pub task_budget_tokens: AnthropicOptionalU32Override,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, Default)]
65
66pub struct LLMRequest {
67 pub messages: Vec<Message>,
68 pub system_prompt: Option<Arc<String>>,
69 pub tools: Option<Arc<Vec<ToolDefinition>>>,
70 pub model: String,
71 pub max_tokens: Option<u32>,
72 pub temperature: Option<f32>,
73 pub stream: bool,
74
75 pub output_format: Option<Value>,
78
79 pub tool_choice: Option<ToolChoice>,
82
83 pub parallel_tool_calls: Option<bool>,
85
86 pub parallel_tool_config: Option<Box<ParallelToolConfig>>,
88
89 pub reasoning_effort: Option<ReasoningEffortLevel>,
92
93 pub effort: Option<String>,
98
99 pub verbosity: Option<VerbosityLevel>,
102
103 pub do_sample: Option<bool>,
105 pub top_p: Option<f32>,
106 pub top_k: Option<i32>,
107 pub presence_penalty: Option<f32>,
108 pub frequency_penalty: Option<f32>,
109 pub stop_sequences: Option<Vec<String>>,
110 pub thinking_budget: Option<u32>,
113
114 pub betas: Option<Vec<String>>,
116
117 pub context_management: Option<Value>,
119
120 pub prefill: Option<String>,
123
124 pub character_reinforcement: bool,
126
127 pub character_name: Option<String>,
129
130 pub coding_agent_settings: Option<Box<CodingAgentSettings>>,
132
133 pub metadata: Option<Value>,
136
137 pub previous_response_id: Option<String>,
140
141 pub response_store: Option<bool>,
144
145 pub responses_include: Option<Vec<String>>,
148
149 pub service_tier: Option<String>,
152
153 pub prompt_cache_key: Option<String>,
156
157 pub prompt_cache_profile: Option<PromptCacheProfile>,
159
160 pub anthropic_request_overrides: Option<AnthropicRequestOverrides>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
167pub struct ResponsesCompactionOptions {
168 pub instructions: Option<String>,
170 pub max_output_tokens: Option<u32>,
172 pub reasoning_effort: Option<ReasoningEffortLevel>,
174 pub verbosity: Option<VerbosityLevel>,
176 pub responses_include: Option<Vec<String>>,
178 pub response_store: Option<bool>,
180 pub service_tier: Option<String>,
182 pub prompt_cache_key: Option<String>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, Default)]
188pub struct CodingAgentSettings {
189 pub force_xml_tags: bool,
191 pub prefill_thought: bool,
193 pub allow_uncertainty: bool,
195 pub strict_grounding: bool,
197 pub long_context_optimization: bool,
199 pub use_xml_document_format: bool,
201 pub force_quote_grounding: bool,
203 pub role_specialization: Option<String>,
205 pub enforce_structured_thought: bool,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
213#[serde(untagged)]
214#[derive(Default)]
215pub enum ToolChoice {
216 #[default]
219 Auto,
220
221 None,
224
225 Any,
228
229 Specific(SpecificToolChoice),
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct SpecificToolChoice {
237 #[serde(rename = "type")]
238 pub tool_type: String, pub function: SpecificFunctionChoice,
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct SpecificFunctionChoice {
246 pub name: String,
247}
248
249impl ToolChoice {
250 pub fn auto() -> Self {
252 Self::Auto
253 }
254
255 pub fn none() -> Self {
257 Self::None
258 }
259
260 pub fn any() -> Self {
262 Self::Any
263 }
264
265 pub fn function(name: String) -> Self {
267 Self::Specific(SpecificToolChoice {
268 tool_type: "function".to_owned(),
269 function: SpecificFunctionChoice { name },
270 })
271 }
272
273 pub fn allows_parallel_tools(&self) -> bool {
276 match self {
277 Self::Auto => true,
279 Self::Any => true,
281 Self::Specific(_) => false,
283 Self::None => false,
285 }
286 }
287
288 pub fn description(&self) -> &'static str {
290 match self {
291 Self::Auto => "Model decides when to use tools (allows parallel)",
292 Self::None => "No tools will be used",
293 Self::Any => "At least one tool must be used (allows parallel)",
294 Self::Specific(_) => "Specific tool must be used (no parallel)",
295 }
296 }
297
298 const OPENAI_STYLE_PROVIDERS: &'static [&'static str] = &[
300 "openai",
301 "deepseek",
302 "huggingface",
303 "mistral",
304 "openrouter",
305 "zai",
306 "moonshot",
307 "stepfun",
308 "evolink",
309 "lmstudio",
310 "llamacpp",
311 ];
312
313 #[inline]
315 pub fn to_provider_format(&self, provider: &str) -> Value {
316 if Self::OPENAI_STYLE_PROVIDERS.contains(&provider) {
317 return self.to_openai_format();
318 }
319
320 match provider {
321 "anthropic" => self.to_anthropic_format(),
322 "gemini" => self.to_gemini_format(),
323 _ => self.to_openai_format(), }
325 }
326
327 #[inline]
328 fn to_openai_format(&self) -> Value {
329 match self {
330 Self::Auto => json!("auto"),
331 Self::None => json!("none"),
332 Self::Any => json!("required"),
333 Self::Specific(choice) => json!(choice),
334 }
335 }
336
337 #[inline]
338 fn to_anthropic_format(&self) -> Value {
339 match self {
340 Self::Auto => json!({"type": "auto"}),
341 Self::None => json!({"type": "none"}),
342 Self::Any => json!({"type": "any"}),
343 Self::Specific(choice) => json!({"type": "tool", "name": &choice.function.name}),
344 }
345 }
346
347 #[inline]
348 fn to_gemini_format(&self) -> Value {
349 match self {
350 Self::Auto => json!({"mode": "auto"}),
351 Self::None => json!({"mode": "none"}),
352 Self::Any => json!({"mode": "any"}),
353 Self::Specific(choice) => {
354 json!({"mode": "any", "allowed_function_names": [&choice.function.name]})
355 }
356 }
357 }
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct ParallelToolConfig {
364 pub disable_parallel_tool_use: bool,
367
368 pub max_parallel_tools: Option<usize>,
371
372 pub encourage_parallel: bool,
374}
375
376impl Default for ParallelToolConfig {
377 fn default() -> Self {
378 Self {
379 disable_parallel_tool_use: false,
380 max_parallel_tools: Some(5), encourage_parallel: true,
382 }
383 }
384}
385
386impl ParallelToolConfig {
387 pub fn anthropic_optimized() -> Self {
389 Self {
390 disable_parallel_tool_use: false,
391 max_parallel_tools: None, encourage_parallel: true,
393 }
394 }
395
396 pub fn sequential_only() -> Self {
398 Self {
399 disable_parallel_tool_use: true,
400 max_parallel_tools: Some(1),
401 encourage_parallel: false,
402 }
403 }
404}