|
|
|
@ -190,41 +190,12 @@ fn strip_code_fences(text: &str) -> &str {
|
|
|
|
|
|
|
|
|
|
|
|
/// Map Anthropic API error responses to appropriate `AppError` variants.
|
|
|
|
/// Map Anthropic API error responses to appropriate `AppError` variants.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Handles common error codes without exposing internal details.
|
|
|
|
/// Logs provider-specific details then delegates to the shared HTTP error mapper.
|
|
|
|
fn map_anthropic_error(status: u16, body: &Value) -> AppError {
|
|
|
|
fn map_anthropic_error(status: u16, body: &Value) -> AppError {
|
|
|
|
let error_message = body
|
|
|
|
let error_message = body.get("error").and_then(|e| e.get("message")).and_then(|m| m.as_str()).unwrap_or("Unknown error");
|
|
|
|
.get("error")
|
|
|
|
let error_type = body.get("error").and_then(|e| e.get("type")).and_then(|t| t.as_str()).unwrap_or("");
|
|
|
|
.and_then(|e| e.get("message"))
|
|
|
|
tracing::error!("Anthropic API error (HTTP {}): {} (type: {})", status, error_message, error_type);
|
|
|
|
.and_then(|m| m.as_str())
|
|
|
|
super::map_provider_http_error(status, "Anthropic")
|
|
|
|
.unwrap_or("Unknown error");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let error_type = body
|
|
|
|
|
|
|
|
.get("error")
|
|
|
|
|
|
|
|
.and_then(|e| e.get("type"))
|
|
|
|
|
|
|
|
.and_then(|t| t.as_str())
|
|
|
|
|
|
|
|
.unwrap_or("");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Log error details but NEVER the API key
|
|
|
|
|
|
|
|
tracing::error!(
|
|
|
|
|
|
|
|
"Anthropic API error (HTTP {}): {} (type: {})",
|
|
|
|
|
|
|
|
status,
|
|
|
|
|
|
|
|
error_message,
|
|
|
|
|
|
|
|
error_type
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match status {
|
|
|
|
|
|
|
|
400 => AppError::BadRequest("Invalid request to LLM provider".into()),
|
|
|
|
|
|
|
|
401 => AppError::BadRequest("Invalid or unauthorized API key".into()),
|
|
|
|
|
|
|
|
403 => AppError::BadRequest("Access denied by LLM provider".into()),
|
|
|
|
|
|
|
|
404 => AppError::BadRequest("Model not found or not available".into()),
|
|
|
|
|
|
|
|
429 => AppError::RateLimited(
|
|
|
|
|
|
|
|
"LLM provider rate limit exceeded. Please try again later.".into(),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
529 => AppError::RateLimited(
|
|
|
|
|
|
|
|
"LLM provider is overloaded. Please try again later.".into(),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
_ => AppError::Internal(anyhow::anyhow!("LLM provider returned an error")),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
|
@ -415,7 +386,7 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
|
|
let err = map_anthropic_error(529, &body);
|
|
|
|
let err = map_anthropic_error(529, &body);
|
|
|
|
match err {
|
|
|
|
match err {
|
|
|
|
AppError::RateLimited(msg) => assert!(msg.contains("overloaded")),
|
|
|
|
AppError::RateLimited(msg) => assert!(msg.contains("rate limit")),
|
|
|
|
_ => panic!("Expected RateLimited for 529 (overloaded)"),
|
|
|
|
_ => panic!("Expected RateLimited for 529 (overloaded)"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|