agent: Handle context window exceeded errors from Anthropic (#28688)

![CleanShot 2025-04-14 at 11 15
38@2x](https://github.com/user-attachments/assets/9e803ffb-74fd-486b-bebc-2155a407a9fa)

Release Notes:

- agent: Handle context window exceeded errors from Anthropic
This commit is contained in:
Agus Zubiaga 2025-04-14 08:39:33 -06:00 committed by GitHub
parent 4a57664c7f
commit b45230784d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 190 additions and 28 deletions

View file

@ -1,4 +1,4 @@
use anthropic::{AnthropicError, AnthropicModelMode};
use anthropic::{AnthropicError, AnthropicModelMode, parse_prompt_too_long};
use anyhow::{Result, anyhow};
use client::{
Client, EXPIRED_LLM_TOKEN_HEADER_NAME, MAX_LLM_MONTHLY_SPEND_REACHED_HEADER_NAME,
@ -14,7 +14,7 @@ use gpui::{AnyElement, AnyView, App, AsyncApp, Context, Entity, Subscription, Ta
use http_client::{AsyncBody, HttpClient, Method, Response, StatusCode};
use language_model::{
AuthenticateError, CloudModel, LanguageModel, LanguageModelCacheConfiguration, LanguageModelId,
LanguageModelName, LanguageModelProviderId, LanguageModelProviderName,
LanguageModelKnownError, LanguageModelName, LanguageModelProviderId, LanguageModelProviderName,
LanguageModelProviderState, LanguageModelProviderTosView, LanguageModelRequest,
LanguageModelToolSchemaFormat, RateLimiter, ZED_CLOUD_PROVIDER_ID,
};
@ -33,6 +33,7 @@ use std::{
time::Duration,
};
use strum::IntoEnumIterator;
use thiserror::Error;
use ui::{TintColor, prelude::*};
use crate::AllLanguageModelSettings;
@ -575,14 +576,19 @@ impl CloudLanguageModel {
} else {
let mut body = String::new();
response.body_mut().read_to_string(&mut body).await?;
return Err(anyhow!(
"cloud language model completion failed with status {status}: {body}",
));
return Err(anyhow!(ApiError { status, body }));
}
}
}
}
#[derive(Debug, Error)]
#[error("cloud language model completion failed with status {status}: {body}")]
struct ApiError {
status: StatusCode,
body: String,
}
impl LanguageModel for CloudLanguageModel {
fn id(&self) -> LanguageModelId {
self.id.clone()
@ -696,7 +702,23 @@ impl LanguageModel for CloudLanguageModel {
)?)?,
},
)
.await?;
.await
.map_err(|err| match err.downcast::<ApiError>() {
Ok(api_err) => {
if api_err.status == StatusCode::BAD_REQUEST {
if let Some(tokens) = parse_prompt_too_long(&api_err.body) {
return anyhow!(
LanguageModelKnownError::ContextWindowLimitExceeded {
tokens
}
);
}
}
anyhow!(api_err)
}
Err(err) => anyhow!(err),
})?;
Ok(
crate::provider::anthropic::map_to_language_model_completion_events(
Box::pin(response_lines(response).map_err(AnthropicError::Other)),