agent visits: track when agents successfully process nodes

New append-only visits.capnp log records which agent processed which
node and when. Only recorded on successful completion — transient
errors don't mark nodes as "seen."

Schema: AgentVisit{nodeUuid, nodeKey, agent, timestamp, outcome}
Storage: append_visits(), replay_visits(), in-memory VisitIndex
Recording: daemon records visits after successful LLM call
API: agent_prompt() returns AgentBatch{prompt, node_keys} so callers
know which nodes to mark as visited.

Groundwork for using visit recency in agent node selection — agents
will deprioritize recently-visited nodes.
This commit is contained in:
ProofOfConcept 2026-03-10 14:30:53 -04:00
parent 9f14a29181
commit 0e1e5a1981
6 changed files with 237 additions and 34 deletions

View file

@ -98,8 +98,8 @@ pub fn consolidate_full_with_progress(
*store = Store::load()?;
}
let prompt = match super::prompts::agent_prompt(store, agent_type, *count) {
Ok(p) => p,
let agent_batch = match super::prompts::agent_prompt(store, agent_type, *count) {
Ok(b) => b,
Err(e) => {
let msg = format!(" ERROR building prompt: {}", e);
log_line(&mut log_buf, &msg);
@ -109,10 +109,10 @@ pub fn consolidate_full_with_progress(
}
};
log_line(&mut log_buf, &format!(" Prompt: {} chars (~{} tokens)",
prompt.len(), prompt.len() / 4));
log_line(&mut log_buf, &format!(" Prompt: {} chars (~{} tokens), {} nodes",
agent_batch.prompt.len(), agent_batch.prompt.len() / 4, agent_batch.node_keys.len()));
let response = match call_sonnet("consolidate", &prompt) {
let response = match call_sonnet("consolidate", &agent_batch.prompt) {
Ok(r) => r,
Err(e) => {
let msg = format!(" ERROR from Sonnet: {}", e);
@ -131,6 +131,13 @@ pub fn consolidate_full_with_progress(
store::Provenance::AgentConsolidate).ok();
reports.push(report_key.clone());
// Record visits for successfully processed nodes
if !agent_batch.node_keys.is_empty() {
if let Err(e) = store.record_agent_visits(&agent_batch.node_keys, agent_type) {
log_line(&mut log_buf, &format!(" Visit recording: {}", e));
}
}
let msg = format!(" Done: {} lines → {}", response.lines().count(), report_key);
log_line(&mut log_buf, &msg);
on_progress(&msg);