1use serde::{Deserialize, Serialize};
5
6use crate::defaults::default_true;
7
8fn default_acp_agent_name() -> String {
9 "zeph".to_owned()
10}
11
12fn default_acp_agent_version() -> String {
13 env!("CARGO_PKG_VERSION").to_owned()
14}
15
16fn default_acp_max_sessions() -> usize {
17 4
18}
19
20fn default_acp_session_idle_timeout_secs() -> u64 {
21 1800
22}
23
24fn default_acp_broadcast_capacity() -> usize {
25 256
26}
27
28fn default_acp_transport() -> AcpTransport {
29 AcpTransport::Stdio
30}
31
32fn default_acp_http_bind() -> String {
33 "127.0.0.1:9800".to_owned()
34}
35
36fn default_acp_discovery_enabled() -> bool {
37 true
38}
39
40fn default_acp_lsp_max_diagnostics_per_file() -> usize {
41 20
42}
43
44fn default_acp_lsp_max_diagnostic_files() -> usize {
45 5
46}
47
48fn default_acp_lsp_max_references() -> usize {
49 100
50}
51
52fn default_acp_lsp_max_workspace_symbols() -> usize {
53 50
54}
55
56fn default_acp_lsp_request_timeout_secs() -> u64 {
57 10
58}
59
60#[cfg(feature = "lsp-context")]
61fn default_lsp_mcp_server_id() -> String {
62 "mcpls".into()
63}
64
65#[cfg(feature = "lsp-context")]
66fn default_lsp_token_budget() -> usize {
67 2000
68}
69
70#[cfg(feature = "lsp-context")]
71fn default_lsp_max_per_file() -> usize {
72 20
73}
74
75#[cfg(feature = "lsp-context")]
76fn default_lsp_max_symbols() -> usize {
77 10
78}
79
80#[cfg(feature = "lsp-context")]
81fn default_lsp_call_timeout_secs() -> u64 {
82 5
83}
84
85#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize)]
86pub struct TuiConfig {
87 #[serde(default)]
88 pub show_source_labels: bool,
89}
90
91#[derive(Debug, Clone, Default, Deserialize, Serialize)]
93#[serde(rename_all = "lowercase")]
94pub enum AcpTransport {
95 #[default]
97 Stdio,
98 Http,
100 Both,
102}
103
104#[derive(Clone, Deserialize, Serialize)]
105pub struct AcpConfig {
106 #[serde(default)]
107 pub enabled: bool,
108 #[serde(default = "default_acp_agent_name")]
109 pub agent_name: String,
110 #[serde(default = "default_acp_agent_version")]
111 pub agent_version: String,
112 #[serde(default = "default_acp_max_sessions")]
113 pub max_sessions: usize,
114 #[serde(default = "default_acp_session_idle_timeout_secs")]
115 pub session_idle_timeout_secs: u64,
116 #[serde(default = "default_acp_broadcast_capacity")]
117 pub broadcast_capacity: usize,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub permission_file: Option<std::path::PathBuf>,
120 #[serde(default)]
123 pub available_models: Vec<String>,
124 #[serde(default = "default_acp_transport")]
126 pub transport: AcpTransport,
127 #[serde(default = "default_acp_http_bind")]
129 pub http_bind: String,
130 #[serde(skip_serializing_if = "Option::is_none")]
135 pub auth_token: Option<String>,
136 #[serde(default = "default_acp_discovery_enabled")]
139 pub discovery_enabled: bool,
140 #[serde(default)]
142 pub lsp: AcpLspConfig,
143}
144
145impl Default for AcpConfig {
146 fn default() -> Self {
147 Self {
148 enabled: false,
149 agent_name: default_acp_agent_name(),
150 agent_version: default_acp_agent_version(),
151 max_sessions: default_acp_max_sessions(),
152 session_idle_timeout_secs: default_acp_session_idle_timeout_secs(),
153 broadcast_capacity: default_acp_broadcast_capacity(),
154 permission_file: None,
155 available_models: Vec::new(),
156 transport: default_acp_transport(),
157 http_bind: default_acp_http_bind(),
158 auth_token: None,
159 discovery_enabled: default_acp_discovery_enabled(),
160 lsp: AcpLspConfig::default(),
161 }
162 }
163}
164
165impl std::fmt::Debug for AcpConfig {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 f.debug_struct("AcpConfig")
168 .field("enabled", &self.enabled)
169 .field("agent_name", &self.agent_name)
170 .field("agent_version", &self.agent_version)
171 .field("max_sessions", &self.max_sessions)
172 .field("session_idle_timeout_secs", &self.session_idle_timeout_secs)
173 .field("broadcast_capacity", &self.broadcast_capacity)
174 .field("permission_file", &self.permission_file)
175 .field("available_models", &self.available_models)
176 .field("transport", &self.transport)
177 .field("http_bind", &self.http_bind)
178 .field(
179 "auth_token",
180 &self.auth_token.as_ref().map(|_| "[REDACTED]"),
181 )
182 .field("discovery_enabled", &self.discovery_enabled)
183 .field("lsp", &self.lsp)
184 .finish()
185 }
186}
187
188#[derive(Debug, Clone, Deserialize, Serialize)]
193pub struct AcpLspConfig {
194 #[serde(default = "default_true")]
196 pub enabled: bool,
197 #[serde(default = "default_true")]
199 pub auto_diagnostics_on_save: bool,
200 #[serde(default = "default_acp_lsp_max_diagnostics_per_file")]
202 pub max_diagnostics_per_file: usize,
203 #[serde(default = "default_acp_lsp_max_diagnostic_files")]
205 pub max_diagnostic_files: usize,
206 #[serde(default = "default_acp_lsp_max_references")]
208 pub max_references: usize,
209 #[serde(default = "default_acp_lsp_max_workspace_symbols")]
211 pub max_workspace_symbols: usize,
212 #[serde(default = "default_acp_lsp_request_timeout_secs")]
214 pub request_timeout_secs: u64,
215}
216
217impl Default for AcpLspConfig {
218 fn default() -> Self {
219 Self {
220 enabled: true,
221 auto_diagnostics_on_save: true,
222 max_diagnostics_per_file: default_acp_lsp_max_diagnostics_per_file(),
223 max_diagnostic_files: default_acp_lsp_max_diagnostic_files(),
224 max_references: default_acp_lsp_max_references(),
225 max_workspace_symbols: default_acp_lsp_max_workspace_symbols(),
226 request_timeout_secs: default_acp_lsp_request_timeout_secs(),
227 }
228 }
229}
230
231#[cfg(feature = "lsp-context")]
235#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
236#[serde(rename_all = "lowercase")]
237pub enum DiagnosticSeverity {
238 #[default]
239 Error,
240 Warning,
241 Info,
242 Hint,
243}
244
245#[cfg(feature = "lsp-context")]
249#[derive(Debug, Clone, Deserialize, Serialize)]
250#[serde(default)]
251pub struct DiagnosticsConfig {
252 pub enabled: bool,
254 #[serde(default = "default_lsp_max_per_file")]
256 pub max_per_file: usize,
257 #[serde(default)]
259 pub min_severity: DiagnosticSeverity,
260}
261
262#[cfg(feature = "lsp-context")]
263impl Default for DiagnosticsConfig {
264 fn default() -> Self {
265 Self {
266 enabled: true,
267 max_per_file: default_lsp_max_per_file(),
268 min_severity: DiagnosticSeverity::default(),
269 }
270 }
271}
272
273#[cfg(feature = "lsp-context")]
275#[derive(Debug, Clone, Deserialize, Serialize)]
276#[serde(default)]
277pub struct HoverConfig {
278 pub enabled: bool,
280 #[serde(default = "default_lsp_max_symbols")]
282 pub max_symbols: usize,
283}
284
285#[cfg(feature = "lsp-context")]
286impl Default for HoverConfig {
287 fn default() -> Self {
288 Self {
289 enabled: false,
290 max_symbols: default_lsp_max_symbols(),
291 }
292 }
293}
294
295#[cfg(feature = "lsp-context")]
297#[derive(Debug, Clone, Deserialize, Serialize)]
298#[serde(default)]
299pub struct LspConfig {
300 pub enabled: bool,
302 #[serde(default = "default_lsp_mcp_server_id")]
304 pub mcp_server_id: String,
305 #[serde(default = "default_lsp_token_budget")]
307 pub token_budget: usize,
308 #[serde(default = "default_lsp_call_timeout_secs")]
310 pub call_timeout_secs: u64,
311 #[serde(default)]
313 pub diagnostics: DiagnosticsConfig,
314 #[serde(default)]
316 pub hover: HoverConfig,
317}
318
319#[cfg(feature = "lsp-context")]
320impl Default for LspConfig {
321 fn default() -> Self {
322 Self {
323 enabled: false,
324 mcp_server_id: default_lsp_mcp_server_id(),
325 token_budget: default_lsp_token_budget(),
326 call_timeout_secs: default_lsp_call_timeout_secs(),
327 diagnostics: DiagnosticsConfig::default(),
328 hover: HoverConfig::default(),
329 }
330 }
331}