Skip to main content

zeph_config/
root.rs

1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use std::collections::HashMap;
5
6use serde::{Deserialize, Serialize};
7use zeph_common::secret::Secret;
8use zeph_tools::ToolsConfig;
9
10use crate::agent::{AgentConfig, FocusConfig, SubAgentConfig};
11use crate::channels::{A2aServerConfig, DiscordConfig, McpConfig, SlackConfig, TelegramConfig};
12use crate::classifiers::ClassifiersConfig;
13use crate::defaults::{default_skill_paths, default_sqlite_path_field};
14use crate::experiment::{ExperimentConfig, OrchestrationConfig};
15use crate::features::{
16    CostConfig, DaemonConfig, DebugConfig, GatewayConfig, IndexConfig, SchedulerConfig,
17    SkillPromptMode, SkillsConfig, VaultConfig,
18};
19use crate::hooks::HooksConfig;
20use crate::learning::LearningConfig;
21use crate::logging::LoggingConfig;
22use crate::memory::{
23    CompressionConfig, DocumentConfig, GraphConfig, MagicDocsConfig, MemoryConfig, SemanticConfig,
24    SessionsConfig, SidequestConfig, TierConfig, VectorBackend,
25};
26use crate::metrics::MetricsConfig;
27use crate::providers::{
28    LlmConfig, get_default_embedding_model, get_default_response_cache_ttl_secs,
29    get_default_router_ema_alpha, get_default_router_reorder_interval,
30};
31use crate::security::TrustConfig;
32use crate::security::{SecurityConfig, TimeoutConfig};
33use crate::telemetry::TelemetryConfig;
34use crate::ui::LspConfig;
35use crate::ui::{AcpConfig, TuiConfig};
36
37/// Top-level agent configuration.
38///
39/// Loaded from a TOML file via [`Config::load`]. Env-var overrides can be applied
40/// via `apply_env_overrides`. Secret resolution via `VaultProvider`
41/// is handled in `zeph-core` through the `SecretResolver` trait.
42#[derive(Debug, Deserialize, Serialize)]
43pub struct Config {
44    pub agent: AgentConfig,
45    pub llm: LlmConfig,
46    pub skills: SkillsConfig,
47    pub memory: MemoryConfig,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub telegram: Option<TelegramConfig>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub discord: Option<DiscordConfig>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub slack: Option<SlackConfig>,
54    #[serde(default)]
55    pub tools: ToolsConfig,
56    #[serde(default)]
57    pub a2a: A2aServerConfig,
58    #[serde(default)]
59    pub mcp: McpConfig,
60    #[serde(default)]
61    pub index: IndexConfig,
62    #[serde(default)]
63    pub vault: VaultConfig,
64    #[serde(default)]
65    pub security: SecurityConfig,
66    #[serde(default)]
67    pub timeouts: TimeoutConfig,
68    #[serde(default)]
69    pub cost: CostConfig,
70    #[serde(default)]
71    pub gateway: GatewayConfig,
72    #[serde(default)]
73    pub daemon: DaemonConfig,
74    #[serde(default)]
75    pub scheduler: SchedulerConfig,
76    #[serde(default)]
77    pub tui: TuiConfig,
78    #[serde(default)]
79    pub acp: AcpConfig,
80    #[serde(default)]
81    pub agents: SubAgentConfig,
82    #[serde(default)]
83    pub orchestration: OrchestrationConfig,
84    #[serde(default)]
85    pub classifiers: ClassifiersConfig,
86    #[serde(default)]
87    pub experiments: ExperimentConfig,
88    #[serde(default)]
89    pub debug: DebugConfig,
90    #[serde(default)]
91    pub logging: LoggingConfig,
92    #[serde(default)]
93    pub hooks: HooksConfig,
94    #[serde(default)]
95    pub lsp: LspConfig,
96    /// `MagicDocs` auto-maintained markdown (#2702).
97    #[serde(default)]
98    pub magic_docs: MagicDocsConfig,
99    /// Profiling and distributed tracing configuration.
100    #[serde(default)]
101    pub telemetry: TelemetryConfig,
102    /// Prometheus metrics export configuration.
103    #[serde(default)]
104    pub metrics: MetricsConfig,
105    /// Session UX settings (recap-on-resume, etc.).
106    #[serde(default)]
107    pub session: crate::session::SessionConfig,
108    /// Resolved secrets from vault. Never serialized — populated at runtime.
109    #[serde(skip)]
110    pub secrets: ResolvedSecrets,
111}
112
113/// Secrets resolved from the vault at runtime.
114///
115/// Populated by `SecretResolver::resolve_secrets()` in `zeph-core`.
116/// Never serialized to TOML.
117#[derive(Debug, Default)]
118pub struct ResolvedSecrets {
119    pub claude_api_key: Option<Secret>,
120    pub openai_api_key: Option<Secret>,
121    pub gemini_api_key: Option<Secret>,
122    pub compatible_api_keys: HashMap<String, Secret>,
123    pub discord_token: Option<Secret>,
124    pub slack_bot_token: Option<Secret>,
125    pub slack_signing_secret: Option<Secret>,
126    /// Arbitrary skill secrets resolved from `ZEPH_SECRET_*` vault keys.
127    /// Key is the lowercased name after stripping the prefix (e.g. `github_token`).
128    pub custom: HashMap<String, Secret>,
129}
130
131impl Default for Config {
132    #[allow(clippy::too_many_lines)] // flat struct literal with one field per config section — no meaningful split exists
133    fn default() -> Self {
134        Self {
135            agent: AgentConfig {
136                name: "Zeph".into(),
137                max_tool_iterations: 10,
138                auto_update_check: true,
139                instruction_files: Vec::new(),
140                instruction_auto_detect: true,
141                max_tool_retries: 2,
142                tool_repeat_threshold: 2,
143                max_retry_duration_secs: 30,
144                focus: FocusConfig::default(),
145                tool_filter: crate::agent::ToolFilterConfig::default(),
146                budget_hint_enabled: true,
147                supervisor: crate::agent::TaskSupervisorConfig::default(),
148            },
149            llm: LlmConfig {
150                providers: Vec::new(),
151                routing: crate::providers::LlmRoutingStrategy::None,
152                routes: std::collections::HashMap::new(),
153                embedding_model: get_default_embedding_model(),
154                candle: None,
155                stt: None,
156                response_cache_enabled: false,
157                response_cache_ttl_secs: get_default_response_cache_ttl_secs(),
158                semantic_cache_enabled: false,
159                semantic_cache_threshold: 0.95,
160                semantic_cache_max_candidates: 10,
161                router_ema_enabled: false,
162                router_ema_alpha: get_default_router_ema_alpha(),
163                router_reorder_interval: get_default_router_reorder_interval(),
164                router: None,
165                instruction_file: None,
166                summary_model: None,
167                summary_provider: None,
168                complexity_routing: None,
169                coe: None,
170            },
171            skills: SkillsConfig {
172                paths: default_skill_paths(),
173                max_active_skills: 5,
174                disambiguation_threshold: 0.20,
175                min_injection_score: 0.20,
176                cosine_weight: 0.7,
177                hybrid_search: true,
178                learning: LearningConfig::default(),
179                trust: TrustConfig::default(),
180                prompt_mode: SkillPromptMode::Auto,
181                two_stage_matching: false,
182                confusability_threshold: 0.0,
183                rl_routing_enabled: false,
184                rl_learning_rate: 0.01,
185                rl_weight: 0.3,
186                rl_persist_interval: 10,
187                rl_warmup_updates: 50,
188                rl_embed_dim: None,
189                generation_provider: crate::providers::ProviderName::default(),
190                generation_output_dir: None,
191                mining: crate::features::SkillMiningConfig::default(),
192            },
193            memory: MemoryConfig {
194                sqlite_path: default_sqlite_path_field(),
195                history_limit: 50,
196                qdrant_url: "http://localhost:6334".into(),
197                semantic: SemanticConfig::default(),
198                summarization_threshold: 50,
199                context_budget_tokens: 0,
200                soft_compaction_threshold: 0.60,
201                hard_compaction_threshold: 0.90,
202                compaction_preserve_tail: 6,
203                compaction_cooldown_turns: 2,
204                auto_budget: true,
205                prune_protect_tokens: 40_000,
206                cross_session_score_threshold: 0.35,
207                vector_backend: VectorBackend::default(),
208                token_safety_margin: 1.0,
209                redact_credentials: true,
210                autosave_assistant: true,
211                autosave_min_length: 20,
212                tool_call_cutoff: 6,
213                sqlite_pool_size: 5,
214                sessions: SessionsConfig::default(),
215                documents: DocumentConfig::default(),
216                eviction: zeph_memory::EvictionConfig::default(),
217                compression: CompressionConfig::default(),
218                sidequest: SidequestConfig::default(),
219                graph: GraphConfig::default(),
220                compression_guidelines: zeph_memory::CompressionGuidelinesConfig::default(),
221                shutdown_summary: true,
222                shutdown_summary_min_messages: 4,
223                shutdown_summary_max_messages: 20,
224                shutdown_summary_timeout_secs: 10,
225                structured_summaries: false,
226                tiers: TierConfig::default(),
227                admission: crate::memory::AdmissionConfig::default(),
228                digest: crate::memory::DigestConfig::default(),
229                context_strategy: crate::memory::ContextStrategy::default(),
230                crossover_turn_threshold: 20,
231                consolidation: crate::memory::ConsolidationConfig::default(),
232                forgetting: crate::memory::ForgettingConfig::default(),
233                database_url: None,
234                store_routing: crate::memory::StoreRoutingConfig::default(),
235                persona: crate::memory::PersonaConfig::default(),
236                trajectory: crate::memory::TrajectoryConfig::default(),
237                category: crate::memory::CategoryConfig::default(),
238                tree: crate::memory::TreeConfig::default(),
239                microcompact: crate::memory::MicrocompactConfig::default(),
240                autodream: crate::memory::AutoDreamConfig::default(),
241                key_facts_dedup_threshold: 0.95,
242            },
243            telegram: None,
244            discord: None,
245            slack: None,
246            tools: ToolsConfig::default(),
247            a2a: A2aServerConfig::default(),
248            mcp: McpConfig::default(),
249            index: IndexConfig::default(),
250            vault: VaultConfig::default(),
251            security: SecurityConfig::default(),
252            timeouts: TimeoutConfig::default(),
253            cost: CostConfig::default(),
254            gateway: GatewayConfig::default(),
255            daemon: DaemonConfig::default(),
256            scheduler: SchedulerConfig::default(),
257            tui: TuiConfig::default(),
258            acp: AcpConfig::default(),
259            agents: SubAgentConfig::default(),
260            orchestration: OrchestrationConfig::default(),
261            classifiers: ClassifiersConfig::default(),
262            experiments: ExperimentConfig::default(),
263            debug: DebugConfig::default(),
264            logging: LoggingConfig::default(),
265            lsp: LspConfig::default(),
266            hooks: HooksConfig::default(),
267            magic_docs: MagicDocsConfig::default(),
268            telemetry: TelemetryConfig::default(),
269            metrics: MetricsConfig::default(),
270            session: crate::session::SessionConfig::default(),
271            secrets: ResolvedSecrets::default(),
272        }
273    }
274}