feat: Vestige v1.3.0 — importance scoring, session checkpoints, duplicate detection

3 new MCP tools (16 → 19 total):
- importance_score: 4-channel neuroscience importance scoring (novelty/arousal/reward/attention)
- session_checkpoint: batch smart_ingest up to 20 items with PE Gating
- find_duplicates: cosine similarity clustering with union-find for dedup

CLI: vestige ingest command for memory ingestion via command line
Core: made get_node_embedding public, added get_all_embeddings for dedup scanning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam Valladares 2026-02-12 05:02:09 -06:00
parent 5cca386d6b
commit 04a3062328
9 changed files with 848 additions and 5 deletions

View file

@ -478,7 +478,7 @@ impl Storage {
/// Get the embedding vector for a node
#[cfg(all(feature = "embeddings", feature = "vector-search"))]
fn get_node_embedding(&self, node_id: &str) -> Result<Option<Vec<f32>>> {
pub fn get_node_embedding(&self, node_id: &str) -> Result<Option<Vec<f32>>> {
let mut stmt = self.conn.prepare(
"SELECT embedding FROM node_embeddings WHERE node_id = ?1"
)?;
@ -492,6 +492,29 @@ impl Storage {
}))
}
/// Get all embedding vectors for duplicate detection
#[cfg(all(feature = "embeddings", feature = "vector-search"))]
pub fn get_all_embeddings(&self) -> Result<Vec<(String, Vec<f32>)>> {
let mut stmt = self
.conn
.prepare("SELECT node_id, embedding FROM node_embeddings")?;
let results: Vec<(String, Vec<f32>)> = stmt
.query_map([], |row| {
let node_id: String = row.get(0)?;
let embedding_bytes: Vec<u8> = row.get(1)?;
Ok((node_id, embedding_bytes))
})?
.filter_map(|r| r.ok())
.filter_map(|(id, bytes)| {
crate::embeddings::Embedding::from_bytes(&bytes)
.map(|e| (id, e.vector))
})
.collect();
Ok(results)
}
/// Update the content of an existing node
pub fn update_node_content(&mut self, id: &str, new_content: &str) -> Result<()> {
let now = Utc::now();