agent: Show an error when the model requests limit has been reached (#28868)
This PR adds an error message when the model requests limit has been hit. Release Notes: - N/A Co-authored-by: Oleksiy Syvokon <oleksiy.syvokon@gmail.com>
This commit is contained in:
parent
c641209341
commit
cb79420773
7 changed files with 178 additions and 31 deletions
78
Cargo.lock
generated
78
Cargo.lock
generated
|
@ -324,7 +324,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
@ -567,7 +567,7 @@ dependencies = [
|
||||||
"settings",
|
"settings",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"smol",
|
"smol",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"telemetry_events",
|
"telemetry_events",
|
||||||
"text",
|
"text",
|
||||||
"theme",
|
"theme",
|
||||||
|
@ -1881,7 +1881,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
|
@ -3028,7 +3028,7 @@ dependencies = [
|
||||||
"settings",
|
"settings",
|
||||||
"sha2",
|
"sha2",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"subtle",
|
"subtle",
|
||||||
"supermaven_api",
|
"supermaven_api",
|
||||||
"telemetry_events",
|
"telemetry_events",
|
||||||
|
@ -3360,7 +3360,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"task",
|
"task",
|
||||||
"theme",
|
"theme",
|
||||||
"ui",
|
"ui",
|
||||||
|
@ -4477,7 +4477,7 @@ dependencies = [
|
||||||
"optfield",
|
"optfield",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5122,7 +5122,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"settings",
|
"settings",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"telemetry",
|
"telemetry",
|
||||||
"theme",
|
"theme",
|
||||||
"ui",
|
"ui",
|
||||||
|
@ -5973,7 +5973,7 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"telemetry",
|
"telemetry",
|
||||||
"theme",
|
"theme",
|
||||||
"time",
|
"time",
|
||||||
|
@ -6066,7 +6066,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -6172,7 +6172,7 @@ dependencies = [
|
||||||
"slotmap",
|
"slotmap",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"smol",
|
"smol",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"sum_tree",
|
"sum_tree",
|
||||||
"taffy",
|
"taffy",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
@ -6820,7 +6820,7 @@ name = "icons"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -7088,7 +7088,7 @@ dependencies = [
|
||||||
"paths",
|
"paths",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"serde",
|
"serde",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"util",
|
"util",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
@ -7674,7 +7674,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smol",
|
"smol",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"telemetry_events",
|
"telemetry_events",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"util",
|
"util",
|
||||||
|
@ -7734,7 +7734,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
"smol",
|
"smol",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"theme",
|
"theme",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tiktoken-rs",
|
"tiktoken-rs",
|
||||||
|
@ -7742,6 +7742,7 @@ dependencies = [
|
||||||
"ui",
|
"ui",
|
||||||
"util",
|
"util",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
|
"zed_llm_client",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -8706,7 +8707,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -9553,7 +9554,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -12132,7 +12133,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"tracing",
|
"tracing",
|
||||||
"util",
|
"util",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
|
@ -12660,7 +12661,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"time",
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -13705,7 +13706,7 @@ dependencies = [
|
||||||
"settings",
|
"settings",
|
||||||
"simplelog",
|
"simplelog",
|
||||||
"story",
|
"story",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"theme",
|
"theme",
|
||||||
"title_bar",
|
"title_bar",
|
||||||
"ui",
|
"ui",
|
||||||
|
@ -13787,7 +13788,16 @@ version = "0.26.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum_macros",
|
"strum_macros 0.26.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.27.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
|
||||||
|
dependencies = [
|
||||||
|
"strum_macros 0.27.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13803,6 +13813,19 @@ dependencies = [
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.27.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
|
@ -14418,7 +14441,7 @@ dependencies = [
|
||||||
"serde_json_lenient",
|
"serde_json_lenient",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"settings",
|
"settings",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"util",
|
"util",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -14452,7 +14475,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_json_lenient",
|
"serde_json_lenient",
|
||||||
"simplelog",
|
"simplelog",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"theme",
|
"theme",
|
||||||
"vscode_theme",
|
"vscode_theme",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
|
@ -15453,7 +15476,7 @@ dependencies = [
|
||||||
"settings",
|
"settings",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"story",
|
"story",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"theme",
|
"theme",
|
||||||
"ui_macros",
|
"ui_macros",
|
||||||
"util",
|
"util",
|
||||||
|
@ -17624,7 +17647,7 @@ dependencies = [
|
||||||
"settings",
|
"settings",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"sqlez",
|
"sqlez",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"task",
|
"task",
|
||||||
"telemetry",
|
"telemetry",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
@ -17769,7 +17792,7 @@ dependencies = [
|
||||||
"sqlx-macros-core",
|
"sqlx-macros-core",
|
||||||
"sqlx-postgres",
|
"sqlx-postgres",
|
||||||
"sqlx-sqlite",
|
"sqlx-sqlite",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"subtle",
|
"subtle",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
|
@ -18328,12 +18351,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed_llm_client"
|
name = "zed_llm_client"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bf21350eced858d129840589158a8f6895c4fa4327ae56dd8c7d6a98495bed4"
|
checksum = "1d28a5d6bdb0f40acf5261c39cabbf65a13b55ba4b86d9beb5b8b1c484373f1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"strum 0.27.1",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -601,7 +601,7 @@ wasmtime-wasi = "29"
|
||||||
which = "6.0.0"
|
which = "6.0.0"
|
||||||
wit-component = "0.221"
|
wit-component = "0.221"
|
||||||
workspace-hack = "0.1.0"
|
workspace-hack = "0.1.0"
|
||||||
zed_llm_client = "0.4"
|
zed_llm_client = "0.4.2"
|
||||||
zstd = "0.11"
|
zstd = "0.11"
|
||||||
metal = "0.29"
|
metal = "0.29"
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use language_model_selector::ToggleModelSelector;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use prompt_library::{PromptLibrary, open_prompt_library};
|
use prompt_library::{PromptLibrary, open_prompt_library};
|
||||||
use prompt_store::PromptBuilder;
|
use prompt_store::PromptBuilder;
|
||||||
|
use proto::Plan;
|
||||||
use settings::{Settings, update_settings_file};
|
use settings::{Settings, update_settings_file};
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
use ui::{
|
use ui::{
|
||||||
|
@ -1449,6 +1450,9 @@ impl AssistantPanel {
|
||||||
ThreadError::MaxMonthlySpendReached => {
|
ThreadError::MaxMonthlySpendReached => {
|
||||||
self.render_max_monthly_spend_reached_error(cx)
|
self.render_max_monthly_spend_reached_error(cx)
|
||||||
}
|
}
|
||||||
|
ThreadError::ModelRequestLimitReached { plan } => {
|
||||||
|
self.render_model_request_limit_reached_error(plan, cx)
|
||||||
|
}
|
||||||
ThreadError::Message { header, message } => {
|
ThreadError::Message { header, message } => {
|
||||||
self.render_error_message(header, message, cx)
|
self.render_error_message(header, message, cx)
|
||||||
}
|
}
|
||||||
|
@ -1551,6 +1555,67 @@ impl AssistantPanel {
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_model_request_limit_reached_error(
|
||||||
|
&self,
|
||||||
|
plan: Plan,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> AnyElement {
|
||||||
|
let error_message = match plan {
|
||||||
|
Plan::Free => "Model request limit reached. Upgrade to Zed Pro for more requests.",
|
||||||
|
Plan::ZedPro => {
|
||||||
|
"Model request limit reached. Upgrade to usage-based billing for more requests."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let call_to_action = match plan {
|
||||||
|
Plan::Free => "Upgrade to Zed Pro",
|
||||||
|
Plan::ZedPro => "Upgrade to usage-based billing",
|
||||||
|
};
|
||||||
|
|
||||||
|
v_flex()
|
||||||
|
.gap_0p5()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_1p5()
|
||||||
|
.items_center()
|
||||||
|
.child(Icon::new(IconName::XCircle).color(Color::Error))
|
||||||
|
.child(Label::new("Model Request Limit Reached").weight(FontWeight::MEDIUM)),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("error-message")
|
||||||
|
.max_h_24()
|
||||||
|
.overflow_y_scroll()
|
||||||
|
.child(Label::new(error_message)),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.justify_end()
|
||||||
|
.mt_1()
|
||||||
|
.child(
|
||||||
|
Button::new("subscribe", call_to_action).on_click(cx.listener(
|
||||||
|
|this, _, _, cx| {
|
||||||
|
this.thread.update(cx, |this, _cx| {
|
||||||
|
this.clear_last_error();
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.open_url(&zed_urls::account_url(cx));
|
||||||
|
cx.notify();
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.child(Button::new("dismiss", "Dismiss").on_click(cx.listener(
|
||||||
|
|this, _, _, cx| {
|
||||||
|
this.thread.update(cx, |this, _cx| {
|
||||||
|
this.clear_last_error();
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.notify();
|
||||||
|
},
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
.into_any()
|
||||||
|
}
|
||||||
|
|
||||||
fn render_error_message(
|
fn render_error_message(
|
||||||
&self,
|
&self,
|
||||||
header: SharedString,
|
header: SharedString,
|
||||||
|
|
|
@ -18,12 +18,13 @@ use language_model::{
|
||||||
ConfiguredModel, LanguageModel, LanguageModelCompletionEvent, LanguageModelId,
|
ConfiguredModel, LanguageModel, LanguageModelCompletionEvent, LanguageModelId,
|
||||||
LanguageModelKnownError, LanguageModelRegistry, LanguageModelRequest,
|
LanguageModelKnownError, LanguageModelRegistry, LanguageModelRequest,
|
||||||
LanguageModelRequestMessage, LanguageModelRequestTool, LanguageModelToolResult,
|
LanguageModelRequestMessage, LanguageModelRequestTool, LanguageModelToolResult,
|
||||||
LanguageModelToolUseId, MaxMonthlySpendReachedError, MessageContent, PaymentRequiredError,
|
LanguageModelToolUseId, MaxMonthlySpendReachedError, MessageContent,
|
||||||
Role, StopReason, TokenUsage,
|
ModelRequestLimitReachedError, PaymentRequiredError, Role, StopReason, TokenUsage,
|
||||||
};
|
};
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use project::git_store::{GitStore, GitStoreCheckpoint, RepositoryState};
|
use project::git_store::{GitStore, GitStoreCheckpoint, RepositoryState};
|
||||||
use prompt_store::PromptBuilder;
|
use prompt_store::PromptBuilder;
|
||||||
|
use proto::Plan;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
@ -1150,6 +1151,12 @@ impl Thread {
|
||||||
cx.emit(ThreadEvent::ShowError(
|
cx.emit(ThreadEvent::ShowError(
|
||||||
ThreadError::MaxMonthlySpendReached,
|
ThreadError::MaxMonthlySpendReached,
|
||||||
));
|
));
|
||||||
|
} else if let Some(error) =
|
||||||
|
error.downcast_ref::<ModelRequestLimitReachedError>()
|
||||||
|
{
|
||||||
|
cx.emit(ThreadEvent::ShowError(
|
||||||
|
ThreadError::ModelRequestLimitReached { plan: error.plan },
|
||||||
|
));
|
||||||
} else if let Some(known_error) =
|
} else if let Some(known_error) =
|
||||||
error.downcast_ref::<LanguageModelKnownError>()
|
error.downcast_ref::<LanguageModelKnownError>()
|
||||||
{
|
{
|
||||||
|
@ -1929,6 +1936,8 @@ pub enum ThreadError {
|
||||||
PaymentRequired,
|
PaymentRequired,
|
||||||
#[error("Max monthly spend reached")]
|
#[error("Max monthly spend reached")]
|
||||||
MaxMonthlySpendReached,
|
MaxMonthlySpendReached,
|
||||||
|
#[error("Model request limit reached")]
|
||||||
|
ModelRequestLimitReached { plan: Plan },
|
||||||
#[error("Message {header}: {message}")]
|
#[error("Message {header}: {message}")]
|
||||||
Message {
|
Message {
|
||||||
header: SharedString,
|
header: SharedString,
|
||||||
|
|
|
@ -142,6 +142,24 @@ impl fmt::Display for MaxMonthlySpendReachedError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub struct ModelRequestLimitReachedError {
|
||||||
|
pub plan: Plan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ModelRequestLimitReachedError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let message = match self.plan {
|
||||||
|
Plan::Free => "Model request limit reached. Upgrade to Zed Pro for more requests.",
|
||||||
|
Plan::ZedPro => {
|
||||||
|
"Model request limit reached. Upgrade to usage-based billing for more requests."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "{message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct LlmApiToken(Arc<RwLock<Option<String>>>);
|
pub struct LlmApiToken(Arc<RwLock<Option<String>>>);
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
workspace-hack.workspace = true
|
workspace-hack.workspace = true
|
||||||
|
zed_llm_client.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
editor = { workspace = true, features = ["test-support"] }
|
||||||
|
|
|
@ -16,18 +16,21 @@ use language_model::{
|
||||||
AuthenticateError, CloudModel, LanguageModel, LanguageModelCacheConfiguration, LanguageModelId,
|
AuthenticateError, CloudModel, LanguageModel, LanguageModelCacheConfiguration, LanguageModelId,
|
||||||
LanguageModelKnownError, LanguageModelName, LanguageModelProviderId, LanguageModelProviderName,
|
LanguageModelKnownError, LanguageModelName, LanguageModelProviderId, LanguageModelProviderName,
|
||||||
LanguageModelProviderState, LanguageModelProviderTosView, LanguageModelRequest,
|
LanguageModelProviderState, LanguageModelProviderTosView, LanguageModelRequest,
|
||||||
LanguageModelToolSchemaFormat, RateLimiter, ZED_CLOUD_PROVIDER_ID,
|
LanguageModelToolSchemaFormat, ModelRequestLimitReachedError, RateLimiter,
|
||||||
|
ZED_CLOUD_PROVIDER_ID,
|
||||||
};
|
};
|
||||||
use language_model::{
|
use language_model::{
|
||||||
LanguageModelAvailability, LanguageModelCompletionEvent, LanguageModelProvider, LlmApiToken,
|
LanguageModelAvailability, LanguageModelCompletionEvent, LanguageModelProvider, LlmApiToken,
|
||||||
MaxMonthlySpendReachedError, PaymentRequiredError, RefreshLlmTokenListener,
|
MaxMonthlySpendReachedError, PaymentRequiredError, RefreshLlmTokenListener,
|
||||||
};
|
};
|
||||||
|
use proto::Plan;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use smol::Timer;
|
use smol::Timer;
|
||||||
use smol::io::{AsyncReadExt, BufReader};
|
use smol::io::{AsyncReadExt, BufReader};
|
||||||
|
use std::str::FromStr as _;
|
||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, LazyLock},
|
sync::{Arc, LazyLock},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
|
@ -35,6 +38,7 @@ use std::{
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use ui::{TintColor, prelude::*};
|
use ui::{TintColor, prelude::*};
|
||||||
|
use zed_llm_client::{CURRENT_PLAN_HEADER_NAME, SUBSCRIPTION_LIMIT_RESOURCE_HEADER_NAME};
|
||||||
|
|
||||||
use crate::AllLanguageModelSettings;
|
use crate::AllLanguageModelSettings;
|
||||||
use crate::provider::anthropic::{count_anthropic_tokens, into_anthropic};
|
use crate::provider::anthropic::{count_anthropic_tokens, into_anthropic};
|
||||||
|
@ -551,6 +555,32 @@ impl CloudLanguageModel {
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
return Err(anyhow!(MaxMonthlySpendReachedError));
|
return Err(anyhow!(MaxMonthlySpendReachedError));
|
||||||
|
} else if status == StatusCode::FORBIDDEN
|
||||||
|
&& response
|
||||||
|
.headers()
|
||||||
|
.get(SUBSCRIPTION_LIMIT_RESOURCE_HEADER_NAME)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
if let Some("model_requests") = response
|
||||||
|
.headers()
|
||||||
|
.get(SUBSCRIPTION_LIMIT_RESOURCE_HEADER_NAME)
|
||||||
|
.and_then(|resource| resource.to_str().ok())
|
||||||
|
{
|
||||||
|
if let Some(plan) = response
|
||||||
|
.headers()
|
||||||
|
.get(CURRENT_PLAN_HEADER_NAME)
|
||||||
|
.and_then(|plan| plan.to_str().ok())
|
||||||
|
.and_then(|plan| zed_llm_client::Plan::from_str(plan).ok())
|
||||||
|
{
|
||||||
|
let plan = match plan {
|
||||||
|
zed_llm_client::Plan::Free => Plan::Free,
|
||||||
|
zed_llm_client::Plan::ZedPro => Plan::ZedPro,
|
||||||
|
};
|
||||||
|
return Err(anyhow!(ModelRequestLimitReachedError { plan }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(anyhow!("Forbidden"));
|
||||||
} else if status.as_u16() >= 500 && status.as_u16() < 600 {
|
} else if status.as_u16() >= 500 && status.as_u16() < 600 {
|
||||||
// If we encounter an error in the 500 range, retry after a delay.
|
// If we encounter an error in the 500 range, retry after a delay.
|
||||||
// We've seen at least these in the wild from API providers:
|
// We've seen at least these in the wild from API providers:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue