1pub mod constants {
2 pub mod defaults;
3 pub mod ui;
4}
5
6pub mod loader;
7pub mod types;
8
9use anyhow::Result;
10use serde::{Deserialize, Serialize};
11
12pub use types::{
13 ReasoningEffortLevel, SystemPromptMode, ToolDocumentationMode, UiSurfacePreference,
14 VerbosityLevel,
15};
16
17#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
18#[serde(rename_all = "snake_case")]
19pub enum ToolOutputMode {
20 #[default]
21 Compact,
22 Full,
23}
24
25#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
26#[serde(rename_all = "snake_case")]
27pub enum UiDisplayMode {
28 Full,
29 #[default]
30 Minimal,
31 Focused,
32}
33
34#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
35#[serde(rename_all = "snake_case")]
36pub enum NotificationDeliveryMode {
37 Terminal,
38 #[default]
39 Hybrid,
40 Desktop,
41}
42
43#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
44#[serde(rename_all = "snake_case")]
45pub enum AgentClientProtocolZedWorkspaceTrustMode {
46 FullAuto,
47 #[default]
48 ToolsPolicy,
49}
50
51#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
52#[serde(rename_all = "lowercase")]
53pub enum ToolPolicy {
54 Allow,
55 #[default]
56 Prompt,
57 Deny,
58}
59
60#[derive(Debug, Clone, Deserialize, Serialize)]
61pub struct KeyboardProtocolConfig {
62 pub enabled: bool,
63 pub mode: String,
64 pub disambiguate_escape_codes: bool,
65 pub report_event_types: bool,
66 pub report_alternate_keys: bool,
67 pub report_all_keys: bool,
68}
69
70impl Default for KeyboardProtocolConfig {
71 fn default() -> Self {
72 Self {
73 enabled: true,
74 mode: "default".to_string(),
75 disambiguate_escape_codes: true,
76 report_event_types: true,
77 report_alternate_keys: true,
78 report_all_keys: false,
79 }
80 }
81}
82
83impl KeyboardProtocolConfig {
84 pub fn validate(&self) -> Result<()> {
85 match self.mode.as_str() {
86 "default" | "full" | "minimal" | "custom" => Ok(()),
87 _ => anyhow::bail!(
88 "Invalid keyboard protocol mode '{}'. Must be: default, full, minimal, or custom",
89 self.mode
90 ),
91 }
92 }
93}
94
95#[derive(Debug, Clone, Deserialize, Serialize)]
96pub struct UiNotificationsConfig {
97 pub enabled: bool,
98 pub delivery_mode: NotificationDeliveryMode,
99 pub suppress_when_focused: bool,
100 pub tool_failure: bool,
101 pub error: bool,
102 pub completion: bool,
103 pub hitl: bool,
104 pub tool_success: bool,
105}
106
107impl Default for UiNotificationsConfig {
108 fn default() -> Self {
109 Self {
110 enabled: true,
111 delivery_mode: NotificationDeliveryMode::Hybrid,
112 suppress_when_focused: true,
113 tool_failure: true,
114 error: true,
115 completion: true,
116 hitl: true,
117 tool_success: false,
118 }
119 }
120}
121
122#[derive(Debug, Clone, Deserialize, Serialize)]
123pub struct UiConfig {
124 pub tool_output_mode: ToolOutputMode,
125 pub allow_tool_ansi: bool,
126 pub inline_viewport_rows: u16,
127 pub keyboard_protocol: KeyboardProtocolConfig,
128 pub display_mode: UiDisplayMode,
129 pub show_sidebar: bool,
130 pub dim_completed_todos: bool,
131 pub message_block_spacing: bool,
132 pub show_turn_timer: bool,
133 pub notifications: UiNotificationsConfig,
134}
135
136impl Default for UiConfig {
137 fn default() -> Self {
138 Self {
139 tool_output_mode: ToolOutputMode::Compact,
140 allow_tool_ansi: false,
141 inline_viewport_rows: constants::ui::DEFAULT_INLINE_VIEWPORT_ROWS,
142 keyboard_protocol: KeyboardProtocolConfig::default(),
143 display_mode: UiDisplayMode::Minimal,
144 show_sidebar: true,
145 dim_completed_todos: true,
146 message_block_spacing: false,
147 show_turn_timer: false,
148 notifications: UiNotificationsConfig::default(),
149 }
150 }
151}
152
153#[derive(Debug, Clone, Deserialize, Serialize, Default)]
154pub struct AgentCheckpointingConfig {
155 pub enabled: bool,
156}
157
158#[derive(Debug, Clone, Deserialize, Serialize, Default)]
159pub struct AgentSmallModelConfig {
160 pub enabled: bool,
161}
162
163#[derive(Debug, Clone, Deserialize, Serialize, Default)]
164pub struct AgentVibeCodingConfig {
165 pub enabled: bool,
166}
167
168#[derive(Debug, Clone, Deserialize, Serialize)]
169pub struct AgentConfig {
170 pub default_model: String,
171 pub theme: String,
172 pub reasoning_effort: ReasoningEffortLevel,
173 pub system_prompt_mode: SystemPromptMode,
174 pub tool_documentation_mode: ToolDocumentationMode,
175 pub verbosity: VerbosityLevel,
176 pub todo_planning_mode: bool,
177 pub checkpointing: AgentCheckpointingConfig,
178 pub small_model: AgentSmallModelConfig,
179 pub vibe_coding: AgentVibeCodingConfig,
180 pub max_conversation_turns: usize,
181}
182
183impl Default for AgentConfig {
184 fn default() -> Self {
185 Self {
186 default_model: "gpt-5-mini".to_string(),
187 theme: "default".to_string(),
188 reasoning_effort: ReasoningEffortLevel::Medium,
189 system_prompt_mode: SystemPromptMode::Default,
190 tool_documentation_mode: ToolDocumentationMode::Full,
191 verbosity: VerbosityLevel::Medium,
192 todo_planning_mode: false,
193 checkpointing: AgentCheckpointingConfig::default(),
194 small_model: AgentSmallModelConfig::default(),
195 vibe_coding: AgentVibeCodingConfig::default(),
196 max_conversation_turns: 100,
197 }
198 }
199}
200
201#[derive(Debug, Clone, Deserialize, Serialize)]
202pub struct PromptCacheConfig {
203 pub enabled: bool,
204}
205
206impl Default for PromptCacheConfig {
207 fn default() -> Self {
208 Self { enabled: true }
209 }
210}
211
212#[derive(Debug, Clone, Deserialize, Serialize)]
213pub struct McpConfig {
214 pub enabled: bool,
215}
216
217impl Default for McpConfig {
218 fn default() -> Self {
219 Self { enabled: true }
220 }
221}
222
223#[derive(Debug, Clone, Deserialize, Serialize)]
224pub struct AcpZedConfig {
225 pub workspace_trust: AgentClientProtocolZedWorkspaceTrustMode,
226}
227
228impl Default for AcpZedConfig {
229 fn default() -> Self {
230 Self {
231 workspace_trust: AgentClientProtocolZedWorkspaceTrustMode::ToolsPolicy,
232 }
233 }
234}
235
236#[derive(Debug, Clone, Deserialize, Serialize, Default)]
237pub struct AcpConfig {
238 pub zed: AcpZedConfig,
239}
240
241#[derive(Debug, Clone, Deserialize, Serialize, Default)]
242pub struct FullAutoConfig {
243 pub enabled: bool,
244}
245
246#[derive(Debug, Clone, Deserialize, Serialize, Default)]
247pub struct AutomationConfig {
248 pub full_auto: FullAutoConfig,
249}
250
251#[derive(Debug, Clone, Deserialize, Serialize)]
252pub struct ToolsConfig {
253 pub default_policy: ToolPolicy,
254}
255
256impl Default for ToolsConfig {
257 fn default() -> Self {
258 Self {
259 default_policy: ToolPolicy::Prompt,
260 }
261 }
262}
263
264#[derive(Debug, Clone, Deserialize, Serialize)]
265pub struct SecurityConfig {
266 pub human_in_the_loop: bool,
267}
268
269impl Default for SecurityConfig {
270 fn default() -> Self {
271 Self {
272 human_in_the_loop: true,
273 }
274 }
275}
276
277#[derive(Debug, Clone, Deserialize, Serialize)]
278pub struct ContextConfig {
279 pub max_context_tokens: usize,
280 pub trim_to_percent: u8,
281}
282
283impl Default for ContextConfig {
284 fn default() -> Self {
285 Self {
286 max_context_tokens: 128_000,
287 trim_to_percent: 80,
288 }
289 }
290}
291
292#[derive(Debug, Clone, Deserialize, Serialize)]
293pub struct SyntaxHighlightingConfig {
294 pub enabled: bool,
295 pub theme: String,
296 pub cache_themes: bool,
297 pub max_file_size_mb: usize,
298 pub enabled_languages: Vec<String>,
299 pub highlight_timeout_ms: u64,
300}
301
302impl Default for SyntaxHighlightingConfig {
303 fn default() -> Self {
304 Self {
305 enabled: true,
306 theme: "base16-ocean.dark".to_string(),
307 cache_themes: true,
308 max_file_size_mb: 5,
309 enabled_languages: vec![
310 "rust".to_string(),
311 "python".to_string(),
312 "javascript".to_string(),
313 "typescript".to_string(),
314 "go".to_string(),
315 "bash".to_string(),
316 "json".to_string(),
317 "yaml".to_string(),
318 "toml".to_string(),
319 "markdown".to_string(),
320 ],
321 highlight_timeout_ms: 300,
322 }
323 }
324}
325
326#[derive(Debug, Clone, Deserialize, Serialize)]
327pub struct PtyConfig {
328 pub enabled: bool,
329 pub default_rows: u16,
330 pub default_cols: u16,
331 pub command_timeout_seconds: u64,
332}
333
334impl Default for PtyConfig {
335 fn default() -> Self {
336 Self {
337 enabled: true,
338 default_rows: 24,
339 default_cols: 80,
340 command_timeout_seconds: 300,
341 }
342 }
343}
344
345pub fn keyboard_protocol_to_flags(
347 config: &KeyboardProtocolConfig,
348) -> ratatui::crossterm::event::KeyboardEnhancementFlags {
349 use ratatui::crossterm::event::KeyboardEnhancementFlags;
350
351 if !config.enabled {
352 return KeyboardEnhancementFlags::empty();
353 }
354
355 match config.mode.as_str() {
356 "default" => {
357 KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
358 | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
359 | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
360 }
361 "full" => {
362 KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
363 | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
364 | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
365 | KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES
366 }
367 "minimal" => KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES,
368 "custom" => {
369 let mut flags = KeyboardEnhancementFlags::empty();
370 if config.disambiguate_escape_codes {
371 flags |= KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES;
372 }
373 if config.report_event_types {
374 flags |= KeyboardEnhancementFlags::REPORT_EVENT_TYPES;
375 }
376 if config.report_alternate_keys {
377 flags |= KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS;
378 }
379 if config.report_all_keys {
380 flags |= KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES;
381 }
382 flags
383 }
384 _ => {
385 KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
386 | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
387 | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
388 }
389 }
390}