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

Michael Sloan created

Release Notes:

- N/A

Change summary

Cargo.lock                                                |   1 
crates/language_models/Cargo.toml                         |   2 
crates/language_models/src/provider/anthropic.rs          |  66 --
crates/language_models/src/provider/bedrock.rs            | 181 +-------
crates/language_models/src/provider/cloud.rs              |   4 
crates/language_models/src/provider/copilot_chat.rs       |   2 
crates/language_models/src/provider/deepseek.rs           |  60 --
crates/language_models/src/provider/google.rs             |  64 --
crates/language_models/src/provider/lmstudio.rs           |  10 
crates/language_models/src/provider/mistral.rs            |  65 --
crates/language_models/src/provider/ollama.rs             |  18 
crates/language_models/src/provider/open_ai.rs            |  10 
crates/language_models/src/provider/open_ai_compatible.rs |  10 
crates/language_models/src/provider/open_router.rs        |  65 --
crates/language_models/src/provider/vercel.rs             |  10 
crates/language_models/src/provider/x_ai.rs               |  10 
16 files changed, 116 insertions(+), 462 deletions(-)

Detailed changes

Cargo.lock 🔗

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

crates/language_models/Cargo.toml 🔗

@@ -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"] }

crates/language_models/src/provider/anthropic.rs 🔗

@@ -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."),

crates/language_models/src/provider/bedrock.rs 🔗

@@ -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()
     }
 }

crates/language_models/src/provider/cloud.rs 🔗

@@ -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())
     }
 }

crates/language_models/src/provider/copilot_chat.rs 🔗

@@ -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())
     }
 }

crates/language_models/src/provider/deepseek.rs 🔗

@@ -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."

crates/language_models/src/provider/google.rs 🔗

@@ -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."),

crates/language_models/src/provider/lmstudio.rs 🔗

@@ -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| {

crates/language_models/src/provider/mistral.rs 🔗

@@ -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."),

crates/language_models/src/provider/ollama.rs 🔗

@@ -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()

crates/language_models/src/provider/open_ai.rs 🔗

@@ -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,

crates/language_models/src/provider/open_ai_compatible.rs 🔗

@@ -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,

crates/language_models/src/provider/open_router.rs 🔗

@@ -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."),

crates/language_models/src/provider/vercel.rs 🔗

@@ -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,

crates/language_models/src/provider/x_ai.rs 🔗

@@ -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,