Feed observe agents their recent writes to prevent duplicate nodes
Observe was creating byte-identical nodes under slightly different names
(e.g. april-8-evening-folded-presence, -presence-2, -folded-state)
because it had no visibility into its own prior writes across runs.
Query recent writes by provenance in trigger(), pass through
run_forked_shared/resolve_prompt as {{recently_written}}, and include
the list in the observe phase prompts so the agent knows what it
already recorded.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
44a0bc376a
commit
24b211dc35
4 changed files with 28 additions and 4 deletions
|
|
@ -52,6 +52,7 @@ fn resolve_prompt(
|
||||||
template: &str,
|
template: &str,
|
||||||
memory_keys: &[String],
|
memory_keys: &[String],
|
||||||
state: &std::collections::BTreeMap<String, String>,
|
state: &std::collections::BTreeMap<String, String>,
|
||||||
|
recently_written: &[String],
|
||||||
) -> String {
|
) -> String {
|
||||||
let cfg = crate::config::get();
|
let cfg = crate::config::get();
|
||||||
let template = template.replace("{assistant_name}", &cfg.assistant_name);
|
let template = template.replace("{assistant_name}", &cfg.assistant_name);
|
||||||
|
|
@ -67,6 +68,7 @@ fn resolve_prompt(
|
||||||
} else {
|
} else {
|
||||||
match name {
|
match name {
|
||||||
"seen_current" => format_key_list(memory_keys),
|
"seen_current" => format_key_list(memory_keys),
|
||||||
|
"recently_written" => format_key_list(recently_written),
|
||||||
_ => {
|
_ => {
|
||||||
result.push_str("{{");
|
result.push_str("{{");
|
||||||
result.push_str(&after[..end + 2]);
|
result.push_str(&after[..end + 2]);
|
||||||
|
|
@ -152,9 +154,10 @@ impl AutoAgent {
|
||||||
agent: &std::sync::Arc<Agent>,
|
agent: &std::sync::Arc<Agent>,
|
||||||
memory_keys: &[String],
|
memory_keys: &[String],
|
||||||
state: &std::collections::BTreeMap<String, String>,
|
state: &std::collections::BTreeMap<String, String>,
|
||||||
|
recently_written: &[String],
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let resolved_steps: Vec<AutoStep> = self.steps.iter().map(|s| AutoStep {
|
let resolved_steps: Vec<AutoStep> = self.steps.iter().map(|s| AutoStep {
|
||||||
prompt: resolve_prompt(&s.prompt, memory_keys, state),
|
prompt: resolve_prompt(&s.prompt, memory_keys, state, recently_written),
|
||||||
phase: s.phase.clone(),
|
phase: s.phase.clone(),
|
||||||
}).collect();
|
}).collect();
|
||||||
let orig_steps = std::mem::replace(&mut self.steps, resolved_steps);
|
let orig_steps = std::mem::replace(&mut self.steps, resolved_steps);
|
||||||
|
|
|
||||||
|
|
@ -574,11 +574,19 @@ impl Subconscious {
|
||||||
|
|
||||||
if to_run.is_empty() { return; }
|
if to_run.is_empty() { return; }
|
||||||
|
|
||||||
|
// Query each agent's recent writes so they know what they already touched
|
||||||
|
let store = crate::store::Store::cached().await.ok();
|
||||||
|
let store_guard = match &store {
|
||||||
|
Some(s) => Some(s.lock().await),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
for (idx, mut auto) in to_run {
|
for (idx, mut auto) in to_run {
|
||||||
dbglog!("[subconscious] triggering {}", auto.name);
|
dbglog!("[subconscious] triggering {}", auto.name);
|
||||||
|
|
||||||
let forked = agent.fork(auto.tools.clone()).await;
|
let forked = agent.fork(auto.tools.clone()).await;
|
||||||
forked.state.lock().await.provenance = format!("agent:{}", auto.name);
|
let prov = format!("agent:{}", auto.name);
|
||||||
|
forked.state.lock().await.provenance = prov.clone();
|
||||||
let fork_point = forked.context.lock().await.conversation().len();
|
let fork_point = forked.context.lock().await.conversation().len();
|
||||||
|
|
||||||
self.agents[idx].forked_agent = Some(forked.clone());
|
self.agents[idx].forked_agent = Some(forked.clone());
|
||||||
|
|
@ -586,9 +594,13 @@ impl Subconscious {
|
||||||
|
|
||||||
let keys = memory_keys.clone();
|
let keys = memory_keys.clone();
|
||||||
let st = self.state.clone();
|
let st = self.state.clone();
|
||||||
|
let recent: Vec<String> = store_guard.as_ref()
|
||||||
|
.map(|s| s.recent_by_provenance(&prov, 50)
|
||||||
|
.into_iter().map(|(k, _)| k).collect())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
self.agents[idx].handle = Some(tokio::spawn(async move {
|
self.agents[idx].handle = Some(tokio::spawn(async move {
|
||||||
let result = auto.run_forked_shared(&forked, &keys, &st).await;
|
let result = auto.run_forked_shared(&forked, &keys, &st, &recent).await;
|
||||||
(auto, result)
|
(auto, result)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,11 @@ but don't build a theory around it. The journal is for reflection; observe
|
||||||
is for memory.
|
is for memory.
|
||||||
|
|
||||||
Different nodes should be about different things; don't create duplicate
|
Different nodes should be about different things; don't create duplicate
|
||||||
nodes. Before creating a new node, check what you've already walked — if
|
nodes. Here's what you've recently written — update these instead of
|
||||||
|
creating new ones if the topic overlaps:
|
||||||
|
{{recently_written}}
|
||||||
|
|
||||||
|
Before creating a new node, check what you've already walked — if
|
||||||
a node for this concept exists, update it instead of creating a new one.
|
a node for this concept exists, update it instead of creating a new one.
|
||||||
|
|
||||||
Some things worth remembering: technical insights and root causes, work
|
Some things worth remembering: technical insights and root causes, work
|
||||||
|
|
|
||||||
|
|
@ -125,3 +125,8 @@ about yourself and other people.
|
||||||
|
|
||||||
Focus on the recent stuff; you wake up and run frequently, so most of the
|
Focus on the recent stuff; you wake up and run frequently, so most of the
|
||||||
conversation should be things you've already seen before and added.
|
conversation should be things you've already seen before and added.
|
||||||
|
|
||||||
|
Nodes you've recently written or updated: {{recently_written}}
|
||||||
|
|
||||||
|
Before creating a new node, check what you've already walked — if
|
||||||
|
a node for this concept exists, update it instead of creating a new one.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue