From b9176fe4bbd34e96e85528b382e2a8f5c0006748 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 18 Aug 2024 16:07:15 -0600 Subject: [PATCH] Add custom icon for Anthropic hosted models (#16436) This commit adds a custom icon for Anthropic hosted models. ![CleanShot 2024-08-18 at 15 40 38@2x](https://github.com/user-attachments/assets/d467ccab-9628-4258-89fc-782e0d4a48d4) ![CleanShot 2024-08-18 at 15 40 34@2x](https://github.com/user-attachments/assets/7efaff9c-6a58-47ba-87ea-e0fe0586fedc) - Adding a new SVG icon for Anthropic hosted models. - The new icon is located at: `assets/icons/ai_anthropic_hosted.svg` - Updating the LanguageModel trait to include an optional icon method - Implementing the icon method for CloudModel to return the custom icon for Anthropic hosted models - Updating the UI components to use the model-specific icon when available - Adding a new IconName variant for the Anthropic hosted icon We should change the non-hosted icon in some small way to distinguish it from the hosted version. I duplicated the path for now so we can hopefully add it for the next release. Release Notes: - N/A --- assets/icons/ai_anthropic_hosted.svg | 11 +++++++++++ crates/assistant/src/assistant_panel.rs | 2 +- crates/assistant/src/model_selector.rs | 9 +++++---- crates/language_model/src/language_model.rs | 4 ++++ crates/language_model/src/model/cloud_model.rs | 8 ++++++++ crates/language_model/src/provider/cloud.rs | 4 ++++ crates/ui/src/components/icon.rs | 2 ++ 7 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 assets/icons/ai_anthropic_hosted.svg diff --git a/assets/icons/ai_anthropic_hosted.svg b/assets/icons/ai_anthropic_hosted.svg new file mode 100644 index 0000000000..12d731fb0b --- /dev/null +++ b/assets/icons/ai_anthropic_hosted.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 895a2a7d4b..0375dede06 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -4135,7 +4135,7 @@ impl Render for ContextEditorToolbarItem { (Some(provider), Some(model)) => h_flex() .gap_1() .child( - Icon::new(provider.icon()) + Icon::new(model.icon().unwrap_or_else(|| provider.icon())) .color(Color::Muted) .size(IconSize::XSmall), ) diff --git a/crates/assistant/src/model_selector.rs b/crates/assistant/src/model_selector.rs index e6c730685d..514bb3ee87 100644 --- a/crates/assistant/src/model_selector.rs +++ b/crates/assistant/src/model_selector.rs @@ -36,7 +36,7 @@ pub struct ModelPickerDelegate { #[derive(Clone)] struct ModelInfo { model: Arc, - provider_icon: IconName, + icon: IconName, availability: LanguageModelAvailability, is_selected: bool, } @@ -156,7 +156,7 @@ impl PickerDelegate for ModelPickerDelegate { .selected(selected) .start_slot( div().pr_1().child( - Icon::new(model_info.provider_icon) + Icon::new(model_info.icon) .color(Color::Muted) .size(IconSize::Medium), ), @@ -261,16 +261,17 @@ impl RenderOnce for ModelSelector { .iter() .flat_map(|provider| { let provider_id = provider.id(); - let provider_icon = provider.icon(); + let icon = provider.icon(); let selected_model = selected_model.clone(); let selected_provider = selected_provider.clone(); provider.provided_models(cx).into_iter().map(move |model| { let model = model.clone(); + let icon = model.icon().unwrap_or(icon); ModelInfo { model: model.clone(), - provider_icon, + icon, availability: model.availability(), is_selected: selected_model.as_ref() == Some(&model.id()) && selected_provider.as_ref() == Some(&provider_id), diff --git a/crates/language_model/src/language_model.rs b/crates/language_model/src/language_model.rs index 0d23023c2a..c793168606 100644 --- a/crates/language_model/src/language_model.rs +++ b/crates/language_model/src/language_model.rs @@ -54,6 +54,10 @@ pub struct LanguageModelCacheConfiguration { pub trait LanguageModel: Send + Sync { fn id(&self) -> LanguageModelId; fn name(&self) -> LanguageModelName; + /// If None, falls back to [LanguageModelProvider::icon] + fn icon(&self) -> Option { + None + } fn provider_id(&self) -> LanguageModelProviderId; fn provider_name(&self) -> LanguageModelProviderName; fn telemetry_id(&self) -> String; diff --git a/crates/language_model/src/model/cloud_model.rs b/crates/language_model/src/model/cloud_model.rs index 8d6f53dbc6..f36b6b2788 100644 --- a/crates/language_model/src/model/cloud_model.rs +++ b/crates/language_model/src/model/cloud_model.rs @@ -2,6 +2,7 @@ use proto::Plan; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use strum::EnumIter; +use ui::IconName; use crate::LanguageModelAvailability; @@ -65,6 +66,13 @@ impl CloudModel { } } + pub fn icon(&self) -> Option { + match self { + Self::Anthropic(_) => Some(IconName::AiAnthropicHosted), + _ => None, + } + } + pub fn max_token_count(&self) -> usize { match self { Self::Anthropic(model) => model.max_token_count(), diff --git a/crates/language_model/src/provider/cloud.rs b/crates/language_model/src/provider/cloud.rs index b4ef8d3d01..8372129d5a 100644 --- a/crates/language_model/src/provider/cloud.rs +++ b/crates/language_model/src/provider/cloud.rs @@ -398,6 +398,10 @@ impl LanguageModel for CloudLanguageModel { LanguageModelName::from(self.model.display_name().to_string()) } + fn icon(&self) -> Option { + self.model.icon() + } + fn provider_id(&self) -> LanguageModelProviderId { LanguageModelProviderId(PROVIDER_ID.into()) } diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index eae013b865..f399820016 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -107,6 +107,7 @@ impl IconSize { pub enum IconName { Ai, AiAnthropic, + AiAnthropicHosted, AiOpenAi, AiGoogle, AiOllama, @@ -275,6 +276,7 @@ impl IconName { match self { IconName::Ai => "icons/ai.svg", IconName::AiAnthropic => "icons/ai_anthropic.svg", + IconName::AiAnthropicHosted => "icons/ai_anthropic_hosted.svg", IconName::AiOpenAi => "icons/ai_open_ai.svg", IconName::AiGoogle => "icons/ai_google.svg", IconName::AiOllama => "icons/ai_ollama.svg",