1use derive_builder::Builder;
2use serde::{Deserialize, Serialize};
3
4use super::common::{Metadata, Usage};
5use super::content::{ContentBlock, MessageParam, MessageRole, SystemParam};
6use super::tools::{Tool, ToolChoice};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
13#[serde(tag = "type", rename_all = "snake_case")]
14#[allow(clippy::derive_partial_eq_without_eq)] pub enum OutputFormat {
16 #[serde(rename = "json_schema")]
18 JsonSchema {
19 schema: serde_json::Value,
21 },
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Builder, Default)]
26#[builder(setter(into, strip_option), default)]
27pub struct MessagesCreateRequest {
28 #[builder(default)]
30 pub model: String,
31 #[builder(default)]
33 pub max_tokens: u32,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub system: Option<SystemParam>,
37 #[builder(default)]
39 pub messages: Vec<MessageParam>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub temperature: Option<f32>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub stop_sequences: Option<Vec<String>>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub top_p: Option<f32>,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub top_k: Option<u32>,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub metadata: Option<Metadata>,
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub tools: Option<Vec<Tool>>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub tool_choice: Option<ToolChoice>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub stream: Option<bool>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub output_format: Option<OutputFormat>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
71pub struct MessagesCreateResponse {
72 pub id: String,
74 #[serde(rename = "type")]
76 pub kind: String,
77 pub role: MessageRole,
79 pub content: Vec<ContentBlock>,
81 pub model: String,
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub stop_reason: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub usage: Option<Usage>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
93pub struct MessageTokensCountRequest {
94 pub model: String,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub system: Option<SystemParam>,
99 pub messages: Vec<MessageParam>,
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub tools: Option<Vec<Tool>>,
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub tool_choice: Option<ToolChoice>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
111pub struct MessageTokensCountResponse {
112 pub input_tokens: u64,
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::types::content::{ContentBlockParam, MessageContentParam};
120
121 #[test]
122 fn message_request_ser() {
123 let req = MessagesCreateRequest {
124 model: "claude-3-5-sonnet-20241022".into(),
125 max_tokens: 128,
126 system: None,
127 messages: vec![MessageParam {
128 role: MessageRole::User,
129 content: "Hello".into(),
130 }],
131 temperature: None,
132 stop_sequences: None,
133 top_p: None,
134 top_k: None,
135 metadata: None,
136 tools: None,
137 tool_choice: None,
138 stream: None,
139 output_format: None,
140 };
141 let s = serde_json::to_string(&req).unwrap();
142 assert!(s.contains(r#""model":"claude-3-5-sonnet-20241022""#));
143 assert!(s.contains(r#""max_tokens":128"#));
144 assert!(s.contains(r#""Hello""#));
145 assert!(!s.contains("stream"));
147 assert!(!s.contains("output_format"));
148 }
149
150 #[test]
151 fn message_request_with_system_string() {
152 let req = MessagesCreateRequest {
153 model: "claude-3-5-sonnet-20241022".into(),
154 max_tokens: 128,
155 system: Some("You are helpful".into()),
156 messages: vec![MessageParam {
157 role: MessageRole::User,
158 content: "Hello".into(),
159 }],
160 temperature: None,
161 stop_sequences: None,
162 top_p: None,
163 top_k: None,
164 metadata: None,
165 tools: None,
166 tool_choice: None,
167 stream: None,
168 output_format: None,
169 };
170 let s = serde_json::to_string(&req).unwrap();
171 assert!(s.contains(r#""system":"You are helpful""#));
172 }
173
174 #[test]
175 fn message_request_with_blocks() {
176 let req = MessagesCreateRequest {
177 model: "claude-3-5-sonnet-20241022".into(),
178 max_tokens: 128,
179 system: None,
180 messages: vec![MessageParam {
181 role: MessageRole::User,
182 content: MessageContentParam::Blocks(vec![ContentBlockParam::Text {
183 text: "Block content".into(),
184 cache_control: None,
185 }]),
186 }],
187 temperature: Some(0.7),
188 stop_sequences: None,
189 top_p: None,
190 top_k: None,
191 metadata: None,
192 tools: None,
193 tool_choice: None,
194 stream: None,
195 output_format: None,
196 };
197 let s = serde_json::to_string(&req).unwrap();
198 assert!(s.contains(r#""Block content""#));
199 assert!(s.contains(r#""temperature":0.7"#));
200 }
201}