use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct VaultConfig {
#[serde(default)]
pub vault: VaultSection,
#[serde(default)]
pub embed: EmbedConfig,
#[serde(default)]
pub curator: CuratorConfig,
#[serde(default)]
pub index: IndexConfig,
#[serde(default)]
pub drift: DriftConfig,
#[serde(default)]
pub audit: AuditConfig,
#[serde(default)]
pub history: HistoryConfig,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct VaultSection {
pub default_tenant_id: Option<String>,
pub schema_version: Option<u32>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EmbedConfig {
pub embeddable_status: Option<Vec<String>>,
pub embedder_id: Option<String>,
pub dim: Option<u16>,
pub backend: Option<String>,
pub fallback_backend: Option<String>,
pub http_url: Option<String>,
pub http_timeout_ms: Option<u32>,
pub http_model: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CuratorConfig {
pub heuristic_admit_threshold: Option<f32>,
pub heuristic_default_status: Option<String>,
pub llm_review_enabled: Option<bool>,
pub confidence_threshold: Option<f32>,
pub llm_review_endpoint: Option<String>,
pub llm_review_model: Option<String>,
pub llm_review_timeout_ms: Option<u32>,
pub llm_review_max_tokens: Option<u32>,
pub llm_review_fallback: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct IndexConfig {
pub backend: Option<String>,
pub fts_tokenizer: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DriftConfig {
pub scan_interval_seconds: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryConfig {
pub max_versions: usize,
pub ttl_days: Option<u32>,
}
impl Default for HistoryConfig {
fn default() -> Self {
Self {
max_versions: 50,
ttl_days: None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AuditConfig {
pub rotation: Option<String>,
pub retention_days: Option<u32>,
#[serde(default)]
pub strict_mode: bool,
}
impl VaultConfig {
pub fn load_from_root(root: &Path) -> Result<Self, ConfigError> {
let path = root.join(".gradatum").join("config.toml");
match std::fs::read_to_string(&path) {
Ok(content) => toml::from_str(&content).map_err(ConfigError::Parse),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(Self::default()),
Err(e) => Err(ConfigError::Io(e)),
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("config IO: {0}")]
Io(#[from] std::io::Error),
#[error("config parse: {0}")]
Parse(#[from] toml::de::Error),
}