diff --git a/Cargo.lock b/Cargo.lock index 8a4cfca517..2db749cacc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8981,6 +8981,7 @@ dependencies = [ "gpui", "gpui_tokio", "http_client", + "language", "language_model", "lmstudio", "log", diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 027f9842cc..51f0984a1f 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -24,6 +24,7 @@ use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServer use node_runtime::NodeRuntime; use parking_lot::Mutex; use request::StatusNotification; +use serde_json::json; use settings::SettingsStore; use sign_in::{reinstall_and_sign_in_within_workspace, sign_out_within_workspace}; use std::collections::hash_map::Entry; @@ -61,7 +62,15 @@ pub fn init( node_runtime: NodeRuntime, cx: &mut App, ) { - copilot_chat::init(fs.clone(), http.clone(), cx); + let language_settings = all_language_settings(None, cx); + let configuration = copilot_chat::CopilotChatConfiguration { + enterprise_uri: language_settings + .edit_predictions + .copilot + .enterprise_uri + .clone(), + }; + copilot_chat::init(fs.clone(), http.clone(), configuration, cx); let copilot = cx.new({ let node_runtime = node_runtime.clone(); @@ -347,8 +356,11 @@ impl Copilot { _subscription: cx.on_app_quit(Self::shutdown_language_server), }; this.start_copilot(true, false, cx); - cx.observe_global::(move |this, cx| this.start_copilot(true, false, cx)) - .detach(); + cx.observe_global::(move |this, cx| { + this.start_copilot(true, false, cx); + this.send_configuration_update(cx); + }) + .detach(); this } @@ -435,6 +447,43 @@ impl Copilot { if env.is_empty() { None } else { Some(env) } } + fn send_configuration_update(&mut self, cx: &mut Context) { + let copilot_settings = all_language_settings(None, cx) + .edit_predictions + .copilot + .clone(); + + let settings = json!({ + "http": { + "proxy": copilot_settings.proxy, + "proxyStrictSSL": !copilot_settings.proxy_no_verify.unwrap_or(false) + }, + "github-enterprise": { + "uri": copilot_settings.enterprise_uri + } + }); + + if let Some(copilot_chat) = copilot_chat::CopilotChat::global(cx) { + copilot_chat.update(cx, |chat, cx| { + chat.set_configuration( + copilot_chat::CopilotChatConfiguration { + enterprise_uri: copilot_settings.enterprise_uri.clone(), + }, + cx, + ); + }); + } + + if let Ok(server) = self.server.as_running() { + server + .lsp + .notify::( + &lsp::DidChangeConfigurationParams { settings }, + ) + .log_err(); + } + } + #[cfg(any(test, feature = "test-support"))] pub fn fake(cx: &mut gpui::TestAppContext) -> (Entity, lsp::FakeLanguageServer) { use fs::FakeFs; @@ -541,12 +590,6 @@ impl Copilot { .into_response() .context("copilot: check status")?; - server - .request::(editor_info) - .await - .into_response() - .context("copilot: set editor info")?; - anyhow::Ok((server, status)) }; @@ -564,6 +607,8 @@ impl Copilot { }); cx.emit(Event::CopilotLanguageServerStarted); this.update_sign_in_status(status, cx); + // Send configuration now that the LSP is fully started + this.send_configuration_update(cx); } Err(error) => { this.server = CopilotServer::Error(error.to_string().into()); diff --git a/crates/copilot/src/copilot_chat.rs b/crates/copilot/src/copilot_chat.rs index 7e8240c942..0f81df2e08 100644 --- a/crates/copilot/src/copilot_chat.rs +++ b/crates/copilot/src/copilot_chat.rs @@ -19,10 +19,47 @@ use settings::watch_config_dir; pub const COPILOT_OAUTH_ENV_VAR: &str = "GH_COPILOT_TOKEN"; #[derive(Default, Clone, Debug, PartialEq)] -pub struct CopilotChatSettings { - pub api_url: Arc, - pub auth_url: Arc, - pub models_url: Arc, +pub struct CopilotChatConfiguration { + pub enterprise_uri: Option, +} + +impl CopilotChatConfiguration { + pub fn token_url(&self) -> String { + if let Some(enterprise_uri) = &self.enterprise_uri { + let domain = Self::parse_domain(enterprise_uri); + format!("https://api.{}/copilot_internal/v2/token", domain) + } else { + "https://api.github.com/copilot_internal/v2/token".to_string() + } + } + + pub fn oauth_domain(&self) -> String { + if let Some(enterprise_uri) = &self.enterprise_uri { + Self::parse_domain(enterprise_uri) + } else { + "github.com".to_string() + } + } + + pub fn api_url_from_endpoint(&self, endpoint: &str) -> String { + format!("{}/chat/completions", endpoint) + } + + pub fn models_url_from_endpoint(&self, endpoint: &str) -> String { + format!("{}/models", endpoint) + } + + fn parse_domain(enterprise_uri: &str) -> String { + let uri = enterprise_uri.trim_end_matches('/'); + + if let Some(domain) = uri.strip_prefix("https://") { + domain.split('/').next().unwrap_or(domain).to_string() + } else if let Some(domain) = uri.strip_prefix("http://") { + domain.split('/').next().unwrap_or(domain).to_string() + } else { + uri.split('/').next().unwrap_or(uri).to_string() + } + } } // Copilot's base model; defined by Microsoft in premium requests table @@ -309,12 +346,19 @@ pub struct FunctionChunk { struct ApiTokenResponse { token: String, expires_at: i64, + endpoints: ApiTokenResponseEndpoints, +} + +#[derive(Deserialize)] +struct ApiTokenResponseEndpoints { + api: String, } #[derive(Clone)] struct ApiToken { api_key: String, expires_at: DateTime, + api_endpoint: String, } impl ApiToken { @@ -335,6 +379,7 @@ impl TryFrom for ApiToken { Ok(Self { api_key: response.token, expires_at, + api_endpoint: response.endpoints.api, }) } } @@ -346,13 +391,18 @@ impl Global for GlobalCopilotChat {} pub struct CopilotChat { oauth_token: Option, api_token: Option, - settings: CopilotChatSettings, + configuration: CopilotChatConfiguration, models: Option>, client: Arc, } -pub fn init(fs: Arc, client: Arc, cx: &mut App) { - let copilot_chat = cx.new(|cx| CopilotChat::new(fs, client, cx)); +pub fn init( + fs: Arc, + client: Arc, + configuration: CopilotChatConfiguration, + cx: &mut App, +) { + let copilot_chat = cx.new(|cx| CopilotChat::new(fs, client, configuration, cx)); cx.set_global(GlobalCopilotChat(copilot_chat)); } @@ -380,10 +430,15 @@ impl CopilotChat { .map(|model| model.0.clone()) } - fn new(fs: Arc, client: Arc, cx: &mut Context) -> Self { + fn new( + fs: Arc, + client: Arc, + configuration: CopilotChatConfiguration, + cx: &mut Context, + ) -> Self { let config_paths: HashSet = copilot_chat_config_paths().into_iter().collect(); let dir_path = copilot_chat_config_dir(); - let settings = CopilotChatSettings::default(); + cx.spawn(async move |this, cx| { let mut parent_watch_rx = watch_config_dir( cx.background_executor(), @@ -392,7 +447,9 @@ impl CopilotChat { config_paths, ); while let Some(contents) = parent_watch_rx.next().await { - let oauth_token = extract_oauth_token(contents); + let oauth_domain = + this.read_with(cx, |this, _| this.configuration.oauth_domain())?; + let oauth_token = extract_oauth_token(contents, &oauth_domain); this.update(cx, |this, cx| { this.oauth_token = oauth_token.clone(); @@ -411,9 +468,10 @@ impl CopilotChat { oauth_token: std::env::var(COPILOT_OAUTH_ENV_VAR).ok(), api_token: None, models: None, - settings, + configuration, client, }; + if this.oauth_token.is_some() { cx.spawn(async move |this, mut cx| Self::update_models(&this, &mut cx).await) .detach_and_log_err(cx); @@ -423,30 +481,26 @@ impl CopilotChat { } async fn update_models(this: &WeakEntity, cx: &mut AsyncApp) -> Result<()> { - let (oauth_token, client, auth_url) = this.read_with(cx, |this, _| { + let (oauth_token, client, configuration) = this.read_with(cx, |this, _| { ( this.oauth_token.clone(), this.client.clone(), - this.settings.auth_url.clone(), + this.configuration.clone(), ) })?; - let api_token = request_api_token( - &oauth_token.ok_or_else(|| { - anyhow!("OAuth token is missing while updating Copilot Chat models") - })?, - auth_url, - client.clone(), - ) - .await?; - let models_url = this.update(cx, |this, cx| { - this.api_token = Some(api_token.clone()); - cx.notify(); - this.settings.models_url.clone() - })?; - let models = get_models(models_url, api_token.api_key, client.clone()).await?; + let oauth_token = oauth_token + .ok_or_else(|| anyhow!("OAuth token is missing while updating Copilot Chat models"))?; + + let token_url = configuration.token_url(); + let api_token = request_api_token(&oauth_token, token_url.into(), client.clone()).await?; + + let models_url = configuration.models_url_from_endpoint(&api_token.api_endpoint); + let models = + get_models(models_url.into(), api_token.api_key.clone(), client.clone()).await?; this.update(cx, |this, cx| { + this.api_token = Some(api_token); this.models = Some(models); cx.notify(); })?; @@ -471,23 +525,23 @@ impl CopilotChat { .flatten() .context("Copilot chat is not enabled")?; - let (oauth_token, api_token, client, api_url, auth_url) = - this.read_with(&cx, |this, _| { - ( - this.oauth_token.clone(), - this.api_token.clone(), - this.client.clone(), - this.settings.api_url.clone(), - this.settings.auth_url.clone(), - ) - })?; + let (oauth_token, api_token, client, configuration) = this.read_with(&cx, |this, _| { + ( + this.oauth_token.clone(), + this.api_token.clone(), + this.client.clone(), + this.configuration.clone(), + ) + })?; let oauth_token = oauth_token.context("No OAuth token available")?; let token = match api_token { Some(api_token) if api_token.remaining_seconds() > 5 * 60 => api_token.clone(), _ => { - let token = request_api_token(&oauth_token, auth_url, client.clone()).await?; + let token_url = configuration.token_url(); + let token = + request_api_token(&oauth_token, token_url.into(), client.clone()).await?; this.update(&mut cx, |this, cx| { this.api_token = Some(token.clone()); cx.notify(); @@ -496,13 +550,19 @@ impl CopilotChat { } }; - stream_completion(client.clone(), token.api_key, api_url, request).await + let api_url = configuration.api_url_from_endpoint(&token.api_endpoint); + stream_completion(client.clone(), token.api_key, api_url.into(), request).await } - pub fn set_settings(&mut self, settings: CopilotChatSettings, cx: &mut Context) { - let same_settings = self.settings == settings; - self.settings = settings; - if !same_settings { + pub fn set_configuration( + &mut self, + configuration: CopilotChatConfiguration, + cx: &mut Context, + ) { + let same_configuration = self.configuration == configuration; + self.configuration = configuration; + if !same_configuration { + self.api_token = None; cx.spawn(async move |this, cx| { Self::update_models(&this, cx).await?; Ok::<_, anyhow::Error>(()) @@ -522,16 +582,12 @@ async fn get_models( let mut models: Vec = all_models .into_iter() .filter(|model| { - // Ensure user has access to the model; Policy is present only for models that must be - // enabled in the GitHub dashboard model.model_picker_enabled && model .policy .as_ref() .is_none_or(|policy| policy.state == "enabled") }) - // The first model from the API response, in any given family, appear to be the non-tagged - // models, which are likely the best choice (e.g. gpt-4o rather than gpt-4o-2024-11-20) .dedup_by(|a, b| a.capabilities.family == b.capabilities.family) .collect(); @@ -608,12 +664,12 @@ async fn request_api_token( } } -fn extract_oauth_token(contents: String) -> Option { +fn extract_oauth_token(contents: String, domain: &str) -> Option { serde_json::from_str::(&contents) .map(|v| { v.as_object().and_then(|obj| { obj.iter().find_map(|(key, value)| { - if key.starts_with("github.com") { + if key.starts_with(domain) { value["oauth_token"].as_str().map(|v| v.to_string()) } else { None diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index 6793329b61..9dda60b6a6 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -288,6 +288,8 @@ pub struct CopilotSettings { pub proxy: Option, /// Disable certificate verification for proxy (not recommended). pub proxy_no_verify: Option, + /// Enterprise URI for Copilot. + pub enterprise_uri: Option, } /// The settings for all languages. @@ -607,6 +609,11 @@ pub struct CopilotSettingsContent { /// Default: false #[serde(default)] pub proxy_no_verify: Option, + /// Enterprise URI for Copilot. + /// + /// Default: none + #[serde(default)] + pub enterprise_uri: Option, } /// The settings for enabling/disabling features. @@ -1228,10 +1235,10 @@ impl settings::Settings for AllLanguageSettings { let mut copilot_settings = default_value .edit_predictions .as_ref() - .map(|settings| settings.copilot.clone()) - .map(|copilot| CopilotSettings { - proxy: copilot.proxy, - proxy_no_verify: copilot.proxy_no_verify, + .map(|settings| CopilotSettings { + proxy: settings.copilot.proxy.clone(), + proxy_no_verify: settings.copilot.proxy_no_verify, + enterprise_uri: settings.copilot.enterprise_uri.clone(), }) .unwrap_or_default(); @@ -1287,6 +1294,14 @@ impl settings::Settings for AllLanguageSettings { copilot_settings.proxy_no_verify = Some(proxy_no_verify); } + if let Some(enterprise_uri) = user_settings + .edit_predictions + .as_ref() + .and_then(|settings| settings.copilot.enterprise_uri.clone()) + { + copilot_settings.enterprise_uri = Some(enterprise_uri); + } + // A user's global settings override the default global settings and // all default language-specific settings. merge_settings(&mut defaults, &user_settings.defaults); diff --git a/crates/language_models/Cargo.toml b/crates/language_models/Cargo.toml index ab5090e9ba..908e2e79b3 100644 --- a/crates/language_models/Cargo.toml +++ b/crates/language_models/Cargo.toml @@ -58,6 +58,7 @@ ui.workspace = true util.workspace = true workspace-hack.workspace = true zed_llm_client.workspace = true +language.workspace = true [dev-dependencies] editor = { workspace = true, features = ["test-support"] } diff --git a/crates/language_models/src/provider/copilot_chat.rs b/crates/language_models/src/provider/copilot_chat.rs index 11015aa455..475f77c318 100644 --- a/crates/language_models/src/provider/copilot_chat.rs +++ b/crates/language_models/src/provider/copilot_chat.rs @@ -10,15 +10,14 @@ use copilot::copilot_chat::{ ToolCall, }; use copilot::{Copilot, Status}; -use editor::{Editor, EditorElement, EditorStyle}; -use fs::Fs; use futures::future::BoxFuture; use futures::stream::BoxStream; use futures::{FutureExt, Stream, StreamExt}; use gpui::{ - Action, Animation, AnimationExt, AnyView, App, AsyncApp, Entity, FontStyle, Render, - Subscription, Task, TextStyle, Transformation, WhiteSpace, percentage, svg, + Action, Animation, AnimationExt, AnyView, App, AsyncApp, Entity, Render, Subscription, Task, + Transformation, percentage, svg, }; +use language::language_settings::all_language_settings; use language_model::{ AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent, LanguageModelId, LanguageModelName, LanguageModelProvider, LanguageModelProviderId, @@ -27,18 +26,14 @@ use language_model::{ LanguageModelToolSchemaFormat, LanguageModelToolUse, MessageContent, RateLimiter, Role, StopReason, }; -use settings::{Settings, SettingsStore, update_settings_file}; +use settings::SettingsStore; use std::time::Duration; -use theme::ThemeSettings; use ui::prelude::*; use util::debug_panic; -use crate::{AllLanguageModelSettings, CopilotChatSettingsContent}; - use super::anthropic::count_anthropic_tokens; use super::google::count_google_tokens; use super::open_ai::count_open_ai_tokens; -pub(crate) use copilot::copilot_chat::CopilotChatSettings; const PROVIDER_ID: &str = "copilot_chat"; const PROVIDER_NAME: &str = "GitHub Copilot Chat"; @@ -69,11 +64,16 @@ impl CopilotChatLanguageModelProvider { _copilot_chat_subscription: copilot_chat_subscription, _settings_subscription: cx.observe_global::(|_, cx| { if let Some(copilot_chat) = CopilotChat::global(cx) { - let settings = AllLanguageModelSettings::get_global(cx) - .copilot_chat - .clone(); + let language_settings = all_language_settings(None, cx); + let configuration = copilot::copilot_chat::CopilotChatConfiguration { + enterprise_uri: language_settings + .edit_predictions + .copilot + .enterprise_uri + .clone(), + }; copilot_chat.update(cx, |chat, cx| { - chat.set_settings(settings, cx); + chat.set_configuration(configuration, cx); }); } cx.notify(); @@ -174,10 +174,9 @@ impl LanguageModelProvider for CopilotChatLanguageModelProvider { Task::ready(Err(err.into())) } - fn configuration_view(&self, window: &mut Window, cx: &mut App) -> AnyView { + fn configuration_view(&self, _: &mut Window, cx: &mut App) -> AnyView { let state = self.state.clone(); - cx.new(|cx| ConfigurationView::new(state, window, cx)) - .into() + cx.new(|cx| ConfigurationView::new(state, cx)).into() } fn reset_credentials(&self, _cx: &mut App) -> Task> { @@ -622,38 +621,15 @@ fn into_copilot_chat( struct ConfigurationView { copilot_status: Option, - api_url_editor: Entity, - models_url_editor: Entity, - auth_url_editor: Entity, state: Entity, _subscription: Option, } impl ConfigurationView { - pub fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { + pub fn new(state: Entity, cx: &mut Context) -> Self { let copilot = Copilot::global(cx); - let settings = AllLanguageModelSettings::get_global(cx) - .copilot_chat - .clone(); - let api_url_editor = cx.new(|cx| Editor::single_line(window, cx)); - api_url_editor.update(cx, |this, cx| { - this.set_text(settings.api_url.clone(), window, cx); - this.set_placeholder_text("GitHub Copilot API URL", cx); - }); - let models_url_editor = cx.new(|cx| Editor::single_line(window, cx)); - models_url_editor.update(cx, |this, cx| { - this.set_text(settings.models_url.clone(), window, cx); - this.set_placeholder_text("GitHub Copilot Models URL", cx); - }); - let auth_url_editor = cx.new(|cx| Editor::single_line(window, cx)); - auth_url_editor.update(cx, |this, cx| { - this.set_text(settings.auth_url.clone(), window, cx); - this.set_placeholder_text("GitHub Copilot Auth URL", cx); - }); + Self { - api_url_editor, - models_url_editor, - auth_url_editor, copilot_status: copilot.as_ref().map(|copilot| copilot.read(cx).status()), state, _subscription: copilot.as_ref().map(|copilot| { @@ -664,104 +640,6 @@ impl ConfigurationView { }), } } - fn make_input_styles(&self, cx: &App) -> 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 make_text_style(&self, cx: &Context) -> 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 render_api_url_editor(&self, cx: &mut Context) -> impl IntoElement { - let text_style = self.make_text_style(cx); - - EditorElement::new( - &self.api_url_editor, - EditorStyle { - background: cx.theme().colors().editor_background, - local_player: cx.theme().players().local(), - text: text_style, - ..Default::default() - }, - ) - } - - fn render_auth_url_editor(&self, cx: &mut Context) -> impl IntoElement { - let text_style = self.make_text_style(cx); - - EditorElement::new( - &self.auth_url_editor, - EditorStyle { - background: cx.theme().colors().editor_background, - local_player: cx.theme().players().local(), - text: text_style, - ..Default::default() - }, - ) - } - fn render_models_editor(&self, cx: &mut Context) -> impl IntoElement { - let text_style = self.make_text_style(cx); - - EditorElement::new( - &self.models_url_editor, - EditorStyle { - background: cx.theme().colors().editor_background, - local_player: cx.theme().players().local(), - text: text_style, - ..Default::default() - }, - ) - } - - fn update_copilot_settings(&self, cx: &mut Context<'_, Self>) { - let settings = CopilotChatSettings { - api_url: self.api_url_editor.read(cx).text(cx).into(), - models_url: self.models_url_editor.read(cx).text(cx).into(), - auth_url: self.auth_url_editor.read(cx).text(cx).into(), - }; - update_settings_file::(::global(cx), cx, { - let settings = settings.clone(); - move |content, _| { - content.copilot_chat = Some(CopilotChatSettingsContent { - api_url: Some(settings.api_url.as_ref().into()), - models_url: Some(settings.models_url.as_ref().into()), - auth_url: Some(settings.auth_url.as_ref().into()), - }); - } - }); - if let Some(chat) = CopilotChat::global(cx) { - chat.update(cx, |this, cx| { - this.set_settings(settings, cx); - }); - } - } } impl Render for ConfigurationView { @@ -819,59 +697,15 @@ impl Render for ConfigurationView { } _ => { const LABEL: &str = "To use Zed's assistant with GitHub Copilot, you need to be logged in to GitHub. Note that your GitHub account must have an active Copilot Chat subscription."; - v_flex() - .gap_2() - .child(Label::new(LABEL)) - .on_action(cx.listener(|this, _: &menu::Confirm, window, cx| { - this.update_copilot_settings(cx); - copilot::initiate_sign_in(window, cx); - })) - .child( - v_flex() - .gap_0p5() - .child(Label::new("API URL").size(LabelSize::Small)) - .child( - self.make_input_styles(cx) - .child(self.render_api_url_editor(cx)), - ), - ) - .child( - v_flex() - .gap_0p5() - .child(Label::new("Auth URL").size(LabelSize::Small)) - .child( - self.make_input_styles(cx) - .child(self.render_auth_url_editor(cx)), - ), - ) - .child( - v_flex() - .gap_0p5() - .child(Label::new("Models list URL").size(LabelSize::Small)) - .child( - self.make_input_styles(cx) - .child(self.render_models_editor(cx)), - ), - ) - .child( - Button::new("sign_in", "Sign in to use GitHub Copilot") - .icon_color(Color::Muted) - .icon(IconName::Github) - .icon_position(IconPosition::Start) - .icon_size(IconSize::Medium) - .full_width() - .on_click(cx.listener(|this, _, window, cx| { - this.update_copilot_settings(cx); - copilot::initiate_sign_in(window, cx) - })), - ) - .child( - Label::new( - format!("You can also assign the {} environment variable and restart Zed.", copilot::copilot_chat::COPILOT_OAUTH_ENV_VAR), - ) - .size(LabelSize::Small) - .color(Color::Muted), - ) + v_flex().gap_2().child(Label::new(LABEL)).child( + Button::new("sign_in", "Sign in to use GitHub Copilot") + .icon_color(Color::Muted) + .icon(IconName::Github) + .icon_position(IconPosition::Start) + .icon_size(IconSize::Medium) + .full_width() + .on_click(|_, window, cx| copilot::initiate_sign_in(window, cx)), + ) } }, None => v_flex().gap_6().child(Label::new(ERROR_LABEL)), diff --git a/crates/language_models/src/settings.rs b/crates/language_models/src/settings.rs index 3eec480a8e..92fe5895c9 100644 --- a/crates/language_models/src/settings.rs +++ b/crates/language_models/src/settings.rs @@ -13,7 +13,6 @@ use crate::provider::{ anthropic::AnthropicSettings, bedrock::AmazonBedrockSettings, cloud::{self, ZedDotDevSettings}, - copilot_chat::CopilotChatSettings, deepseek::DeepSeekSettings, google::GoogleSettings, lmstudio::LmStudioSettings, @@ -65,7 +64,7 @@ pub struct AllLanguageModelSettings { pub open_router: OpenRouterSettings, pub zed_dot_dev: ZedDotDevSettings, pub google: GoogleSettings, - pub copilot_chat: CopilotChatSettings, + pub lmstudio: LmStudioSettings, pub deepseek: DeepSeekSettings, pub mistral: MistralSettings, @@ -83,7 +82,7 @@ pub struct AllLanguageModelSettingsContent { pub zed_dot_dev: Option, pub google: Option, pub deepseek: Option, - pub copilot_chat: Option, + pub mistral: Option, } @@ -271,13 +270,6 @@ pub struct ZedDotDevSettingsContent { available_models: Option>, } -#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -pub struct CopilotChatSettingsContent { - pub api_url: Option, - pub auth_url: Option, - pub models_url: Option, -} - #[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] pub struct OpenRouterSettingsContent { pub api_url: Option, @@ -435,24 +427,6 @@ impl settings::Settings for AllLanguageModelSettings { .as_ref() .and_then(|s| s.available_models.clone()), ); - - // Copilot Chat - let copilot_chat = value.copilot_chat.clone().unwrap_or_default(); - - settings.copilot_chat.api_url = copilot_chat.api_url.map_or_else( - || Arc::from("https://api.githubcopilot.com/chat/completions"), - Arc::from, - ); - - settings.copilot_chat.auth_url = copilot_chat.auth_url.map_or_else( - || Arc::from("https://api.github.com/copilot_internal/v2/token"), - Arc::from, - ); - - settings.copilot_chat.models_url = copilot_chat.models_url.map_or_else( - || Arc::from("https://api.githubcopilot.com/models"), - Arc::from, - ); } Ok(settings) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index b70647e5a8..0b6d0facf5 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -4293,7 +4293,12 @@ mod tests { project_panel::init(cx); outline_panel::init(cx); terminal_view::init(cx); - copilot::copilot_chat::init(app_state.fs.clone(), app_state.client.http_client(), cx); + copilot::copilot_chat::init( + app_state.fs.clone(), + app_state.client.http_client(), + copilot::copilot_chat::CopilotChatConfiguration::default(), + cx, + ); image_viewer::init(cx); language_model::init(app_state.client.clone(), cx); language_models::init(