language_models: Surface disabled cloud models (#59781)
Extends the support for disabled model state introduced in https://github.com/zed-industries/zed/pull/59606 to Zed Cloud hosted models. Release Notes: - N/A
This commit is contained in:
1 parent
4306847359
commit
8d21284fbb
3 files changed
+80
-24
No files matched your search
@@ -316,6 +316,10 @@ pub struct LanguageModel {
|
||||
/// Only used by OpenAI and xAI.
|
||||
#[serde(default)]
|
||||
pub supports_parallel_tool_calls: bool,
|
||||
#[serde(default)]
|
||||
pub is_disabled: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub disabled_reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
@@ -662,6 +662,31 @@ mod tests {
|
||||
sign_in_task
|
||||
}
|
||||
|
||||
fn test_cloud_model(
|
||||
model_id: cloud_llm_client::LanguageModelId,
|
||||
) -> cloud_llm_client::LanguageModel {
|
||||
cloud_llm_client::LanguageModel {
|
||||
provider: cloud_llm_client::LanguageModelProvider::Anthropic,
|
||||
id: model_id,
|
||||
display_name: "Test Model".to_string(),
|
||||
is_latest: true,
|
||||
max_token_count: 200_000,
|
||||
max_token_count_in_max_mode: None,
|
||||
max_output_tokens: 8_192,
|
||||
supports_tools: true,
|
||||
supports_images: false,
|
||||
supports_thinking: false,
|
||||
supports_disabling_thinking: false,
|
||||
supports_fast_mode: false,
|
||||
supports_server_side_compaction: false,
|
||||
supported_effort_levels: Vec::new(),
|
||||
supports_streaming_tools: false,
|
||||
supports_parallel_tool_calls: false,
|
||||
is_disabled: false,
|
||||
disabled_reason: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn provider_authenticate_does_not_start_sign_in_when_signed_out(cx: &mut TestAppContext) {
|
||||
let (client, _user_store, provider) = cx.update(init_test);
|
||||
@@ -754,6 +779,41 @@ mod tests {
|
||||
assert!(error.to_string().contains("AuthenticationError"));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn provided_models_surface_disabled_reason(cx: &mut TestAppContext) {
|
||||
let (_client, _user_store, provider) = cx.update(init_test);
|
||||
let model_id = cloud_llm_client::LanguageModelId(Arc::from("disabled-model"));
|
||||
let disabled_reason = "This model is temporarily unavailable.";
|
||||
|
||||
cx.update(|cx| {
|
||||
let cloud_model_provider = provider.state.read(cx).provider.clone();
|
||||
cloud_model_provider.update(cx, |cloud_model_provider, cx| {
|
||||
let mut model = test_cloud_model(model_id.clone());
|
||||
model.is_disabled = true;
|
||||
model.disabled_reason = Some(disabled_reason.to_string());
|
||||
cloud_model_provider.update_models(cloud_llm_client::ListModelsResponse {
|
||||
models: vec![model],
|
||||
default_model: Some(model_id.clone()),
|
||||
default_fast_model: None,
|
||||
recommended_models: vec![model_id],
|
||||
});
|
||||
cx.notify();
|
||||
});
|
||||
});
|
||||
|
||||
let model = cx.read(|cx| {
|
||||
provider
|
||||
.provided_models(cx)
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("disabled model should be provided")
|
||||
});
|
||||
assert_eq!(
|
||||
model.is_disabled(),
|
||||
Some(language_model::DisabledReason::new(disabled_reason))
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn sign_out_hides_cached_cloud_models(cx: &mut TestAppContext) {
|
||||
let (client, _user_store, provider) = cx.update(init_test);
|
||||
@@ -780,24 +840,7 @@ mod tests {
|
||||
let cloud_model_provider = provider.state.read(cx).provider.clone();
|
||||
cloud_model_provider.update(cx, |cloud_model_provider, cx| {
|
||||
cloud_model_provider.update_models(cloud_llm_client::ListModelsResponse {
|
||||
models: vec![cloud_llm_client::LanguageModel {
|
||||
provider: cloud_llm_client::LanguageModelProvider::Anthropic,
|
||||
id: model_id.clone(),
|
||||
display_name: "Test Model".to_string(),
|
||||
is_latest: true,
|
||||
max_token_count: 200_000,
|
||||
max_token_count_in_max_mode: None,
|
||||
max_output_tokens: 8_192,
|
||||
supports_tools: true,
|
||||
supports_images: false,
|
||||
supports_thinking: false,
|
||||
supports_disabling_thinking: false,
|
||||
supports_fast_mode: false,
|
||||
supports_server_side_compaction: false,
|
||||
supported_effort_levels: Vec::new(),
|
||||
supports_streaming_tools: false,
|
||||
supports_parallel_tool_calls: false,
|
||||
}],
|
||||
models: vec![test_cloud_model(model_id.clone())],
|
||||
default_model: Some(model_id.clone()),
|
||||
default_fast_model: None,
|
||||
recommended_models: vec![model_id],
|
||||
|
||||
@@ -19,12 +19,13 @@ use http_client::{
|
||||
AsyncBody, HttpClient, HttpClientWithUrl, HttpRequestExt, Method, Response, StatusCode,
|
||||
};
|
||||
use language_model::{
|
||||
ANTHROPIC_PROVIDER_ID, ANTHROPIC_PROVIDER_NAME, GOOGLE_PROVIDER_ID, GOOGLE_PROVIDER_NAME,
|
||||
LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
|
||||
LanguageModelEffortLevel, LanguageModelId, LanguageModelName, LanguageModelProviderId,
|
||||
LanguageModelProviderName, LanguageModelRequest, LanguageModelToolChoice,
|
||||
LanguageModelToolSchemaFormat, OPEN_AI_PROVIDER_ID, OPEN_AI_PROVIDER_NAME, RateLimiter,
|
||||
X_AI_PROVIDER_ID, X_AI_PROVIDER_NAME, ZED_CLOUD_PROVIDER_ID, ZED_CLOUD_PROVIDER_NAME,
|
||||
ANTHROPIC_PROVIDER_ID, ANTHROPIC_PROVIDER_NAME, DisabledReason, GOOGLE_PROVIDER_ID,
|
||||
GOOGLE_PROVIDER_NAME, LanguageModel, LanguageModelCompletionError,
|
||||
LanguageModelCompletionEvent, LanguageModelEffortLevel, LanguageModelId, LanguageModelName,
|
||||
LanguageModelProviderId, LanguageModelProviderName, LanguageModelRequest,
|
||||
LanguageModelToolChoice, LanguageModelToolSchemaFormat, OPEN_AI_PROVIDER_ID,
|
||||
OPEN_AI_PROVIDER_NAME, RateLimiter, X_AI_PROVIDER_ID, X_AI_PROVIDER_NAME,
|
||||
ZED_CLOUD_PROVIDER_ID, ZED_CLOUD_PROVIDER_NAME,
|
||||
};
|
||||
|
||||
use schemars::JsonSchema;
|
||||
@@ -322,6 +323,14 @@ impl<TP: CloudLlmTokenProvider + 'static> LanguageModel for CloudLanguageModel<T
|
||||
self.model.is_latest
|
||||
}
|
||||
|
||||
fn is_disabled(&self) -> Option<DisabledReason> {
|
||||
if self.model.is_disabled {
|
||||
self.model.disabled_reason.clone().map(DisabledReason::new)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn requires_data_retention(&self) -> bool {
|
||||
// Anthropic cannot offer Fable models with Zero Data Retention
|
||||
self.id
|
||||
|
||||
Reference in new issue
Block a user