1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum NodeRole {
12 #[default]
14 All,
15 Orchestrator,
17 Kernel,
19 Voice,
21 Worker,
23 NightAgent,
25}
26
27impl NodeRole {
28 pub fn as_str(&self) -> &'static str {
29 match self {
30 Self::All => "all",
31 Self::Orchestrator => "orchestrator",
32 Self::Kernel => "kernel",
33 Self::Voice => "voice",
34 Self::Worker => "worker",
35 Self::NightAgent => "nightagent",
36 }
37 }
38}
39
40impl std::fmt::Display for NodeRole {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 f.write_str(self.as_str())
43 }
44}
45
46#[derive(Debug, Clone, Deserialize)]
47#[serde(default)]
48pub struct NodeConfig {
49 pub name: String,
50 pub role: NodeRole,
52}
53
54impl Default for NodeConfig {
55 fn default() -> Self {
56 Self {
57 name: String::new(),
58 role: NodeRole::All,
59 }
60 }
61}
62
63#[derive(Debug, Clone, Deserialize, Default)]
64#[serde(default)]
65pub struct TailscaleConfig {
66 pub enabled: bool,
67 pub auth_key: String,
68}
69
70#[derive(Debug, Clone, Deserialize)]
71#[serde(default)]
72pub struct MeshConfig {
73 pub transport: String,
74 pub discovery: String,
75 pub peers: Vec<String>,
76 pub tailscale: TailscaleConfig,
77}
78
79impl Default for MeshConfig {
80 fn default() -> Self {
81 Self {
82 transport: "lan".to_string(),
83 discovery: "mdns".to_string(),
84 peers: Vec::new(),
85 tailscale: TailscaleConfig::default(),
86 }
87 }
88}
89
90#[derive(Debug, Clone, Deserialize, PartialEq)]
91#[serde(default)]
92pub struct InferenceFallbackConfig {
93 pub max_attempts: usize,
94 pub t1: Vec<String>,
95 pub t2: Vec<String>,
96 pub t3: Vec<String>,
97 pub t4: Vec<String>,
98}
99
100impl Default for InferenceFallbackConfig {
101 fn default() -> Self {
102 Self {
103 max_attempts: 3,
104 t1: vec!["local".into(), "haiku".into(), "sonnet".into()],
105 t2: vec!["haiku".into(), "local".into(), "sonnet".into()],
106 t3: vec!["sonnet".into(), "opus".into()],
107 t4: vec!["opus".into(), "sonnet".into()],
108 }
109 }
110}
111
112#[derive(Debug, Clone, Deserialize)]
113#[serde(default)]
114pub struct InferenceConfig {
115 pub default_model: String,
116 pub api_key_env: String,
117 pub fallback: InferenceFallbackConfig,
118}
119
120impl Default for InferenceConfig {
121 fn default() -> Self {
122 Self {
123 default_model: "claude-sonnet-4-6".to_string(),
124 api_key_env: "ANTHROPIC_API_KEY".to_string(),
125 fallback: InferenceFallbackConfig::default(),
126 }
127 }
128}
129
130#[derive(Debug, Clone, Deserialize)]
131#[serde(default)]
132pub struct KernelConfig {
133 pub model: String,
134 pub model_path: String,
135 pub escalation_model: String,
136 pub max_tokens: u32,
137}
138
139impl Default for KernelConfig {
140 fn default() -> Self {
141 Self {
142 model: "none".to_string(),
143 model_path: String::new(),
144 escalation_model: String::new(),
145 max_tokens: 2048,
146 }
147 }
148}
149
150#[derive(Debug, Clone, Deserialize, Default)]
151#[serde(default)]
152pub struct TelegramConfig {
153 pub enabled: bool,
154 pub token_keychain: String,
155}
156
157#[derive(Debug, Clone, Deserialize)]
158#[serde(default)]
159pub struct NightConfig {
160 pub night_mode: bool,
161 pub night_hours: String,
163 pub night_model: String,
164}
165
166impl Default for NightConfig {
167 fn default() -> Self {
168 Self {
169 night_mode: false,
170 night_hours: "23:00-07:00".to_string(),
171 night_model: "claude-haiku-4-5".to_string(),
172 }
173 }
174}
175
176#[derive(Debug, Clone, Deserialize)]
177#[serde(default)]
178pub struct DaemonConfig {
179 pub port: u16,
180 pub quiet_hours: Option<String>,
181 pub timezone: Option<String>,
182 pub auto_update: bool,
183}
184
185impl Default for DaemonConfig {
186 fn default() -> Self {
187 Self {
188 port: 8420,
189 quiet_hours: None,
190 timezone: None,
191 auto_update: true,
192 }
193 }
194}
195
196#[derive(Debug, Clone, Deserialize, Default)]
198#[serde(default)]
199pub struct ConvergioConfig {
200 pub node: NodeConfig,
201 pub daemon: DaemonConfig,
202 pub night: NightConfig,
203 pub mesh: MeshConfig,
204 pub inference: InferenceConfig,
205 pub kernel: KernelConfig,
206 pub telegram: TelegramConfig,
207}