Skip to main content

claude_code_sdk_rust/
types.rs

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// Enums and String Constants
18
19#[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// MCP Server Config Types (tagged enum pattern)
109
110#[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// Simple Struct Types
136
137#[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// MCP Server Status Config (tagged enum)
439
440#[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}