(&self, request: LlmRequest)
| 233 | } |
| 234 | |
| 235 | async fn complete(&self, request: LlmRequest) -> GraphBitResult<LlmResponse> { |
| 236 | let url = format!("{}/messages", self.base_url); |
| 237 | |
| 238 | let enable_caching = request.enable_prompt_caching; |
| 239 | let (system_prompt, messages) = Self::convert_messages(&request.messages, enable_caching); |
| 240 | |
| 241 | // Convert tools to `Anthropic` format, adding cache_control to the last tool |
| 242 | // when prompt caching is enabled (caches the entire tool-definition block). |
| 243 | let tools: Option<Vec<AnthropicTool>> = if request.tools.is_empty() { |
| 244 | tracing::info!("No tools provided in request"); |
| 245 | None |
| 246 | } else { |
| 247 | tracing::info!("Converting {} tools for Anthropic", request.tools.len()); |
| 248 | let last_idx = request.tools.len() - 1; |
| 249 | Some( |
| 250 | request |
| 251 | .tools |
| 252 | .iter() |
| 253 | .enumerate() |
| 254 | .map(|(i, t)| Self::convert_tool(t, enable_caching && i == last_idx)) |
| 255 | .collect(), |
| 256 | ) |
| 257 | }; |
| 258 | |
| 259 | let body = AnthropicRequest { |
| 260 | model: self.model.clone(), |
| 261 | max_tokens: request.max_tokens.unwrap_or(4096), |
| 262 | messages, |
| 263 | system: system_prompt, |
| 264 | temperature: request.temperature, |
| 265 | top_p: request.top_p, |
| 266 | tools, |
| 267 | }; |
| 268 | |
| 269 | tracing::info!( |
| 270 | "Sending request to Anthropic with {} tools (prompt_caching={})", |
| 271 | body.tools.as_ref().map_or(0, Vec::len), |
| 272 | enable_caching |
| 273 | ); |
| 274 | |
| 275 | let mut req_builder = self |
| 276 | .client |
| 277 | .post(&url) |
| 278 | .header("x-api-key", &self.api_key) |
| 279 | .header("Content-Type", "application/json") |
| 280 | .header("anthropic-version", "2023-06-01"); |
| 281 | |
| 282 | if enable_caching { |
| 283 | req_builder = |
| 284 | req_builder.header("anthropic-beta", "prompt-caching-2024-07-31"); |
| 285 | } |
| 286 | |
| 287 | let response = req_builder.json(&body).send().await.map_err(|e| { |
| 288 | GraphBitError::llm_provider("anthropic", format!("Request failed: {e}")) |
| 289 | })?; |
| 290 | |
| 291 | if !response.status().is_success() { |
| 292 | let error_text = response |
nothing calls this directly
no test coverage detected