From afafb66f76c1a2965007cedbeeb9a0fd53717df3 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 6 Feb 2026 14:03:03 -0500 Subject: [PATCH] agent: Highlight latest models available through the Zed provider (#48614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the model selector to highlight the latest models that are available through the Zed provider: Screenshot 2026-02-06 at 1 46 41 PM Closes CLO-205. Release Notes: - Added a "Latest" indicator to highlight the latest models available through the Zed provider. --- crates/acp_thread/src/connection.rs | 3 +++ crates/agent/src/agent.rs | 2 ++ crates/agent_ui/src/acp/model_selector.rs | 6 ++++++ crates/agent_ui/src/language_model_selector.rs | 1 + crates/agent_ui/src/ui/model_selector_components.rs | 12 ++++++++++-- crates/cloud_llm_client/src/cloud_llm_client.rs | 2 ++ crates/language_model/src/language_model.rs | 5 +++++ crates/language_models/src/provider/cloud.rs | 4 ++++ 8 files changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/acp_thread/src/connection.rs b/crates/acp_thread/src/connection.rs index d5dde48e3fee2270a279673c6dd785c73801cca8..371b97393f67ad4016055b78c54e4b7006fe375b 100644 --- a/crates/acp_thread/src/connection.rs +++ b/crates/acp_thread/src/connection.rs @@ -382,6 +382,7 @@ pub struct AgentModelInfo { pub name: SharedString, pub description: Option, pub icon: Option, + pub is_latest: bool, } impl From for AgentModelInfo { @@ -391,6 +392,7 @@ impl From for AgentModelInfo { name: info.name.into(), description: info.description.map(|desc| desc.into()), icon: None, + is_latest: false, } } } @@ -744,6 +746,7 @@ mod test_support { name: "Visual Test Model".into(), description: Some("A stub model for visual testing".into()), icon: Some(AgentModelIcon::Named(ui::IconName::ZedAssistant)), + is_latest: false, })), } } diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index b63c1f14cda35f8fa3ca06f1ae56f45294ab005a..5df384bbfd9100e166f245ca011619e0200bd727 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -165,6 +165,7 @@ impl LanguageModels { IconOrSvg::Svg(path) => acp_thread::AgentModelIcon::Path(path), IconOrSvg::Icon(name) => acp_thread::AgentModelIcon::Named(name), }), + is_latest: model.is_latest(), } } @@ -1768,6 +1769,7 @@ mod internal_tests { icon: Some(acp_thread::AgentModelIcon::Named( ui::IconName::ZedAssistant )), + is_latest: false, }] )]) ); diff --git a/crates/agent_ui/src/acp/model_selector.rs b/crates/agent_ui/src/acp/model_selector.rs index e2f2bee9c4a64a7ad9784464e70ec61b387a607f..2de72d7bba2919e3519a3a0b3892c8bef7de43f3 100644 --- a/crates/agent_ui/src/acp/model_selector.rs +++ b/crates/agent_ui/src/acp/model_selector.rs @@ -367,6 +367,7 @@ impl PickerDelegate for AcpModelPickerDelegate { }) .is_selected(is_selected) .is_focused(selected) + .is_latest(model_info.is_latest) .is_favorite(is_favorite) .on_toggle_favorite(handle_action_click), ) @@ -552,6 +553,7 @@ mod tests { name: model.to_string().into(), description: None, icon: None, + is_latest: false, }) .collect::>(), ) @@ -774,12 +776,14 @@ mod tests { name: "Claude".into(), description: None, icon: None, + is_latest: false, }, acp_thread::AgentModelInfo { id: acp::ModelId::new("zed/gemini".to_string()), name: "Gemini".into(), description: None, icon: None, + is_latest: false, }, ]); let favorites = create_favorites(vec!["zed/gemini"]); @@ -820,12 +824,14 @@ mod tests { name: "Favorite".into(), description: None, icon: None, + is_latest: false, }, acp_thread::AgentModelInfo { id: acp::ModelId::new("regular-model".to_string()), name: "Regular".into(), description: None, icon: None, + is_latest: false, }, ]); let favorites = create_favorites(vec!["favorite-model"]); diff --git a/crates/agent_ui/src/language_model_selector.rs b/crates/agent_ui/src/language_model_selector.rs index 48eafe494c1111d4311baf02e44c474e7354e350..3a6505a2c1ad73574735abc076ff80d44af9a869 100644 --- a/crates/agent_ui/src/language_model_selector.rs +++ b/crates/agent_ui/src/language_model_selector.rs @@ -589,6 +589,7 @@ impl PickerDelegate for LanguageModelPickerDelegate { }) .is_selected(is_selected) .is_focused(selected) + .is_latest(model_info.model.is_latest()) .is_favorite(is_favorite) .on_toggle_favorite(handle_action_click) .into_any_element(), diff --git a/crates/agent_ui/src/ui/model_selector_components.rs b/crates/agent_ui/src/ui/model_selector_components.rs index de4036b8dec27b735e13a3b4f0de80cfa11111df..57b64dec94b0985e36d1221c3846837458ec88d8 100644 --- a/crates/agent_ui/src/ui/model_selector_components.rs +++ b/crates/agent_ui/src/ui/model_selector_components.rs @@ -1,5 +1,5 @@ use gpui::{Action, ClickEvent, FocusHandle, prelude::*}; -use ui::{ElevationIndex, KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*}; +use ui::{Chip, ElevationIndex, KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*}; use zed_actions::agent::ToggleModelSelector; use crate::CycleFavoriteModels; @@ -50,6 +50,7 @@ pub struct ModelSelectorListItem { icon: Option, is_selected: bool, is_focused: bool, + is_latest: bool, is_favorite: bool, on_toggle_favorite: Option>, } @@ -62,6 +63,7 @@ impl ModelSelectorListItem { icon: None, is_selected: false, is_focused: false, + is_latest: false, is_favorite: false, on_toggle_favorite: None, } @@ -87,6 +89,11 @@ impl ModelSelectorListItem { self } + pub fn is_latest(mut self, is_latest: bool) -> Self { + self.is_latest = is_latest; + self + } + pub fn is_favorite(mut self, is_favorite: bool) -> Self { self.is_favorite = is_favorite; self @@ -129,7 +136,8 @@ impl RenderOnce for ModelSelectorListItem { .size(IconSize::Small), ) }) - .child(Label::new(self.title).truncate()), + .child(Label::new(self.title).truncate()) + .when(self.is_latest, |parent| parent.child(Chip::new("Latest"))), ) .end_slot(div().pr_2().when(self.is_selected, |this| { this.child(Icon::new(IconName::Check).color(Color::Accent)) diff --git a/crates/cloud_llm_client/src/cloud_llm_client.rs b/crates/cloud_llm_client/src/cloud_llm_client.rs index f3a41ec3816d29b528a816968bb73259361f15a3..01194e66e7db9eb399e431aa16dc9b9bbe0a6177 100644 --- a/crates/cloud_llm_client/src/cloud_llm_client.rs +++ b/crates/cloud_llm_client/src/cloud_llm_client.rs @@ -291,6 +291,8 @@ pub struct LanguageModel { pub provider: LanguageModelProvider, pub id: LanguageModelId, pub display_name: String, + #[serde(default)] + pub is_latest: bool, pub max_token_count: usize, pub max_token_count_in_max_mode: Option, pub max_output_tokens: usize, diff --git a/crates/language_model/src/language_model.rs b/crates/language_model/src/language_model.rs index a5f6b796afab01c9253987617321313d07465043..1ff58babbc77dc3ce8881fcd352afe393da7761d 100644 --- a/crates/language_model/src/language_model.rs +++ b/crates/language_model/src/language_model.rs @@ -592,6 +592,11 @@ pub trait LanguageModel: Send + Sync { self.provider_name() } + /// Returns whether this model is the "latest", so we can highlight it in the UI. + fn is_latest(&self) -> bool { + false + } + fn telemetry_id(&self) -> String; fn api_key(&self, _cx: &App) -> Option { diff --git a/crates/language_models/src/provider/cloud.rs b/crates/language_models/src/provider/cloud.rs index b91ee734d364dd878872eec5eb41a3ba29e9881f..2473d37e363da06752214b3e9ac1de685840a4ea 100644 --- a/crates/language_models/src/provider/cloud.rs +++ b/crates/language_models/src/provider/cloud.rs @@ -566,6 +566,10 @@ impl LanguageModel for CloudLanguageModel { } } + fn is_latest(&self) -> bool { + self.model.is_latest + } + fn supports_tools(&self) -> bool { self.model.supports_tools }