agent_servers.rs

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