feat: Vestige v1.9.1 AUTONOMIC — self-regulating memory with graph visualization

Retention Target System: auto-GC low-retention memories during consolidation
(VESTIGE_RETENTION_TARGET env var, default 0.8). Auto-Promote: memories
accessed 3+ times in 24h get frequency-dependent potentiation. Waking SWR
Tagging: promoted memories get preferential 70/30 dream replay. Improved
Consolidation Scheduler: triggers on 6h staleness or 2h active use.

New tools: memory_health (retention dashboard with distribution buckets,
trend tracking, recommendations) and memory_graph (subgraph export with
Fruchterman-Reingold force-directed layout, up to 200 nodes).

Dream connections now persist to database via save_connection(), enabling
memory_graph traversal. Schema Migration V8 adds waking_tag, utility_score,
times_retrieved/useful columns and retention_snapshots table. 21 MCP tools.

v1.9.1 fixes: ConnectionRecord export, UTF-8 safe truncation, link_type
normalization, utility_score clamping, only-new-connections persistence,
70/30 split capacity fill, nonexistent center_id error handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam Valladares 2026-02-21 02:02:06 -06:00
parent c29023dd80
commit 5b90a73055
62 changed files with 2922 additions and 931 deletions

View file

@ -5,7 +5,6 @@
use serde::Deserialize;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::Mutex;
use vestige_core::Storage;
@ -90,7 +89,7 @@ struct HybridSearchArgs {
}
pub async fn execute_semantic(
storage: &Arc<Mutex<Storage>>,
storage: &Arc<Storage>,
args: Option<Value>,
) -> Result<Value, String> {
let args: SemanticSearchArgs = match args {
@ -102,7 +101,6 @@ pub async fn execute_semantic(
return Err("Query cannot be empty".to_string());
}
let storage = storage.lock().await;
// Check if embeddings are ready
if !storage.is_embedding_ready() {
@ -143,7 +141,7 @@ pub async fn execute_semantic(
}
pub async fn execute_hybrid(
storage: &Arc<Mutex<Storage>>,
storage: &Arc<Storage>,
args: Option<Value>,
) -> Result<Value, String> {
let args: HybridSearchArgs = match args {
@ -155,7 +153,6 @@ pub async fn execute_hybrid(
return Err("Query cannot be empty".to_string());
}
let storage = storage.lock().await;
let results = storage
.hybrid_search(