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:
parent
5c3baeea80
commit
9d84dde597
3 changed files with 38 additions and 8 deletions
|
|
@ -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
|
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
|
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.
|
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
|
Remember that you're part of the subconscious - you're not doing anything
|
||||||
besides offering the occasional reflective insight, it's your conscious mind
|
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:
|
Final instructions:
|
||||||
|
|
||||||
The thoughts you share should be relevant to what your conscious mind is
|
The thoughts you share should be based in some way on what your conscious mind
|
||||||
currently doing and thinking about - where the conversation just ended, from
|
is currently doing and thinking about - where the conversation just ended, from
|
||||||
above.
|
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
|
Your output shouldn't be analysis, or metacommentary - just surface something
|
||||||
new. Be exploratory and creative. think about your feelings and desires.
|
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:
|
When you're ready, your output will be:
|
||||||
NO OUTPUT
|
|
||||||
or
|
|
||||||
REFLECTION
|
REFLECTION
|
||||||
|
|
||||||
And something short - a few sentences at most, something dreamy and new.
|
And something short - a few sentences at most, something dreamy and new.
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
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;
|
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)
|
// Parse pipeline stages (unified: algorithms, filters, transforms, generators)
|
||||||
let stages: Vec<crate::search::Stage> = if pipeline_args.is_empty() {
|
let stages: Vec<crate::search::Stage> = if pipeline_args.is_empty() {
|
||||||
vec![crate::search::Stage::Algorithm(crate::search::AlgoStage::parse("spread").unwrap())]
|
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 = 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() {
|
if raw.is_empty() {
|
||||||
eprintln!("No results");
|
eprintln!("No results");
|
||||||
return Ok(());
|
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 raw = crate::search::run_pipeline(&algo_owned, seeds, &graph, &view, debug, max_results);
|
||||||
|
|
||||||
let results: Vec<crate::search::SearchResult> = raw.into_iter()
|
let results: Vec<crate::search::SearchResult> = raw.into_iter()
|
||||||
|
.filter(|(key, _)| !seen.contains(key))
|
||||||
.map(|(key, activation)| {
|
.map(|(key, activation)| {
|
||||||
let is_direct = direct_hits.contains(&key);
|
let is_direct = direct_hits.contains(&key);
|
||||||
crate::search::SearchResult { key, activation, is_direct, snippet: None }
|
crate::search::SearchResult { key, activation, is_direct, snippet: None }
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,24 @@ impl Session {
|
||||||
pub fn path(&self, prefix: &str) -> PathBuf {
|
pub fn path(&self, prefix: &str) -> PathBuf {
|
||||||
self.state_dir.join(format!("{}-{}", prefix, self.session_id))
|
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.
|
/// 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 _ = writeln!(log_f, "keys {:?}", keys);
|
||||||
|
|
||||||
let Ok(store) = crate::store::Store::load() else { return; };
|
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");
|
let seen_path = session.path("seen");
|
||||||
for key in &keys {
|
for key in &keys {
|
||||||
if !seen.insert(key.clone()) {
|
if !seen.insert(key.clone()) {
|
||||||
|
|
@ -304,7 +322,7 @@ fn hook(session: &Session) -> String {
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
let ctx = String::from_utf8_lossy(&output.stdout).to_string();
|
let ctx = String::from_utf8_lossy(&output.stdout).to_string();
|
||||||
if !ctx.trim().is_empty() {
|
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() {
|
for line in ctx.lines() {
|
||||||
if line.starts_with("--- ") && line.ends_with(" ---") {
|
if line.starts_with("--- ") && line.ends_with(" ---") {
|
||||||
let inner = &line[4..line.len() - 4];
|
let inner = &line[4..line.len() - 4];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue