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