From 1fe10117b70297dfda104c73a9847950eb3b476a Mon Sep 17 00:00:00 2001 From: Clauses Kim <152622750+clauses3@users.noreply.github.com> Date: Mon, 9 Jun 2025 10:39:44 +0000 Subject: [PATCH] Add GitHub token environment variable support for Copilot (#31392) Add support for environment variables as authentication alternatives to OAuth flow for Copilot. Closes #31172 We can include the token in HTTPS request headers to hopefully resolve the rate limiting issue in #9483. This change will be part of a separate PR. Release Notes: - Added support for manually providing an OAuth token for GitHub Copilot Chat by assigning the GH_COPILOT_TOKEN environment variable --------- Co-authored-by: Bennet Bo Fenner --- crates/copilot/src/copilot.rs | 22 ++++++++++++------- crates/copilot/src/copilot_chat.rs | 12 ++++++++-- .../src/provider/copilot_chat.rs | 7 ++++++ docs/src/ai/configuration.md | 7 +++++- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 66472a78dc..ef93b1f3a2 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -408,24 +408,30 @@ impl Copilot { let proxy_url = copilot_settings.proxy.clone()?; let no_verify = copilot_settings.proxy_no_verify; let http_or_https_proxy = if proxy_url.starts_with("http:") { - "HTTP_PROXY" + Some("HTTP_PROXY") } else if proxy_url.starts_with("https:") { - "HTTPS_PROXY" + Some("HTTPS_PROXY") } else { log::error!( "Unsupported protocol scheme for language server proxy (must be http or https)" ); - return None; + None }; let mut env = HashMap::default(); - env.insert(http_or_https_proxy.to_string(), proxy_url); - if let Some(true) = no_verify { - env.insert("NODE_TLS_REJECT_UNAUTHORIZED".to_string(), "0".to_string()); - }; + if let Some(proxy_type) = http_or_https_proxy { + env.insert(proxy_type.to_string(), proxy_url); + if let Some(true) = no_verify { + env.insert("NODE_TLS_REJECT_UNAUTHORIZED".to_string(), "0".to_string()); + }; + } - Some(env) + if let Ok(oauth_token) = env::var(copilot_chat::COPILOT_OAUTH_ENV_VAR) { + env.insert(copilot_chat::COPILOT_OAUTH_ENV_VAR.to_string(), oauth_token); + } + + if env.is_empty() { None } else { Some(env) } } #[cfg(any(test, feature = "test-support"))] diff --git a/crates/copilot/src/copilot_chat.rs b/crates/copilot/src/copilot_chat.rs index 314926ed36..7e8240c942 100644 --- a/crates/copilot/src/copilot_chat.rs +++ b/crates/copilot/src/copilot_chat.rs @@ -16,6 +16,8 @@ use paths::home_dir; use serde::{Deserialize, Serialize}; 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, @@ -405,13 +407,19 @@ impl CopilotChat { }) .detach_and_log_err(cx); - Self { - oauth_token: None, + let this = Self { + oauth_token: std::env::var(COPILOT_OAUTH_ENV_VAR).ok(), api_token: None, models: None, settings, 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); } + + this } async fn update_models(this: &WeakEntity, cx: &mut AsyncApp) -> Result<()> { diff --git a/crates/language_models/src/provider/copilot_chat.rs b/crates/language_models/src/provider/copilot_chat.rs index 78c9e8581d..fc655e0c6f 100644 --- a/crates/language_models/src/provider/copilot_chat.rs +++ b/crates/language_models/src/provider/copilot_chat.rs @@ -863,6 +863,13 @@ impl Render for ConfigurationView { 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), + ) } }, None => v_flex().gap_6().child(Label::new(ERROR_LABEL)), diff --git a/docs/src/ai/configuration.md b/docs/src/ai/configuration.md index 50a792d05a..ad8715c959 100644 --- a/docs/src/ai/configuration.md +++ b/docs/src/ai/configuration.md @@ -209,7 +209,12 @@ Custom models will be listed in the model dropdown in the Agent Panel. You can a > ✅ Supports tool use in some cases. > Visit [the Copilot Chat code](https://github.com/zed-industries/zed/blob/9e0330ba7d848755c9734bf456c716bddf0973f3/crates/language_models/src/provider/copilot_chat.rs#L189-L198) for the supported subset. -You can use GitHub Copilot chat with the Zed assistant by choosing it via the model dropdown in the Agent Panel. +You can use GitHub Copilot Chat with the Zed assistant by choosing it via the model dropdown in the Agent Panel. + +1. Open the settings view (`agent: open configuration`) and go to the GitHub Copilot Chat section +2. Click on `Sign in to use GitHub Copilot`, follow the steps shown in the modal. + +Alternatively, you can provide an OAuth token via the `GH_COPILOT_TOKEN` environment variable. ### Google AI {#google-ai}