memory: add spreading activation tool
Add `poc-memory graph spread` command that takes multiple seed node keys, runs spreading activation through the graph, and returns nodes ranked by total activation — nodes that bridge multiple seed concepts score highest. Expose spreading_activation() as pub from the query engine. Add memory_spread and memory_search_content tool definitions for MCP. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
c5b5051772
commit
6f2e0938f0
3 changed files with 49 additions and 1 deletions
|
|
@ -6,6 +6,7 @@
|
||||||
// trace, spectral-*, organize, interference.
|
// trace, spectral-*, organize, interference.
|
||||||
|
|
||||||
use crate::{store, graph, neuro, spectral};
|
use crate::{store, graph, neuro, spectral};
|
||||||
|
use crate::store::StoreView;
|
||||||
|
|
||||||
pub fn cmd_graph() -> Result<(), String> {
|
pub fn cmd_graph() -> Result<(), String> {
|
||||||
let store = store::Store::load()?;
|
let store = store::Store::load()?;
|
||||||
|
|
@ -109,6 +110,45 @@ pub fn cmd_normalize_strengths(apply: bool) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cmd_spread(keys: &[String], max_results: usize) -> Result<(), String> {
|
||||||
|
if keys.is_empty() {
|
||||||
|
return Err("spread requires at least one seed key".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let store = store::Store::load()?;
|
||||||
|
let graph = graph::build_graph_fast(&store);
|
||||||
|
let params = store.params();
|
||||||
|
|
||||||
|
let seeds: Vec<(String, f64)> = keys.iter()
|
||||||
|
.filter_map(|k| {
|
||||||
|
let resolved = store.resolve_key(k).ok()?;
|
||||||
|
Some((resolved, 1.0))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if seeds.is_empty() {
|
||||||
|
return Err("no valid seed keys found".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let results = crate::search::spreading_activation(
|
||||||
|
&seeds, &graph, &store,
|
||||||
|
params.max_hops, params.edge_decay, params.min_activation,
|
||||||
|
);
|
||||||
|
|
||||||
|
let seed_keys: std::collections::HashSet<&str> = seeds.iter()
|
||||||
|
.map(|(k, _)| k.as_str())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for (key, score) in results.iter()
|
||||||
|
.filter(|(k, _)| !seed_keys.contains(k.as_str()))
|
||||||
|
.take(max_results)
|
||||||
|
{
|
||||||
|
println!(" {:.2} {}", score, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cmd_link(key: &[String]) -> Result<(), String> {
|
pub fn cmd_link(key: &[String]) -> Result<(), String> {
|
||||||
if key.is_empty() {
|
if key.is_empty() {
|
||||||
return Err("link requires a key".into());
|
return Err("link requires a key".into());
|
||||||
|
|
|
||||||
|
|
@ -1377,7 +1377,7 @@ fn run_manifold(
|
||||||
/// sum at each node, and the combined activation map propagates on
|
/// sum at each node, and the combined activation map propagates on
|
||||||
/// the next hop. This creates interference patterns — nodes where
|
/// the next hop. This creates interference patterns — nodes where
|
||||||
/// multiple wavefronts overlap get reinforced and radiate stronger.
|
/// multiple wavefronts overlap get reinforced and radiate stronger.
|
||||||
fn spreading_activation(
|
pub fn spreading_activation(
|
||||||
seeds: &[(String, f64)],
|
seeds: &[(String, f64)],
|
||||||
graph: &Graph,
|
graph: &Graph,
|
||||||
store: &impl StoreView,
|
store: &impl StoreView,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,14 @@ pub fn definitions() -> Vec<ToolDef> {
|
||||||
ToolDef::new("memory_search",
|
ToolDef::new("memory_search",
|
||||||
"Search the memory graph by keyword.",
|
"Search the memory graph by keyword.",
|
||||||
json!({"type":"object","properties":{"query":{"type":"string","description":"Search terms"}},"required":["query"]})),
|
json!({"type":"object","properties":{"query":{"type":"string","description":"Search terms"}},"required":["query"]})),
|
||||||
|
ToolDef::new("memory_search_content",
|
||||||
|
"Search the memory graph by keyword (searches node content, not just keys).",
|
||||||
|
json!({"type":"object","properties":{"query":{"type":"string","description":"Search terms"}},"required":["query"]})),
|
||||||
|
ToolDef::new("memory_spread",
|
||||||
|
"Find related nodes via spreading activation from multiple seed nodes. \
|
||||||
|
Propagates activation through the graph and returns nodes ranked by \
|
||||||
|
total activation. Use to find nodes that connect multiple concepts.",
|
||||||
|
json!({"type":"object","properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Seed node keys to activate from"}},"required":["keys"]})),
|
||||||
ToolDef::new("memory_links",
|
ToolDef::new("memory_links",
|
||||||
"Show a node's neighbors with link strengths.",
|
"Show a node's neighbors with link strengths.",
|
||||||
json!({"type":"object","properties":{"key":{"type":"string","description":"Node key"}},"required":["key"]})),
|
json!({"type":"object","properties":{"key":{"type":"string","description":"Node key"}},"required":["key"]})),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue