1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
7pub enum DeepSeekModel {
8 #[serde(rename = "deepseek-v4-pro")]
10 #[default]
11 V4Pro,
12 #[serde(rename = "deepseek-reasoner")]
14 Reasoner,
15 #[serde(rename = "deepseek-chat")]
17 Chat,
18}
19
20impl DeepSeekModel {
21 pub fn as_str(&self) -> &'static str {
22 match self {
23 Self::V4Pro => "deepseek-v4-pro",
24 Self::Reasoner => "deepseek-reasoner",
25 Self::Chat => "deepseek-chat",
26 }
27 }
28
29 pub fn from_alias(alias: &str) -> Self {
30 match alias {
31 "v4" | "v4-pro" | "pro" | "latest" => Self::V4Pro,
32 "reasoner" | "r1" | "deep" | "opus" => Self::Reasoner,
33 "chat" | "v3" | "fast" | "sonnet" | "haiku" => Self::Chat,
34 _ => Self::V4Pro,
35 }
36 }
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ChatMessage {
43 pub role: String,
44 pub content: ChatContent,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub reasoning_content: Option<String>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub tool_calls: Option<Vec<ToolCall>>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub tool_call_id: Option<String>,
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub name: Option<String>,
53}
54
55#[derive(Debug, Clone)]
56pub enum ChatContent {
57 Text(String),
58 Null,
59}
60
61impl ChatContent {
62 pub fn as_str(&self) -> &str {
63 match self {
64 Self::Text(s) => s,
65 Self::Null => "",
66 }
67 }
68}
69
70impl Serialize for ChatContent {
71 fn serialize<S: serde::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
72 match self {
73 Self::Text(s) => serializer.serialize_str(s),
74 Self::Null => serializer.serialize_none(),
75 }
76 }
77}
78
79impl<'de> Deserialize<'de> for ChatContent {
80 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
81 let value = serde_json::Value::deserialize(deserializer)?;
82 match value {
83 serde_json::Value::String(s) => Ok(Self::Text(s)),
84 serde_json::Value::Null => Ok(Self::Null),
85 other => Ok(Self::Text(other.to_string())),
86 }
87 }
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct ToolCall {
92 pub id: String,
93 pub r#type: String,
94 pub function: FunctionCall,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct FunctionCall {
99 pub name: String,
100 pub arguments: String,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct ChatRequest {
105 pub model: String,
106 pub messages: Vec<ChatMessage>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub tools: Option<Vec<ToolSchema>>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub tool_choice: Option<serde_json::Value>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub temperature: Option<f64>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub max_tokens: Option<u32>,
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub stream: Option<bool>,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub reasoning_effort: Option<String>,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub thinking: Option<serde_json::Value>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct ToolSchema {
125 pub r#type: String,
126 pub function: FunctionSchema,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct FunctionSchema {
131 pub name: String,
132 pub description: String,
133 pub parameters: serde_json::Value,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct ChatResponse {
138 pub id: String,
139 pub choices: Vec<Choice>,
140 pub usage: Option<UsageInfo>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct Choice {
145 pub index: u32,
146 pub message: ChatMessage,
147 pub finish_reason: Option<String>,
148}
149
150#[derive(Debug, Clone, Deserialize, Serialize)]
151pub struct UsageInfo {
152 pub prompt_tokens: u32,
153 pub completion_tokens: u32,
154 pub total_tokens: u32,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct AgentResult {
161 pub success: bool,
162 pub result: Option<String>,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub error: Option<String>,
165 pub turns: u32,
166 pub usage: UsageInfo,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub tool_calls_made: Option<Vec<String>>,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub session_id: Option<String>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct AgentDefinition {
177 pub name: String,
178 pub description: String,
179 pub prompt: String,
180 #[serde(default)]
181 pub model: DeepSeekModel,
182 #[serde(default)]
183 pub tools: Vec<String>,
184 #[serde(default)]
185 pub disallowed_tools: Vec<String>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub max_turns: Option<u32>,
188}
189
190#[derive(Debug, Clone, Default, Serialize, Deserialize)]
193pub enum EffortLevel {
194 Low,
195 Medium,
196 #[default]
197 High,
198 Max,
199}
200
201impl EffortLevel {
202 pub fn temperature(&self) -> f64 {
204 match self {
205 Self::Low => 0.1,
206 Self::Medium => 0.5,
207 Self::High => 0.7,
208 Self::Max => 1.0,
209 }
210 }
211
212 pub fn max_tokens(&self) -> u32 {
214 match self {
215 Self::Low => 2048,
216 Self::Medium => 4096,
217 Self::High => 8192,
218 Self::Max => 16384,
219 }
220 }
221}
222
223pub fn system_msg(content: &str) -> ChatMessage {
226 ChatMessage {
227 role: "system".into(),
228 content: ChatContent::Text(content.into()),
229 reasoning_content: None,
230 tool_calls: None,
231 tool_call_id: None,
232 name: None,
233 }
234}
235
236pub fn user_msg(content: &str) -> ChatMessage {
237 ChatMessage {
238 role: "user".into(),
239 content: ChatContent::Text(content.into()),
240 reasoning_content: None,
241 tool_calls: None,
242 tool_call_id: None,
243 name: None,
244 }
245}
246
247pub fn assistant_msg(content: &str) -> ChatMessage {
248 ChatMessage {
249 role: "assistant".into(),
250 content: ChatContent::Text(content.into()),
251 reasoning_content: None,
252 tool_calls: None,
253 tool_call_id: None,
254 name: None,
255 }
256}
257
258pub struct ReasonerOutput {
261 pub reasoning: String,
263 pub content: String,
265}
266
267pub fn tool_result_msg(tool_call_id: &str, content: &str) -> ChatMessage {
268 ChatMessage {
269 role: "tool".into(),
270 content: ChatContent::Text(content.into()),
271 reasoning_content: None,
272 tool_calls: None,
273 tool_call_id: Some(tool_call_id.into()),
274 name: None,
275 }
276}