provider configuration: Use SingleLineInput instead of Editor (#38814)

Release Notes:

- N/A
This commit is contained in:
Michael Sloan 2025-09-25 16:38:27 -06:00 committed by GitHub
parent d83d7d35cb
commit 67984d5e49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 116 additions and 462 deletions

1
Cargo.lock generated
View file

@ -8706,7 +8706,6 @@ dependencies = [
"settings",
"smol",
"strum 0.27.1",
"theme",
"thiserror 2.0.12",
"tiktoken-rs",
"tokio",

View file

@ -28,7 +28,6 @@ convert_case.workspace = true
copilot.workspace = true
credentials_provider.workspace = true
deepseek = { workspace = true, features = ["schemars"] }
editor.workspace = true
fs.workspace = true
futures.workspace = true
google_ai = { workspace = true, features = ["schemars"] }
@ -52,7 +51,6 @@ serde_json.workspace = true
settings.workspace = true
smol.workspace = true
strum.workspace = true
theme.workspace = true
thiserror.workspace = true
tiktoken-rs.workspace = true
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }

View file

@ -1,14 +1,11 @@
use crate::api_key::ApiKeyState;
use crate::ui::InstructionListItem;
use anthropic::{
ANTHROPIC_API_URL, AnthropicError, AnthropicModelMode, ContentDelta, Event, ResponseContent,
ToolResultContent, ToolResultPart, Usage,
};
use anyhow::{Result, anyhow};
use collections::{BTreeMap, HashMap};
use editor::{Editor, EditorElement, EditorStyle};
use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture, stream::BoxStream};
use gpui::{AnyView, App, AsyncApp, Context, Entity, FontStyle, Task, TextStyle, WhiteSpace};
use gpui::{AnyView, App, AsyncApp, Context, Entity, Task};
use http_client::HttpClient;
use language_model::{
AuthenticateError, ConfigurationViewTargetAgent, LanguageModel,
@ -23,11 +20,14 @@ use std::pin::Pin;
use std::str::FromStr;
use std::sync::{Arc, LazyLock};
use strum::IntoEnumIterator;
use theme::ThemeSettings;
use ui::{Icon, IconName, List, Tooltip, prelude::*};
use ui_input::SingleLineInput;
use util::{ResultExt, truncate_and_trailoff};
use zed_env_vars::{EnvVar, env_var};
use crate::api_key::ApiKeyState;
use crate::ui::InstructionListItem;
pub use settings::AnthropicAvailableModel as AvailableModel;
const PROVIDER_ID: LanguageModelProviderId = language_model::ANTHROPIC_PROVIDER_ID;
@ -42,7 +42,7 @@ pub struct AnthropicSettings {
pub struct AnthropicLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
const API_KEY_ENV_VAR_NAME: &str = "ANTHROPIC_API_KEY";
@ -123,7 +123,7 @@ impl AnthropicLanguageModelProvider {
impl LanguageModelProviderState for AnthropicLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -226,7 +226,7 @@ impl LanguageModelProvider for AnthropicLanguageModelProvider {
pub struct AnthropicModel {
id: LanguageModelId,
model: anthropic::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -823,8 +823,8 @@ fn convert_usage(usage: &Usage) -> language_model::TokenUsage {
}
struct ConfigurationView {
api_key_editor: Entity<Editor>,
state: gpui::Entity<State>,
api_key_editor: Entity<SingleLineInput>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
target_agent: ConfigurationViewTargetAgent,
}
@ -833,7 +833,7 @@ impl ConfigurationView {
const PLACEHOLDER_TEXT: &'static str = "sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
fn new(
state: gpui::Entity<State>,
state: Entity<State>,
target_agent: ConfigurationViewTargetAgent,
window: &mut Window,
cx: &mut Context<Self>,
@ -862,11 +862,7 @@ impl ConfigurationView {
}));
Self {
api_key_editor: cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text(Self::PLACEHOLDER_TEXT, window, cx);
editor
}),
api_key_editor: cx.new(|cx| SingleLineInput::new(window, cx, Self::PLACEHOLDER_TEXT)),
state,
load_credentials_task,
target_agent,
@ -905,31 +901,6 @@ impl ConfigurationView {
.detach_and_log_err(cx);
}
fn render_api_key_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_size: rems(0.875).into(),
font_weight: settings.ui_font.weight,
font_style: FontStyle::Normal,
line_height: relative(1.3),
white_space: WhiteSpace::Normal,
..Default::default()
};
EditorElement::new(
&self.api_key_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn should_render_editor(&self, cx: &mut Context<Self>) -> bool {
!self.state.read(cx).is_authenticated()
}
@ -962,18 +933,7 @@ impl Render for ConfigurationView {
InstructionListItem::text_only("Paste your API key below and hit enter to start using the agent")
)
)
.child(
h_flex()
.w_full()
.my_2()
.px_2()
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
.child(self.api_key_editor.clone())
.child(
Label::new(
format!("You can also assign the {API_KEY_ENV_VAR_NAME} environment variable and restart Zed."),

View file

@ -23,12 +23,8 @@ use bedrock::{
};
use collections::{BTreeMap, HashMap};
use credentials_provider::CredentialsProvider;
use editor::{Editor, EditorElement, EditorStyle};
use futures::{FutureExt, Stream, StreamExt, future::BoxFuture, stream::BoxStream};
use gpui::{
AnyView, App, AsyncApp, Context, Entity, FontStyle, FontWeight, Subscription, Task, TextStyle,
WhiteSpace,
};
use gpui::{AnyView, App, AsyncApp, Context, Entity, FontWeight, Subscription, Task};
use gpui_tokio::Tokio;
use http_client::HttpClient;
use language_model::{
@ -45,8 +41,8 @@ use serde_json::Value;
use settings::{BedrockAvailableModel as AvailableModel, Settings, SettingsStore};
use smol::lock::OnceCell;
use strum::{EnumIter, IntoEnumIterator, IntoStaticStr};
use theme::ThemeSettings;
use ui::{Icon, IconName, List, Tooltip, prelude::*};
use ui_input::SingleLineInput;
use util::ResultExt;
use crate::AllLanguageModelSettings;
@ -243,7 +239,7 @@ impl State {
pub struct BedrockLanguageModelProvider {
http_client: AwsHttpClient,
handle: tokio::runtime::Handle,
state: gpui::Entity<State>,
state: Entity<State>,
}
impl BedrockLanguageModelProvider {
@ -366,7 +362,7 @@ impl LanguageModelProvider for BedrockLanguageModelProvider {
impl LanguageModelProviderState for BedrockLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -377,7 +373,7 @@ struct BedrockModel {
http_client: AwsHttpClient,
handle: tokio::runtime::Handle,
client: OnceCell<BedrockClient>,
state: gpui::Entity<State>,
state: Entity<State>,
request_limiter: RateLimiter,
}
@ -1010,11 +1006,11 @@ pub fn map_to_language_model_completion_events(
}
struct ConfigurationView {
access_key_id_editor: Entity<Editor>,
secret_access_key_editor: Entity<Editor>,
session_token_editor: Entity<Editor>,
region_editor: Entity<Editor>,
state: gpui::Entity<State>,
access_key_id_editor: Entity<SingleLineInput>,
secret_access_key_editor: Entity<SingleLineInput>,
session_token_editor: Entity<SingleLineInput>,
region_editor: Entity<SingleLineInput>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
@ -1025,7 +1021,7 @@ impl ConfigurationView {
const PLACEHOLDER_SESSION_TOKEN_TEXT: &'static str = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const PLACEHOLDER_REGION: &'static str = "us-east-1";
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
cx.observe(&state, |_, _, cx| {
cx.notify();
})
@ -1051,24 +1047,19 @@ impl ConfigurationView {
Self {
access_key_id_editor: cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text(Self::PLACEHOLDER_ACCESS_KEY_ID_TEXT, window, cx);
editor
SingleLineInput::new(window, cx, Self::PLACEHOLDER_ACCESS_KEY_ID_TEXT)
.label("Access Key ID")
}),
secret_access_key_editor: cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text(Self::PLACEHOLDER_SECRET_ACCESS_KEY_TEXT, window, cx);
editor
SingleLineInput::new(window, cx, Self::PLACEHOLDER_SECRET_ACCESS_KEY_TEXT)
.label("Secret Access Key")
}),
session_token_editor: cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text(Self::PLACEHOLDER_SESSION_TOKEN_TEXT, window, cx);
editor
SingleLineInput::new(window, cx, Self::PLACEHOLDER_SESSION_TOKEN_TEXT)
.label("Session Token (Optional)")
}),
region_editor: cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text(Self::PLACEHOLDER_REGION, window, cx);
editor
SingleLineInput::new(window, cx, Self::PLACEHOLDER_REGION).label("Region")
}),
state,
load_credentials_task,
@ -1148,41 +1139,6 @@ impl ConfigurationView {
.detach_and_log_err(cx);
}
fn make_text_style(&self, cx: &Context<Self>) -> TextStyle {
let settings = ThemeSettings::get_global(cx);
TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_size: rems(0.875).into(),
font_weight: settings.ui_font.weight,
font_style: FontStyle::Normal,
line_height: relative(1.3),
background_color: None,
underline: None,
strikethrough: None,
white_space: WhiteSpace::Normal,
text_overflow: None,
text_align: Default::default(),
line_clamp: None,
}
}
fn make_input_styles(&self, cx: &Context<Self>) -> Div {
let bg_color = cx.theme().colors().editor_background;
let border_color = cx.theme().colors().border;
h_flex()
.w_full()
.px_2()
.py_1()
.bg(bg_color)
.border_1()
.border_color(border_color)
.rounded_sm()
}
fn should_render_editor(&self, cx: &Context<Self>) -> bool {
self.state.read(cx).is_authenticated()
}
@ -1265,8 +1221,8 @@ impl Render for ConfigurationView {
)
)
)
.child(self.render_static_credentials_ui(cx))
.child(self.render_common_fields(cx))
.child(self.render_static_credentials_ui())
.child(self.region_editor.clone())
.child(
Label::new(
format!("You can also assign the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR} AND {ZED_BEDROCK_REGION_VAR} environment variables and restart Zed."),
@ -1287,63 +1243,7 @@ impl Render for ConfigurationView {
}
impl ConfigurationView {
fn render_access_key_id_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let text_style = self.make_text_style(cx);
EditorElement::new(
&self.access_key_id_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn render_secret_key_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let text_style = self.make_text_style(cx);
EditorElement::new(
&self.secret_access_key_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn render_session_token_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let text_style = self.make_text_style(cx);
EditorElement::new(
&self.session_token_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn render_region_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let text_style = self.make_text_style(cx);
EditorElement::new(
&self.region_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn render_static_credentials_ui(&self, cx: &mut Context<Self>) -> AnyElement {
fn render_static_credentials_ui(&self) -> AnyElement {
v_flex()
.my_2()
.gap_1p5()
@ -1376,41 +1276,10 @@ impl ConfigurationView {
"Enter these credentials below",
)),
)
.child(
v_flex()
.gap_0p5()
.child(Label::new("Access Key ID").size(LabelSize::Small))
.child(
self.make_input_styles(cx)
.child(self.render_access_key_id_editor(cx)),
),
)
.child(
v_flex()
.gap_0p5()
.child(Label::new("Secret Access Key").size(LabelSize::Small))
.child(self.make_input_styles(cx).child(self.render_secret_key_editor(cx))),
)
.child(
v_flex()
.gap_0p5()
.child(Label::new("Session Token (Optional)").size(LabelSize::Small))
.child(
self.make_input_styles(cx)
.child(self.render_session_token_editor(cx)),
),
)
.into_any_element()
}
fn render_common_fields(&self, cx: &mut Context<Self>) -> AnyElement {
v_flex()
.gap_0p5()
.child(Label::new("Region").size(LabelSize::Small))
.child(
self.make_input_styles(cx)
.child(self.render_region_editor(cx)),
)
.child(self.access_key_id_editor.clone())
.child(self.secret_access_key_editor.clone())
.child(self.session_token_editor.clone())
.child(self.region_editor.clone())
.into_any_element()
}
}

View file

@ -76,7 +76,7 @@ impl From<ModelMode> for AnthropicModelMode {
pub struct CloudLanguageModelProvider {
client: Arc<Client>,
state: gpui::Entity<State>,
state: Entity<State>,
_maintain_client_status: Task<()>,
}
@ -287,7 +287,7 @@ impl CloudLanguageModelProvider {
impl LanguageModelProviderState for CloudLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}

View file

@ -89,7 +89,7 @@ impl CopilotChatLanguageModelProvider {
impl LanguageModelProviderState for CopilotChatLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}

View file

@ -1,13 +1,10 @@
use anyhow::{Result, anyhow};
use collections::{BTreeMap, HashMap};
use deepseek::DEEPSEEK_API_URL;
use editor::{Editor, EditorElement, EditorStyle};
use futures::Stream;
use futures::{FutureExt, StreamExt, future, future::BoxFuture, stream::BoxStream};
use gpui::{
AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace,
Window,
};
use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window};
use http_client::HttpClient;
use language_model::{
AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
@ -21,8 +18,9 @@ use settings::{Settings, SettingsStore};
use std::pin::Pin;
use std::str::FromStr;
use std::sync::{Arc, LazyLock};
use theme::ThemeSettings;
use ui::{Icon, IconName, List, prelude::*};
use ui_input::SingleLineInput;
use util::{ResultExt, truncate_and_trailoff};
use zed_env_vars::{EnvVar, env_var};
@ -527,18 +525,15 @@ impl DeepSeekEventMapper {
}
struct ConfigurationView {
api_key_editor: Entity<Editor>,
api_key_editor: Entity<SingleLineInput>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text("sk-00000000000000000000000000000000", window, cx);
editor
});
let api_key_editor =
cx.new(|cx| SingleLineInput::new(window, cx, "sk-00000000000000000000000000000000"));
cx.observe(&state, |_, _, cx| {
cx.notify();
@ -598,34 +593,6 @@ impl ConfigurationView {
.detach_and_log_err(cx);
}
fn render_api_key_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_size: rems(0.875).into(),
font_weight: settings.ui_font.weight,
font_style: FontStyle::Normal,
line_height: relative(1.3),
background_color: None,
underline: None,
strikethrough: None,
white_space: WhiteSpace::Normal,
..Default::default()
};
EditorElement::new(
&self.api_key_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn should_render_editor(&self, cx: &mut Context<Self>) -> bool {
!self.state.read(cx).is_authenticated()
}
@ -653,18 +620,7 @@ impl Render for ConfigurationView {
"Paste your API key below and hit enter to start using the assistant",
)),
)
.child(
h_flex()
.w_full()
.my_2()
.px_2()
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
.child(self.api_key_editor.clone())
.child(
Label::new(format!(
"Or set the {API_KEY_ENV_VAR_NAME} environment variable."

View file

@ -1,16 +1,12 @@
use anyhow::{Context as _, Result, anyhow};
use collections::BTreeMap;
use credentials_provider::CredentialsProvider;
use editor::{Editor, EditorElement, EditorStyle};
use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture};
use google_ai::{
FunctionDeclaration, GenerateContentResponse, GoogleModelMode, Part, SystemInstruction,
ThinkingConfig, UsageMetadata,
};
use gpui::{
AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace,
Window,
};
use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window};
use http_client::HttpClient;
use language_model::{
AuthenticateError, ConfigurationViewTargetAgent, LanguageModelCompletionError,
@ -32,8 +28,8 @@ use std::sync::{
atomic::{self, AtomicU64},
};
use strum::IntoEnumIterator;
use theme::ThemeSettings;
use ui::{Icon, IconName, List, Tooltip, prelude::*};
use ui_input::SingleLineInput;
use util::{ResultExt, truncate_and_trailoff};
use zed_env_vars::EnvVar;
@ -63,7 +59,7 @@ pub enum ModelMode {
pub struct GoogleLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -165,7 +161,7 @@ impl GoogleLanguageModelProvider {
impl LanguageModelProviderState for GoogleLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -255,7 +251,7 @@ impl LanguageModelProvider for GoogleLanguageModelProvider {
pub struct GoogleLanguageModel {
id: LanguageModelId,
model: google_ai::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -755,15 +751,15 @@ fn convert_usage(usage: &UsageMetadata) -> language_model::TokenUsage {
}
struct ConfigurationView {
api_key_editor: Entity<Editor>,
state: gpui::Entity<State>,
api_key_editor: Entity<SingleLineInput>,
state: Entity<State>,
target_agent: language_model::ConfigurationViewTargetAgent,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(
state: gpui::Entity<State>,
state: Entity<State>,
target_agent: language_model::ConfigurationViewTargetAgent,
window: &mut Window,
cx: &mut Context<Self>,
@ -792,11 +788,7 @@ impl ConfigurationView {
}));
Self {
api_key_editor: cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text("AIzaSy...", window, cx);
editor
}),
api_key_editor: cx.new(|cx| SingleLineInput::new(window, cx, "AIzaSy...")),
target_agent,
state,
load_credentials_task,
@ -835,31 +827,6 @@ impl ConfigurationView {
.detach_and_log_err(cx);
}
fn render_api_key_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_size: rems(0.875).into(),
font_weight: settings.ui_font.weight,
font_style: FontStyle::Normal,
line_height: relative(1.3),
white_space: WhiteSpace::Normal,
..Default::default()
};
EditorElement::new(
&self.api_key_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn should_render_editor(&self, cx: &mut Context<Self>) -> bool {
!self.state.read(cx).is_authenticated()
}
@ -890,18 +857,7 @@ impl Render for ConfigurationView {
"Paste your API key below and hit enter to start using the assistant",
)),
)
.child(
h_flex()
.w_full()
.my_2()
.px_2()
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
.child(self.api_key_editor.clone())
.child(
Label::new(
format!("You can also assign the {GEMINI_API_KEY_VAR_NAME} environment variable and restart Zed."),

View file

@ -2,7 +2,7 @@ use anyhow::{Result, anyhow};
use collections::HashMap;
use futures::Stream;
use futures::{FutureExt, StreamExt, future::BoxFuture, stream::BoxStream};
use gpui::{AnyView, App, AsyncApp, Context, Subscription, Task};
use gpui::{AnyView, App, AsyncApp, Context, Entity, Subscription, Task};
use http_client::HttpClient;
use language_model::{
AuthenticateError, LanguageModelCompletionError, LanguageModelCompletionEvent,
@ -41,7 +41,7 @@ pub struct LmStudioSettings {
pub struct LmStudioLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -162,7 +162,7 @@ impl LmStudioLanguageModelProvider {
impl LanguageModelProviderState for LmStudioLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -635,12 +635,12 @@ fn add_message_content_part(
}
struct ConfigurationView {
state: gpui::Entity<State>,
state: Entity<State>,
loading_models_task: Option<Task<()>>,
}
impl ConfigurationView {
pub fn new(state: gpui::Entity<State>, cx: &mut Context<Self>) -> Self {
pub fn new(state: Entity<State>, cx: &mut Context<Self>) -> Self {
let loading_models_task = Some(cx.spawn({
let state = state.clone();
async move |this, cx| {

View file

@ -1,11 +1,7 @@
use anyhow::{Result, anyhow};
use collections::BTreeMap;
use editor::{Editor, EditorElement, EditorStyle};
use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture, stream::BoxStream};
use gpui::{
AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace,
Window,
};
use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window};
use http_client::HttpClient;
use language_model::{
AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
@ -22,8 +18,8 @@ use std::pin::Pin;
use std::str::FromStr;
use std::sync::{Arc, LazyLock};
use strum::IntoEnumIterator;
use theme::ThemeSettings;
use ui::{Icon, IconName, List, Tooltip, prelude::*};
use ui_input::SingleLineInput;
use util::{ResultExt, truncate_and_trailoff};
use zed_env_vars::{EnvVar, env_var};
@ -43,7 +39,7 @@ pub struct MistralSettings {
pub struct MistralLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -121,7 +117,7 @@ impl MistralLanguageModelProvider {
impl LanguageModelProviderState for MistralLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -215,7 +211,7 @@ impl LanguageModelProvider for MistralLanguageModelProvider {
pub struct MistralLanguageModel {
id: LanguageModelId,
model: mistral::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -694,18 +690,15 @@ struct RawToolCall {
}
struct ConfigurationView {
api_key_editor: Entity<Editor>,
state: gpui::Entity<State>,
api_key_editor: Entity<SingleLineInput>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text("0aBCDEFGhIjKLmNOpqrSTUVwxyzabCDE1f2", window, cx);
editor
});
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor =
cx.new(|cx| SingleLineInput::new(window, cx, "0aBCDEFGhIjKLmNOpqrSTUVwxyzabCDE1f2"));
cx.observe(&state, |_, _, cx| {
cx.notify();
@ -770,31 +763,6 @@ impl ConfigurationView {
.detach_and_log_err(cx);
}
fn render_api_key_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_size: rems(0.875).into(),
font_weight: settings.ui_font.weight,
font_style: FontStyle::Normal,
line_height: relative(1.3),
white_space: WhiteSpace::Normal,
..Default::default()
};
EditorElement::new(
&self.api_key_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn should_render_editor(&self, cx: &mut Context<Self>) -> bool {
!self.state.read(cx).is_authenticated()
}
@ -825,18 +793,7 @@ impl Render for ConfigurationView {
"Paste your API key below and hit enter to start using the assistant",
)),
)
.child(
h_flex()
.w_full()
.my_2()
.px_2()
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
.child(self.api_key_editor.clone())
.child(
Label::new(
format!("You can also assign the {API_KEY_ENV_VAR_NAME} environment variable and restart Zed."),

View file

@ -2,7 +2,7 @@ use anyhow::{Result, anyhow};
use fs::Fs;
use futures::{FutureExt, StreamExt, future::BoxFuture, stream::BoxStream};
use futures::{Stream, TryFutureExt, stream};
use gpui::{AnyView, App, AsyncApp, Context, Task};
use gpui::{AnyView, App, AsyncApp, Context, CursorStyle, Entity, Task};
use http_client::HttpClient;
use language_model::{
AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
@ -48,7 +48,7 @@ pub struct OllamaSettings {
pub struct OllamaLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -209,7 +209,7 @@ impl OllamaLanguageModelProvider {
impl LanguageModelProviderState for OllamaLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -322,7 +322,7 @@ pub struct OllamaLanguageModel {
model: ollama::Model,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
state: gpui::Entity<State>,
state: Entity<State>,
}
impl OllamaLanguageModel {
@ -623,13 +623,13 @@ fn map_to_language_model_completion_events(
}
struct ConfigurationView {
api_key_editor: gpui::Entity<SingleLineInput>,
api_url_editor: gpui::Entity<SingleLineInput>,
state: gpui::Entity<State>,
api_key_editor: Entity<SingleLineInput>,
api_url_editor: Entity<SingleLineInput>,
state: Entity<State>,
}
impl ConfigurationView {
pub fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
pub fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor =
cx.new(|cx| SingleLineInput::new(window, cx, "63e02e...").label("API key"));
@ -900,7 +900,7 @@ impl Render for ConfigurationView {
this.child(
ButtonLike::new("connected")
.disabled(true)
.cursor_style(gpui::CursorStyle::Arrow)
.cursor_style(CursorStyle::Arrow)
.child(
h_flex()
.gap_2()

View file

@ -41,7 +41,7 @@ pub struct OpenAiSettings {
pub struct OpenAiLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -119,7 +119,7 @@ impl OpenAiLanguageModelProvider {
impl LanguageModelProviderState for OpenAiLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -203,7 +203,7 @@ impl LanguageModelProvider for OpenAiLanguageModelProvider {
pub struct OpenAiLanguageModel {
id: LanguageModelId,
model: open_ai::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -676,12 +676,12 @@ pub fn count_open_ai_tokens(
struct ConfigurationView {
api_key_editor: Entity<SingleLineInput>,
state: gpui::Entity<State>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
SingleLineInput::new(
window,

View file

@ -33,7 +33,7 @@ pub struct OpenAiCompatibleLanguageModelProvider {
id: LanguageModelProviderId,
name: LanguageModelProviderName,
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -125,7 +125,7 @@ impl OpenAiCompatibleLanguageModelProvider {
impl LanguageModelProviderState for OpenAiCompatibleLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -195,7 +195,7 @@ pub struct OpenAiCompatibleLanguageModel {
provider_id: LanguageModelProviderId,
provider_name: LanguageModelProviderName,
model: AvailableModel,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -341,12 +341,12 @@ impl LanguageModel for OpenAiCompatibleLanguageModel {
struct ConfigurationView {
api_key_editor: Entity<SingleLineInput>,
state: gpui::Entity<State>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
SingleLineInput::new(
window,

View file

@ -1,10 +1,7 @@
use anyhow::{Result, anyhow};
use collections::HashMap;
use editor::{Editor, EditorElement, EditorStyle};
use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture};
use gpui::{
AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace,
};
use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task};
use http_client::HttpClient;
use language_model::{
AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
@ -20,8 +17,8 @@ use settings::{OpenRouterAvailableModel as AvailableModel, Settings, SettingsSto
use std::pin::Pin;
use std::str::FromStr as _;
use std::sync::{Arc, LazyLock};
use theme::ThemeSettings;
use ui::{Icon, IconName, List, Tooltip, prelude::*};
use ui_input::SingleLineInput;
use util::{ResultExt, truncate_and_trailoff};
use zed_env_vars::{EnvVar, env_var};
@ -41,7 +38,7 @@ pub struct OpenRouterSettings {
pub struct OpenRouterLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -174,7 +171,7 @@ impl OpenRouterLanguageModelProvider {
impl LanguageModelProviderState for OpenRouterLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -260,7 +257,7 @@ impl LanguageModelProvider for OpenRouterLanguageModelProvider {
pub struct OpenRouterLanguageModel {
id: LanguageModelId,
model: open_router::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -695,21 +692,19 @@ pub fn count_open_router_tokens(
}
struct ConfigurationView {
api_key_editor: Entity<Editor>,
state: gpui::Entity<State>,
api_key_editor: Entity<SingleLineInput>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);
editor.set_placeholder_text(
"sk_or_000000000000000000000000000000000000000000000000",
SingleLineInput::new(
window,
cx,
);
editor
"sk_or_000000000000000000000000000000000000000000000000",
)
});
cx.observe(&state, |_, _, cx| {
@ -774,31 +769,6 @@ impl ConfigurationView {
.detach_and_log_err(cx);
}
fn render_api_key_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_size: rems(0.875).into(),
font_weight: settings.ui_font.weight,
font_style: FontStyle::Normal,
line_height: relative(1.3),
white_space: WhiteSpace::Normal,
..Default::default()
};
EditorElement::new(
&self.api_key_editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
fn should_render_editor(&self, cx: &mut Context<Self>) -> bool {
!self.state.read(cx).is_authenticated()
}
@ -829,18 +799,7 @@ impl Render for ConfigurationView {
"Paste your API key below and hit enter to start using the assistant",
)),
)
.child(
h_flex()
.w_full()
.my_2()
.px_2()
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
.child(self.api_key_editor.clone())
.child(
Label::new(
format!("You can also assign the {API_KEY_ENV_VAR_NAME} environment variable and restart Zed."),

View file

@ -36,7 +36,7 @@ pub struct VercelSettings {
pub struct VercelLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -114,7 +114,7 @@ impl VercelLanguageModelProvider {
impl LanguageModelProviderState for VercelLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -195,7 +195,7 @@ impl LanguageModelProvider for VercelLanguageModelProvider {
pub struct VercelLanguageModel {
id: LanguageModelId,
model: vercel::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -363,12 +363,12 @@ pub fn count_vercel_tokens(
struct ConfigurationView {
api_key_editor: Entity<SingleLineInput>,
state: gpui::Entity<State>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
SingleLineInput::new(
window,

View file

@ -36,7 +36,7 @@ pub struct XAiSettings {
pub struct XAiLanguageModelProvider {
http_client: Arc<dyn HttpClient>,
state: gpui::Entity<State>,
state: Entity<State>,
}
pub struct State {
@ -114,7 +114,7 @@ impl XAiLanguageModelProvider {
impl LanguageModelProviderState for XAiLanguageModelProvider {
type ObservableEntity = State;
fn observable_entity(&self) -> Option<gpui::Entity<Self::ObservableEntity>> {
fn observable_entity(&self) -> Option<Entity<Self::ObservableEntity>> {
Some(self.state.clone())
}
}
@ -195,7 +195,7 @@ impl LanguageModelProvider for XAiLanguageModelProvider {
pub struct XAiLanguageModel {
id: LanguageModelId,
model: x_ai::Model,
state: gpui::Entity<State>,
state: Entity<State>,
http_client: Arc<dyn HttpClient>,
request_limiter: RateLimiter,
}
@ -357,12 +357,12 @@ pub fn count_xai_tokens(
struct ConfigurationView {
api_key_editor: Entity<SingleLineInput>,
state: gpui::Entity<State>,
state: Entity<State>,
load_credentials_task: Option<Task<()>>,
}
impl ConfigurationView {
fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
fn new(state: Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let api_key_editor = cx.new(|cx| {
SingleLineInput::new(
window,