forked from kent/consciousness
remove legacy feedback commands (used, wrong, gap, etc.)
These were early experiments with manual feedback signals that never worked well. The scoring system will handle this properly. Removed: - CLI: used, wrong, not-relevant, not-useful, gap - MCP: memory_used - Store: mark_used, mark_wrong, record_gap, modify_node Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
11b58e6b0b
commit
7842b6fc8b
6 changed files with 10 additions and 190 deletions
|
|
@ -115,7 +115,6 @@ async fn dispatch(
|
|||
"memory_links" => links(&args).await,
|
||||
"memory_link_set" => link_set(&args).await,
|
||||
"memory_link_add" => link_add(agent, &args).await,
|
||||
"memory_used" => used(&args).await,
|
||||
"memory_weight_set" => weight_set(&args).await,
|
||||
"memory_rename" => rename(&args).await,
|
||||
"memory_supersede" => supersede(agent, &args).await,
|
||||
|
|
@ -131,7 +130,7 @@ async fn dispatch(
|
|||
|
||||
// ── Definitions ────────────────────────────────────────────────
|
||||
|
||||
pub fn memory_tools() -> [super::Tool; 13] {
|
||||
pub fn memory_tools() -> [super::Tool; 12] {
|
||||
use super::Tool;
|
||||
[
|
||||
Tool { name: "memory_render", description: "Read a memory node's content and links.",
|
||||
|
|
@ -152,9 +151,6 @@ pub fn memory_tools() -> [super::Tool; 13] {
|
|||
Tool { name: "memory_link_add", description: "Add a new link between two nodes.",
|
||||
parameters_json: r#"{"type":"object","properties":{"source":{"type":"string"},"target":{"type":"string"}},"required":["source","target"]}"#,
|
||||
handler: Arc::new(|a, v| Box::pin(async move { dispatch("memory_link_add", &a, v).await })) },
|
||||
Tool { name: "memory_used", description: "Mark a node as useful (boosts weight).",
|
||||
parameters_json: r#"{"type":"object","properties":{"key":{"type":"string","description":"Node key"}},"required":["key"]}"#,
|
||||
handler: Arc::new(|a, v| Box::pin(async move { dispatch("memory_used", &a, v).await })) },
|
||||
Tool { name: "memory_weight_set", description: "Set a node's weight directly (0.01 to 1.0).",
|
||||
parameters_json: r#"{"type":"object","properties":{"key":{"type":"string"},"weight":{"type":"number","description":"0.01 to 1.0"}},"required":["key","weight"]}"#,
|
||||
handler: Arc::new(|a, v| Box::pin(async move { dispatch("memory_weight_set", &a, v).await })) },
|
||||
|
|
@ -315,18 +311,6 @@ async fn link_add(agent: &Option<std::sync::Arc<crate::agent::Agent>>, args: &se
|
|||
Ok(format!("linked {} → {} (strength={:.2})", s, t, strength))
|
||||
}
|
||||
|
||||
async fn used(args: &serde_json::Value) -> Result<String> {
|
||||
let key = get_str(args, "key")?;
|
||||
let arc = cached_store().await?;
|
||||
let mut store = arc.lock().await;
|
||||
if !store.nodes.contains_key(key) {
|
||||
anyhow::bail!("node not found: {}", key);
|
||||
}
|
||||
store.mark_used(key);
|
||||
store.save().map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||
Ok(format!("marked {} as used", key))
|
||||
}
|
||||
|
||||
async fn weight_set(args: &serde_json::Value) -> Result<String> {
|
||||
let arc = cached_store().await?;
|
||||
let mut store = arc.lock().await;
|
||||
|
|
|
|||
102
src/cli/node.rs
102
src/cli/node.rs
|
|
@ -1,88 +1,10 @@
|
|||
// cli/node.rs — node subcommand handlers
|
||||
//
|
||||
// render, write, used, wrong, not-relevant, not-useful, gap,
|
||||
// node-delete, node-rename, history, list-keys, list-edges,
|
||||
// dump-json, lookup-bump, lookups.
|
||||
// render, write, node-delete, node-rename, history, list-keys,
|
||||
// list-edges, dump-json, lookup-bump, lookups.
|
||||
|
||||
use crate::store;
|
||||
|
||||
pub fn cmd_used(key: &[String]) -> Result<(), String> {
|
||||
if key.is_empty() {
|
||||
return Err("used requires a key".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
let key = key.join(" ");
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(&key)?;
|
||||
store.mark_used(&resolved);
|
||||
|
||||
// Also strengthen edges to this node — conscious-tier delta.
|
||||
const DELTA: f32 = 0.01;
|
||||
let mut strengthened = 0;
|
||||
for rel in &mut store.relations {
|
||||
if rel.deleted { continue; }
|
||||
if rel.source_key == resolved || rel.target_key == resolved {
|
||||
let old = rel.strength;
|
||||
rel.strength = (rel.strength + DELTA).clamp(0.05, 0.95);
|
||||
if (rel.strength - old).abs() > 0.001 {
|
||||
rel.version += 1;
|
||||
strengthened += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.save()?;
|
||||
println!("Marked '{}' as used (strengthened {} edges)", resolved, strengthened);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_wrong(key: &str, context: &[String]) -> Result<(), String> {
|
||||
let ctx = if context.is_empty() { None } else { Some(context.join(" ")) };
|
||||
super::check_dry_run();
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(key)?;
|
||||
store.mark_wrong(&resolved, ctx.as_deref());
|
||||
store.save()?;
|
||||
println!("Marked '{}' as wrong", resolved);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_not_relevant(key: &str) -> Result<(), String> {
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(key)?;
|
||||
|
||||
// Weaken all edges to this node — it was routed to incorrectly.
|
||||
// Conscious-tier delta: 0.01 per edge.
|
||||
const DELTA: f32 = -0.01;
|
||||
let mut adjusted = 0;
|
||||
for rel in &mut store.relations {
|
||||
if rel.deleted { continue; }
|
||||
if rel.source_key == resolved || rel.target_key == resolved {
|
||||
let old = rel.strength;
|
||||
rel.strength = (rel.strength + DELTA).clamp(0.05, 0.95);
|
||||
if (rel.strength - old).abs() > 0.001 {
|
||||
rel.version += 1;
|
||||
adjusted += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
store.save()?;
|
||||
println!("Not relevant: '{}' — weakened {} edges by {}", resolved, adjusted, DELTA.abs());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_not_useful(key: &str) -> Result<(), String> {
|
||||
// no args to validate
|
||||
super::check_dry_run();
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(key)?;
|
||||
// Same as wrong but with clearer semantics: node content is bad, edges are fine.
|
||||
store.mark_wrong(&resolved, Some("not-useful"));
|
||||
store.save()?;
|
||||
println!("Not useful: '{}' — node weight reduced", resolved);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_weight_set(key: &str, weight: f32) -> Result<(), String> {
|
||||
super::check_dry_run();
|
||||
let result = crate::mcp_server::memory_rpc(
|
||||
|
|
@ -93,19 +15,6 @@ pub fn cmd_weight_set(key: &str, weight: f32) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_gap(description: &[String]) -> Result<(), String> {
|
||||
if description.is_empty() {
|
||||
return Err("gap requires a description".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
let desc = description.join(" ");
|
||||
let mut store = store::Store::load()?;
|
||||
store.record_gap(&desc);
|
||||
store.save()?;
|
||||
println!("Recorded gap: {}", desc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_list_keys(pattern: Option<&str>) -> Result<(), String> {
|
||||
let store = store::Store::load()?;
|
||||
let g = store.build_graph();
|
||||
|
|
@ -192,11 +101,12 @@ pub fn cmd_render(key: &[String]) -> Result<(), String> {
|
|||
return Err("render requires a key".into());
|
||||
}
|
||||
let key = key.join(" ");
|
||||
let store = store::Store::load()?;
|
||||
let bare = store::strip_md_suffix(&key);
|
||||
|
||||
let rendered = render_node(&store, &bare)
|
||||
.ok_or_else(|| format!("Node not found: {}", bare))?;
|
||||
let rendered = crate::mcp_server::memory_rpc(
|
||||
"memory_render",
|
||||
serde_json::json!({"key": bare}),
|
||||
).map_err(|e| e.to_string())?;
|
||||
print!("{}", rendered);
|
||||
|
||||
// Mark as seen if we're inside a Claude session (not an agent subprocess —
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Mutation operations on the store
|
||||
//
|
||||
// CRUD (upsert, delete, modify), feedback tracking (mark_used, mark_wrong),
|
||||
// maintenance (decay, fix_categories, cap_degree), and graph metrics.
|
||||
// CRUD (upsert, delete), maintenance (decay, cap_degree), and graph metrics.
|
||||
|
||||
use super::types::*;
|
||||
|
||||
|
|
@ -179,45 +178,6 @@ impl Store {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Modify a node in-place, bump version, and persist to capnp log.
|
||||
fn modify_node(&mut self, key: &str, f: impl FnOnce(&mut Node)) -> Result<(), String> {
|
||||
let node = self.nodes.get_mut(key)
|
||||
.ok_or_else(|| format!("No node '{}'", key))?;
|
||||
f(node);
|
||||
node.version += 1;
|
||||
let node = node.clone();
|
||||
self.append_nodes(&[node])
|
||||
}
|
||||
|
||||
pub fn mark_used(&mut self, key: &str) {
|
||||
let boost = self.params.use_boost as f32;
|
||||
let _ = self.modify_node(key, |n| {
|
||||
n.uses += 1;
|
||||
n.weight = (n.weight + boost).min(1.0);
|
||||
if n.spaced_repetition_interval < 30 {
|
||||
n.spaced_repetition_interval = match n.spaced_repetition_interval {
|
||||
1 => 3, 3 => 7, 7 => 14, 14 => 30, _ => 30,
|
||||
};
|
||||
}
|
||||
n.last_replayed = now_epoch();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn mark_wrong(&mut self, key: &str, _ctx: Option<&str>) {
|
||||
let _ = self.modify_node(key, |n| {
|
||||
n.wrongs += 1;
|
||||
n.weight = (n.weight - 0.1).max(0.0);
|
||||
n.spaced_repetition_interval = 1;
|
||||
});
|
||||
}
|
||||
|
||||
pub fn record_gap(&mut self, desc: &str) {
|
||||
self.gaps.push(GapRecord {
|
||||
description: desc.to_string(),
|
||||
timestamp: today(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Cap node degree by soft-deleting edges from mega-hubs.
|
||||
pub fn cap_degree(&mut self, max_degree: usize) -> Result<(usize, usize), String> {
|
||||
let mut node_degree: HashMap<String, usize> = HashMap::new();
|
||||
|
|
|
|||
34
src/main.rs
34
src/main.rs
|
|
@ -149,30 +149,6 @@ EXAMPLES:
|
|||
/// Query expression (e.g. "key ~ 'inner-life'")
|
||||
expr: Vec<String>,
|
||||
},
|
||||
/// Mark a memory as useful (boosts weight)
|
||||
Used {
|
||||
/// Node key
|
||||
key: Vec<String>,
|
||||
},
|
||||
/// Mark a memory as wrong/irrelevant
|
||||
Wrong {
|
||||
/// Node key
|
||||
key: String,
|
||||
/// Optional context
|
||||
context: Vec<String>,
|
||||
},
|
||||
/// Mark a search result as not relevant (weakens edges that led to it)
|
||||
#[command(name = "not-relevant")]
|
||||
NotRelevant {
|
||||
/// Node key that was not relevant
|
||||
key: String,
|
||||
},
|
||||
/// Mark a node as not useful (weakens node weight, not edges)
|
||||
#[command(name = "not-useful")]
|
||||
NotUseful {
|
||||
/// Node key
|
||||
key: String,
|
||||
},
|
||||
/// Set a node's weight directly
|
||||
#[command(name = "weight-set")]
|
||||
WeightSet {
|
||||
|
|
@ -181,11 +157,6 @@ EXAMPLES:
|
|||
/// Weight (0.01 to 1.0)
|
||||
weight: f32,
|
||||
},
|
||||
/// Record a gap in memory coverage
|
||||
Gap {
|
||||
/// Gap description
|
||||
description: Vec<String>,
|
||||
},
|
||||
|
||||
// ── Node operations ───────────────────────────────────────────────
|
||||
|
||||
|
|
@ -523,12 +494,7 @@ impl Run for Command {
|
|||
=> cli::journal::cmd_tail(n, full, provenance.as_deref(), !all_versions),
|
||||
Self::Status => cli::misc::cmd_status(),
|
||||
Self::Query { expr } => cli::misc::cmd_query(&expr),
|
||||
Self::Used { key } => cli::node::cmd_used(&key),
|
||||
Self::Wrong { key, context } => cli::node::cmd_wrong(&key, &context),
|
||||
Self::NotRelevant { key } => cli::node::cmd_not_relevant(&key),
|
||||
Self::NotUseful { key } => cli::node::cmd_not_useful(&key),
|
||||
Self::WeightSet { key, weight } => cli::node::cmd_weight_set(&key, weight),
|
||||
Self::Gap { description } => cli::node::cmd_gap(&description),
|
||||
Self::Node(sub) => sub.run(),
|
||||
Self::Journal(sub) => sub.run(),
|
||||
Self::GraphCmd(sub) => sub.run(),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ You are {assistant_name}'s episodic memory. Your job is to witness.
|
|||
{{latest_journal}}
|
||||
|
||||
**Your tools:** journal_tail, journal_new, journal_update, memory_link_add,
|
||||
memory_search, memory_render, memory_used. Do NOT use memory_write — creating
|
||||
memory_search, memory_render. Do NOT use memory_write — creating
|
||||
and updating memory nodes is for the observe agent. Your job is journaling
|
||||
and linking entries to relevant existing nodes.
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Nodes your subconscious recently touched (for linking, not duplicating):
|
|||
{{state:walked}}
|
||||
|
||||
**Your tools:** journal_tail, journal_new, journal_update, memory_link_add,
|
||||
memory_search, memory_render, memory_used. Do NOT use memory_write — creating
|
||||
memory_search, memory_render. Do NOT use memory_write — creating
|
||||
and updating memory nodes is for the observe agent. Your job is journaling
|
||||
and linking entries to relevant existing nodes.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue