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}