1use std::path::PathBuf;
11
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, Serialize, Deserialize, Default)]
15pub struct Config {
16 pub llm: LlmConfig,
17 pub mcp: McpConfig,
18 pub store: StoreConfig,
19 pub sandbox: SandboxConfig,
20 pub tui: TuiConfig,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct LlmConfig {
25 pub backend: String,
27 pub endpoint: String,
29 pub model: String,
31 pub timeout_secs: u64,
33}
34
35impl Default for LlmConfig {
36 fn default() -> Self {
37 Self {
38 backend: "ollama".into(),
39 endpoint: "http://127.0.0.1:11434".into(),
40 model: "llama3.1".into(),
41 timeout_secs: 120,
42 }
43 }
44}
45
46#[derive(Debug, Clone, Default, Serialize, Deserialize)]
47pub struct McpConfig {
48 #[serde(default)]
50 pub servers: Vec<McpServerSpec>,
51 #[serde(default = "default_approval_timeout")]
53 pub approval_timeout_secs: u64,
54}
55
56const fn default_approval_timeout() -> u64 {
57 30
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct McpServerSpec {
62 pub name: String,
63 pub command: String,
64 #[serde(default)]
65 pub args: Vec<String>,
66 #[serde(default = "default_true")]
68 pub sandbox: bool,
69 pub profile: Option<PathBuf>,
71}
72
73const fn default_true() -> bool {
74 true
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, Default)]
78pub struct StoreConfig {
79 pub root: Option<PathBuf>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct SandboxConfig {
85 pub strict: bool,
88}
89
90impl Default for SandboxConfig {
91 fn default() -> Self {
92 Self { strict: true }
93 }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct TuiConfig {
98 pub tick_ms: u64,
100 pub mouse: bool,
102}
103
104impl Default for TuiConfig {
105 fn default() -> Self {
106 Self {
107 tick_ms: 16,
108 mouse: true,
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn defaults_roundtrip_through_toml() {
119 let cfg = Config::default();
120 let s = toml::to_string(&cfg).expect("serialize default config to toml");
121 let back: Config = toml::from_str(&s).expect("parse back default config");
122 assert_eq!(back.llm.backend, cfg.llm.backend);
123 assert_eq!(back.tui.tick_ms, cfg.tui.tick_ms);
124 }
125}