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 pub 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, Deserialize, Serialize)]
194pub struct AcpAuthConfig {
195 #[serde(default = "default_auth_method")]
198 pub default_method: String,
199
200 #[serde(default)]
203 pub env_var_name: Option<String>,
204
205 #[serde(default)]
207 pub auth_url: Option<String>,
208}
209
210fn default_auth_method() -> String {
211 "agent".to_string()
212}
213
214impl Default for AcpAuthConfig {
215 fn default() -> Self {
216 Self {
217 default_method: default_auth_method(),
218 env_var_name: None,
219 auth_url: None,
220 }
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn defaults_use_stdio_transport() {
230 let cfg = AgentClientProtocolConfig::default();
231 assert!(matches!(
232 cfg.zed.transport,
233 AgentClientProtocolTransport::Stdio
234 ));
235 assert!(cfg.zed.tools.read_file);
236 assert!(cfg.zed.tools.list_files);
237 assert!(matches!(
238 cfg.zed.workspace_trust,
239 AgentClientProtocolZedWorkspaceTrustMode::FullAuto
240 ));
241 }
242
243 #[test]
244 fn test_acp_auth_config_defaults() {
245 let auth = AcpAuthConfig::default();
246 assert_eq!(auth.default_method, "agent");
247 assert!(auth.env_var_name.is_none());
248 assert!(auth.auth_url.is_none());
249 }
250
251 #[test]
252 fn test_acp_auth_config_in_zed_config() {
253 let cfg = AgentClientProtocolZedConfig::default();
254 assert_eq!(cfg.auth.default_method, "agent");
255 }
256
257 #[test]
258 fn test_acp_auth_config_deserialization() {
259 let toml_str = r#"
260default_method = "env_var"
261env_var_name = "OPENAI_API_KEY"
262auth_url = "https://platform.openai.com/api-keys"
263"#;
264 let auth: AcpAuthConfig = toml::from_str(toml_str).unwrap();
265 assert_eq!(auth.default_method, "env_var");
266 assert_eq!(auth.env_var_name, Some("OPENAI_API_KEY".to_string()));
267 assert_eq!(
268 auth.auth_url,
269 Some("https://platform.openai.com/api-keys".to_string())
270 );
271 }
272}