diff --git a/CHANGELOG.md b/CHANGELOG.md index a4210ea8f..d6b8c945a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed +- config: enable temporal decay, MMR, and importance scoring by default in semantic memory; existing configs with explicit `enabled = false` are unaffected (#2101) +- config: change default vector backend from Qdrant to SQLite — zero-dependency out-of-box experience; set `vector_backend = "qdrant"` to revert (#2101) +- config: enable anomaly detection, audit logging, and cost tracking by default; `max_daily_cents = 0` (unlimited) — cost is tracked but not capped (#2101) +- config: enable `autosave_assistant` by default (`min_length = 20`); assistant responses are now persisted to semantic memory unless explicitly disabled (#2101) + - refactor(zeph-llm): remove redundant `schema` feature gate — `schemars` is now a mandatory dependency of `zeph-llm`; all `#[cfg(feature = "schema")]` / `#[cfg_attr(feature = "schema", ...)]` annotations removed; `chat_typed`, `chat_typed_erased`, structured output types, and the `extractor` module are always compiled (#2100) - Promote `scheduler` and `guardrail` features to the default feature set; users with `default-features = false` are unaffected diff --git a/config/default.toml b/config/default.toml index 80eaa678a..4824d3b09 100644 --- a/config/default.toml +++ b/config/default.toml @@ -227,13 +227,13 @@ prune_protect_tokens = 40000 # Minimum relevance score for cross-session memory results (0.0-1.0) cross_session_score_threshold = 0.35 # Vector backend: "qdrant" (external) or "sqlite" (embedded, zero-dependency) -# vector_backend = "qdrant" +vector_backend = "sqlite" # Token safety margin multiplier for compaction budget (must be > 0) # token_safety_margin = 1.0 # Redact credentials from LLM context before sending # redact_credentials = true # Auto-save assistant responses to semantic memory -# autosave_assistant = false +autosave_assistant = true # Minimum character length for autosave (shorter responses skip embedding) # autosave_min_length = 20 # Store a lightweight session summary on shutdown when no hard compaction fired @@ -270,14 +270,14 @@ recall_limit = 5 vector_weight = 0.7 keyword_weight = 0.3 # Temporal decay: penalize older memories by age -# temporal_decay_enabled = false +temporal_decay_enabled = true # temporal_decay_half_life_days = 30 # MMR re-ranking: diversify recall results -# mmr_enabled = false +mmr_enabled = true # mmr_lambda = 0.7 # Write-time importance scoring: boost recall rank for messages with explicit markers (#2021) -# importance_enabled = false -# importance_weight = 0.15 +importance_enabled = true +importance_weight = 0.15 # Code RAG: AST-based code indexing and hybrid retrieval # Requires Qdrant for semantic retrieval; tree-sitter grammars are always available @@ -364,9 +364,9 @@ max_dynamic_servers = 10 [cost] # Track LLM API costs and enforce daily budget -enabled = false +enabled = true # Maximum daily spend in cents (0 = unlimited) -max_daily_cents = 500 +max_daily_cents = 0 [observability] # Tracing exporter: "" (disabled) or "otlp" (requires otel feature) @@ -462,7 +462,7 @@ max_overflow_bytes = 10485760 [tools.audit] # Enable audit logging for tool executions -enabled = false +enabled = true # Audit destination: "stdout" or file path (e.g., "./data/audit.jsonl") destination = "stdout" @@ -487,7 +487,7 @@ default_effect = "deny" [tools.anomaly] # Enable sliding-window anomaly detection for tool execution errors -enabled = false +enabled = true # Number of recent tool calls to track in the window window_size = 10 # Error ratio threshold for warning alerts (0.0-1.0) diff --git a/crates/zeph-config/config/default.toml b/crates/zeph-config/config/default.toml index 35e5ca429..44b606f5a 100644 --- a/crates/zeph-config/config/default.toml +++ b/crates/zeph-config/config/default.toml @@ -225,13 +225,13 @@ prune_protect_tokens = 40000 # Minimum relevance score for cross-session memory results (0.0-1.0) cross_session_score_threshold = 0.35 # Vector backend: "qdrant" (external) or "sqlite" (embedded, zero-dependency) -# vector_backend = "qdrant" +vector_backend = "sqlite" # Token safety margin multiplier for compaction budget (must be > 0) # token_safety_margin = 1.0 # Redact credentials from LLM context before sending # redact_credentials = true # Auto-save assistant responses to semantic memory -# autosave_assistant = false +autosave_assistant = true # Minimum character length for autosave (shorter responses skip embedding) # autosave_min_length = 20 # Use structured anchored summaries for context compaction (experimental, off by default) @@ -264,11 +264,14 @@ recall_limit = 5 vector_weight = 0.7 keyword_weight = 0.3 # Temporal decay: penalize older memories by age -# temporal_decay_enabled = false +temporal_decay_enabled = true # temporal_decay_half_life_days = 30 # MMR re-ranking: diversify recall results -# mmr_enabled = false +mmr_enabled = true # mmr_lambda = 0.7 +# Write-time importance scoring: boost recall rank for messages with explicit markers (#2021) +importance_enabled = true +importance_weight = 0.15 # Code RAG: AST-based code indexing and hybrid retrieval # Requires Qdrant for semantic retrieval; tree-sitter grammars are always available @@ -334,9 +337,9 @@ max_dynamic_servers = 10 [cost] # Track LLM API costs and enforce daily budget -enabled = false +enabled = true # Maximum daily spend in cents (0 = unlimited) -max_daily_cents = 500 +max_daily_cents = 0 [observability] # Tracing exporter: "" (disabled) or "otlp" (requires otel feature) @@ -432,7 +435,7 @@ max_overflow_bytes = 10485760 [tools.audit] # Enable audit logging for tool executions -enabled = false +enabled = true # Audit destination: "stdout" or file path (e.g., "./data/audit.jsonl") destination = "stdout" @@ -446,7 +449,7 @@ default_effect = "deny" [tools.anomaly] # Enable sliding-window anomaly detection for tool execution errors -enabled = false +enabled = true # Number of recent tool calls to track in the window window_size = 10 # Error ratio threshold for warning alerts (0.0-1.0) diff --git a/crates/zeph-config/src/features.rs b/crates/zeph-config/src/features.rs index 90f15a757..76109933e 100644 --- a/crates/zeph-config/src/features.rs +++ b/crates/zeph-config/src/features.rs @@ -56,7 +56,7 @@ fn default_vault_backend() -> String { } fn default_max_daily_cents() -> u32 { - 500 + 0 } fn default_otlp_endpoint() -> String { @@ -180,7 +180,7 @@ impl Default for VaultConfig { #[derive(Debug, Deserialize, Serialize)] pub struct CostConfig { - #[serde(default)] + #[serde(default = "default_true")] pub enabled: bool, #[serde(default = "default_max_daily_cents")] pub max_daily_cents: u32, @@ -189,7 +189,7 @@ pub struct CostConfig { impl Default for CostConfig { fn default() -> Self { Self { - enabled: false, + enabled: true, max_daily_cents: default_max_daily_cents(), } } diff --git a/crates/zeph-config/src/memory.rs b/crates/zeph-config/src/memory.rs index 1944027e9..68dc627a2 100644 --- a/crates/zeph-config/src/memory.rs +++ b/crates/zeph-config/src/memory.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; -use crate::defaults::default_sqlite_path_field; +use crate::defaults::{default_sqlite_path_field, default_true}; fn default_sqlite_pool_size() -> u32 { 5 @@ -504,8 +504,8 @@ impl Default for NoteLinkingConfig { #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] pub enum VectorBackend { - #[default] Qdrant, + #[default] Sqlite, } @@ -558,7 +558,7 @@ pub struct MemoryConfig { pub token_safety_margin: f32, #[serde(default = "default_redact_credentials")] pub redact_credentials: bool, - #[serde(default)] + #[serde(default = "default_true")] pub autosave_assistant: bool, #[serde(default = "default_autosave_min_length")] pub autosave_min_length: usize, @@ -674,15 +674,15 @@ pub struct SemanticConfig { pub vector_weight: f64, #[serde(default = "default_keyword_weight")] pub keyword_weight: f64, - #[serde(default)] + #[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)] + #[serde(default = "default_true")] pub mmr_enabled: bool, #[serde(default = "default_mmr_lambda")] pub mmr_lambda: f32, - #[serde(default)] + #[serde(default = "default_true")] pub importance_enabled: bool, #[serde( default = "default_importance_weight", @@ -698,11 +698,11 @@ impl Default for SemanticConfig { recall_limit: default_recall_limit(), vector_weight: default_vector_weight(), keyword_weight: default_keyword_weight(), - temporal_decay_enabled: false, + temporal_decay_enabled: true, temporal_decay_half_life_days: default_temporal_decay_half_life_days(), - mmr_enabled: false, + mmr_enabled: true, mmr_lambda: default_mmr_lambda(), - importance_enabled: false, + importance_enabled: true, importance_weight: default_importance_weight(), } } diff --git a/crates/zeph-config/src/root.rs b/crates/zeph-config/src/root.rs index c1a53df09..f226c0cbf 100644 --- a/crates/zeph-config/src/root.rs +++ b/crates/zeph-config/src/root.rs @@ -183,7 +183,7 @@ impl Default for Config { vector_backend: VectorBackend::default(), token_safety_margin: 1.0, redact_credentials: true, - autosave_assistant: false, + autosave_assistant: true, autosave_min_length: 20, tool_call_cutoff: 6, sqlite_pool_size: 5, diff --git a/crates/zeph-core/src/agent/builder.rs b/crates/zeph-core/src/agent/builder.rs index 8ed731684..5db4012a0 100644 --- a/crates/zeph-core/src/agent/builder.rs +++ b/crates/zeph-core/src/agent/builder.rs @@ -1229,7 +1229,8 @@ mod tests { fn apply_session_config_skips_anomaly_detector_when_disabled() { use crate::config::Config; - let config = Config::default(); // anomaly.enabled defaults to false + let mut config = Config::default(); + config.tools.anomaly.enabled = false; // explicitly disable to test the disabled path let session_cfg = AgentSessionConfig::from_config(&config, 100_000); assert!(!session_cfg.anomaly_config.enabled); diff --git a/crates/zeph-core/src/cost.rs b/crates/zeph-core/src/cost.rs index 79ff7a2d6..788abf5c9 100644 --- a/crates/zeph-core/src/cost.rs +++ b/crates/zeph-core/src/cost.rs @@ -204,7 +204,7 @@ impl CostTracker { state.spent_cents = 0.0; state.day = today; } - if state.spent_cents >= self.max_daily_cents { + if self.max_daily_cents > 0.0 && state.spent_cents >= self.max_daily_cents { return Err(BudgetExhausted { spent_cents: state.spent_cents, budget_cents: self.max_daily_cents, diff --git a/crates/zeph-tools/src/config.rs b/crates/zeph-tools/src/config.rs index dd31ec35c..3b3b6aae5 100644 --- a/crates/zeph-tools/src/config.rs +++ b/crates/zeph-tools/src/config.rs @@ -89,7 +89,7 @@ fn default_anomaly_critical_threshold() -> f64 { /// Configuration for the sliding-window anomaly detector. #[derive(Debug, Clone, Deserialize, Serialize)] pub struct AnomalyConfig { - #[serde(default)] + #[serde(default = "default_true")] pub enabled: bool, #[serde(default = "default_anomaly_window")] pub window_size: usize, @@ -102,7 +102,7 @@ pub struct AnomalyConfig { impl Default for AnomalyConfig { fn default() -> Self { Self { - enabled: false, + enabled: true, window_size: default_anomaly_window(), error_threshold: default_anomaly_error_threshold(), critical_threshold: default_anomaly_critical_threshold(), @@ -284,7 +284,7 @@ pub struct ShellConfig { /// Configuration for audit logging of tool executions. #[derive(Debug, Deserialize, Serialize)] pub struct AuditConfig { - #[serde(default)] + #[serde(default = "default_true")] pub enabled: bool, #[serde(default = "default_audit_destination")] pub destination: String, @@ -327,7 +327,7 @@ impl Default for ShellConfig { impl Default for AuditConfig { fn default() -> Self { Self { - enabled: false, + enabled: true, destination: default_audit_destination(), } } @@ -401,7 +401,7 @@ mod tests { assert!(config.summarize_output); assert_eq!(config.shell.timeout, 30); assert!(config.shell.blocked_commands.is_empty()); - assert!(!config.audit.enabled); + assert!(config.audit.enabled); } #[test] @@ -440,7 +440,7 @@ mod tests { assert!(!config.shell.confirm_patterns.is_empty()); assert_eq!(config.scrape.timeout, 15); assert_eq!(config.scrape.max_body_bytes, 4_194_304); - assert!(!config.audit.enabled); + assert!(config.audit.enabled); assert_eq!(config.audit.destination, "stdout"); assert!(config.summarize_output); } @@ -521,7 +521,7 @@ mod tests { #[test] fn default_audit_config() { let config = AuditConfig::default(); - assert!(!config.enabled); + assert!(config.enabled); assert_eq!(config.destination, "stdout"); }