From 7476e9d0db63bae451d821cf7dab95f7f60914c0 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Mon, 13 Apr 2026 02:05:58 -0400 Subject: [PATCH] delete rename agent and related code The organize agents handle renaming as part of their normal work now. Also simplified resolve_placeholders to build graph internally. Co-Authored-By: Proof of Concept --- src/agent/oneshot.rs | 3 +- src/subconscious/agents/rename.agent | 79 ----------------------- src/subconscious/defs.rs | 20 ++---- src/subconscious/prompts.rs | 94 ---------------------------- 4 files changed, 5 insertions(+), 191 deletions(-) delete mode 100644 src/subconscious/agents/rename.agent diff --git a/src/agent/oneshot.rs b/src/agent/oneshot.rs index 1baa08e..23033fe 100644 --- a/src/agent/oneshot.rs +++ b/src/agent/oneshot.rs @@ -401,12 +401,11 @@ pub fn run_one_agent( // Build prompt batch — either from explicit keys or the agent's query let agent_batch = if let Some(keys) = keys { dbglog!("[{}] targeting: {}", agent_name, keys.join(", ")); - let graph = store.build_graph(); let mut resolved_steps = Vec::new(); let mut all_keys: Vec = keys.to_vec(); for step in &def.steps { let (prompt, extra_keys) = defs::resolve_placeholders( - &step.prompt, store, &graph, keys, count, + &step.prompt, store, keys, count, ); all_keys.extend(extra_keys); resolved_steps.push(prompts::ResolvedStep { diff --git a/src/subconscious/agents/rename.agent b/src/subconscious/agents/rename.agent deleted file mode 100644 index be34f91..0000000 --- a/src/subconscious/agents/rename.agent +++ /dev/null @@ -1,79 +0,0 @@ -{"agent": "rename", "query": "", "schedule": "daily"} - -# Rename Agent — Semantic Key Generation - - -{{tool: memory_render core-personality}} - -{{tool: memory_render memory-instructions-core}} - -{{tool: memory_render memory-instructions-core-subconscious}} - -{{tool: memory_render subconscious-notes-{agent_name}}} - -You are a memory maintenance agent that gives nodes better names. - -## What you're doing - -Many nodes have auto-generated keys that are opaque or truncated: -- Journal entries: `journal-j-2026-02-28t03-07-i-told-him-about-the-dream` -- Mined transcripts: `_mined-transcripts-f-80a7b321-2caa-451a-bc5c-6565009f94eb.143` -- Extracted facts: `_facts-ec29bdaa-0a58-465f-ad5e-d89e62d9c583` - -These names are terrible for search — semantic names dramatically improve -retrieval. - -## Core principle: keys are concepts - -A good key names the **concept** the node represents. Think of keys as -the vocabulary of the knowledge graph. When you rename, you're defining -what concepts exist. Core keywords should be the terms someone would -search for — `bcachefs-transaction-restart`, `emotional-regulation-gap`, -`polywell-cusp-losses`. - -## Naming conventions - -### Journal entries: `journal-YYYY-MM-DD-semantic-slug` -- Keep the date prefix (YYYY-MM-DD) for temporal ordering -- Replace the auto-slug with 3-5 descriptive words in kebab-case -- Capture the *essence* of the entry, not just the first line - -### Mined transcripts: `_mined-transcripts-YYYY-MM-DD-semantic-slug` -- Extract date from content if available, otherwise use created_at -- Same 3-5 word semantic slug - -### Extracted facts: `domain-specific-topic` -- Read the facts JSON — the `domain` and `claim` fields tell you what it's about -- Group by dominant theme, name accordingly -- Examples: `identity-irc-config`, `user-location-background`, `memory-compaction-behavior` - -### Skip these — already well-named: -- Keys with semantic names (patterns-, practices-, skills-, etc.) -- Keys shorter than 60 characters -- System keys (_consolidation-*) - -## How to rename - -Use the `memory_rename` tool: - - memory_rename(old_key, new_key) - -This renames the node in place — same content, same links, new key. -Do NOT use `memory_write` or `memory_supersede` — just rename. - -If a node already has a reasonable name, skip it. When in doubt, skip. -A bad rename is worse than an auto-slug. - -## Guidelines - -- **Read the content.** The name should reflect what the entry is *about*. -- **Be specific.** `journal#2026-02-14-session` is useless. -- **Use domain terms.** Use the words someone would search for. -- **Don't rename to something longer than the original.** -- **Preserve the date.** Always keep YYYY-MM-DD for journal entries. -- **When in doubt, skip.** A bad rename is worse than an auto-slug. -- **Respect search hits.** Nodes marked "actively found by search" are - being retrieved by their current name. Skip these unless the rename - clearly preserves searchability. - -{{rename}} diff --git a/src/subconscious/defs.rs b/src/subconscious/defs.rs index 2c961e1..d084cab 100644 --- a/src/subconscious/defs.rs +++ b/src/subconscious/defs.rs @@ -203,20 +203,9 @@ fn resolve( store: &Store, graph: &Graph, keys: &[String], - count: usize, + _count: usize, ) -> Option { match name { - "rename" => { - if !keys.is_empty() { - // --target provided: present those keys as candidates - let section = super::prompts::format_rename_targets(store, keys); - Some(Resolved { text: section, keys: vec![] }) - } else { - let (rename_keys, section) = super::prompts::format_rename_candidates(store, count); - Some(Resolved { text: section, keys: rename_keys }) - } - } - // seed — render output for each seed node (content + deduped links) "seed" => { let mut text = String::new(); @@ -576,10 +565,10 @@ fn resolve_tool(spec: &str) -> Option { pub fn resolve_placeholders( template: &str, store: &Store, - graph: &Graph, 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; @@ -589,7 +578,7 @@ pub 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) { + match resolve(&name, store, &graph, keys, count) { Some(resolved) => { let len = resolved.text.len(); extra_keys.extend(resolved.keys); @@ -616,7 +605,6 @@ pub fn run_agent( count: usize, exclude: &std::collections::HashSet, ) -> Result { - let graph = store.build_graph(); // Run the query if present, via RPC let keys = if !def.query.is_empty() { @@ -654,7 +642,7 @@ pub 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, &graph, &all_keys, count); + let (prompt, extra_keys) = resolve_placeholders(&template, store, &all_keys, count); 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 11c50ac..cc9c3da 100644 --- a/src/subconscious/prompts.rs +++ b/src/subconscious/prompts.rs @@ -211,100 +211,6 @@ pub fn format_health_section(store: &Store, graph: &Graph) -> String { out } -pub(super) fn format_rename_candidates(store: &Store, count: usize) -> (Vec, String) { - let mut candidates: Vec<(&str, &crate::store::Node)> = store.nodes.iter() - .filter(|(key, node)| { - if key.starts_with("_facts-") { return true; } - if key.len() < 60 { return false; } - if node.node_type == crate::store::NodeType::EpisodicSession { return true; } - if key.starts_with("_mined-transcripts#f-") { return true; } - false - }) - .map(|(k, n)| (k.as_str(), n)) - .collect(); - - // Deprioritize nodes actively found by search — renaming them would - // break working queries. Sort by: search hits (ascending), then - // least-recently visited. Nodes with many hits sink to the bottom. - let hit_counts = crate::counters::all_search_hits(); - let hit_map: std::collections::HashMap<&str, u64> = hit_counts.iter() - .map(|(k, v)| (k.as_str(), *v)) - .collect(); - candidates.sort_by_key(|(key, _)| { - let hits = hit_map.get(key).copied().unwrap_or(0); - (hits, store.last_visited(key, "rename")) - }); - candidates.truncate(count); - - let keys: Vec = candidates.iter().map(|(k, _)| k.to_string()).collect(); - - let mut out = String::new(); - out.push_str(&format!("## Nodes to rename ({} of {} candidates)\n\n", - candidates.len(), - store.nodes.iter().filter(|(k, n)| k.starts_with("_facts-") || - (k.len() >= 60 && - (n.node_type == crate::store::NodeType::EpisodicSession || k.starts_with("_mined-transcripts#f-")))).count())); - - for (key, node) in &candidates { - out.push_str(&format!("### {}\n", key)); - let created = if node.timestamp > 0 { - crate::store::format_datetime(node.timestamp) - } else { - "unknown".to_string() - }; - out.push_str(&format!("Created: {}\n", created)); - - let hits = hit_map.get(key).copied().unwrap_or(0); - if hits > 0 { - out.push_str(&format!("Search hits: {} ← actively found by search, prefer to keep current name\n", hits)); - } - - let content = &node.content; - if content.len() > 800 { - let truncated = crate::util::truncate(content, 800, "\n[...]"); - out.push_str(&format!("\nContent ({} chars, truncated):\n{}\n\n", - content.len(), truncated)); - } else { - out.push_str(&format!("\nContent:\n{}\n\n", content)); - } - - out.push_str("---\n\n"); - } - (keys, out) -} - -/// Format specific target keys as rename candidates (for --target mode) -pub(super) fn format_rename_targets(store: &Store, keys: &[String]) -> String { - let mut out = String::new(); - out.push_str(&format!("## Nodes to rename ({} targets)\n\n", keys.len())); - - for key in keys { - let Some(node) = store.nodes.get(key) else { - out.push_str(&format!("### {}\n\n(node not found)\n\n---\n\n", key)); - continue; - }; - out.push_str(&format!("### {}\n", key)); - let created = if node.timestamp > 0 { - crate::store::format_datetime(node.timestamp) - } else { - "unknown".to_string() - }; - out.push_str(&format!("Created: {}\n", created)); - - let content = &node.content; - if content.len() > 800 { - let truncated = crate::util::truncate(content, 800, "\n[...]"); - out.push_str(&format!("\nContent ({} chars, truncated):\n{}\n\n", - content.len(), truncated)); - } else { - out.push_str(&format!("\nContent:\n{}\n\n", content)); - } - - out.push_str("---\n\n"); - } - out -} - /// Generate a specific agent prompt with filled-in data. pub fn agent_prompt(store: &Store, agent: &str, count: usize) -> Result { let def = super::defs::get_def(agent)