agent_servers.rs

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