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