Surface upstream rate limits from Anthropic (#16118)
This PR makes it so hitting upstream rate limits from Anthropic result in an HTTP 429 response instead of an HTTP 500. To do this we need to surface structured errors out of the `anthropic` crate. Release Notes: - N/A
This commit is contained in:
parent
fbb533b3e0
commit
ebdb755fef
6 changed files with 144 additions and 47 deletions
|
@ -3,6 +3,7 @@ use crate::{
|
|||
LanguageModelProvider, LanguageModelProviderId, LanguageModelProviderName,
|
||||
LanguageModelProviderState, LanguageModelRequest, RateLimiter, Role,
|
||||
};
|
||||
use anthropic::AnthropicError;
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use collections::BTreeMap;
|
||||
use editor::{Editor, EditorElement, EditorStyle};
|
||||
|
@ -259,7 +260,9 @@ impl AnthropicModel {
|
|||
|
||||
async move {
|
||||
let api_key = api_key.ok_or_else(|| anyhow!("missing api key"))?;
|
||||
anthropic::complete(http_client.as_ref(), &api_url, &api_key, request).await
|
||||
anthropic::complete(http_client.as_ref(), &api_url, &api_key, request)
|
||||
.await
|
||||
.context("failed to retrieve completion")
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
@ -268,7 +271,8 @@ impl AnthropicModel {
|
|||
&self,
|
||||
request: anthropic::Request,
|
||||
cx: &AsyncAppContext,
|
||||
) -> BoxFuture<'static, Result<BoxStream<'static, Result<anthropic::Event>>>> {
|
||||
) -> BoxFuture<'static, Result<BoxStream<'static, Result<anthropic::Event, AnthropicError>>>>
|
||||
{
|
||||
let http_client = self.http_client.clone();
|
||||
|
||||
let Ok((api_key, api_url, low_speed_timeout)) = cx.read_model(&self.state, |state, cx| {
|
||||
|
@ -291,7 +295,7 @@ impl AnthropicModel {
|
|||
request,
|
||||
low_speed_timeout,
|
||||
);
|
||||
request.await
|
||||
request.await.context("failed to stream completion")
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
@ -338,10 +342,16 @@ impl LanguageModel for AnthropicModel {
|
|||
let request = request.into_anthropic(self.model.id().into());
|
||||
let request = self.stream_completion(request, cx);
|
||||
let future = self.request_limiter.stream(async move {
|
||||
let response = request.await?;
|
||||
let response = request.await.map_err(|err| anyhow!(err))?;
|
||||
Ok(anthropic::extract_text_from_events(response))
|
||||
});
|
||||
async move { Ok(future.await?.boxed()) }.boxed()
|
||||
async move {
|
||||
Ok(future
|
||||
.await?
|
||||
.map(|result| result.map_err(|err| anyhow!(err)))
|
||||
.boxed())
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn use_any_tool(
|
||||
|
|
|
@ -4,7 +4,8 @@ use crate::{
|
|||
LanguageModelName, LanguageModelProviderId, LanguageModelProviderName,
|
||||
LanguageModelProviderState, LanguageModelRequest, RateLimiter, ZedModel,
|
||||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use anthropic::AnthropicError;
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use client::{Client, PerformCompletionParams, UserStore, EXPIRED_LLM_TOKEN_HEADER_NAME};
|
||||
use collections::BTreeMap;
|
||||
use feature_flags::{FeatureFlagAppExt, LanguageModels};
|
||||
|
@ -446,16 +447,23 @@ impl LanguageModel for CloudLanguageModel {
|
|||
match body.read_line(&mut buffer).await {
|
||||
Ok(0) => Ok(None),
|
||||
Ok(_) => {
|
||||
let event: anthropic::Event = serde_json::from_str(&buffer)?;
|
||||
let event: anthropic::Event = serde_json::from_str(&buffer)
|
||||
.context("failed to parse Anthropic event")?;
|
||||
Ok(Some((event, body)))
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
Err(err) => Err(AnthropicError::Other(err.into())),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(anthropic::extract_text_from_events(stream))
|
||||
});
|
||||
async move { Ok(future.await?.boxed()) }.boxed()
|
||||
async move {
|
||||
Ok(future
|
||||
.await?
|
||||
.map(|result| result.map_err(|err| anyhow!(err)))
|
||||
.boxed())
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
CloudModel::OpenAi(model) => {
|
||||
let client = self.client.clone();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue