lib_client_anthropic/
types.rs

1//! Data types for the Anthropic API.
2
3use serde::{Deserialize, Serialize};
4
5/// Message role.
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7#[serde(rename_all = "lowercase")]
8pub enum Role {
9    User,
10    Assistant,
11}
12
13/// Content block in a message.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15#[serde(tag = "type", rename_all = "snake_case")]
16pub enum ContentBlock {
17    /// Text content.
18    Text { text: String },
19    /// Tool use request.
20    ToolUse {
21        id: String,
22        name: String,
23        input: serde_json::Value,
24    },
25    /// Tool result.
26    ToolResult {
27        tool_use_id: String,
28        content: String,
29        #[serde(skip_serializing_if = "Option::is_none")]
30        is_error: Option<bool>,
31    },
32}
33
34/// Message content (can be string or blocks).
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(untagged)]
37pub enum MessageContent {
38    /// Simple text content.
39    Text(String),
40    /// Block-based content.
41    Blocks(Vec<ContentBlock>),
42}
43
44/// A message in the conversation.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct Message {
47    /// Message role (user or assistant).
48    pub role: Role,
49    /// Message content.
50    pub content: MessageContent,
51}
52
53impl Message {
54    /// Create a user message with text content.
55    pub fn user(text: impl Into<String>) -> Self {
56        Self {
57            role: Role::User,
58            content: MessageContent::Text(text.into()),
59        }
60    }
61
62    /// Create an assistant message with text content.
63    pub fn assistant(text: impl Into<String>) -> Self {
64        Self {
65            role: Role::Assistant,
66            content: MessageContent::Text(text.into()),
67        }
68    }
69
70    /// Create a user message with content blocks.
71    pub fn user_blocks(blocks: Vec<ContentBlock>) -> Self {
72        Self {
73            role: Role::User,
74            content: MessageContent::Blocks(blocks),
75        }
76    }
77
78    /// Create an assistant message with content blocks.
79    pub fn assistant_blocks(blocks: Vec<ContentBlock>) -> Self {
80        Self {
81            role: Role::Assistant,
82            content: MessageContent::Blocks(blocks),
83        }
84    }
85}
86
87/// Tool definition.
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct Tool {
90    /// Tool name.
91    pub name: String,
92    /// Tool description.
93    pub description: String,
94    /// JSON schema for input parameters.
95    pub input_schema: serde_json::Value,
96}
97
98impl Tool {
99    /// Create a new tool definition.
100    pub fn new(
101        name: impl Into<String>,
102        description: impl Into<String>,
103        input_schema: serde_json::Value,
104    ) -> Self {
105        Self {
106            name: name.into(),
107            description: description.into(),
108            input_schema,
109        }
110    }
111}
112
113/// Request to create a message.
114#[derive(Debug, Clone, Serialize)]
115pub struct CreateMessageRequest {
116    /// Model to use.
117    pub model: String,
118    /// Messages in the conversation.
119    pub messages: Vec<Message>,
120    /// Maximum tokens to generate.
121    pub max_tokens: usize,
122    /// System prompt.
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub system: Option<String>,
125    /// Temperature for sampling.
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub temperature: Option<f32>,
128    /// Top-p sampling.
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub top_p: Option<f32>,
131    /// Stop sequences.
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub stop_sequences: Option<Vec<String>>,
134    /// Available tools.
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub tools: Option<Vec<Tool>>,
137    /// Whether to stream the response.
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub stream: Option<bool>,
140}
141
142impl CreateMessageRequest {
143    /// Create a new message request.
144    pub fn new(model: impl Into<String>, messages: Vec<Message>, max_tokens: usize) -> Self {
145        Self {
146            model: model.into(),
147            messages,
148            max_tokens,
149            system: None,
150            temperature: None,
151            top_p: None,
152            stop_sequences: None,
153            tools: None,
154            stream: None,
155        }
156    }
157
158    /// Set the system prompt.
159    pub fn with_system(mut self, system: impl Into<String>) -> Self {
160        self.system = Some(system.into());
161        self
162    }
163
164    /// Set the temperature.
165    pub fn with_temperature(mut self, temperature: f32) -> Self {
166        self.temperature = Some(temperature);
167        self
168    }
169
170    /// Set top-p sampling.
171    pub fn with_top_p(mut self, top_p: f32) -> Self {
172        self.top_p = Some(top_p);
173        self
174    }
175
176    /// Set stop sequences.
177    pub fn with_stop_sequences(mut self, sequences: Vec<String>) -> Self {
178        self.stop_sequences = Some(sequences);
179        self
180    }
181
182    /// Set available tools.
183    pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
184        self.tools = Some(tools);
185        self
186    }
187}
188
189/// Token usage statistics.
190#[derive(Debug, Clone, Deserialize)]
191pub struct Usage {
192    /// Input tokens.
193    pub input_tokens: usize,
194    /// Output tokens.
195    pub output_tokens: usize,
196}
197
198/// Response from creating a message.
199#[derive(Debug, Clone, Deserialize)]
200pub struct CreateMessageResponse {
201    /// Response ID.
202    pub id: String,
203    /// Response type (always "message").
204    #[serde(rename = "type")]
205    pub response_type: String,
206    /// Role (always "assistant").
207    pub role: Role,
208    /// Content blocks.
209    pub content: Vec<ContentBlock>,
210    /// Model used.
211    pub model: String,
212    /// Stop reason.
213    pub stop_reason: Option<String>,
214    /// Stop sequence that triggered stop.
215    pub stop_sequence: Option<String>,
216    /// Token usage.
217    pub usage: Usage,
218}
219
220impl CreateMessageResponse {
221    /// Extract text content from the response.
222    pub fn text(&self) -> Option<String> {
223        for block in &self.content {
224            if let ContentBlock::Text { text } = block {
225                return Some(text.clone());
226            }
227        }
228        None
229    }
230
231    /// Extract tool use blocks from the response.
232    pub fn tool_uses(&self) -> Vec<(&str, &str, &serde_json::Value)> {
233        self.content
234            .iter()
235            .filter_map(|block| {
236                if let ContentBlock::ToolUse { id, name, input } = block {
237                    Some((id.as_str(), name.as_str(), input))
238                } else {
239                    None
240                }
241            })
242            .collect()
243    }
244
245    /// Check if the response contains tool calls.
246    pub fn has_tool_use(&self) -> bool {
247        self.content
248            .iter()
249            .any(|block| matches!(block, ContentBlock::ToolUse { .. }))
250    }
251}
252
253/// Model information.
254#[derive(Debug, Clone, Deserialize)]
255pub struct Model {
256    /// Model ID.
257    pub id: String,
258    /// Display name.
259    pub display_name: String,
260    /// Creation timestamp.
261    pub created_at: String,
262}
263
264/// Error response from the API.
265#[derive(Debug, Clone, Deserialize)]
266pub struct ErrorResponse {
267    /// Error type.
268    #[serde(rename = "type")]
269    pub error_type: String,
270    /// Error details.
271    pub error: ErrorDetail,
272}
273
274/// Error detail.
275#[derive(Debug, Clone, Deserialize)]
276pub struct ErrorDetail {
277    /// Error type.
278    #[serde(rename = "type")]
279    pub error_type: String,
280    /// Error message.
281    pub message: String,
282}