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