1use crate::constants::env::acp::AgentClientProtocolEnvKey;
2use serde::{Deserialize, Serialize};
3
4fn parse_env_bool(key: AgentClientProtocolEnvKey, default: bool) -> bool {
5 crate::env_helpers::parse_env_bool(key.as_str(), default)
6}
7
8fn default_enabled() -> bool {
9 parse_env_bool(AgentClientProtocolEnvKey::Enabled, false)
10}
11
12fn default_zed_enabled() -> bool {
13 parse_env_bool(AgentClientProtocolEnvKey::ZedEnabled, default_enabled())
14}
15
16fn default_zed_tools_read_file_enabled() -> bool {
17 parse_env_bool(AgentClientProtocolEnvKey::ZedToolsReadFileEnabled, true)
18}
19
20fn default_zed_tools_list_files_enabled() -> bool {
21 parse_env_bool(AgentClientProtocolEnvKey::ZedToolsListFilesEnabled, true)
22}
23
24fn parse_env_trust_mode(
25 key: AgentClientProtocolEnvKey,
26 default: AgentClientProtocolZedWorkspaceTrustMode,
27) -> AgentClientProtocolZedWorkspaceTrustMode {
28 std::env::var(key.as_str())
29 .ok()
30 .and_then(|value| AgentClientProtocolZedWorkspaceTrustMode::from_env_value(&value))
31 .unwrap_or(default)
32}
33
34fn default_zed_workspace_trust_mode() -> AgentClientProtocolZedWorkspaceTrustMode {
35 parse_env_trust_mode(
36 AgentClientProtocolEnvKey::ZedWorkspaceTrust,
37 AgentClientProtocolZedWorkspaceTrustMode::FullAuto,
38 )
39}
40
41fn default_transport() -> AgentClientProtocolTransport {
42 AgentClientProtocolTransport::Stdio
43}
44
45#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
47#[derive(Debug, Clone, Deserialize, Serialize)]
48pub struct AgentClientProtocolConfig {
49 #[serde(default = "default_enabled")]
51 pub enabled: bool,
52
53 #[serde(default)]
55 pub zed: AgentClientProtocolZedConfig,
56}
57
58impl Default for AgentClientProtocolConfig {
59 fn default() -> Self {
60 Self {
61 enabled: default_enabled(),
62 zed: AgentClientProtocolZedConfig::default(),
63 }
64 }
65}
66
67#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
70#[serde(rename_all = "snake_case")]
71pub enum AgentClientProtocolTransport {
72 Stdio,
74}
75
76impl Default for AgentClientProtocolTransport {
77 fn default() -> Self {
78 default_transport()
79 }
80}
81
82#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
84#[derive(Debug, Clone, Deserialize, Serialize)]
85pub struct AgentClientProtocolZedConfig {
86 #[serde(default = "default_zed_enabled")]
88 pub enabled: bool,
89
90 #[serde(default = "default_transport")]
92 pub transport: AgentClientProtocolTransport,
93
94 #[serde(default)]
96 pub tools: AgentClientProtocolZedToolsConfig,
97
98 #[serde(default = "default_zed_workspace_trust_mode")]
100 pub workspace_trust: AgentClientProtocolZedWorkspaceTrustMode,
101
102 #[serde(default)]
104 auth: AcpAuthConfig,
105}
106
107impl Default for AgentClientProtocolZedConfig {
108 fn default() -> Self {
109 Self {
110 enabled: default_zed_enabled(),
111 transport: default_transport(),
112 tools: AgentClientProtocolZedToolsConfig::default(),
113 workspace_trust: default_zed_workspace_trust_mode(),
114 auth: AcpAuthConfig::default(),
115 }
116 }
117}
118
119#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
121#[derive(Debug, Clone, Deserialize, Serialize)]
122pub struct AgentClientProtocolZedToolsConfig {
123 #[serde(default = "default_zed_tools_read_file_enabled")]
125 pub read_file: bool,
126
127 #[serde(default = "default_zed_tools_list_files_enabled")]
129 pub list_files: bool,
130}
131
132impl Default for AgentClientProtocolZedToolsConfig {
133 fn default() -> Self {
134 Self {
135 read_file: default_zed_tools_read_file_enabled(),
136 list_files: default_zed_tools_list_files_enabled(),
137 }
138 }
139}
140
141#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
143#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
144#[serde(rename_all = "snake_case")]
145pub enum AgentClientProtocolZedWorkspaceTrustMode {
146 FullAuto,
148 ToolsPolicy,
150}
151
152impl AgentClientProtocolZedWorkspaceTrustMode {
153 fn from_env_value(value: &str) -> Option<Self> {
154 let normalized = value.trim().to_ascii_lowercase();
155 match normalized.as_str() {
156 "full_auto" | "full-auto" | "full" => Some(Self::FullAuto),
157 "tools_policy" | "tools-policy" | "tools" => Some(Self::ToolsPolicy),
158 _ => None,
159 }
160 }
161
162 pub fn to_workspace_trust_level(self) -> WorkspaceTrustLevel {
164 match self {
165 Self::FullAuto => WorkspaceTrustLevel::FullAuto,
166 Self::ToolsPolicy => WorkspaceTrustLevel::ToolsPolicy,
167 }
168 }
169}
170
171#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
173#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
174#[serde(rename_all = "snake_case")]
175#[derive(Default)]
176pub enum WorkspaceTrustLevel {
177 #[default]
178 ToolsPolicy,
179 FullAuto,
180}
181
182impl std::fmt::Display for WorkspaceTrustLevel {
183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 match self {
185 WorkspaceTrustLevel::ToolsPolicy => write!(f, "tools policy"),
186 WorkspaceTrustLevel::FullAuto => write!(f, "full auto"),
187 }
188 }
189}
190
191#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
194#[serde(rename_all = "snake_case")]
195pub enum AcpAuthMethod {
196 #[default]
198 Agent,
199 EnvVar,
201 Terminal,
203 #[serde(other)]
205 Unknown,
206}
207
208impl AcpAuthMethod {
209 fn as_str(&self) -> &str {
211 match self {
212 Self::Agent => "agent",
213 Self::EnvVar => "env_var",
214 Self::Terminal => "terminal",
215 Self::Unknown => "unknown",
216 }
217 }
218}
219
220impl std::fmt::Display for AcpAuthMethod {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 f.write_str(self.as_str())
223 }
224}
225
226#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
228#[derive(Debug, Clone, Deserialize, Serialize)]
229pub struct AcpAuthConfig {
230 #[serde(default = "default_auth_method")]
233 default_method: AcpAuthMethod,
234
235 #[serde(default)]
238 env_var_name: Option<String>,
239
240 #[serde(default)]
242 auth_url: Option<String>,
243}
244
245fn default_auth_method() -> AcpAuthMethod {
246 AcpAuthMethod::Agent
247}
248
249impl Default for AcpAuthConfig {
250 fn default() -> Self {
251 Self {
252 default_method: default_auth_method(),
253 env_var_name: None,
254 auth_url: None,
255 }
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn defaults_use_stdio_transport() {
265 let cfg = AgentClientProtocolConfig::default();
266 assert!(matches!(cfg.zed.transport, AgentClientProtocolTransport::Stdio));
267 assert!(cfg.zed.tools.read_file);
268 assert!(cfg.zed.tools.list_files);
269 assert!(matches!(cfg.zed.workspace_trust, AgentClientProtocolZedWorkspaceTrustMode::FullAuto));
270 }
271
272 #[test]
273 fn test_acp_auth_config_defaults() {
274 let auth = AcpAuthConfig::default();
275 assert_eq!(auth.default_method, AcpAuthMethod::Agent);
276 assert!(auth.env_var_name.is_none());
277 assert!(auth.auth_url.is_none());
278 }
279
280 #[test]
281 fn test_acp_auth_config_in_zed_config() {
282 let cfg = AgentClientProtocolZedConfig::default();
283 assert_eq!(cfg.auth.default_method, AcpAuthMethod::Agent);
284 }
285
286 #[test]
287 fn test_acp_auth_config_deserialization() {
288 let toml_str = r#"
289default_method = "env_var"
290env_var_name = "OPENAI_API_KEY"
291auth_url = "https://platform.openai.com/api-keys"
292"#;
293 let auth: AcpAuthConfig = toml::from_str(toml_str).unwrap();
294 assert_eq!(auth.default_method, AcpAuthMethod::EnvVar);
295 assert_eq!(auth.env_var_name, Some("OPENAI_API_KEY".to_string()));
296 assert_eq!(auth.auth_url, Some("https://platform.openai.com/api-keys".to_string()));
297 }
298}