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