Skip to main content

openai_protocol/
messages.rs

1//! Anthropic Messages API protocol definitions
2//!
3//! This module provides Rust types for the Anthropic Messages API.
4//! See: https://docs.anthropic.com/en/api/messages
5
6use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use validator::Validate;
11
12use crate::validated::Normalizable;
13
14// ============================================================================
15// Request Types
16// ============================================================================
17
18/// Request to create a message using the Anthropic Messages API.
19///
20/// This is the main request type for `/v1/messages` endpoint.
21#[serde_with::skip_serializing_none]
22#[derive(Debug, Clone, Serialize, Deserialize, Validate, schemars::JsonSchema)]
23#[validate(schema(function = "validate_mcp_config"))]
24pub struct CreateMessageRequest {
25    /// The model that will complete your prompt.
26    #[validate(length(min = 1, message = "model field is required and cannot be empty"))]
27    pub model: String,
28
29    /// Input messages for the conversation.
30    #[validate(length(min = 1, message = "messages array is required and cannot be empty"))]
31    pub messages: Vec<InputMessage>,
32
33    /// The maximum number of tokens to generate before stopping.
34    #[validate(range(min = 1, message = "max_tokens must be greater than 0"))]
35    pub max_tokens: u32,
36
37    /// An object describing metadata about the request.
38    pub metadata: Option<Metadata>,
39
40    /// Service tier for the request (auto or standard_only).
41    pub service_tier: Option<ServiceTier>,
42
43    /// Custom text sequences that will cause the model to stop generating.
44    pub stop_sequences: Option<Vec<String>>,
45
46    /// Whether to incrementally stream the response using server-sent events.
47    pub stream: Option<bool>,
48
49    /// System prompt for providing context and instructions.
50    pub system: Option<SystemContent>,
51
52    /// Amount of randomness injected into the response (0.0 to 1.0).
53    pub temperature: Option<f64>,
54
55    /// Configuration for extended thinking.
56    pub thinking: Option<ThinkingConfig>,
57
58    /// How the model should use the provided tools.
59    pub tool_choice: Option<ToolChoice>,
60
61    /// Definitions of tools that the model may use.
62    pub tools: Option<Vec<Tool>>,
63
64    /// Only sample from the top K options for each subsequent token.
65    pub top_k: Option<u32>,
66
67    /// Use nucleus sampling.
68    pub top_p: Option<f64>,
69
70    // Beta features
71    /// Container configuration for code execution (beta).
72    pub container: Option<ContainerConfig>,
73
74    /// MCP servers to be utilized in this request (beta).
75    pub mcp_servers: Option<Vec<McpServerConfig>>,
76}
77
78impl Normalizable for CreateMessageRequest {
79    // Use default no-op implementation
80}
81
82impl CreateMessageRequest {
83    /// Check if the request is for streaming
84    pub fn is_stream(&self) -> bool {
85        self.stream.unwrap_or(false)
86    }
87
88    /// Get the model name
89    pub fn get_model(&self) -> &str {
90        &self.model
91    }
92
93    /// Check if the request contains any `mcp_toolset` tool entries.
94    pub fn has_mcp_toolset(&self) -> bool {
95        self.tools
96            .as_ref()
97            .is_some_and(|tools| tools.iter().any(|t| matches!(t, Tool::McpToolset(_))))
98    }
99
100    /// Return MCP server configs if present and non-empty.
101    pub fn mcp_server_configs(&self) -> Option<&[McpServerConfig]> {
102        self.mcp_servers
103            .as_deref()
104            .filter(|servers| !servers.is_empty())
105    }
106}
107
108/// Validate that `mcp_servers` is non-empty when `mcp_toolset` tools are present.
109fn validate_mcp_config(req: &CreateMessageRequest) -> Result<(), validator::ValidationError> {
110    if req.has_mcp_toolset() && req.mcp_server_configs().is_none() {
111        let mut e = validator::ValidationError::new("mcp_servers_required");
112        e.message = Some("mcp_servers is required when mcp_toolset tools are present".into());
113        return Err(e);
114    }
115    Ok(())
116}
117
118/// Request metadata
119#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
120pub struct Metadata {
121    /// An external identifier for the user who is associated with the request.
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub user_id: Option<String>,
124}
125
126/// Service tier options
127#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
128#[serde(rename_all = "snake_case")]
129pub enum ServiceTier {
130    Auto,
131    StandardOnly,
132}
133
134/// System content can be a string or an array of text blocks
135#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
136#[serde(untagged)]
137pub enum SystemContent {
138    String(String),
139    Blocks(Vec<TextBlock>),
140}
141
142/// A single input message in a conversation
143#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
144pub struct InputMessage {
145    /// The role of the message sender (user or assistant)
146    pub role: Role,
147
148    /// The content of the message
149    pub content: InputContent,
150}
151
152/// Role of a message sender
153#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, schemars::JsonSchema)]
154#[serde(rename_all = "lowercase")]
155pub enum Role {
156    User,
157    Assistant,
158}
159
160/// Input content can be a string or an array of content blocks
161#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
162#[serde(untagged)]
163pub enum InputContent {
164    String(String),
165    Blocks(Vec<InputContentBlock>),
166}
167
168// ============================================================================
169// Input Content Blocks
170// ============================================================================
171
172/// Input content block types
173#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
174#[serde(tag = "type", rename_all = "snake_case")]
175pub enum InputContentBlock {
176    /// Text content
177    Text(TextBlock),
178    /// Image content
179    Image(ImageBlock),
180    /// Document content
181    Document(DocumentBlock),
182    /// Tool use block (for assistant messages)
183    ToolUse(ToolUseBlock),
184    /// Tool result block (for user messages)
185    ToolResult(ToolResultBlock),
186    /// Thinking block
187    Thinking(ThinkingBlock),
188    /// Redacted thinking block
189    RedactedThinking(RedactedThinkingBlock),
190    /// Server tool use block
191    ServerToolUse(ServerToolUseBlock),
192    /// Search result block
193    SearchResult(SearchResultBlock),
194    /// Web search tool result block
195    WebSearchToolResult(WebSearchToolResultBlock),
196    /// Tool search tool result block
197    ToolSearchToolResult(ToolSearchToolResultBlock),
198    /// Tool reference block
199    ToolReference(ToolReferenceBlock),
200}
201
202/// Text content block
203#[serde_with::skip_serializing_none]
204#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
205pub struct TextBlock {
206    /// The text content
207    pub text: String,
208
209    /// Cache control for this block
210    pub cache_control: Option<CacheControl>,
211
212    /// Citations for this text block
213    pub citations: Option<Vec<Citation>>,
214}
215
216/// Image content block
217#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
218pub struct ImageBlock {
219    /// The image source
220    pub source: ImageSource,
221
222    /// Cache control for this block
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub cache_control: Option<CacheControl>,
225}
226
227/// Image source (base64 or URL)
228#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
229#[serde(tag = "type", rename_all = "snake_case")]
230pub enum ImageSource {
231    Base64 { media_type: String, data: String },
232    Url { url: String },
233}
234
235/// Document content block
236#[serde_with::skip_serializing_none]
237#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
238pub struct DocumentBlock {
239    /// The document source
240    pub source: DocumentSource,
241
242    /// Cache control for this block
243    pub cache_control: Option<CacheControl>,
244
245    /// Optional title for the document
246    pub title: Option<String>,
247
248    /// Optional context for the document
249    pub context: Option<String>,
250
251    /// Citations configuration
252    pub citations: Option<CitationsConfig>,
253}
254
255/// Document source (base64, text, or URL)
256#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
257#[serde(tag = "type", rename_all = "snake_case")]
258pub enum DocumentSource {
259    Base64 { media_type: String, data: String },
260    Text { data: String },
261    Url { url: String },
262    Content { content: Vec<InputContentBlock> },
263}
264
265/// Tool use block (in assistant messages)
266#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
267pub struct ToolUseBlock {
268    /// Unique identifier for this tool use
269    pub id: String,
270
271    /// Name of the tool being used
272    pub name: String,
273
274    /// Input arguments for the tool
275    pub input: Value,
276
277    /// Cache control for this block
278    #[serde(skip_serializing_if = "Option::is_none")]
279    pub cache_control: Option<CacheControl>,
280}
281
282/// Tool result block (in user messages)
283#[serde_with::skip_serializing_none]
284#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
285pub struct ToolResultBlock {
286    /// The ID of the tool use this is a result for
287    pub tool_use_id: String,
288
289    /// The result content (string or blocks)
290    pub content: Option<ToolResultContent>,
291
292    /// Whether this result indicates an error
293    pub is_error: Option<bool>,
294
295    /// Cache control for this block
296    pub cache_control: Option<CacheControl>,
297}
298
299/// Tool result content (string or blocks)
300#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
301#[serde(untagged)]
302pub enum ToolResultContent {
303    String(String),
304    Blocks(Vec<ToolResultContentBlock>),
305}
306
307/// Content blocks allowed in tool results
308#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
309#[serde(tag = "type", rename_all = "snake_case")]
310pub enum ToolResultContentBlock {
311    Text(TextBlock),
312    Image(ImageBlock),
313    Document(DocumentBlock),
314    SearchResult(SearchResultBlock),
315}
316
317/// Thinking block
318#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
319pub struct ThinkingBlock {
320    /// The thinking content
321    pub thinking: String,
322
323    /// Signature for the thinking block
324    pub signature: String,
325}
326
327/// Redacted thinking block
328#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
329pub struct RedactedThinkingBlock {
330    /// The encrypted/redacted data
331    pub data: String,
332}
333
334/// Server tool use block
335#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
336pub struct ServerToolUseBlock {
337    /// Unique identifier for this tool use
338    pub id: String,
339
340    /// Name of the server tool
341    pub name: String,
342
343    /// Input arguments for the tool
344    pub input: Value,
345
346    /// Cache control for this block
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub cache_control: Option<CacheControl>,
349}
350
351/// Search result block
352#[serde_with::skip_serializing_none]
353#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
354pub struct SearchResultBlock {
355    /// Source URL or identifier
356    pub source: String,
357
358    /// Title of the search result
359    pub title: String,
360
361    /// Content of the search result
362    pub content: Vec<TextBlock>,
363
364    /// Cache control for this block
365    pub cache_control: Option<CacheControl>,
366
367    /// Citations configuration
368    pub citations: Option<CitationsConfig>,
369}
370
371/// Web search tool result block
372#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
373pub struct WebSearchToolResultBlock {
374    /// The tool use ID this result is for
375    pub tool_use_id: String,
376
377    /// The search results or error
378    pub content: WebSearchToolResultContent,
379
380    /// Cache control for this block
381    #[serde(skip_serializing_if = "Option::is_none")]
382    pub cache_control: Option<CacheControl>,
383}
384
385/// Web search tool result content
386#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
387#[serde(untagged)]
388pub enum WebSearchToolResultContent {
389    Results(Vec<WebSearchResultBlock>),
390    Error(WebSearchToolResultError),
391}
392
393/// Web search result block
394#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
395pub struct WebSearchResultBlock {
396    /// Title of the search result
397    pub title: String,
398
399    /// URL of the search result
400    pub url: String,
401
402    /// Encrypted content
403    pub encrypted_content: String,
404
405    /// Page age (if available)
406    #[serde(skip_serializing_if = "Option::is_none")]
407    pub page_age: Option<String>,
408}
409
410/// Web search tool result error
411#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
412pub struct WebSearchToolResultError {
413    #[serde(rename = "type")]
414    pub error_type: String,
415    pub error_code: WebSearchToolResultErrorCode,
416}
417
418/// Web search tool result error codes
419#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
420#[serde(rename_all = "snake_case")]
421pub enum WebSearchToolResultErrorCode {
422    InvalidToolInput,
423    Unavailable,
424    MaxUsesExceeded,
425    TooManyRequests,
426    QueryTooLong,
427}
428
429/// Cache control configuration
430#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
431#[serde(tag = "type", rename_all = "snake_case")]
432pub enum CacheControl {
433    Ephemeral,
434}
435
436/// Citations configuration
437#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
438pub struct CitationsConfig {
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub enabled: Option<bool>,
441}
442
443/// Citation types
444#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
445#[serde(tag = "type", rename_all = "snake_case")]
446#[expect(
447    clippy::enum_variant_names,
448    reason = "variant names match the OpenAI API citation type discriminators (char_location, page_location, etc.)"
449)]
450pub enum Citation {
451    CharLocation(CharLocationCitation),
452    PageLocation(PageLocationCitation),
453    ContentBlockLocation(ContentBlockLocationCitation),
454    WebSearchResultLocation(WebSearchResultLocationCitation),
455    SearchResultLocation(SearchResultLocationCitation),
456}
457
458/// Character location citation
459#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
460pub struct CharLocationCitation {
461    pub cited_text: String,
462    pub document_index: u32,
463    pub document_title: Option<String>,
464    pub start_char_index: u32,
465    pub end_char_index: u32,
466    #[serde(skip_serializing_if = "Option::is_none")]
467    pub file_id: Option<String>,
468}
469
470/// Page location citation
471#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
472pub struct PageLocationCitation {
473    pub cited_text: String,
474    pub document_index: u32,
475    pub document_title: Option<String>,
476    pub start_page_number: u32,
477    pub end_page_number: u32,
478}
479
480/// Content block location citation
481#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
482pub struct ContentBlockLocationCitation {
483    pub cited_text: String,
484    pub document_index: u32,
485    pub document_title: Option<String>,
486    pub start_block_index: u32,
487    pub end_block_index: u32,
488}
489
490/// Web search result location citation
491#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
492pub struct WebSearchResultLocationCitation {
493    pub cited_text: String,
494    pub url: String,
495    pub title: Option<String>,
496    pub encrypted_index: String,
497}
498
499/// Search result location citation
500#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
501pub struct SearchResultLocationCitation {
502    pub cited_text: String,
503    pub search_result_index: u32,
504    pub source: String,
505    pub title: Option<String>,
506    pub start_block_index: u32,
507    pub end_block_index: u32,
508}
509
510// ============================================================================
511// Tool Definitions
512// ============================================================================
513
514/// Tool definition
515#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
516#[serde(untagged)]
517#[expect(
518    clippy::enum_variant_names,
519    reason = "ToolSearch matches Anthropic API naming"
520)]
521#[schemars(rename = "MessagesTool")]
522pub enum Tool {
523    /// MCP toolset definition
524    McpToolset(McpToolset),
525    /// Custom tool definition (must come before ToolSearch: CustomTool requires
526    /// `input_schema` which acts as a discriminator — ToolSearchTool JSON lacks
527    /// it and falls through, while CustomTool JSON with "type" would incorrectly
528    /// match ToolSearchTool's less-restrictive shape if tried first)
529    Custom(CustomTool),
530    /// Tool search tool
531    ToolSearch(ToolSearchTool),
532    /// Bash tool (computer use)
533    Bash(BashTool),
534    /// Text editor tool (computer use)
535    TextEditor(TextEditorTool),
536    /// Web search tool
537    WebSearch(WebSearchTool),
538}
539
540/// Custom tool definition
541#[serde_with::skip_serializing_none]
542#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
543pub struct CustomTool {
544    /// Name of the tool
545    pub name: String,
546
547    /// Optional type (defaults to "custom")
548    #[serde(rename = "type")]
549    pub tool_type: Option<String>,
550
551    /// Description of what this tool does
552    pub description: Option<String>,
553
554    /// JSON schema for the tool's input
555    pub input_schema: InputSchema,
556
557    /// Whether to defer loading this tool
558    pub defer_loading: Option<bool>,
559
560    /// Cache control for this tool
561    pub cache_control: Option<CacheControl>,
562}
563
564/// JSON Schema for tool input
565#[serde_with::skip_serializing_none]
566#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
567pub struct InputSchema {
568    #[serde(rename = "type")]
569    pub schema_type: String,
570
571    pub properties: Option<HashMap<String, Value>>,
572
573    pub required: Option<Vec<String>>,
574
575    /// Additional properties can be stored here
576    #[serde(flatten)]
577    pub additional: HashMap<String, Value>,
578}
579
580/// Bash tool for computer use
581#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
582pub struct BashTool {
583    #[serde(rename = "type")]
584    pub tool_type: String, // "bash_20250124"
585
586    pub name: String, // "bash"
587
588    #[serde(skip_serializing_if = "Option::is_none")]
589    pub cache_control: Option<CacheControl>,
590}
591
592/// Text editor tool for computer use
593#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
594pub struct TextEditorTool {
595    #[serde(rename = "type")]
596    pub tool_type: String, // "text_editor_20250124", etc.
597
598    pub name: String, // "str_replace_editor"
599
600    #[serde(skip_serializing_if = "Option::is_none")]
601    pub cache_control: Option<CacheControl>,
602}
603
604/// Web search tool
605#[serde_with::skip_serializing_none]
606#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
607pub struct WebSearchTool {
608    #[serde(rename = "type")]
609    pub tool_type: String, // "web_search_20250305"
610
611    pub name: String, // "web_search"
612
613    pub allowed_domains: Option<Vec<String>>,
614
615    pub blocked_domains: Option<Vec<String>>,
616
617    pub max_uses: Option<u32>,
618
619    pub user_location: Option<UserLocation>,
620
621    pub cache_control: Option<CacheControl>,
622}
623
624/// User location for web search
625#[serde_with::skip_serializing_none]
626#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
627pub struct UserLocation {
628    #[serde(rename = "type")]
629    pub location_type: String, // "approximate"
630
631    pub city: Option<String>,
632
633    pub region: Option<String>,
634
635    pub country: Option<String>,
636
637    pub timezone: Option<String>,
638}
639
640// ============================================================================
641// Tool Choice
642// ============================================================================
643
644/// How the model should use the provided tools
645#[serde_with::skip_serializing_none]
646#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
647#[serde(tag = "type", rename_all = "snake_case")]
648#[schemars(rename = "MessagesToolChoice")]
649pub enum ToolChoice {
650    /// The model will automatically decide whether to use tools
651    Auto {
652        disable_parallel_tool_use: Option<bool>,
653    },
654    /// The model will use any available tools
655    Any {
656        disable_parallel_tool_use: Option<bool>,
657    },
658    /// The model will use the specified tool
659    Tool {
660        name: String,
661        disable_parallel_tool_use: Option<bool>,
662    },
663    /// The model will not use tools
664    None,
665}
666
667// ============================================================================
668// Thinking Configuration
669// ============================================================================
670
671/// Configuration for extended thinking
672#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
673#[serde(tag = "type", rename_all = "snake_case")]
674pub enum ThinkingConfig {
675    /// Enable extended thinking
676    Enabled {
677        /// Budget in tokens for thinking (minimum 1024)
678        budget_tokens: u32,
679    },
680    /// Disable extended thinking
681    Disabled,
682}
683
684// ============================================================================
685// Response Types
686// ============================================================================
687
688/// Response message from the API
689#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
690pub struct Message {
691    /// Unique object identifier
692    pub id: String,
693
694    /// Object type (always "message")
695    #[serde(rename = "type")]
696    pub message_type: String,
697
698    /// Conversational role (always "assistant")
699    pub role: String,
700
701    /// Content generated by the model
702    pub content: Vec<ContentBlock>,
703
704    /// The model that generated the message
705    pub model: String,
706
707    /// The reason the model stopped generating
708    pub stop_reason: Option<StopReason>,
709
710    /// Which custom stop sequence was generated (if any)
711    pub stop_sequence: Option<String>,
712
713    /// Billing and rate-limit usage
714    pub usage: Usage,
715}
716
717/// Output content block types
718#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
719#[serde(tag = "type", rename_all = "snake_case")]
720pub enum ContentBlock {
721    /// Text content
722    Text {
723        text: String,
724        #[serde(skip_serializing_if = "Option::is_none")]
725        citations: Option<Vec<Citation>>,
726    },
727    /// Tool use by the model
728    ToolUse {
729        id: String,
730        name: String,
731        input: Value,
732    },
733    /// Thinking content
734    Thinking { thinking: String, signature: String },
735    /// Redacted thinking content
736    RedactedThinking { data: String },
737    /// Server tool use
738    ServerToolUse {
739        id: String,
740        name: String,
741        input: Value,
742    },
743    /// Web search tool result
744    WebSearchToolResult {
745        tool_use_id: String,
746        content: WebSearchToolResultContent,
747    },
748    /// Tool search tool result
749    ToolSearchToolResult {
750        tool_use_id: String,
751        content: ToolSearchResultContent,
752    },
753    /// Tool reference (returned by tool search)
754    ToolReference {
755        tool_name: String,
756        #[serde(skip_serializing_if = "Option::is_none")]
757        description: Option<String>,
758    },
759    /// MCP tool use (beta) - model requesting tool execution via MCP
760    McpToolUse {
761        id: String,
762        name: String,
763        server_name: String,
764        input: Value,
765    },
766    /// MCP tool result (beta) - result from MCP tool execution
767    McpToolResult {
768        tool_use_id: String,
769        content: Option<ToolResultContent>,
770        is_error: Option<bool>,
771    },
772}
773
774/// Stop reasons
775#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, schemars::JsonSchema)]
776#[serde(rename_all = "snake_case")]
777pub enum StopReason {
778    /// The model reached a natural stopping point
779    EndTurn,
780    /// We exceeded the requested max_tokens
781    MaxTokens,
782    /// One of the custom stop_sequences was generated
783    StopSequence,
784    /// The model invoked one or more tools
785    ToolUse,
786    /// We paused a long-running turn
787    PauseTurn,
788    /// Streaming classifiers intervened
789    Refusal,
790}
791
792/// Billing and rate-limit usage
793#[serde_with::skip_serializing_none]
794#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
795#[schemars(rename = "MessagesUsage")]
796pub struct Usage {
797    /// The number of input tokens used
798    pub input_tokens: u32,
799
800    /// The number of output tokens used
801    pub output_tokens: u32,
802
803    /// The number of input tokens used to create the cache entry
804    pub cache_creation_input_tokens: Option<u32>,
805
806    /// The number of input tokens read from the cache
807    pub cache_read_input_tokens: Option<u32>,
808
809    /// Breakdown of cached tokens by TTL
810    pub cache_creation: Option<CacheCreation>,
811
812    /// Server tool usage information
813    pub server_tool_use: Option<ServerToolUsage>,
814
815    /// Service tier used for the request
816    pub service_tier: Option<String>,
817}
818
819/// Cache creation breakdown
820#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
821pub struct CacheCreation {
822    #[serde(flatten)]
823    pub tokens_by_ttl: HashMap<String, u32>,
824}
825
826/// Server tool usage information
827#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
828pub struct ServerToolUsage {
829    pub web_search_requests: u32,
830}
831
832// ============================================================================
833// Streaming Event Types
834// ============================================================================
835
836/// Server-sent event wrapper
837#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
838#[serde(tag = "type", rename_all = "snake_case")]
839pub enum MessageStreamEvent {
840    /// Start of a new message
841    MessageStart { message: Message },
842    /// Update to a message
843    MessageDelta {
844        delta: MessageDelta,
845        usage: MessageDeltaUsage,
846    },
847    /// End of a message
848    MessageStop,
849    /// Start of a content block
850    ContentBlockStart {
851        index: u32,
852        content_block: ContentBlock,
853    },
854    /// Update to a content block
855    ContentBlockDelta {
856        index: u32,
857        delta: ContentBlockDelta,
858    },
859    /// End of a content block
860    ContentBlockStop { index: u32 },
861    /// Ping event (for keep-alive)
862    Ping,
863    /// Error event
864    Error { error: ErrorResponse },
865}
866
867/// Message delta for streaming updates
868#[serde_with::skip_serializing_none]
869#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
870pub struct MessageDelta {
871    pub stop_reason: Option<StopReason>,
872
873    pub stop_sequence: Option<String>,
874}
875
876/// Usage delta for streaming updates
877#[serde_with::skip_serializing_none]
878#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
879pub struct MessageDeltaUsage {
880    pub output_tokens: u32,
881
882    pub input_tokens: Option<u32>,
883
884    pub cache_creation_input_tokens: Option<u32>,
885
886    pub cache_read_input_tokens: Option<u32>,
887
888    pub server_tool_use: Option<ServerToolUsage>,
889}
890
891/// Content block delta for streaming updates
892#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
893#[serde(tag = "type", rename_all = "snake_case")]
894#[expect(
895    clippy::enum_variant_names,
896    reason = "variant names match the OpenAI/Anthropic streaming delta type discriminators (text_delta, input_json_delta, etc.)"
897)]
898pub enum ContentBlockDelta {
899    /// Text delta
900    TextDelta { text: String },
901    /// JSON input delta (for tool use)
902    InputJsonDelta { partial_json: String },
903    /// Thinking delta
904    ThinkingDelta { thinking: String },
905    /// Signature delta
906    SignatureDelta { signature: String },
907    /// Citations delta
908    CitationsDelta { citation: Citation },
909}
910
911// ============================================================================
912// Error Types
913// ============================================================================
914
915/// Error response
916#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
917#[schemars(rename = "MessagesErrorResponse")]
918pub struct ErrorResponse {
919    #[serde(rename = "type")]
920    pub error_type: String,
921
922    pub message: String,
923}
924
925/// API error types
926#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
927#[serde(tag = "type", rename_all = "snake_case")]
928#[expect(
929    clippy::enum_variant_names,
930    reason = "variant names match the OpenAI API error type discriminators (invalid_request_error, authentication_error, etc.)"
931)]
932pub enum ApiError {
933    InvalidRequestError { message: String },
934    AuthenticationError { message: String },
935    BillingError { message: String },
936    PermissionError { message: String },
937    NotFoundError { message: String },
938    RateLimitError { message: String },
939    TimeoutError { message: String },
940    ApiError { message: String },
941    OverloadedError { message: String },
942}
943
944// ============================================================================
945// Count Tokens Types
946// ============================================================================
947
948/// Request to count tokens in a message
949#[serde_with::skip_serializing_none]
950#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
951pub struct CountMessageTokensRequest {
952    /// The model to use for token counting
953    pub model: String,
954
955    /// Input messages
956    pub messages: Vec<InputMessage>,
957
958    /// System prompt
959    pub system: Option<SystemContent>,
960
961    /// Thinking configuration
962    pub thinking: Option<ThinkingConfig>,
963
964    /// Tool choice
965    pub tool_choice: Option<ToolChoice>,
966
967    /// Tool definitions
968    pub tools: Option<Vec<Tool>>,
969}
970
971/// Response from token counting
972#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
973pub struct CountMessageTokensResponse {
974    pub input_tokens: u32,
975}
976
977// ============================================================================
978// Model Info Types
979// ============================================================================
980
981/// Model information
982#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
983pub struct ModelInfo {
984    /// Object type (always "model")
985    #[serde(rename = "type")]
986    pub model_type: String,
987
988    /// Model ID
989    pub id: String,
990
991    /// Display name
992    pub display_name: String,
993
994    /// When the model was created
995    pub created_at: String,
996}
997
998/// List of models response
999#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1000pub struct ListModelsResponse {
1001    pub data: Vec<ModelInfo>,
1002    pub has_more: bool,
1003    pub first_id: Option<String>,
1004    pub last_id: Option<String>,
1005}
1006
1007// ============================================================================
1008// Beta Features - Container & MCP Configuration
1009// ============================================================================
1010
1011/// Container configuration for code execution (beta)
1012#[serde_with::skip_serializing_none]
1013#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1014pub struct ContainerConfig {
1015    /// Container ID for reuse across requests
1016    pub id: Option<String>,
1017
1018    /// Skills to be loaded in the container
1019    pub skills: Option<Vec<String>>,
1020}
1021
1022/// MCP server configuration (beta)
1023#[serde_with::skip_serializing_none]
1024#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1025pub struct McpServerConfig {
1026    /// Server type (always "url")
1027    #[serde(rename = "type", default = "McpServerConfig::default_type")]
1028    pub server_type: String,
1029
1030    /// Name of the MCP server
1031    pub name: String,
1032
1033    /// MCP server URL
1034    pub url: String,
1035
1036    /// Authorization token (if required)
1037    pub authorization_token: Option<String>,
1038
1039    /// Tool configuration for this server
1040    pub tool_configuration: Option<McpToolConfiguration>,
1041}
1042
1043impl McpServerConfig {
1044    fn default_type() -> String {
1045        "url".to_string()
1046    }
1047}
1048
1049/// MCP tool configuration
1050#[serde_with::skip_serializing_none]
1051#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1052pub struct McpToolConfiguration {
1053    /// Whether to allow all tools
1054    pub enabled: Option<bool>,
1055
1056    /// Allowed tool names
1057    pub allowed_tools: Option<Vec<String>>,
1058}
1059
1060// ============================================================================
1061// Beta Features - MCP Tool Types
1062// ============================================================================
1063
1064/// MCP tool use block (beta) - for assistant messages
1065#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1066pub struct McpToolUseBlock {
1067    /// Unique identifier for this tool use
1068    pub id: String,
1069
1070    /// Name of the tool being used
1071    pub name: String,
1072
1073    /// Name of the MCP server
1074    pub server_name: String,
1075
1076    /// Input arguments for the tool
1077    pub input: Value,
1078
1079    /// Cache control for this block
1080    #[serde(skip_serializing_if = "Option::is_none")]
1081    pub cache_control: Option<CacheControl>,
1082}
1083
1084/// MCP tool result block (beta) - for user messages
1085#[serde_with::skip_serializing_none]
1086#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1087pub struct McpToolResultBlock {
1088    /// The ID of the tool use this is a result for
1089    pub tool_use_id: String,
1090
1091    /// The result content
1092    pub content: Option<ToolResultContent>,
1093
1094    /// Whether this result indicates an error
1095    pub is_error: Option<bool>,
1096
1097    /// Cache control for this block
1098    pub cache_control: Option<CacheControl>,
1099}
1100
1101/// MCP toolset definition (beta)
1102#[serde_with::skip_serializing_none]
1103#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1104pub struct McpToolset {
1105    #[serde(rename = "type")]
1106    pub toolset_type: String, // "mcp_toolset"
1107
1108    /// Name of the MCP server to configure tools for
1109    pub mcp_server_name: String,
1110
1111    /// Default configuration applied to all tools from this server
1112    pub default_config: Option<McpToolDefaultConfig>,
1113
1114    /// Configuration overrides for specific tools
1115    pub configs: Option<HashMap<String, McpToolConfig>>,
1116
1117    /// Cache control for this toolset
1118    pub cache_control: Option<CacheControl>,
1119}
1120
1121/// Default configuration for MCP tools
1122#[serde_with::skip_serializing_none]
1123#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1124pub struct McpToolDefaultConfig {
1125    /// Whether tools are enabled
1126    pub enabled: Option<bool>,
1127
1128    /// Whether to defer loading
1129    pub defer_loading: Option<bool>,
1130}
1131
1132/// Per-tool MCP configuration
1133#[serde_with::skip_serializing_none]
1134#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1135pub struct McpToolConfig {
1136    /// Whether this tool is enabled
1137    pub enabled: Option<bool>,
1138
1139    /// Whether to defer loading
1140    pub defer_loading: Option<bool>,
1141}
1142
1143// ============================================================================
1144// Beta Features - Code Execution Types
1145// ============================================================================
1146
1147/// Code execution tool (beta)
1148#[serde_with::skip_serializing_none]
1149#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1150pub struct CodeExecutionTool {
1151    #[serde(rename = "type")]
1152    pub tool_type: String, // "code_execution_20250522" or "code_execution_20250825"
1153
1154    pub name: String, // "code_execution"
1155
1156    /// Allowed callers for this tool
1157    pub allowed_callers: Option<Vec<String>>,
1158
1159    /// Whether to defer loading
1160    pub defer_loading: Option<bool>,
1161
1162    /// Whether to use strict mode
1163    pub strict: Option<bool>,
1164
1165    /// Cache control for this tool
1166    pub cache_control: Option<CacheControl>,
1167}
1168
1169/// Code execution result block (beta)
1170#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1171pub struct CodeExecutionResultBlock {
1172    /// Stdout output
1173    pub stdout: String,
1174
1175    /// Stderr output
1176    pub stderr: String,
1177
1178    /// Return code
1179    pub return_code: i32,
1180
1181    /// Output files
1182    pub content: Vec<CodeExecutionOutputBlock>,
1183}
1184
1185/// Code execution output file reference
1186#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1187pub struct CodeExecutionOutputBlock {
1188    #[serde(rename = "type")]
1189    pub block_type: String, // "code_execution_output"
1190
1191    /// File ID
1192    pub file_id: String,
1193}
1194
1195/// Code execution tool result block (beta)
1196#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1197pub struct CodeExecutionToolResultBlock {
1198    /// The ID of the tool use this is a result for
1199    pub tool_use_id: String,
1200
1201    /// The result content (success or error)
1202    pub content: CodeExecutionToolResultContent,
1203
1204    /// Cache control for this block
1205    #[serde(skip_serializing_if = "Option::is_none")]
1206    pub cache_control: Option<CacheControl>,
1207}
1208
1209/// Code execution tool result content
1210#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1211#[serde(untagged)]
1212pub enum CodeExecutionToolResultContent {
1213    Success(CodeExecutionResultBlock),
1214    Error(CodeExecutionToolResultError),
1215}
1216
1217/// Code execution tool result error
1218#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1219pub struct CodeExecutionToolResultError {
1220    #[serde(rename = "type")]
1221    pub error_type: String, // "code_execution_tool_result_error"
1222
1223    pub error_code: CodeExecutionToolResultErrorCode,
1224}
1225
1226/// Code execution error codes
1227#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1228#[serde(rename_all = "snake_case")]
1229pub enum CodeExecutionToolResultErrorCode {
1230    Unavailable,
1231    CodeExecutionExceededTimeout,
1232    ContainerExpired,
1233    InvalidToolInput,
1234}
1235
1236/// Bash code execution result block (beta)
1237#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1238pub struct BashCodeExecutionResultBlock {
1239    /// Stdout output
1240    pub stdout: String,
1241
1242    /// Stderr output
1243    pub stderr: String,
1244
1245    /// Return code
1246    pub return_code: i32,
1247
1248    /// Output files
1249    pub content: Vec<BashCodeExecutionOutputBlock>,
1250}
1251
1252/// Bash code execution output file reference
1253#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1254pub struct BashCodeExecutionOutputBlock {
1255    #[serde(rename = "type")]
1256    pub block_type: String, // "bash_code_execution_output"
1257
1258    /// File ID
1259    pub file_id: String,
1260}
1261
1262/// Bash code execution tool result block (beta)
1263#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1264pub struct BashCodeExecutionToolResultBlock {
1265    /// The ID of the tool use this is a result for
1266    pub tool_use_id: String,
1267
1268    /// The result content (success or error)
1269    pub content: BashCodeExecutionToolResultContent,
1270
1271    /// Cache control for this block
1272    #[serde(skip_serializing_if = "Option::is_none")]
1273    pub cache_control: Option<CacheControl>,
1274}
1275
1276/// Bash code execution tool result content
1277#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1278#[serde(untagged)]
1279pub enum BashCodeExecutionToolResultContent {
1280    Success(BashCodeExecutionResultBlock),
1281    Error(BashCodeExecutionToolResultError),
1282}
1283
1284/// Bash code execution tool result error
1285#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1286pub struct BashCodeExecutionToolResultError {
1287    #[serde(rename = "type")]
1288    pub error_type: String, // "bash_code_execution_tool_result_error"
1289
1290    pub error_code: BashCodeExecutionToolResultErrorCode,
1291}
1292
1293/// Bash code execution error codes
1294#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1295#[serde(rename_all = "snake_case")]
1296pub enum BashCodeExecutionToolResultErrorCode {
1297    Unavailable,
1298    CodeExecutionExceededTimeout,
1299    ContainerExpired,
1300    InvalidToolInput,
1301}
1302
1303/// Text editor code execution tool result block (beta)
1304#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1305pub struct TextEditorCodeExecutionToolResultBlock {
1306    /// The ID of the tool use this is a result for
1307    pub tool_use_id: String,
1308
1309    /// The result content
1310    pub content: TextEditorCodeExecutionToolResultContent,
1311
1312    /// Cache control for this block
1313    #[serde(skip_serializing_if = "Option::is_none")]
1314    pub cache_control: Option<CacheControl>,
1315}
1316
1317/// Text editor code execution result content
1318#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1319#[serde(untagged)]
1320pub enum TextEditorCodeExecutionToolResultContent {
1321    CreateResult(TextEditorCodeExecutionCreateResultBlock),
1322    StrReplaceResult(TextEditorCodeExecutionStrReplaceResultBlock),
1323    ViewResult(TextEditorCodeExecutionViewResultBlock),
1324    Error(TextEditorCodeExecutionToolResultError),
1325}
1326
1327/// Text editor create result block
1328#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1329pub struct TextEditorCodeExecutionCreateResultBlock {
1330    #[serde(rename = "type")]
1331    pub block_type: String, // "text_editor_code_execution_create_result"
1332}
1333
1334/// Text editor str_replace result block
1335#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1336pub struct TextEditorCodeExecutionStrReplaceResultBlock {
1337    #[serde(rename = "type")]
1338    pub block_type: String, // "text_editor_code_execution_str_replace_result"
1339
1340    /// Snippet of content around the replacement
1341    #[serde(skip_serializing_if = "Option::is_none")]
1342    pub snippet: Option<String>,
1343}
1344
1345/// Text editor view result block
1346#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1347pub struct TextEditorCodeExecutionViewResultBlock {
1348    #[serde(rename = "type")]
1349    pub block_type: String, // "text_editor_code_execution_view_result"
1350
1351    /// Content of the viewed file
1352    pub content: String,
1353}
1354
1355/// Text editor code execution tool result error
1356#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1357pub struct TextEditorCodeExecutionToolResultError {
1358    #[serde(rename = "type")]
1359    pub error_type: String,
1360
1361    pub error_code: TextEditorCodeExecutionToolResultErrorCode,
1362}
1363
1364/// Text editor code execution error codes
1365#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1366#[serde(rename_all = "snake_case")]
1367pub enum TextEditorCodeExecutionToolResultErrorCode {
1368    Unavailable,
1369    InvalidToolInput,
1370    FileNotFound,
1371    ContainerExpired,
1372}
1373
1374// ============================================================================
1375// Beta Features - Web Fetch Types
1376// ============================================================================
1377
1378/// Web fetch tool (beta)
1379#[serde_with::skip_serializing_none]
1380#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1381pub struct WebFetchTool {
1382    #[serde(rename = "type")]
1383    pub tool_type: String, // "web_fetch_20250305" or similar
1384
1385    pub name: String, // "web_fetch"
1386
1387    /// Allowed callers for this tool
1388    pub allowed_callers: Option<Vec<String>>,
1389
1390    /// Maximum number of uses
1391    pub max_uses: Option<u32>,
1392
1393    /// Cache control for this tool
1394    pub cache_control: Option<CacheControl>,
1395}
1396
1397/// Web fetch result block (beta)
1398#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1399pub struct WebFetchResultBlock {
1400    #[serde(rename = "type")]
1401    pub block_type: String, // "web_fetch_result"
1402
1403    /// The URL that was fetched
1404    pub url: String,
1405
1406    /// The document content
1407    pub content: DocumentBlock,
1408
1409    /// When the content was retrieved
1410    #[serde(skip_serializing_if = "Option::is_none")]
1411    pub retrieved_at: Option<String>,
1412}
1413
1414/// Web fetch tool result block (beta)
1415#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1416pub struct WebFetchToolResultBlock {
1417    /// The ID of the tool use this is a result for
1418    pub tool_use_id: String,
1419
1420    /// The result content (success or error)
1421    pub content: WebFetchToolResultContent,
1422
1423    /// Cache control for this block
1424    #[serde(skip_serializing_if = "Option::is_none")]
1425    pub cache_control: Option<CacheControl>,
1426}
1427
1428/// Web fetch tool result content
1429#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1430#[serde(untagged)]
1431pub enum WebFetchToolResultContent {
1432    Success(WebFetchResultBlock),
1433    Error(WebFetchToolResultError),
1434}
1435
1436/// Web fetch tool result error
1437#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1438pub struct WebFetchToolResultError {
1439    #[serde(rename = "type")]
1440    pub error_type: String, // "web_fetch_tool_result_error"
1441
1442    pub error_code: WebFetchToolResultErrorCode,
1443}
1444
1445/// Web fetch error codes
1446#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1447#[serde(rename_all = "snake_case")]
1448pub enum WebFetchToolResultErrorCode {
1449    InvalidToolInput,
1450    Unavailable,
1451    MaxUsesExceeded,
1452    TooManyRequests,
1453    UrlNotAllowed,
1454    FetchFailed,
1455    ContentTooLarge,
1456}
1457
1458// ============================================================================
1459// Beta Features - Tool Search Types
1460// ============================================================================
1461
1462/// Tool search tool (beta)
1463#[serde_with::skip_serializing_none]
1464#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1465pub struct ToolSearchTool {
1466    #[serde(rename = "type")]
1467    pub tool_type: String, // "tool_search_tool_regex" or "tool_search_tool_bm25"
1468
1469    pub name: String,
1470
1471    /// Allowed callers for this tool
1472    pub allowed_callers: Option<Vec<String>>,
1473
1474    /// Cache control for this tool
1475    pub cache_control: Option<CacheControl>,
1476}
1477
1478/// Tool reference block (beta) - returned by tool search
1479#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1480pub struct ToolReferenceBlock {
1481    #[serde(rename = "type")]
1482    pub block_type: String, // "tool_reference"
1483
1484    /// Tool name
1485    pub tool_name: String,
1486
1487    /// Tool description
1488    #[serde(skip_serializing_if = "Option::is_none")]
1489    pub description: Option<String>,
1490}
1491
1492/// Tool search result content — wraps tool references returned by tool search
1493#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1494pub struct ToolSearchResultContent {
1495    #[serde(rename = "type")]
1496    pub block_type: String, // "tool_search_tool_search_result"
1497
1498    /// Tool references found by the search
1499    pub tool_references: Vec<ToolReferenceBlock>,
1500}
1501
1502/// Tool search tool result block (beta)
1503#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1504pub struct ToolSearchToolResultBlock {
1505    /// The ID of the tool use this is a result for
1506    pub tool_use_id: String,
1507
1508    /// The search results
1509    pub content: ToolSearchResultContent,
1510
1511    /// Cache control for this block
1512    #[serde(skip_serializing_if = "Option::is_none")]
1513    pub cache_control: Option<CacheControl>,
1514}
1515
1516// ============================================================================
1517// Beta Features - Container Upload Types
1518// ============================================================================
1519
1520/// Container upload block (beta)
1521#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1522pub struct ContainerUploadBlock {
1523    #[serde(rename = "type")]
1524    pub block_type: String, // "container_upload"
1525
1526    /// File ID
1527    pub file_id: String,
1528
1529    /// File name
1530    pub file_name: String,
1531
1532    /// File path in container
1533    #[serde(skip_serializing_if = "Option::is_none")]
1534    pub file_path: Option<String>,
1535}
1536
1537// ============================================================================
1538// Beta Features - Memory Tool Types
1539// ============================================================================
1540
1541/// Memory tool (beta)
1542#[serde_with::skip_serializing_none]
1543#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1544pub struct MemoryTool {
1545    #[serde(rename = "type")]
1546    pub tool_type: String, // "memory_20250818"
1547
1548    pub name: String, // "memory"
1549
1550    /// Allowed callers for this tool
1551    pub allowed_callers: Option<Vec<String>>,
1552
1553    /// Whether to defer loading
1554    pub defer_loading: Option<bool>,
1555
1556    /// Whether to use strict mode
1557    pub strict: Option<bool>,
1558
1559    /// Input examples
1560    pub input_examples: Option<Vec<Value>>,
1561
1562    /// Cache control for this tool
1563    pub cache_control: Option<CacheControl>,
1564}
1565
1566// ============================================================================
1567// Beta Features - Computer Use Tool Types
1568// ============================================================================
1569
1570/// Computer use tool (beta)
1571#[serde_with::skip_serializing_none]
1572#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1573pub struct ComputerUseTool {
1574    #[serde(rename = "type")]
1575    pub tool_type: String, // "computer_20241022" or "computer_20250124"
1576
1577    pub name: String, // "computer"
1578
1579    /// Display width
1580    pub display_width_px: u32,
1581
1582    /// Display height
1583    pub display_height_px: u32,
1584
1585    /// Display number (optional)
1586    pub display_number: Option<u32>,
1587
1588    /// Allowed callers for this tool
1589    pub allowed_callers: Option<Vec<String>>,
1590
1591    /// Cache control for this tool
1592    pub cache_control: Option<CacheControl>,
1593}
1594
1595// ============================================================================
1596// Beta Features - Extended Input Content Block Enum
1597// ============================================================================
1598
1599/// Beta input content block types (extends InputContentBlock)
1600#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1601#[serde(tag = "type", rename_all = "snake_case")]
1602pub enum BetaInputContentBlock {
1603    // Standard types
1604    Text(TextBlock),
1605    Image(ImageBlock),
1606    Document(DocumentBlock),
1607    ToolUse(ToolUseBlock),
1608    ToolResult(ToolResultBlock),
1609    Thinking(ThinkingBlock),
1610    RedactedThinking(RedactedThinkingBlock),
1611    ServerToolUse(ServerToolUseBlock),
1612    SearchResult(SearchResultBlock),
1613    WebSearchToolResult(WebSearchToolResultBlock),
1614
1615    // Beta MCP types
1616    McpToolUse(McpToolUseBlock),
1617    McpToolResult(McpToolResultBlock),
1618
1619    // Beta code execution types
1620    CodeExecutionToolResult(CodeExecutionToolResultBlock),
1621    BashCodeExecutionToolResult(BashCodeExecutionToolResultBlock),
1622    TextEditorCodeExecutionToolResult(TextEditorCodeExecutionToolResultBlock),
1623
1624    // Beta web fetch types
1625    WebFetchToolResult(WebFetchToolResultBlock),
1626
1627    // Beta tool search types
1628    ToolSearchToolResult(ToolSearchToolResultBlock),
1629    ToolReference(ToolReferenceBlock),
1630
1631    // Beta container types
1632    ContainerUpload(ContainerUploadBlock),
1633}
1634
1635/// Beta output content block types (extends ContentBlock)
1636#[serde_with::skip_serializing_none]
1637#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1638#[serde(tag = "type", rename_all = "snake_case")]
1639pub enum BetaContentBlock {
1640    // Standard types
1641    Text {
1642        text: String,
1643        citations: Option<Vec<Citation>>,
1644    },
1645    ToolUse {
1646        id: String,
1647        name: String,
1648        input: Value,
1649    },
1650    Thinking {
1651        thinking: String,
1652        signature: String,
1653    },
1654    RedactedThinking {
1655        data: String,
1656    },
1657    ServerToolUse {
1658        id: String,
1659        name: String,
1660        input: Value,
1661    },
1662    WebSearchToolResult {
1663        tool_use_id: String,
1664        content: WebSearchToolResultContent,
1665    },
1666
1667    // Beta MCP types
1668    McpToolUse {
1669        id: String,
1670        name: String,
1671        server_name: String,
1672        input: Value,
1673    },
1674    McpToolResult {
1675        tool_use_id: String,
1676        content: Option<ToolResultContent>,
1677        is_error: Option<bool>,
1678    },
1679
1680    // Beta code execution types
1681    CodeExecutionToolResult {
1682        tool_use_id: String,
1683        content: CodeExecutionToolResultContent,
1684    },
1685    BashCodeExecutionToolResult {
1686        tool_use_id: String,
1687        content: BashCodeExecutionToolResultContent,
1688    },
1689    TextEditorCodeExecutionToolResult {
1690        tool_use_id: String,
1691        content: TextEditorCodeExecutionToolResultContent,
1692    },
1693
1694    // Beta web fetch types
1695    WebFetchToolResult {
1696        tool_use_id: String,
1697        content: WebFetchToolResultContent,
1698    },
1699
1700    // Beta tool search types
1701    ToolSearchToolResult {
1702        tool_use_id: String,
1703        content: ToolSearchResultContent,
1704    },
1705    ToolReference {
1706        tool_name: String,
1707        description: Option<String>,
1708    },
1709
1710    // Beta container types
1711    ContainerUpload {
1712        file_id: String,
1713        file_name: String,
1714        file_path: Option<String>,
1715    },
1716}
1717
1718/// Beta tool definition (extends Tool)
1719#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1720#[serde(untagged)]
1721pub enum BetaTool {
1722    // Standard tools
1723    Custom(CustomTool),
1724    Bash(BashTool),
1725    TextEditor(TextEditorTool),
1726    WebSearch(WebSearchTool),
1727
1728    // Beta tools
1729    CodeExecution(CodeExecutionTool),
1730    McpToolset(McpToolset),
1731    WebFetch(WebFetchTool),
1732    ToolSearch(ToolSearchTool),
1733    Memory(MemoryTool),
1734    ComputerUse(ComputerUseTool),
1735}
1736
1737/// Server tool names for beta features
1738#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1739#[serde(rename_all = "snake_case")]
1740pub enum BetaServerToolName {
1741    WebSearch,
1742    WebFetch,
1743    CodeExecution,
1744    BashCodeExecution,
1745    TextEditorCodeExecution,
1746    ToolSearchToolRegex,
1747    ToolSearchToolBm25,
1748}
1749
1750/// Server tool caller types (beta)
1751#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
1752#[serde(tag = "type", rename_all = "snake_case")]
1753pub enum ServerToolCaller {
1754    /// Direct caller (the model itself)
1755    Direct,
1756    /// Code execution caller
1757    #[serde(rename = "code_execution_20250825")]
1758    CodeExecution20250825,
1759}
1760
1761#[cfg(test)]
1762mod tests {
1763    use serde_json;
1764
1765    use super::*;
1766
1767    #[test]
1768    fn test_tool_mcp_toolset_defer_loading_deserialization() {
1769        let json = r#"{
1770            "type": "mcp_toolset",
1771            "mcp_server_name": "brave",
1772            "default_config": {"defer_loading": true}
1773        }"#;
1774
1775        let tool: Tool = serde_json::from_str(json).expect("Failed to deserialize McpToolset Tool");
1776        match tool {
1777            Tool::McpToolset(ts) => {
1778                assert_eq!(ts.mcp_server_name, "brave");
1779                let default_config = ts.default_config.expect("default_config should be Some");
1780                assert_eq!(default_config.defer_loading, Some(true));
1781            }
1782            other => panic!(
1783                "Expected McpToolset, got {:?}",
1784                std::mem::discriminant(&other)
1785            ),
1786        }
1787    }
1788
1789    #[test]
1790    fn test_tool_search_tool_deserialization() {
1791        let json = r#"{
1792            "type": "tool_search_tool_regex_20251119",
1793            "name": "tool_search_tool_regex"
1794        }"#;
1795
1796        let tool: Tool = serde_json::from_str(json).expect("Failed to deserialize ToolSearch Tool");
1797        match tool {
1798            Tool::ToolSearch(ts) => {
1799                assert_eq!(ts.name, "tool_search_tool_regex");
1800                assert_eq!(ts.tool_type, "tool_search_tool_regex_20251119");
1801            }
1802            other => panic!(
1803                "Expected ToolSearch, got {:?}",
1804                std::mem::discriminant(&other)
1805            ),
1806        }
1807    }
1808
1809    #[test]
1810    fn test_content_block_tool_search_tool_result_deserialization() {
1811        let json = r#"{
1812            "type": "tool_search_tool_result",
1813            "tool_use_id": "srvtoolu_015dw5iXvktXLmqwpyzo4Dp2",
1814            "content": {
1815                "type": "tool_search_tool_search_result",
1816                "tool_references": [
1817                    {"type": "tool_reference", "tool_name": "get_weather"}
1818                ]
1819            }
1820        }"#;
1821
1822        let block: ContentBlock = serde_json::from_str(json)
1823            .expect("Failed to deserialize tool_search_tool_result ContentBlock");
1824        match block {
1825            ContentBlock::ToolSearchToolResult {
1826                tool_use_id,
1827                content,
1828            } => {
1829                assert_eq!(tool_use_id, "srvtoolu_015dw5iXvktXLmqwpyzo4Dp2");
1830                assert_eq!(content.tool_references.len(), 1);
1831                assert_eq!(content.tool_references[0].tool_name, "get_weather");
1832            }
1833            _ => panic!("Expected ToolSearchToolResult variant"),
1834        }
1835    }
1836
1837    #[test]
1838    fn test_content_block_server_tool_use_deserialization() {
1839        let json = r#"{
1840            "type": "server_tool_use",
1841            "id": "srvtoolu_015dw5iXvktXLmqwpyzo4Dp2",
1842            "name": "tool_search_tool_regex",
1843            "input": {"query": "weather"}
1844        }"#;
1845
1846        let block: ContentBlock =
1847            serde_json::from_str(json).expect("Failed to deserialize server_tool_use ContentBlock");
1848        match block {
1849            ContentBlock::ServerToolUse { id, name, input: _ } => {
1850                assert_eq!(id, "srvtoolu_015dw5iXvktXLmqwpyzo4Dp2");
1851                assert_eq!(name, "tool_search_tool_regex");
1852            }
1853            _ => panic!("Expected ServerToolUse variant"),
1854        }
1855    }
1856
1857    #[test]
1858    fn test_content_block_tool_reference_deserialization() {
1859        let json = r#"{
1860            "type": "tool_reference",
1861            "tool_name": "get_weather",
1862            "description": "Get the weather for a location"
1863        }"#;
1864
1865        let block: ContentBlock =
1866            serde_json::from_str(json).expect("Failed to deserialize tool_reference ContentBlock");
1867        match block {
1868            ContentBlock::ToolReference {
1869                tool_name,
1870                description,
1871            } => {
1872                assert_eq!(tool_name, "get_weather");
1873                assert_eq!(description.unwrap(), "Get the weather for a location");
1874            }
1875            _ => panic!("Expected ToolReference variant"),
1876        }
1877    }
1878
1879    #[test]
1880    fn test_full_message_with_tool_search_flow_deserialization() {
1881        // Simulates the full response from Anthropic API with tool search flow
1882        let json = r#"{
1883            "id": "msg_01TEST",
1884            "type": "message",
1885            "role": "assistant",
1886            "model": "claude-sonnet-4-5-20250929",
1887            "content": [
1888                {
1889                    "type": "server_tool_use",
1890                    "id": "srvtoolu_015dw5iXvktXLmqwpyzo4Dp2",
1891                    "name": "tool_search_tool_regex",
1892                    "input": {"query": "weather"}
1893                },
1894                {
1895                    "type": "tool_search_tool_result",
1896                    "tool_use_id": "srvtoolu_015dw5iXvktXLmqwpyzo4Dp2",
1897                    "content": {
1898                        "type": "tool_search_tool_search_result",
1899                        "tool_references": [
1900                            {"type": "tool_reference", "tool_name": "get_weather"}
1901                        ]
1902                    }
1903                },
1904                {
1905                    "type": "tool_use",
1906                    "id": "toolu_01ABC",
1907                    "name": "get_weather",
1908                    "input": {"location": "San Francisco"}
1909                }
1910            ],
1911            "stop_reason": "tool_use",
1912            "stop_sequence": null,
1913            "usage": {
1914                "input_tokens": 100,
1915                "output_tokens": 50
1916            }
1917        }"#;
1918
1919        let msg: Message = serde_json::from_str(json)
1920            .expect("Failed to deserialize Message with tool search flow");
1921        assert_eq!(msg.content.len(), 3);
1922        assert!(matches!(msg.content[0], ContentBlock::ServerToolUse { .. }));
1923        assert!(matches!(
1924            msg.content[1],
1925            ContentBlock::ToolSearchToolResult { .. }
1926        ));
1927        assert!(matches!(msg.content[2], ContentBlock::ToolUse { .. }));
1928    }
1929}