agent_servers.rs

  1mod acp;
  2mod claude;
  3mod custom;
  4mod gemini;
  5
  6#[cfg(any(test, feature = "test-support"))]
  7pub mod e2e_tests;
  8
  9pub use claude::*;
 10use client::ProxySettings;
 11use collections::HashMap;
 12pub use custom::*;
 13use fs::Fs;
 14pub use gemini::*;
 15use http_client::read_no_proxy_from_env;
 16use project::agent_server_store::AgentServerStore;
 17
 18use acp_thread::AgentConnection;
 19use anyhow::Result;
 20use gpui::{App, AppContext, Entity, SharedString, Task};
 21use project::Project;
 22use settings::SettingsStore;
 23use std::{any::Any, path::Path, rc::Rc, sync::Arc};
 24
 25pub use acp::AcpConnection;
 26
 27pub struct AgentServerDelegate {
 28    store: Entity<AgentServerStore>,
 29    project: Entity<Project>,
 30    status_tx: Option<watch::Sender<SharedString>>,
 31    new_version_available: Option<watch::Sender<Option<String>>>,
 32}
 33
 34impl AgentServerDelegate {
 35    pub fn new(
 36        store: Entity<AgentServerStore>,
 37        project: Entity<Project>,
 38        status_tx: Option<watch::Sender<SharedString>>,
 39        new_version_tx: Option<watch::Sender<Option<String>>>,
 40    ) -> Self {
 41        Self {
 42            store,
 43            project,
 44            status_tx,
 45            new_version_available: new_version_tx,
 46        }
 47    }
 48
 49    pub fn project(&self) -> &Entity<Project> {
 50        &self.project
 51    }
 52}
 53
 54pub trait AgentServer: Send {
 55    fn logo(&self) -> ui::IconName;
 56    fn name(&self) -> SharedString;
 57    fn telemetry_id(&self) -> &'static str;
 58    fn default_mode(&self, _cx: &mut App) -> Option<agent_client_protocol::SessionModeId> {
 59        None
 60    }
 61    fn set_default_mode(
 62        &self,
 63        _mode_id: Option<agent_client_protocol::SessionModeId>,
 64        _fs: Arc<dyn Fs>,
 65        _cx: &mut App,
 66    ) {
 67    }
 68
 69    fn connect(
 70        &self,
 71        root_dir: Option<&Path>,
 72        delegate: AgentServerDelegate,
 73        cx: &mut App,
 74    ) -> Task<Result<(Rc<dyn AgentConnection>, Option<task::SpawnInTerminal>)>>;
 75
 76    fn into_any(self: Rc<Self>) -> Rc<dyn Any>;
 77}
 78
 79impl dyn AgentServer {
 80    pub fn downcast<T: 'static + AgentServer + Sized>(self: Rc<Self>) -> Option<Rc<T>> {
 81        self.into_any().downcast().ok()
 82    }
 83}
 84
 85/// Load the default proxy environment variables to pass through to the agent
 86pub fn load_proxy_env(cx: &mut App) -> HashMap<String, String> {
 87    let proxy_url = cx
 88        .read_global(|settings: &SettingsStore, _| settings.get::<ProxySettings>(None).proxy_url());
 89    let mut env = HashMap::default();
 90
 91    if let Some(proxy_url) = &proxy_url {
 92        let env_var = if proxy_url.scheme() == "https" {
 93            "HTTPS_PROXY"
 94        } else {
 95            "HTTP_PROXY"
 96        };
 97        env.insert(env_var.to_owned(), proxy_url.to_string());
 98    }
 99
100    if let Some(no_proxy) = read_no_proxy_from_env() {
101        env.insert("NO_PROXY".to_owned(), no_proxy);
102    } else if proxy_url.is_some() {
103        // We sometimes need local MCP servers that we don't want to proxy
104        env.insert("NO_PROXY".to_owned(), "localhost,127.0.0.1".to_owned());
105    }
106
107    env
108}