<img width="624" alt="image" src="https://github.com/user-attachments/assets/f492b0bd-14c3-49e2-b2ff-dc78e52b0815"> - [x] Correctly set custom model token count - [x] How to count tokens for Gemini models? - [x] Feature flag zed.dev provider - [x] Figure out how to configure custom models - [ ] Update docs Release Notes: - Added support for quickly switching between multiple language model providers in the assistant panel --------- Co-authored-by: Antonio <antonio@zed.dev>
128 lines
5.5 KiB
Rust
128 lines
5.5 KiB
Rust
use std::sync::Arc;
|
|
|
|
use crate::{
|
|
assistant_settings::AssistantSettings, LanguageModelCompletionProvider, ToggleModelSelector,
|
|
};
|
|
use fs::Fs;
|
|
use language_model::LanguageModelRegistry;
|
|
use settings::update_settings_file;
|
|
use ui::{prelude::*, ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip};
|
|
|
|
#[derive(IntoElement)]
|
|
pub struct ModelSelector {
|
|
handle: PopoverMenuHandle<ContextMenu>,
|
|
fs: Arc<dyn Fs>,
|
|
}
|
|
|
|
impl ModelSelector {
|
|
pub fn new(handle: PopoverMenuHandle<ContextMenu>, fs: Arc<dyn Fs>) -> Self {
|
|
ModelSelector { handle, fs }
|
|
}
|
|
}
|
|
|
|
impl RenderOnce for ModelSelector {
|
|
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
|
PopoverMenu::new("model-switcher")
|
|
.with_handle(self.handle)
|
|
.menu(move |cx| {
|
|
ContextMenu::build(cx, |mut menu, cx| {
|
|
for (provider, available_models) in LanguageModelRegistry::global(cx)
|
|
.read(cx)
|
|
.available_models_grouped_by_provider(cx)
|
|
{
|
|
menu = menu.header(provider.0.clone());
|
|
|
|
if available_models.is_empty() {
|
|
menu = menu.custom_entry(
|
|
{
|
|
move |_| {
|
|
h_flex()
|
|
.w_full()
|
|
.gap_1()
|
|
.child(Icon::new(IconName::Settings))
|
|
.child(Label::new("Configure"))
|
|
.into_any()
|
|
}
|
|
},
|
|
{
|
|
let provider = provider.clone();
|
|
move |cx| {
|
|
LanguageModelCompletionProvider::global(cx).update(
|
|
cx,
|
|
|completion_provider, cx| {
|
|
completion_provider
|
|
.set_active_provider(provider.clone(), cx)
|
|
},
|
|
);
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
for available_model in available_models {
|
|
menu = menu.custom_entry(
|
|
{
|
|
let model_name = available_model.name().0.clone();
|
|
move |_| {
|
|
h_flex()
|
|
.w_full()
|
|
.child(Label::new(model_name.clone()))
|
|
.into_any()
|
|
}
|
|
},
|
|
{
|
|
let fs = self.fs.clone();
|
|
let model = available_model.clone();
|
|
move |cx| {
|
|
let model = model.clone();
|
|
update_settings_file::<AssistantSettings>(
|
|
fs.clone(),
|
|
cx,
|
|
move |settings, _| settings.set_model(model),
|
|
);
|
|
}
|
|
},
|
|
);
|
|
}
|
|
}
|
|
menu
|
|
})
|
|
.into()
|
|
})
|
|
.trigger(
|
|
ButtonLike::new("active-model")
|
|
.style(ButtonStyle::Subtle)
|
|
.child(
|
|
h_flex()
|
|
.w_full()
|
|
.gap_0p5()
|
|
.child(
|
|
div()
|
|
.overflow_x_hidden()
|
|
.flex_grow()
|
|
.whitespace_nowrap()
|
|
.child(
|
|
Label::new(
|
|
LanguageModelCompletionProvider::read_global(cx)
|
|
.active_model()
|
|
.map(|model| model.name().0)
|
|
.unwrap_or_else(|| "No model selected".into()),
|
|
)
|
|
.size(LabelSize::Small)
|
|
.color(Color::Muted),
|
|
),
|
|
)
|
|
.child(
|
|
Icon::new(IconName::ChevronDown)
|
|
.color(Color::Muted)
|
|
.size(IconSize::XSmall),
|
|
),
|
|
)
|
|
.tooltip(move |cx| {
|
|
Tooltip::for_action("Change Model", &ToggleModelSelector, cx)
|
|
}),
|
|
)
|
|
.attach(gpui::AnchorCorner::BottomLeft)
|
|
}
|
|
}
|