mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-10 00:13:29 +00:00
agent_servers: Set proxy env for all ACP agents (#38247)
- Use ProxySettings::proxy_url to read from settings or env - Export HTTP(S)_PROXY and NO_PROXY for agent CLIs - Add read_no_proxy_from_env and move parsing from main Closes https://github.com/zed-industries/claude-code-acp/issues/46 Release Notes: - acp: Pass proxy settings through to all ACP agents
This commit is contained in:
parent
f321d02207
commit
c0710fa8ca
9 changed files with 62 additions and 35 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -300,6 +300,7 @@ dependencies = [
|
|||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"gpui_tokio",
|
||||
"http_client",
|
||||
"indoc",
|
||||
"language",
|
||||
"language_model",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ fs.workspace = true
|
|||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
gpui_tokio = { workspace = true, optional = true }
|
||||
http_client.workspace = true
|
||||
indoc.workspace = true
|
||||
language.workspace = true
|
||||
language_model.workspace = true
|
||||
|
|
|
|||
|
|
@ -7,15 +7,19 @@ mod gemini;
|
|||
pub mod e2e_tests;
|
||||
|
||||
pub use claude::*;
|
||||
use client::ProxySettings;
|
||||
use collections::HashMap;
|
||||
pub use custom::*;
|
||||
use fs::Fs;
|
||||
pub use gemini::*;
|
||||
use http_client::read_no_proxy_from_env;
|
||||
use project::agent_server_store::AgentServerStore;
|
||||
|
||||
use acp_thread::AgentConnection;
|
||||
use anyhow::Result;
|
||||
use gpui::{App, Entity, SharedString, Task};
|
||||
use gpui::{App, AppContext, Entity, SharedString, Task};
|
||||
use project::Project;
|
||||
use settings::SettingsStore;
|
||||
use std::{any::Any, path::Path, rc::Rc, sync::Arc};
|
||||
|
||||
pub use acp::AcpConnection;
|
||||
|
|
@ -77,3 +81,25 @@ impl dyn AgentServer {
|
|||
self.into_any().downcast().ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the default proxy environment variables to pass through to the agent
|
||||
pub fn load_proxy_env(cx: &mut App) -> HashMap<String, String> {
|
||||
let proxy_url = cx
|
||||
.read_global(|settings: &SettingsStore, _| settings.get::<ProxySettings>(None).proxy_url());
|
||||
let mut env = HashMap::default();
|
||||
|
||||
if let Some(proxy_url) = &proxy_url {
|
||||
let env_var = if proxy_url.scheme() == "https" {
|
||||
"HTTPS_PROXY"
|
||||
} else {
|
||||
"HTTP_PROXY"
|
||||
};
|
||||
env.insert(env_var.to_owned(), proxy_url.to_string());
|
||||
}
|
||||
|
||||
if let Some(no_proxy) = read_no_proxy_from_env() {
|
||||
env.insert("NO_PROXY".to_owned(), no_proxy);
|
||||
}
|
||||
|
||||
env
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use anyhow::{Context as _, Result};
|
|||
use gpui::{App, AppContext as _, SharedString, Task};
|
||||
use project::agent_server_store::{AllAgentServersSettings, CLAUDE_CODE_NAME};
|
||||
|
||||
use crate::{AgentServer, AgentServerDelegate};
|
||||
use crate::{AgentServer, AgentServerDelegate, load_proxy_env};
|
||||
use acp_thread::AgentConnection;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -60,6 +60,7 @@ impl AgentServer for ClaudeCode {
|
|||
let root_dir = root_dir.map(|root_dir| root_dir.to_string_lossy().to_string());
|
||||
let is_remote = delegate.project.read(cx).is_via_remote_server();
|
||||
let store = delegate.store.downgrade();
|
||||
let extra_env = load_proxy_env(cx);
|
||||
let default_mode = self.default_mode(cx);
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
|
|
@ -70,7 +71,7 @@ impl AgentServer for ClaudeCode {
|
|||
.context("Claude Code is not registered")?;
|
||||
anyhow::Ok(agent.get_command(
|
||||
root_dir.as_deref(),
|
||||
Default::default(),
|
||||
extra_env,
|
||||
delegate.status_tx,
|
||||
delegate.new_version_available,
|
||||
&mut cx.to_async(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::AgentServerDelegate;
|
||||
use crate::{AgentServerDelegate, load_proxy_env};
|
||||
use acp_thread::AgentConnection;
|
||||
use agent_client_protocol as acp;
|
||||
use anyhow::{Context as _, Result};
|
||||
|
|
@ -65,6 +65,7 @@ impl crate::AgentServer for CustomAgentServer {
|
|||
let is_remote = delegate.project.read(cx).is_via_remote_server();
|
||||
let default_mode = self.default_mode(cx);
|
||||
let store = delegate.store.downgrade();
|
||||
let extra_env = load_proxy_env(cx);
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let (command, root_dir, login) = store
|
||||
|
|
@ -76,7 +77,7 @@ impl crate::AgentServer for CustomAgentServer {
|
|||
})?;
|
||||
anyhow::Ok(agent.get_command(
|
||||
root_dir.as_deref(),
|
||||
Default::default(),
|
||||
extra_env,
|
||||
delegate.status_tx,
|
||||
delegate.new_version_available,
|
||||
&mut cx.to_async(),
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
use std::rc::Rc;
|
||||
use std::{any::Any, path::Path};
|
||||
|
||||
use crate::{AgentServer, AgentServerDelegate};
|
||||
use crate::{AgentServer, AgentServerDelegate, load_proxy_env};
|
||||
use acp_thread::AgentConnection;
|
||||
use anyhow::{Context as _, Result};
|
||||
use client::ProxySettings;
|
||||
use collections::HashMap;
|
||||
use gpui::{App, AppContext, SharedString, Task};
|
||||
use gpui::{App, SharedString, Task};
|
||||
use language_models::provider::google::GoogleLanguageModelProvider;
|
||||
use project::agent_server_store::GEMINI_NAME;
|
||||
use settings::SettingsStore;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Gemini;
|
||||
|
|
@ -37,14 +34,12 @@ impl AgentServer for Gemini {
|
|||
let root_dir = root_dir.map(|root_dir| root_dir.to_string_lossy().to_string());
|
||||
let is_remote = delegate.project.read(cx).is_via_remote_server();
|
||||
let store = delegate.store.downgrade();
|
||||
let proxy_url = cx.read_global(|settings: &SettingsStore, _| {
|
||||
settings.get::<ProxySettings>(None).proxy.clone()
|
||||
});
|
||||
let mut extra_env = load_proxy_env(cx);
|
||||
let default_mode = self.default_mode(cx);
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let mut extra_env = HashMap::default();
|
||||
extra_env.insert("SURFACE".to_owned(), "zed".to_owned());
|
||||
|
||||
if let Some(api_key) = cx
|
||||
.update(GoogleLanguageModelProvider::api_key_for_gemini_cli)?
|
||||
.await
|
||||
|
|
@ -52,7 +47,7 @@ impl AgentServer for Gemini {
|
|||
{
|
||||
extra_env.insert("GEMINI_API_KEY".into(), api_key);
|
||||
}
|
||||
let (mut command, root_dir, login) = store
|
||||
let (command, root_dir, login) = store
|
||||
.update(cx, |store, cx| {
|
||||
let agent = store
|
||||
.get_external_agent(&GEMINI_NAME.into())
|
||||
|
|
@ -67,14 +62,6 @@ impl AgentServer for Gemini {
|
|||
})??
|
||||
.await?;
|
||||
|
||||
// Add proxy flag if proxy settings are configured in Zed and not in the args
|
||||
if let Some(proxy_url_value) = &proxy_url
|
||||
&& !command.args.iter().any(|arg| arg.contains("--proxy"))
|
||||
{
|
||||
command.args.push("--proxy".into());
|
||||
command.args.push(proxy_url_value.clone());
|
||||
}
|
||||
|
||||
let connection = crate::acp::connect(
|
||||
name,
|
||||
command,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use futures::{
|
|||
channel::oneshot, future::BoxFuture,
|
||||
};
|
||||
use gpui::{App, AsyncApp, Entity, Global, Task, WeakEntity, actions};
|
||||
use http_client::{HttpClient, HttpClientWithUrl, http};
|
||||
use http_client::{HttpClient, HttpClientWithUrl, http, read_proxy_from_env};
|
||||
use parking_lot::RwLock;
|
||||
use postage::watch;
|
||||
use proxy::connect_proxy_stream;
|
||||
|
|
@ -132,6 +132,20 @@ pub struct ProxySettings {
|
|||
pub proxy: Option<String>,
|
||||
}
|
||||
|
||||
impl ProxySettings {
|
||||
pub fn proxy_url(&self) -> Option<Url> {
|
||||
self.proxy
|
||||
.as_ref()
|
||||
.and_then(|input| {
|
||||
input
|
||||
.parse::<Url>()
|
||||
.inspect_err(|e| log::error!("Error parsing proxy settings: {}", e))
|
||||
.ok()
|
||||
})
|
||||
.or_else(read_proxy_from_env)
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for ProxySettings {
|
||||
type FileContent = ProxySettingsContent;
|
||||
|
||||
|
|
|
|||
|
|
@ -318,6 +318,12 @@ pub fn read_proxy_from_env() -> Option<Url> {
|
|||
.and_then(|env| env.parse().ok())
|
||||
}
|
||||
|
||||
pub fn read_no_proxy_from_env() -> Option<String> {
|
||||
const ENV_VARS: &[&str] = &["NO_PROXY", "no_proxy"];
|
||||
|
||||
ENV_VARS.iter().find_map(|var| std::env::var(var).ok())
|
||||
}
|
||||
|
||||
pub struct BlockedHttpClient;
|
||||
|
||||
impl BlockedHttpClient {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use git::GitHostingProviderRegistry;
|
|||
use gpui::{App, AppContext, Application, AsyncApp, Focusable as _, UpdateGlobal as _};
|
||||
|
||||
use gpui_tokio::Tokio;
|
||||
use http_client::{Url, read_proxy_from_env};
|
||||
use language::LanguageRegistry;
|
||||
use onboarding::{FIRST_OPEN, show_onboarding_view};
|
||||
use prompt_store::PromptBuilder;
|
||||
|
|
@ -398,16 +397,7 @@ pub fn main() {
|
|||
std::env::consts::OS,
|
||||
std::env::consts::ARCH
|
||||
);
|
||||
let proxy_str = ProxySettings::get_global(cx).proxy.to_owned();
|
||||
let proxy_url = proxy_str
|
||||
.as_ref()
|
||||
.and_then(|input| {
|
||||
input
|
||||
.parse::<Url>()
|
||||
.inspect_err(|e| log::error!("Error parsing proxy settings: {}", e))
|
||||
.ok()
|
||||
})
|
||||
.or_else(read_proxy_from_env);
|
||||
let proxy_url = ProxySettings::get_global(cx).proxy_url();
|
||||
let http = {
|
||||
let _guard = Tokio::handle(cx).enter();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue