walrus_model/claude/
request.rs1use serde::Serialize;
4use serde_json::{Value, json};
5use wcore::model::{Role, Tool, ToolChoice};
6
7#[derive(Debug, Clone, Serialize)]
9pub struct Request {
10 pub model: String,
12 pub max_tokens: usize,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub system: Option<String>,
17 pub messages: Vec<Value>,
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub stream: Option<bool>,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub tools: Option<Vec<Value>>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub tool_choice: Option<Value>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub temperature: Option<f64>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub top_p: Option<f64>,
34}
35
36impl Request {
37 pub fn stream(mut self) -> Self {
39 self.stream = Some(true);
40 self
41 }
42
43 fn with_tools(self, tools: Vec<Tool>) -> Self {
45 let tools = tools
46 .into_iter()
47 .map(|tool| {
48 json!({
49 "name": tool.name,
50 "description": tool.description,
51 "input_schema": tool.parameters,
52 })
53 })
54 .collect::<Vec<_>>();
55 Self {
56 tools: Some(tools),
57 ..self
58 }
59 }
60
61 fn with_tool_choice(self, tool_choice: ToolChoice) -> Self {
63 Self {
64 tool_choice: match tool_choice {
65 ToolChoice::None => Some(json!({"type": "none"})),
66 ToolChoice::Auto => Some(json!({"type": "auto"})),
67 ToolChoice::Required => Some(json!({"type": "any"})),
68 ToolChoice::Function(name) => Some(json!({
69 "type": "tool",
70 "name": name,
71 })),
72 },
73 ..self
74 }
75 }
76}
77
78impl From<wcore::model::Request> for Request {
79 fn from(req: wcore::model::Request) -> Self {
80 let mut system = None;
81 let mut anthropic_msgs = Vec::new();
82
83 for msg in &req.messages {
84 match msg.role {
85 Role::System => {
86 system = Some(msg.content.clone());
87 }
88 Role::User => {
89 anthropic_msgs.push(json!({
90 "role": "user",
91 "content": msg.content,
92 }));
93 }
94 Role::Assistant => {
95 let mut content = Vec::new();
96 if !msg.content.is_empty() {
97 content.push(json!({
98 "type": "text",
99 "text": msg.content,
100 }));
101 }
102 for tc in &msg.tool_calls {
103 let input: Value =
104 serde_json::from_str(&tc.function.arguments).unwrap_or(json!({}));
105 content.push(json!({
106 "type": "tool_use",
107 "id": tc.id,
108 "name": tc.function.name,
109 "input": input,
110 }));
111 }
112 if content.is_empty() {
113 content.push(json!({
114 "type": "text",
115 "text": "",
116 }));
117 }
118 anthropic_msgs.push(json!({
119 "role": "assistant",
120 "content": content,
121 }));
122 }
123 Role::Tool => {
124 anthropic_msgs.push(json!({
125 "role": "user",
126 "content": [{
127 "type": "tool_result",
128 "tool_use_id": msg.tool_call_id,
129 "content": msg.content,
130 }],
131 }));
132 }
133 }
134 }
135
136 let mut result = Self {
137 model: req.model.to_string(),
138 max_tokens: 4096,
139 system,
140 messages: anthropic_msgs,
141 stream: None,
142 tools: None,
143 tool_choice: None,
144 temperature: None,
145 top_p: None,
146 };
147
148 if let Some(tools) = req.tools {
149 result = result.with_tools(tools);
150 }
151 if let Some(tool_choice) = req.tool_choice {
152 result = result.with_tool_choice(tool_choice);
153 }
154
155 result
156 }
157}