1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7#[serde(rename_all = "lowercase")]
8pub enum Role {
9 User,
10 Assistant,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15#[serde(tag = "type", rename_all = "snake_case")]
16pub enum ContentBlock {
17 Text { text: String },
19 ToolUse {
21 id: String,
22 name: String,
23 input: serde_json::Value,
24 },
25 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#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(untagged)]
37pub enum MessageContent {
38 Text(String),
40 Blocks(Vec<ContentBlock>),
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct Message {
47 pub role: Role,
49 pub content: MessageContent,
51}
52
53impl Message {
54 pub fn user(text: impl Into<String>) -> Self {
56 Self {
57 role: Role::User,
58 content: MessageContent::Text(text.into()),
59 }
60 }
61
62 pub fn assistant(text: impl Into<String>) -> Self {
64 Self {
65 role: Role::Assistant,
66 content: MessageContent::Text(text.into()),
67 }
68 }
69
70 pub fn user_blocks(blocks: Vec<ContentBlock>) -> Self {
72 Self {
73 role: Role::User,
74 content: MessageContent::Blocks(blocks),
75 }
76 }
77
78 pub fn assistant_blocks(blocks: Vec<ContentBlock>) -> Self {
80 Self {
81 role: Role::Assistant,
82 content: MessageContent::Blocks(blocks),
83 }
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct Tool {
90 pub name: String,
92 pub description: String,
94 pub input_schema: serde_json::Value,
96}
97
98impl Tool {
99 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#[derive(Debug, Clone, Serialize)]
115pub struct CreateMessageRequest {
116 pub model: String,
118 pub messages: Vec<Message>,
120 pub max_tokens: usize,
122 #[serde(skip_serializing_if = "Option::is_none")]
124 pub system: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub temperature: Option<f32>,
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub top_p: Option<f32>,
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub stop_sequences: Option<Vec<String>>,
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub tools: Option<Vec<Tool>>,
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub stream: Option<bool>,
140}
141
142impl CreateMessageRequest {
143 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 pub fn with_system(mut self, system: impl Into<String>) -> Self {
160 self.system = Some(system.into());
161 self
162 }
163
164 pub fn with_temperature(mut self, temperature: f32) -> Self {
166 self.temperature = Some(temperature);
167 self
168 }
169
170 pub fn with_top_p(mut self, top_p: f32) -> Self {
172 self.top_p = Some(top_p);
173 self
174 }
175
176 pub fn with_stop_sequences(mut self, sequences: Vec<String>) -> Self {
178 self.stop_sequences = Some(sequences);
179 self
180 }
181
182 pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
184 self.tools = Some(tools);
185 self
186 }
187}
188
189#[derive(Debug, Clone, Deserialize)]
191pub struct Usage {
192 pub input_tokens: usize,
194 pub output_tokens: usize,
196}
197
198#[derive(Debug, Clone, Deserialize)]
200pub struct CreateMessageResponse {
201 pub id: String,
203 #[serde(rename = "type")]
205 pub response_type: String,
206 pub role: Role,
208 pub content: Vec<ContentBlock>,
210 pub model: String,
212 pub stop_reason: Option<String>,
214 pub stop_sequence: Option<String>,
216 pub usage: Usage,
218}
219
220impl CreateMessageResponse {
221 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 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 pub fn has_tool_use(&self) -> bool {
247 self.content
248 .iter()
249 .any(|block| matches!(block, ContentBlock::ToolUse { .. }))
250 }
251}
252
253#[derive(Debug, Clone, Deserialize)]
255pub struct Model {
256 pub id: String,
258 pub display_name: String,
260 pub created_at: String,
262}
263
264#[derive(Debug, Clone, Deserialize)]
266pub struct ErrorResponse {
267 #[serde(rename = "type")]
269 pub error_type: String,
270 pub error: ErrorDetail,
272}
273
274#[derive(Debug, Clone, Deserialize)]
276pub struct ErrorDetail {
277 #[serde(rename = "type")]
279 pub error_type: String,
280 pub message: String,
282}