Expose anthropic API errors to the client (#16129)
Now, when an anthropic request is invalid or anthropic's API is down, we'll expose that to the user instead of just returning a generic 500. Release Notes: - N/A Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
parent
f3ec8d425f
commit
1674e12ccb
2 changed files with 20 additions and 12 deletions
|
@ -207,16 +207,22 @@ async fn perform_completion(
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
anthropic::AnthropicError::ApiError(ref api_error) => {
|
anthropic::AnthropicError::ApiError(ref api_error) => match api_error.code() {
|
||||||
if api_error.code() == Some(anthropic::ApiErrorCode::RateLimitError) {
|
Some(anthropic::ApiErrorCode::RateLimitError) => Error::http(
|
||||||
return Error::http(
|
StatusCode::TOO_MANY_REQUESTS,
|
||||||
StatusCode::TOO_MANY_REQUESTS,
|
"Upstream Anthropic rate limit exceeded.".to_string(),
|
||||||
"Upstream Anthropic rate limit exceeded.".to_string(),
|
),
|
||||||
);
|
Some(anthropic::ApiErrorCode::InvalidRequestError) => {
|
||||||
|
Error::http(StatusCode::BAD_REQUEST, api_error.message.clone())
|
||||||
}
|
}
|
||||||
|
Some(anthropic::ApiErrorCode::OverloadedError) => {
|
||||||
Error::Internal(anyhow!(err))
|
Error::http(StatusCode::SERVICE_UNAVAILABLE, api_error.message.clone())
|
||||||
}
|
}
|
||||||
|
Some(_) => {
|
||||||
|
Error::http(StatusCode::INTERNAL_SERVER_ERROR, api_error.message.clone())
|
||||||
|
}
|
||||||
|
None => Error::Internal(anyhow!(err)),
|
||||||
|
},
|
||||||
anthropic::AnthropicError::Other(err) => Error::Internal(err),
|
anthropic::AnthropicError::Other(err) => Error::Internal(err),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use smol::{
|
use smol::{
|
||||||
io::BufReader,
|
io::{AsyncReadExt, BufReader},
|
||||||
lock::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard},
|
lock::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
use std::{future, sync::Arc};
|
use std::{future, sync::Arc};
|
||||||
|
@ -334,7 +334,7 @@ impl CloudLanguageModel {
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.header("Authorization", format!("Bearer {token}"))
|
.header("Authorization", format!("Bearer {token}"))
|
||||||
.body(serde_json::to_string(&body)?.into())?;
|
.body(serde_json::to_string(&body)?.into())?;
|
||||||
let response = http_client.send(request).await?;
|
let mut response = http_client.send(request).await?;
|
||||||
if response.status().is_success() {
|
if response.status().is_success() {
|
||||||
break response;
|
break response;
|
||||||
} else if !did_retry
|
} else if !did_retry
|
||||||
|
@ -346,8 +346,10 @@ impl CloudLanguageModel {
|
||||||
did_retry = true;
|
did_retry = true;
|
||||||
token = llm_api_token.refresh(&client).await?;
|
token = llm_api_token.refresh(&client).await?;
|
||||||
} else {
|
} else {
|
||||||
|
let mut body = String::new();
|
||||||
|
response.body_mut().read_to_string(&mut body).await?;
|
||||||
break Err(anyhow!(
|
break Err(anyhow!(
|
||||||
"cloud language model completion failed with status {}",
|
"cloud language model completion failed with status {}: {body}",
|
||||||
response.status()
|
response.status()
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue