turboclaude_protocol/
types.rs

1//! Common type definitions used across the protocol
2//!
3//! Includes types for models, usage statistics, cache information, and other
4//! common structures used in both REST and Agent protocols.
5
6use serde::{Deserialize, Serialize};
7
8/// Information about token usage in a message or batch
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
10pub struct Usage {
11    /// Number of tokens in the input
12    pub input_tokens: u32,
13
14    /// Number of tokens in the output
15    pub output_tokens: u32,
16}
17
18impl Usage {
19    /// Create a new usage structure
20    pub fn new(input_tokens: u32, output_tokens: u32) -> Self {
21        Self {
22            input_tokens,
23            output_tokens,
24        }
25    }
26
27    /// Get total tokens (input + output)
28    pub fn total_tokens(&self) -> u32 {
29        self.input_tokens + self.output_tokens
30    }
31}
32
33/// Cache usage information
34#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
35pub struct CacheUsage {
36    /// Tokens read from cache
37    #[serde(default)]
38    pub cache_read_input_tokens: u32,
39
40    /// Tokens written to cache
41    #[serde(default)]
42    pub cache_creation_input_tokens: u32,
43}
44
45impl CacheUsage {
46    /// Create new cache usage
47    pub fn new(cache_read_input_tokens: u32, cache_creation_input_tokens: u32) -> Self {
48        Self {
49            cache_read_input_tokens,
50            cache_creation_input_tokens,
51        }
52    }
53}
54
55/// Model information
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
57pub struct Model {
58    /// The model identifier
59    pub id: String,
60
61    /// The type of model (usually "model")
62    pub r#type: String,
63
64    /// When the model was created (ISO 8601 format)
65    pub created_at: String,
66
67    /// Display name for the model
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub display_name: Option<String>,
70
71    /// Additional metadata about the model
72    #[serde(default, skip_serializing_if = "serde_json::Map::is_empty")]
73    pub metadata: serde_json::Map<String, serde_json::Value>,
74}
75
76impl Model {
77    /// Create a new model
78    pub fn new(id: impl Into<String>) -> Self {
79        Self {
80            id: id.into(),
81            r#type: "model".to_string(),
82            created_at: chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
83            display_name: None,
84            metadata: serde_json::Map::new(),
85        }
86    }
87
88    /// Set the display name
89    pub fn with_display_name(mut self, name: impl Into<String>) -> Self {
90        self.display_name = Some(name.into());
91        self
92    }
93}
94
95/// Common model constants matching Anthropic's model IDs
96///
97/// This module provides constants for all available Claude models,
98/// organized by generation and capability tier.
99pub mod models {
100    // ========================================================================
101    // LATEST GENERATION - RECOMMENDED FOR PRODUCTION
102    // ========================================================================
103
104    /// Claude Sonnet 4.5 (September 2025) - **RECOMMENDED**
105    ///
106    /// Best coding model in the world. Strongest for building complex agents,
107    /// best at computer use. Excellent at following instructions and writing code.
108    ///
109    /// **Pricing:** $3 per million input tokens, $15 per million output tokens
110    ///
111    /// **Use cases:** Complex coding, agent workflows, computer use, instruction following
112    pub const CLAUDE_SONNET_4_5_20250929: &str = "claude-sonnet-4-5-20250929";
113
114    /// Claude Sonnet 4.5 with Structured Outputs (September 2025)
115    ///
116    /// Same capabilities as CLAUDE_SONNET_4_5_20250929 but optimized for
117    /// returning structured JSON outputs that conform to provided schemas.
118    ///
119    /// **Requires:** Beta header `structured-outputs-2025-09-17`
120    ///
121    /// **Use cases:** Type-safe API responses, data extraction, form filling
122    pub const CLAUDE_SONNET_4_5_20250929_STRUCTURED_OUTPUTS: &str =
123        "claude-sonnet-4-5-20250929-structured-outputs";
124
125    /// Claude Haiku 4.5 (October 2025) - **RECOMMENDED FOR SPEED**
126    ///
127    /// Small, fast model optimized for low latency. Near-frontier coding quality,
128    /// matches Sonnet 4 on coding, surpasses Sonnet 4 on some computer-use tasks.
129    ///
130    /// **Pricing:** $1 per million input tokens, $5 per million output tokens
131    ///
132    /// **Use cases:** Fast responses, cost optimization, high-volume requests
133    pub const CLAUDE_HAIKU_4_5_20251001: &str = "claude-haiku-4-5-20251001";
134
135    /// Claude Opus 4.1 (August 2025)
136    ///
137    /// Most capable model for complex reasoning and analysis. Improved agentic tasks,
138    /// coding, and reasoning. Scores 74.5% on SWE-bench Verified.
139    ///
140    /// **Pricing:** $15 per million input tokens, $75 per million output tokens
141    ///
142    /// **Use cases:** Complex analysis, research, highest-quality output
143    pub const CLAUDE_OPUS_4_1_20250805: &str = "claude-opus-4-1-20250805";
144
145    // ========================================================================
146    // CONVENIENCE ALIASES
147    // ========================================================================
148
149    /// Alias for the latest Sonnet model (currently 4.5)
150    ///
151    /// **Note:** This alias may point to different models over time as new versions release.
152    /// Use specific version constants for reproducible behavior.
153    pub const SONNET_LATEST: &str = CLAUDE_SONNET_4_5_20250929;
154
155    /// Alias for the latest Haiku model (currently 4.5)
156    pub const HAIKU_LATEST: &str = CLAUDE_HAIKU_4_5_20251001;
157
158    /// Alias for the latest Opus model (currently 4.1)
159    pub const OPUS_LATEST: &str = CLAUDE_OPUS_4_1_20250805;
160
161    /// Default model for new applications
162    pub const DEFAULT: &str = CLAUDE_SONNET_4_5_20250929;
163
164    // ========================================================================
165    // LEGACY GENERATION (backward compatibility)
166    // ========================================================================
167
168    /// Claude 3.5 Sonnet (October 2024)
169    ///
170    /// **Deprecated:** Use [`CLAUDE_SONNET_4_5_20250929`] instead for better performance.
171    #[deprecated(since = "0.2.0", note = "Use CLAUDE_SONNET_4_5_20250929 instead")]
172    pub const CLAUDE_3_5_SONNET_20241022: &str = "claude-3-5-sonnet-20241022";
173
174    /// Claude 3.5 Haiku (October 2024)
175    ///
176    /// **Deprecated:** Use [`CLAUDE_HAIKU_4_5_20251001`] instead for better performance.
177    #[deprecated(since = "0.2.0", note = "Use CLAUDE_HAIKU_4_5_20251001 instead")]
178    pub const CLAUDE_3_5_HAIKU_20241022: &str = "claude-3-5-haiku-20241022";
179
180    /// Claude Sonnet 4.5 (May 2025)
181    ///
182    /// **Deprecated:** Use [`CLAUDE_SONNET_4_5_20250929`] instead for latest improvements.
183    #[deprecated(since = "0.2.0", note = "Use CLAUDE_SONNET_4_5_20250929 instead")]
184    pub const CLAUDE_SONNET_4_5_20250514: &str = "claude-sonnet-4-5-20250514";
185
186    /// Claude 3 Opus (February 2024)
187    ///
188    /// **Deprecated:** Use [`CLAUDE_OPUS_4_1_20250805`] instead.
189    #[deprecated(since = "0.2.0", note = "Use CLAUDE_OPUS_4_1_20250805 instead")]
190    pub const CLAUDE_3_OPUS_20240229: &str = "claude-3-opus-20240229";
191
192    /// Claude 3 Sonnet (February 2024)
193    ///
194    /// **Deprecated:** Use [`CLAUDE_SONNET_4_5_20250929`] instead.
195    #[deprecated(since = "0.2.0", note = "Use CLAUDE_SONNET_4_5_20250929 instead")]
196    pub const CLAUDE_3_SONNET_20240229: &str = "claude-3-sonnet-20240229";
197
198    /// Claude 3 Haiku (March 2024)
199    ///
200    /// **Deprecated:** Use [`CLAUDE_HAIKU_4_5_20251001`] instead.
201    #[deprecated(since = "0.2.0", note = "Use CLAUDE_HAIKU_4_5_20251001 instead")]
202    pub const CLAUDE_3_HAIKU_20240307: &str = "claude-3-haiku-20240307";
203}
204
205/// Stop reason for a message completion
206#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
207#[serde(rename_all = "lowercase")]
208pub enum StopReason {
209    /// The model finished naturally (sent complete message)
210    #[serde(rename = "end_turn")]
211    EndTurn,
212
213    /// The model hit the max tokens limit
214    #[serde(rename = "max_tokens")]
215    MaxTokens,
216
217    /// The model is requesting to use a tool
218    #[serde(rename = "tool_use")]
219    ToolUse,
220
221    /// Stop sequence was encountered
222    #[serde(rename = "stop_sequence")]
223    StopSequence,
224}
225
226/// Permission mode for tool use in agent sessions
227#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
228#[serde(rename_all = "snake_case")]
229pub enum PermissionMode {
230    /// Default: ask for permission for each tool use
231    Default,
232
233    /// Automatically accept edits without asking
234    AcceptEdits,
235
236    /// Bypass permission checks entirely
237    BypassPermissions,
238}
239
240/// Tool definition for agent queries
241#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
242pub struct ToolDefinition {
243    /// Name of the tool
244    pub name: String,
245
246    /// Description of what the tool does
247    pub description: String,
248
249    /// JSON schema for the tool's input
250    pub input_schema: serde_json::Value,
251}
252
253impl ToolDefinition {
254    /// Create a new tool definition
255    pub fn new(
256        name: impl Into<String>,
257        description: impl Into<String>,
258        input_schema: serde_json::Value,
259    ) -> Self {
260        Self {
261            name: name.into(),
262            description: description.into(),
263            input_schema,
264        }
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271
272    #[test]
273    fn test_usage_total() {
274        let usage = Usage::new(100, 50);
275        assert_eq!(usage.total_tokens(), 150);
276    }
277
278    #[test]
279    fn test_model_creation() {
280        let model = Model::new("claude-3-5-sonnet");
281        assert_eq!(model.id, "claude-3-5-sonnet");
282        assert_eq!(model.r#type, "model");
283    }
284
285    #[test]
286    fn test_stop_reason_serialization() {
287        let reasons = vec![
288            StopReason::EndTurn,
289            StopReason::MaxTokens,
290            StopReason::ToolUse,
291        ];
292
293        for reason in reasons {
294            let json = serde_json::to_string(&reason).unwrap();
295            let deserialized: StopReason = serde_json::from_str(&json).unwrap();
296            assert_eq!(reason, deserialized);
297        }
298    }
299}