1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7pub struct ChatRequest {
8 pub model: String,
9 pub messages: Vec<crate::Message>,
10 pub tools: Option<Vec<ToolDefinition>>,
11 pub temperature: Option<f64>,
12 pub max_tokens: Option<u32>,
13 pub top_p: Option<f64>,
14 pub seed: Option<u64>,
15 pub tool_choice: Option<ToolChoice>,
16 pub stop_sequences: Option<Vec<String>>,
17 pub prefill: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
24 pub reasoning: Option<ReasoningConfig>,
25 #[serde(skip_serializing_if = "Option::is_none")]
39 pub max_reasoning_tokens: Option<u32>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub extra: Option<serde_json::Map<String, serde_json::Value>>,
43}
44
45impl ChatRequest {
48 pub fn user_prompt(prompt: String) -> Self {
50 Self {
51 messages: vec![crate::Message::User {
52 content: crate::text_block(prompt),
53 }],
54 ..Default::default()
55 }
56 }
57
58 pub fn with_temperature(mut self, temp: f64) -> Self {
59 self.temperature = Some(temp);
60 self
61 }
62
63 pub fn with_max_tokens(mut self, max: u32) -> Self {
64 self.max_tokens = Some(max);
65 self
66 }
67
68 pub fn with_top_p(mut self, top_p: f64) -> Self {
69 self.top_p = Some(top_p);
70 self
71 }
72
73 pub fn with_seed(mut self, seed: u64) -> Self {
74 self.seed = Some(seed);
75 self
76 }
77
78 pub fn with_model(mut self, model: String) -> Self {
79 self.model = model;
80 self
81 }
82
83 pub fn with_tools(mut self, tools: Vec<ToolDefinition>) -> Self {
84 self.tools = Some(tools);
85 self
86 }
87
88 pub fn with_system_prompt(mut self, prompt: String) -> Self {
90 self.messages.insert(
91 0,
92 crate::Message::System {
93 content: crate::text_block(prompt),
94 },
95 );
96 self
97 }
98
99 pub fn with_reasoning(mut self, reasoning: ReasoningConfig) -> Self {
101 self.reasoning = Some(reasoning);
102 self
103 }
104
105 pub fn with_max_reasoning_tokens(mut self, max: u32) -> Self {
107 self.max_reasoning_tokens = Some(max);
108 self
109 }
110
111 pub fn with_extra(mut self, extra: serde_json::Map<String, serde_json::Value>) -> Self {
113 self.extra = Some(extra);
114 self
115 }
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub enum ToolChoice {
121 Tool { name: String },
122 Any,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct ToolDefinition {
131 pub name: String,
132 pub description: String,
133 pub parameters: serde_json::Value,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub cache_control: Option<crate::message::CacheControl>,
138}
139
140impl ToolDefinition {
141 pub fn with_cache(self, cache: crate::message::CacheControl) -> Self {
143 Self {
144 cache_control: Some(cache),
145 ..self
146 }
147 }
148
149 pub fn compute_and_clean_schema<S: schemars::JsonSchema>() -> serde_json::Value {
156 let root = schemars::schema_for!(S);
157 let val = serde_json::to_value(&root)
158 .expect("Failed to serialize JsonSchema; this is a bug in schemars");
159 Self::clean_schema(val)
160 }
161
162 fn clean_schema(mut value: serde_json::Value) -> serde_json::Value {
167 if let Some(obj) = value.as_object_mut() {
168 obj.remove("$schema");
170 obj.remove("$id");
171 obj.remove("title");
172 obj.remove("description");
173 }
174 value
175 }
176}
177
178#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
194pub enum ReasoningConfig {
195 Disabled,
197 Low,
199 Medium,
201 High,
203}
204
205impl ReasoningConfig {
206 pub fn is_disabled(self) -> bool {
208 matches!(self, Self::Disabled)
209 }
210}