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}