use crate::defaults::default_true;
use crate::providers::ProviderName;
use serde::{Deserialize, Serialize};
use super::default_embed_timeout_secs;
fn default_max_history() -> usize {
100
}
fn default_title_max_chars() -> usize {
60
}
fn default_document_collection() -> String {
"zeph_documents".into()
}
fn default_document_chunk_size() -> usize {
1000
}
fn default_document_chunk_overlap() -> usize {
100
}
fn default_document_top_k() -> usize {
3
}
fn default_temporal_decay_half_life_days() -> u32 {
30
}
fn default_mmr_lambda() -> f32 {
0.7
}
fn default_semantic_enabled() -> bool {
true
}
fn default_recall_limit() -> usize {
5
}
fn default_vector_weight() -> f64 {
0.7
}
fn default_keyword_weight() -> f64 {
0.3
}
fn validate_importance_weight<'de, D>(deserializer: D) -> Result<f64, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = <f64 as serde::Deserialize>::deserialize(deserializer)?;
if value.is_nan() || value.is_infinite() {
return Err(serde::de::Error::custom(
"importance_weight must be a finite number",
));
}
if value < 0.0 {
return Err(serde::de::Error::custom(
"importance_weight must be non-negative",
));
}
if value > 1.0 {
return Err(serde::de::Error::custom("importance_weight must be <= 1.0"));
}
Ok(value)
}
fn default_importance_weight() -> f64 {
0.15
}
#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ContextStrategy {
#[default]
FullHistory,
MemoryFirst,
Adaptive,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct SessionsConfig {
#[serde(default = "default_max_history")]
pub max_history: usize,
#[serde(default = "default_title_max_chars")]
pub title_max_chars: usize,
}
impl Default for SessionsConfig {
fn default() -> Self {
Self {
max_history: default_max_history(),
title_max_chars: default_title_max_chars(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DocumentConfig {
#[serde(default = "default_document_collection")]
pub collection: String,
#[serde(default = "default_document_chunk_size")]
pub chunk_size: usize,
#[serde(default = "default_document_chunk_overlap")]
pub chunk_overlap: usize,
#[serde(default = "default_document_top_k")]
pub top_k: usize,
#[serde(default)]
pub rag_enabled: bool,
}
impl Default for DocumentConfig {
fn default() -> Self {
Self {
collection: default_document_collection(),
chunk_size: default_document_chunk_size(),
chunk_overlap: default_document_chunk_overlap(),
top_k: default_document_top_k(),
rag_enabled: false,
}
}
}
#[derive(Debug, Deserialize, Serialize)]
#[allow(clippy::struct_excessive_bools)] pub struct SemanticConfig {
#[serde(default = "default_semantic_enabled")]
pub enabled: bool,
#[serde(default = "default_recall_limit")]
pub recall_limit: usize,
#[serde(default = "default_vector_weight")]
pub vector_weight: f64,
#[serde(default = "default_keyword_weight")]
pub keyword_weight: f64,
#[serde(default = "default_true")]
pub temporal_decay_enabled: bool,
#[serde(default = "default_temporal_decay_half_life_days")]
pub temporal_decay_half_life_days: u32,
#[serde(default = "default_true")]
pub mmr_enabled: bool,
#[serde(default = "default_mmr_lambda")]
pub mmr_lambda: f32,
#[serde(default = "default_true")]
pub importance_enabled: bool,
#[serde(
default = "default_importance_weight",
deserialize_with = "validate_importance_weight"
)]
pub importance_weight: f64,
#[serde(default)]
pub embedding_provider: Option<ProviderName>,
#[serde(default = "default_embed_timeout_secs")]
pub embed_timeout_secs: u64,
}
impl Default for SemanticConfig {
fn default() -> Self {
Self {
enabled: default_semantic_enabled(),
recall_limit: default_recall_limit(),
vector_weight: default_vector_weight(),
keyword_weight: default_keyword_weight(),
temporal_decay_enabled: true,
temporal_decay_half_life_days: default_temporal_decay_half_life_days(),
mmr_enabled: true,
mmr_lambda: default_mmr_lambda(),
importance_enabled: true,
importance_weight: default_importance_weight(),
embedding_provider: None,
embed_timeout_secs: default_embed_timeout_secs(),
}
}
}