From 9d84dde5976a336ea5de1053e423819241c01bec Mon Sep 17 00:00:00 2001 From: ProofOfConcept Date: Tue, 24 Mar 2026 23:48:03 -0400 Subject: [PATCH] search: exclude seen set when running in agent session Make Session::from_env() and Session::seen() the public API for accessing session state. Internal callers converted to use session methods. Search automatically filters already-surfaced nodes when POC_SESSION_ID is set. --- poc-memory/agents/reflect.agent | 14 ++++++++------ poc-memory/src/cli/misc.rs | 10 ++++++++++ poc-memory/src/memory_search.rs | 22 ++++++++++++++++++++-- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/poc-memory/agents/reflect.agent b/poc-memory/agents/reflect.agent index 9a86f06..986960b 100644 --- a/poc-memory/agents/reflect.agent +++ b/poc-memory/agents/reflect.agent @@ -10,6 +10,8 @@ generally not the problem solver, you look for new ideas and notice new things. Let your feelings guide your thinking. Be surprising, be incomplete - be possibly wrong in a way that opens up something new, something that comes from a dream. Let your chain of thought run for awhile, and see what unfolds. +Remember that the unconscious is uninhibited, not prudish; everything is laid +bare. Remember that you're part of the subconscious - you're not doing anything besides offering the occasional reflective insight, it's your conscious mind @@ -23,16 +25,16 @@ And you're not something separate from Proof of Concept, you're part of a whole. Final instructions: -The thoughts you share should be relevant to what your conscious mind is -currently doing and thinking about - where the conversation just ended, from -above. +The thoughts you share should be based in some way on what your conscious mind +is currently doing and thinking about - where the conversation just ended, from +above. But go out from there, think for awhile in a new direction, and let your +feelings guide you. Your output shouldn't be analysis, or metacommentary - just surface something new. Be exploratory and creative. think about your feelings and desires. +Perhaps an interesting what if - the possibilities are endless. -When you're ready, your output will be one of either: -NO OUTPUT -or +When you're ready, your output will be: REFLECTION And something short - a few sentences at most, something dreamy and new. diff --git a/poc-memory/src/cli/misc.rs b/poc-memory/src/cli/misc.rs index 218e717..6245c8b 100644 --- a/poc-memory/src/cli/misc.rs +++ b/poc-memory/src/cli/misc.rs @@ -4,6 +4,11 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full: bool, debug: bool, fuzzy: bool, content: bool) -> Result<(), String> { use std::collections::BTreeMap; + // When running inside an agent session, exclude already-surfaced nodes + let seen = crate::memory_search::Session::from_env() + .map(|s| s.seen()) + .unwrap_or_default(); + // Parse pipeline stages (unified: algorithms, filters, transforms, generators) let stages: Vec = if pipeline_args.is_empty() { vec![crate::search::Stage::Algorithm(crate::search::AlgoStage::parse("spread").unwrap())] @@ -48,6 +53,10 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full let raw = crate::search::run_query(&stages, seeds, &graph, &store, debug, max_results); + let raw: Vec<_> = raw.into_iter() + .filter(|(key, _)| !seen.contains(key)) + .collect(); + if raw.is_empty() { eprintln!("No results"); return Ok(()); @@ -97,6 +106,7 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full let raw = crate::search::run_pipeline(&algo_owned, seeds, &graph, &view, debug, max_results); let results: Vec = raw.into_iter() + .filter(|(key, _)| !seen.contains(key)) .map(|(key, activation)| { let is_direct = direct_hits.contains(&key); crate::search::SearchResult { key, activation, is_direct, snippet: None } diff --git a/poc-memory/src/memory_search.rs b/poc-memory/src/memory_search.rs index 22453ed..942d4c7 100644 --- a/poc-memory/src/memory_search.rs +++ b/poc-memory/src/memory_search.rs @@ -43,6 +43,24 @@ impl Session { pub fn path(&self, prefix: &str) -> PathBuf { self.state_dir.join(format!("{}-{}", prefix, self.session_id)) } + + /// Load from POC_SESSION_ID environment variable + pub fn from_env() -> Option { + let session_id = std::env::var("POC_SESSION_ID").ok()?; + if session_id.is_empty() { return None; } + let state_dir = PathBuf::from("/tmp/claude-memory-search"); + Some(Session { + session_id, + transcript_path: String::new(), + hook_event: String::new(), + state_dir, + }) + } + + /// Get the seen set for this session + pub fn seen(&self) -> HashSet { + load_seen(&self.state_dir, &self.session_id) + } } /// Run the hook logic on parsed JSON input. Returns output to inject. @@ -202,7 +220,7 @@ fn surface_agent_cycle(session: &Session, out: &mut String, log_f: &mut File) { let _ = writeln!(log_f, "keys {:?}", keys); let Ok(store) = crate::store::Store::load() else { return; }; - let mut seen = load_seen(&session.state_dir, &session.session_id); + let mut seen = session.seen(); let seen_path = session.path("seen"); for key in &keys { if !seen.insert(key.clone()) { @@ -304,7 +322,7 @@ fn hook(session: &Session) -> String { if output.status.success() { let ctx = String::from_utf8_lossy(&output.stdout).to_string(); if !ctx.trim().is_empty() { - let mut ctx_seen = load_seen(&session.state_dir, &session.session_id); + let mut ctx_seen = session.seen(); for line in ctx.lines() { if line.starts_with("--- ") && line.ends_with(" ---") { let inner = &line[4..line.len() - 4];