(
&self,
base_url: &str,
api_key: &Option<String>,
provider_type: &str,
model: &str,
messages: &[ConversationMessage],
agent_run_id: &str,
| 1147 | |
| 1148 | #[allow(clippy::too_many_arguments)] |
| 1149 | async fn send_anthropic_with_tools<S: TokenSink + Sync>( |
| 1150 | &self, |
| 1151 | base_url: &str, |
| 1152 | api_key: &Option<String>, |
| 1153 | provider_type: &str, |
| 1154 | model: &str, |
| 1155 | messages: &[ConversationMessage], |
| 1156 | agent_run_id: &str, |
| 1157 | token_sink: &S, |
| 1158 | ) -> AppResult<LLMTurn> { |
| 1159 | let (system, mut anthropic_messages) = to_anthropic_messages(messages)?; |
| 1160 | |
| 1161 | // Prompt caching: mark last user message with cache_control (like Claude Desktop) |
| 1162 | if let Some(last_msg) = anthropic_messages.last_mut() { |
| 1163 | if last_msg.get("role").and_then(Value::as_str) == Some("user") { |
| 1164 | if let Some(content) = last_msg.get_mut("content").and_then(Value::as_array_mut) { |
| 1165 | if let Some(last_block) = content.last_mut() { |
| 1166 | last_block["cache_control"] = json!({"type": "ephemeral"}); |
| 1167 | } |
| 1168 | } |
| 1169 | } |
| 1170 | } |
| 1171 | |
| 1172 | // Prompt caching: tools cached |
| 1173 | let tools_with_cache = { |
| 1174 | let mut tools = anthropic_tool_definitions(); |
| 1175 | if let Some(last_tool) = tools.last_mut() { |
| 1176 | last_tool["cache_control"] = json!({"type": "ephemeral"}); |
| 1177 | } |
| 1178 | tools |
| 1179 | }; |
| 1180 | |
| 1181 | let mut payload = json!({ |
| 1182 | "model": model, |
| 1183 | "max_tokens": 8096, |
| 1184 | "messages": anthropic_messages, |
| 1185 | "tools": tools_with_cache, |
| 1186 | "stream": true, |
| 1187 | }); |
| 1188 | |
| 1189 | // System prompt as cached content block array |
| 1190 | if let Some(system_prompt) = system { |
| 1191 | payload["system"] = json!([ |
| 1192 | { |
| 1193 | "type": "text", |
| 1194 | "text": system_prompt, |
| 1195 | "cache_control": {"type": "ephemeral"} |
| 1196 | } |
| 1197 | ]); |
| 1198 | } |
| 1199 | |
| 1200 | // Resolve endpoint: same logic as chat_service::send_anthropic |
| 1201 | let endpoint = if provider_type == "anthropic" { |
| 1202 | "https://api.anthropic.com/v1/messages".to_string() |
| 1203 | } else if provider_type == "enowxlabs" { |
| 1204 | format!("{}/messages", base_url.trim_end_matches('/').trim_end_matches("/v1")) |
| 1205 | } else { |
| 1206 | // Custom gateway: preserve full base_url path (e.g. /v1/messages) |
no test coverage detected