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