Forked agents: stop gracefully on context overflow instead of compacting
Subconscious agents (observe, etc.) fork the conscious agent's context to share the KV cache prefix. When a multi-step agent fills the context window, compacting blows the KV cache and evicts the step prompts, leaving the model with no idea what it was doing. Fix: forked agents set no_compact=true. On overflow, turn() returns the error immediately (no compact+retry), and run_with_backend catches it and returns Ok — the output tool has already written results to Subconscious.state, so collect_results still picks them up. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
850008ece7
commit
44a0bc376a
2 changed files with 24 additions and 8 deletions
|
|
@ -155,6 +155,9 @@ pub struct AgentState {
|
||||||
pub generation: u64,
|
pub generation: u64,
|
||||||
pub memory_scoring_in_flight: bool,
|
pub memory_scoring_in_flight: bool,
|
||||||
pub active_tools: tools::ActiveTools,
|
pub active_tools: tools::ActiveTools,
|
||||||
|
/// Forked agents should not compact on overflow — it blows the
|
||||||
|
/// KV cache prefix and evicts the step prompts.
|
||||||
|
pub no_compact: bool,
|
||||||
pub changed: Arc<tokio::sync::Notify>,
|
pub changed: Arc<tokio::sync::Notify>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,6 +217,7 @@ impl Agent {
|
||||||
generation: 0,
|
generation: 0,
|
||||||
memory_scoring_in_flight: false,
|
memory_scoring_in_flight: false,
|
||||||
active_tools,
|
active_tools,
|
||||||
|
no_compact: false,
|
||||||
changed: Arc::new(tokio::sync::Notify::new()),
|
changed: Arc::new(tokio::sync::Notify::new()),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
@ -249,6 +253,7 @@ impl Agent {
|
||||||
generation: 0,
|
generation: 0,
|
||||||
memory_scoring_in_flight: false,
|
memory_scoring_in_flight: false,
|
||||||
active_tools: tools::ActiveTools::new(),
|
active_tools: tools::ActiveTools::new(),
|
||||||
|
no_compact: true,
|
||||||
changed: Arc::new(tokio::sync::Notify::new()),
|
changed: Arc::new(tokio::sync::Notify::new()),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
@ -354,12 +359,17 @@ impl Agent {
|
||||||
// Check for stream/parse errors
|
// Check for stream/parse errors
|
||||||
match parser_handle.await {
|
match parser_handle.await {
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
if context::is_context_overflow(&e) && overflow_retries < 2 {
|
if context::is_context_overflow(&e) {
|
||||||
overflow_retries += 1;
|
if agent.state.lock().await.no_compact {
|
||||||
agent.state.lock().await.notify(
|
return Err(e);
|
||||||
format!("context overflow — retrying ({}/2)", overflow_retries));
|
}
|
||||||
agent.compact().await;
|
if overflow_retries < 2 {
|
||||||
continue;
|
overflow_retries += 1;
|
||||||
|
agent.state.lock().await.notify(
|
||||||
|
format!("context overflow — retrying ({}/2)", overflow_retries));
|
||||||
|
agent.compact().await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,8 +186,14 @@ impl AutoAgent {
|
||||||
for _ in 0..max_turns {
|
for _ in 0..max_turns {
|
||||||
self.turn += 1;
|
self.turn += 1;
|
||||||
|
|
||||||
let result = Agent::turn(backend.0.clone()).await
|
let result = match Agent::turn(backend.0.clone()).await {
|
||||||
.map_err(|e| format!("{}: {}", self.name, e))?;
|
Ok(r) => r,
|
||||||
|
Err(e) if super::context::is_context_overflow(&e) => {
|
||||||
|
dbglog!("[auto] {} context full, stopping gracefully", self.name);
|
||||||
|
return Ok(String::new());
|
||||||
|
}
|
||||||
|
Err(e) => return Err(format!("{}: {}", self.name, e)),
|
||||||
|
};
|
||||||
|
|
||||||
if result.had_tool_calls {
|
if result.had_tool_calls {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue