1use crate::error::Result;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::future::Future;
5use std::pin::Pin;
6use std::sync::Arc;
7
8pub mod messages;
9pub use messages::*;
10pub mod hooks;
11pub use hooks::*;
12pub mod config;
13pub use config::*;
14pub mod agent_options;
15pub use agent_options::*;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
20#[serde(rename_all = "camelCase")]
21pub enum PermissionMode {
22 Default,
23 AcceptEdits,
24 Plan,
25 BypassPermissions,
26 DontAsk,
27 Auto,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
31pub enum SdkBeta {
32 #[serde(rename = "context-1m-2025-08-07")]
33 Context1M20250807,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub enum SettingSource {
39 User,
40 Project,
41 Local,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub enum ThinkingConfigType {
47 Adaptive,
48 Enabled,
49 Disabled,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub enum UserContentKind {
55 Text,
56 Blocks,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
60#[serde(rename_all = "snake_case")]
61pub enum AssistantMessageErrorKind {
62 AuthenticationFailed,
63 BillingError,
64 RateLimit,
65 InvalidRequest,
66 ServerError,
67 Unknown,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
71#[serde(rename_all = "snake_case")]
72pub enum TaskNotificationStatus {
73 Completed,
74 Failed,
75 Stopped,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
79#[serde(rename_all = "camelCase")]
80pub enum RateLimitStatus {
81 Allowed,
82 #[serde(alias = "allowed_warning")]
83 AllowedWarning,
84 Rejected,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
88#[serde(rename_all = "snake_case")]
89pub enum RateLimitType {
90 FiveHour,
91 SevenDay,
92 SevenDayOpus,
93 SevenDaySonnet,
94 Overage,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
98#[serde(rename_all = "kebab-case")]
99pub enum MCPServerConnectionStatus {
100 Connected,
101 Failed,
102 #[serde(rename = "needs-auth")]
103 NeedsAuth,
104 Pending,
105 Disabled,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(tag = "type", rename_all = "camelCase")]
112pub enum MCPServerConfig {
113 #[serde(rename = "stdio")]
114 Stdio {
115 command: String,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 args: Option<Vec<String>>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 env: Option<HashMap<String, String>>,
120 },
121 Sse {
122 url: String,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 headers: Option<HashMap<String, String>>,
125 },
126 Http {
127 url: String,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 headers: Option<HashMap<String, String>>,
130 },
131 #[serde(rename = "sdk")]
132 Sdk { name: String },
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(rename_all = "camelCase")]
139pub struct ToolsPreset {
140 pub r#type: String,
141 pub preset: String,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct SystemPromptPreset {
147 pub r#type: String,
148 pub preset: String,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub append: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub exclude_dynamic_sections: Option<bool>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156#[serde(rename_all = "camelCase")]
157pub struct SystemPromptFile {
158 pub r#type: String,
159 pub path: String,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163#[serde(rename_all = "camelCase")]
164pub struct ThinkingConfig {
165 pub r#type: ThinkingConfigType,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub budget_tokens: Option<i32>,
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub display: Option<String>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct TaskBudget {
174 pub total: i32,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct PermissionRuleValue {
180 pub tool_name: String,
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub rule_content: Option<String>,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(rename_all = "camelCase")]
187pub struct PermissionUpdate {
188 pub r#type: String,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub rules: Option<Vec<PermissionRuleValue>>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub behavior: Option<String>,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub mode: Option<PermissionMode>,
195 #[serde(skip_serializing_if = "Option::is_none")]
196 pub directories: Option<Vec<String>>,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub destination: Option<String>,
199}
200
201#[derive(Debug, Clone, Default)]
202pub struct ToolPermissionContext {
203 pub suggestions: Vec<PermissionUpdate>,
204 pub tool_use_id: Option<String>,
205 pub agent_id: Option<String>,
206 pub blocked_path: Option<String>,
207 pub decision_reason: Option<String>,
208 pub title: Option<String>,
209 pub display_name: Option<String>,
210 pub description: Option<String>,
211}
212
213#[derive(Debug, Clone)]
214pub enum PermissionResult {
215 Allow {
216 updated_input: Option<serde_json::Map<String, serde_json::Value>>,
217 updated_permissions: Option<Vec<PermissionUpdate>>,
218 },
219 Deny {
220 message: String,
221 interrupt: bool,
222 },
223}
224
225impl PermissionResult {
226 pub fn allow() -> Self {
227 Self::Allow {
228 updated_input: None,
229 updated_permissions: None,
230 }
231 }
232
233 pub fn deny(message: impl Into<String>) -> Self {
234 Self::Deny {
235 message: message.into(),
236 interrupt: false,
237 }
238 }
239}
240
241pub type CanUseToolFuture = Pin<Box<dyn Future<Output = Result<PermissionResult>> + Send>>;
242type CanUseToolFn = dyn Fn(
243 String,
244 serde_json::Map<String, serde_json::Value>,
245 ToolPermissionContext,
246 ) -> CanUseToolFuture
247 + Send
248 + Sync;
249
250#[derive(Clone)]
251pub struct CanUseToolCallback(Arc<CanUseToolFn>);
252
253impl std::fmt::Debug for CanUseToolCallback {
254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255 f.debug_tuple("CanUseToolCallback")
256 .field(&"<callback>")
257 .finish()
258 }
259}
260
261impl CanUseToolCallback {
262 pub fn new<F, Fut>(callback: F) -> Self
263 where
264 F: Fn(String, serde_json::Map<String, serde_json::Value>, ToolPermissionContext) -> Fut
265 + Send
266 + Sync
267 + 'static,
268 Fut: Future<Output = Result<PermissionResult>> + Send + 'static,
269 {
270 Self(Arc::new(move |tool_name, input, context| {
271 Box::pin(callback(tool_name, input, context))
272 }))
273 }
274
275 pub async fn call(
276 &self,
277 tool_name: String,
278 input: serde_json::Map<String, serde_json::Value>,
279 context: ToolPermissionContext,
280 ) -> Result<PermissionResult> {
281 (self.0)(tool_name, input, context).await
282 }
283}
284
285type StderrFn = dyn Fn(String) + Send + Sync;
286
287#[derive(Clone)]
288pub struct StderrCallback(Arc<StderrFn>);
289
290impl std::fmt::Debug for StderrCallback {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 f.debug_tuple("StderrCallback")
293 .field(&"<callback>")
294 .finish()
295 }
296}
297
298impl StderrCallback {
299 pub fn new<F>(callback: F) -> Self
300 where
301 F: Fn(String) + Send + Sync + 'static,
302 {
303 Self(Arc::new(callback))
304 }
305
306 pub fn call(&self, line: String) {
307 (self.0)(line);
308 }
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313pub struct SDKPluginConfig {
314 pub r#type: String,
315 pub path: String,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319#[serde(rename_all = "camelCase")]
320pub struct MCPToolAnnotations {
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub read_only: Option<bool>,
323 #[serde(skip_serializing_if = "Option::is_none")]
324 pub destructive: Option<bool>,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub open_world: Option<bool>,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct MCPToolInfo {
332 pub name: String,
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub description: Option<String>,
335 #[serde(skip_serializing_if = "Option::is_none")]
336 pub annotations: Option<MCPToolAnnotations>,
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
340#[serde(rename_all = "camelCase")]
341pub struct MCPServerInfo {
342 pub name: String,
343 pub version: String,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
347#[serde(rename_all = "camelCase")]
348pub struct MCPServerStatus {
349 pub name: String,
350 pub status: MCPServerConnectionStatus,
351 #[serde(skip_serializing_if = "Option::is_none")]
352 pub server_info: Option<MCPServerInfo>,
353 #[serde(skip_serializing_if = "Option::is_none")]
354 pub error: Option<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
356 pub config: Option<MCPServerStatusConfig>,
357 #[serde(skip_serializing_if = "Option::is_none")]
358 pub scope: Option<String>,
359 #[serde(skip_serializing_if = "Option::is_none")]
360 pub tools: Option<Vec<MCPToolInfo>>,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
364#[serde(rename_all = "camelCase")]
365pub struct MCPStatusResponse {
366 pub mcp_servers: Vec<MCPServerStatus>,
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize)]
370#[serde(rename_all = "camelCase")]
371pub struct ContextUsageCategory {
372 pub name: String,
373 pub tokens: i32,
374 pub color: String,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 pub is_deferred: Option<bool>,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
380#[serde(rename_all = "camelCase")]
381pub struct ContextUsageResponse {
382 pub categories: Vec<ContextUsageCategory>,
383 pub total_tokens: i32,
384 pub max_tokens: i32,
385 pub raw_max_tokens: i32,
386 pub percentage: f64,
387 pub model: String,
388 pub is_auto_compact_enabled: bool,
389 pub memory_files: Vec<serde_json::Map<String, serde_json::Value>>,
390 pub mcp_tools: Vec<serde_json::Map<String, serde_json::Value>>,
391 pub agents: Vec<serde_json::Map<String, serde_json::Value>>,
392 pub grid_rows: Vec<Vec<serde_json::Map<String, serde_json::Value>>>,
393 #[serde(skip_serializing_if = "Option::is_none")]
394 pub auto_compact_threshold: Option<i32>,
395 #[serde(skip_serializing_if = "Option::is_none")]
396 pub deferred_builtin_tools: Option<Vec<serde_json::Map<String, serde_json::Value>>>,
397 #[serde(skip_serializing_if = "Option::is_none")]
398 pub system_tools: Option<Vec<serde_json::Map<String, serde_json::Value>>>,
399 #[serde(skip_serializing_if = "Option::is_none")]
400 pub system_prompt_sections: Option<Vec<serde_json::Map<String, serde_json::Value>>>,
401 #[serde(skip_serializing_if = "Option::is_none")]
402 pub slash_commands: Option<serde_json::Value>,
403 #[serde(skip_serializing_if = "Option::is_none")]
404 pub skills: Option<serde_json::Value>,
405}
406
407#[derive(Debug, Clone, Serialize, Deserialize)]
408#[serde(rename_all = "camelCase")]
409pub struct TaskUsage {
410 #[serde(alias = "total_tokens")]
411 pub total_tokens: i32,
412 #[serde(alias = "tool_uses")]
413 pub tool_uses: i32,
414 #[serde(alias = "duration_ms")]
415 pub duration_ms: i32,
416}
417
418#[derive(Debug, Clone, Serialize, Deserialize)]
419#[serde(rename_all = "camelCase")]
420pub struct RateLimitInfo {
421 pub status: RateLimitStatus,
422 #[serde(skip_serializing_if = "Option::is_none")]
423 pub resets_at: Option<i64>,
424 #[serde(skip_serializing_if = "Option::is_none")]
425 pub rate_limit_type: Option<RateLimitType>,
426 #[serde(skip_serializing_if = "Option::is_none")]
427 pub utilization: Option<f64>,
428 #[serde(skip_serializing_if = "Option::is_none")]
429 pub overage_status: Option<RateLimitStatus>,
430 #[serde(skip_serializing_if = "Option::is_none")]
431 pub overage_resets_at: Option<i64>,
432 #[serde(skip_serializing_if = "Option::is_none")]
433 pub overage_disabled_reason: Option<String>,
434 #[serde(skip_serializing_if = "Option::is_none")]
435 pub raw: Option<serde_json::Map<String, serde_json::Value>>,
436}
437
438#[derive(Debug, Clone, Serialize, Deserialize)]
441#[serde(tag = "type", rename_all = "camelCase")]
442pub enum MCPServerStatusConfig {
443 #[serde(rename = "sdk")]
444 Sdk { name: String },
445 #[serde(rename = "claudeai-proxy")]
446 ClaudeAiProxy { url: String, id: String },
447 Sse {
448 url: String,
449 #[serde(skip_serializing_if = "Option::is_none")]
450 headers: Option<HashMap<String, String>>,
451 },
452 Http {
453 url: String,
454 #[serde(skip_serializing_if = "Option::is_none")]
455 headers: Option<HashMap<String, String>>,
456 },
457 #[serde(rename = "stdio")]
458 Stdio {
459 #[serde(skip_serializing_if = "Option::is_none")]
460 command: Option<String>,
461 #[serde(skip_serializing_if = "Option::is_none")]
462 args: Option<Vec<String>>,
463 #[serde(skip_serializing_if = "Option::is_none")]
464 env: Option<HashMap<String, String>>,
465 },
466}