diff --git a/src/agent/oneshot.rs b/src/agent/oneshot.rs index e2f984e..f71587b 100644 --- a/src/agent/oneshot.rs +++ b/src/agent/oneshot.rs @@ -405,7 +405,7 @@ pub async fn run_one_agent( let mut all_keys: Vec = keys.to_vec(); for step in &def.steps { let (prompt, extra_keys) = defs::resolve_placeholders( - &step.prompt, store, keys, count, + &step.prompt, keys, count, ).await; all_keys.extend(extra_keys); resolved_steps.push(prompts::ResolvedStep { @@ -420,7 +420,7 @@ pub async fn run_one_agent( batch } else { let effective_count = def.count.unwrap_or(count); - defs::run_agent(store, &def, effective_count, &Default::default()).await? + defs::run_agent(&def, effective_count, &Default::default()).await? }; // Base memory tools + extras from agent def (matching unconscious.rs pattern) diff --git a/src/mind/unconscious.rs b/src/mind/unconscious.rs index b766532..ef974f4 100644 --- a/src/mind/unconscious.rs +++ b/src/mind/unconscious.rs @@ -264,7 +264,7 @@ pub async fn prepare_spawn(name: &str, mut auto: AutoAgent) -> Result = std::collections::HashSet::new(); let batch = match defs::run_agent( - &store, &def, def.count.unwrap_or(5), &exclude, + &def, def.count.unwrap_or(5), &exclude, ).await { Ok(b) => b, Err(e) => { diff --git a/src/subconscious/defs.rs b/src/subconscious/defs.rs index db47109..06f3ddc 100644 --- a/src/subconscious/defs.rs +++ b/src/subconscious/defs.rs @@ -15,8 +15,6 @@ // The query selects what to operate on; placeholders pull in context. use crate::agent::tools::memory::memory_render; -use crate::graph::Graph; -use crate::store::Store; use serde::Deserialize; @@ -201,8 +199,6 @@ struct Resolved { /// Returns the replacement text and any node keys it produced (for visit tracking). async fn resolve( name: &str, - store: &Store, - graph: &Graph, keys: &[String], _count: usize, ) -> Option { @@ -245,6 +241,7 @@ async fn resolve( } "siblings" | "neighborhood" => { + use crate::agent::tools::memory::{memory_render, memory_links}; const MAX_NEIGHBORS: usize = 20; const BUDGET: usize = 400_000; // ~100K tokens @@ -255,19 +252,18 @@ async fn resolve( for key in keys { if included.contains(key) { continue; } included.insert(key.clone()); - let Some(node) = store.nodes.get(key.as_str()) else { continue }; // Seed node with full content - out.push_str(&format!("## {} (seed)\n\n{}\n\n", key, node.content)); + let Ok(content) = memory_render(None, key, Some(true)).await else { continue }; + out.push_str(&format!("## {} (seed)\n\n{}\n\n", key, content)); all_keys.push(key.clone()); - // Rank neighbors by link_strength * node_weight, take top 20 - let mut ranked: Vec<_> = graph.neighbors(key).iter() - .filter_map(|(nbr, strength)| { - store.nodes.get(nbr.as_str()).map(|n| { - let score = strength * n.weight.max(0.01); - (nbr.to_string(), *strength, score) - }) + // Get neighbors with link_strength and node_weight, rank and take top 20 + let Ok(links) = memory_links(None, key).await else { continue }; + let mut ranked: Vec<_> = links.into_iter() + .map(|l| { + let score = l.link_strength * l.node_weight.max(0.01); + (l.key, l.link_strength, score) }) .collect(); ranked.sort_by(|a, b| b.2.total_cmp(&a.2)); @@ -279,15 +275,15 @@ async fn resolve( for (nbr, strength, _) in &ranked { if included.contains(nbr) { continue; } included.insert(nbr.clone()); - if let Some(n) = store.nodes.get(nbr.as_str()) { + if let Ok(content) = memory_render(None, nbr, Some(true)).await { if out.len() > BUDGET { // Header-only past budget - let first = n.content.lines() + let first = content.lines() .find(|l| !l.trim().is_empty()) .unwrap_or("(empty)"); out.push_str(&format!("#### {} ({:.2}) — {}\n", nbr, strength, first)); } else { - out.push_str(&format!("#### {} ({:.2})\n\n{}\n\n", nbr, strength, n.content)); + out.push_str(&format!("#### {} ({:.2})\n\n{}\n\n", nbr, strength, content)); } all_keys.push(nbr.to_string()); } @@ -558,11 +554,9 @@ async fn resolve_tool(spec: &str) -> Option { /// Returns the resolved text and all node keys collected from placeholders. pub async fn resolve_placeholders( template: &str, - store: &Store, keys: &[String], count: usize, ) -> (String, Vec) { - let graph = store.build_graph(); let mut result = template.to_string(); let mut extra_keys = Vec::new(); let mut pos = 0; @@ -572,7 +566,7 @@ pub async fn resolve_placeholders( let Some(rel_end) = result[start + 2..].find("}}") else { break }; let end = start + 2 + rel_end; let name = result[start + 2..end].trim().to_lowercase(); - match resolve(&name, store, &graph, keys, count).await { + match resolve(&name, keys, count).await { Some(resolved) => { let len = resolved.text.len(); extra_keys.extend(resolved.keys); @@ -594,7 +588,6 @@ pub async fn resolve_placeholders( /// `exclude` filters out nodes (and their neighborhoods) already being /// worked on by other agents, preventing concurrent collisions. pub async fn run_agent( - store: &Store, def: &AgentDef, count: usize, exclude: &std::collections::HashSet, @@ -635,7 +628,7 @@ pub async fn run_agent( .replace("{agent_name}", &def.agent) .replace("{user_name}", &cfg.user_name) .replace("{assistant_name}", &cfg.assistant_name); - let (prompt, extra_keys) = resolve_placeholders(&template, store, &all_keys, count).await; + let (prompt, extra_keys) = resolve_placeholders(&template, &all_keys, count).await; all_keys.extend(extra_keys); resolved_steps.push(super::prompts::ResolvedStep { prompt, diff --git a/src/subconscious/prompts.rs b/src/subconscious/prompts.rs index 5faad24..12b76c3 100644 --- a/src/subconscious/prompts.rs +++ b/src/subconscious/prompts.rs @@ -212,8 +212,8 @@ pub fn format_health_section(store: &Store, graph: &Graph) -> String { } /// Generate a specific agent prompt with filled-in data. -pub async fn agent_prompt(store: &Store, agent: &str, count: usize) -> Result { +pub async fn agent_prompt(agent: &str, count: usize) -> Result { let def = super::defs::get_def(agent) .ok_or_else(|| format!("Unknown agent: {}", agent))?; - super::defs::run_agent(store, &def, count, &Default::default()).await + super::defs::run_agent(&def, count, &Default::default()).await }