training: per-node scoring with graph weight updates
Memory scoring now uses the graph as source of truth: - last_scored timestamp on each node (new capnp field @22) - Nodes scored when older than scoring_interval_secs (default 1hr) - Oldest-scored-first ordering - Window: scoring_response_window assistant responses (default 100) - First-quarter memories scored even without full window - Per-response normalization (raw divergence / response count) - Asymmetric weight update: alpha=0.5 up, alpha=0.1 down (responds fast to importance, decays slowly — memories stay surfaced even if only useful 1/4 of the time) Graph writes disabled pending normalization calibration. Also: configurable scoring_interval_secs and scoring_response_window. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
b0603fd1ef
commit
fcd77fb79e
8 changed files with 109 additions and 64 deletions
|
|
@ -219,41 +219,31 @@ impl Session {
|
|||
fn start_memory_scoring(&self) {
|
||||
let agent = self.agent.clone();
|
||||
let ui_tx = self.ui_tx.clone();
|
||||
let cfg = crate::config::get();
|
||||
let max_age = cfg.scoring_interval_secs;
|
||||
let response_window = cfg.scoring_response_window;
|
||||
tokio::spawn(async move {
|
||||
// Check + snapshot under one brief lock
|
||||
let (context, client, cursor) = {
|
||||
let (context, client) = {
|
||||
let mut agent = agent.lock().await;
|
||||
if agent.agent_cycles.memory_scoring_in_flight {
|
||||
return;
|
||||
}
|
||||
let cursor = agent.agent_cycles.memory_score_cursor;
|
||||
agent.agent_cycles.memory_scoring_in_flight = true;
|
||||
// Count total unique memories
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for entry in &agent.context.entries {
|
||||
if let crate::agent::context::ConversationEntry::Memory { key, .. } = entry {
|
||||
seen.insert(key.clone());
|
||||
}
|
||||
}
|
||||
agent.agent_cycles.memory_total = seen.len();
|
||||
let _ = ui_tx.send(UiMessage::AgentUpdate(agent.agent_cycles.snapshots()));
|
||||
(agent.context.clone(), agent.client_clone(), cursor)
|
||||
(agent.context.clone(), agent.client_clone())
|
||||
};
|
||||
// Lock released — event loop is free
|
||||
|
||||
let result = crate::agent::training::score_memories_incremental(
|
||||
&context, cursor, &client, &ui_tx,
|
||||
&context, max_age as i64, response_window, &client, &ui_tx,
|
||||
).await;
|
||||
|
||||
// Brief lock — just update fields, no heavy work
|
||||
{
|
||||
let mut agent = agent.lock().await;
|
||||
agent.agent_cycles.memory_scoring_in_flight = false;
|
||||
if let Ok((new_cursor, ref scores)) = result {
|
||||
agent.agent_cycles.memory_score_cursor = new_cursor;
|
||||
agent.agent_cycles.memory_scores.extend(scores.clone());
|
||||
if let Ok(ref scores) = result {
|
||||
agent.agent_cycles.memory_scores = scores.clone();
|
||||
}
|
||||
}
|
||||
// Snapshot and log outside the lock
|
||||
match result {
|
||||
Ok(_) => {
|
||||
let agent = agent.lock().await;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue