seen_recent: separate current vs pre-compaction seen sets
Present the two seen sets separately to the surface agent: - Current: already in context, don't re-surface - Pre-compaction: context was reset, re-surface if still relevant This lets the agent re-inject important memories after compaction instead of treating everything ever surfaced as "already shown." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
870b87df1b
commit
9512dc0a31
1 changed files with 42 additions and 17 deletions
|
|
@ -495,36 +495,61 @@ fn resolve_seen_recent() -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
let state_dir = std::path::PathBuf::from("/tmp/claude-memory-search");
|
let state_dir = std::path::PathBuf::from("/tmp/claude-memory-search");
|
||||||
let mut entries: Vec<(String, String)> = Vec::new();
|
|
||||||
|
|
||||||
for suffix in ["", "-prev"] {
|
let parse_seen = |suffix: &str| -> Vec<(String, String)> {
|
||||||
let path = state_dir.join(format!("seen{}-{}", suffix, session_id));
|
let path = state_dir.join(format!("seen{}-{}", suffix, session_id));
|
||||||
if let Ok(content) = std::fs::read_to_string(&path) {
|
std::fs::read_to_string(&path).ok()
|
||||||
entries.extend(
|
.map(|content| {
|
||||||
content.lines()
|
content.lines()
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.filter_map(|line| {
|
.filter_map(|line| {
|
||||||
let (ts, key) = line.split_once('\t')?;
|
let (ts, key) = line.split_once('\t')?;
|
||||||
Some((ts.to_string(), key.to_string()))
|
Some((ts.to_string(), key.to_string()))
|
||||||
})
|
})
|
||||||
);
|
.collect()
|
||||||
}
|
})
|
||||||
}
|
.unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
if entries.is_empty() {
|
let current = parse_seen("");
|
||||||
|
let prev = parse_seen("-prev");
|
||||||
|
|
||||||
|
if current.is_empty() && prev.is_empty() {
|
||||||
return "(no memories surfaced yet this session)".to_string();
|
return "(no memories surfaced yet this session)".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort newest first, dedup
|
let mut out = String::new();
|
||||||
entries.sort_by(|a, b| b.0.cmp(&a.0));
|
|
||||||
let mut seen = std::collections::HashSet::new();
|
|
||||||
let recent: Vec<String> = entries.into_iter()
|
|
||||||
.filter(|(_, key)| seen.insert(key.clone()))
|
|
||||||
.take(20)
|
|
||||||
.map(|(ts, key)| format!("- {} (surfaced {})", key, ts))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
recent.join("\n")
|
// Current: already in this context, don't re-surface
|
||||||
|
if !current.is_empty() {
|
||||||
|
out.push_str("Already surfaced this context (don't re-surface unless conversation shifted):\n");
|
||||||
|
let mut seen = std::collections::HashSet::new();
|
||||||
|
for (ts, key) in ¤t {
|
||||||
|
if seen.insert(key.clone()) {
|
||||||
|
out.push_str(&format!("- {} (surfaced {})\n", key, ts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prev: surfaced before compaction, MAY need re-surfacing
|
||||||
|
if !prev.is_empty() {
|
||||||
|
let current_keys: std::collections::HashSet<_> = current.iter()
|
||||||
|
.map(|(_, k)| k.as_str()).collect();
|
||||||
|
let prev_only: Vec<_> = prev.iter()
|
||||||
|
.filter(|(_, k)| !current_keys.contains(k.as_str()))
|
||||||
|
.collect();
|
||||||
|
if !prev_only.is_empty() {
|
||||||
|
out.push_str("\nSurfaced before compaction (context was reset — re-surface if still relevant):\n");
|
||||||
|
let mut seen = std::collections::HashSet::new();
|
||||||
|
for (ts, key) in prev_only {
|
||||||
|
if seen.insert(key.clone()) {
|
||||||
|
out.push_str(&format!("- {} (pre-compaction, {})\n", key, ts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.trim_end().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve all {{placeholder}} patterns in a prompt template.
|
/// Resolve all {{placeholder}} patterns in a prompt template.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue