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.
This commit is contained in:
ProofOfConcept 2026-03-24 23:48:03 -04:00
parent 5c3baeea80
commit 9d84dde597
3 changed files with 38 additions and 8 deletions

View file

@ -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.

View file

@ -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<crate::search::Stage> = 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<crate::search::SearchResult> = 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 }

View file

@ -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<Self> {
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<String> {
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];