Merge pull request #709 from Fail-Safe/fix/touch-agent-before-llm-call

fix: stamp last_active before LLM call to prevent mid-iteration heartbeat timeouts
This commit is contained in:
Jaber Jaber
2026-03-27 16:25:26 +03:00
committed by GitHub
4 changed files with 26 additions and 0 deletions
+6
View File
@@ -5845,6 +5845,12 @@ impl KernelHandle for OpenFangKernel {
.collect()
}
fn touch_agent(&self, agent_id: &str) {
if let Ok(id) = agent_id.parse::<AgentId>() {
self.registry.touch(id);
}
}
fn kill_agent(&self, agent_id: &str) -> Result<(), String> {
let id: AgentId = agent_id
.parse()
+8
View File
@@ -256,6 +256,14 @@ impl AgentRegistry {
Ok(())
}
/// Touch an agent — refresh last_active without changing any other state.
/// Used by the agent loop to prevent heartbeat false-positives during long LLM calls.
pub fn touch(&self, id: AgentId) {
if let Some(mut entry) = self.agents.get_mut(&id) {
entry.last_active = chrono::Utc::now();
}
}
/// Update an agent's system prompt (hot-swap, takes effect on next message).
pub fn update_system_prompt(&self, id: AgentId, new_prompt: String) -> OpenFangResult<()> {
let mut entry = self
@@ -381,6 +381,12 @@ pub async fn run_agent_loop(
cb(LoopPhase::Thinking);
}
// Stamp last_active before the (potentially long) LLM call so the
// heartbeat monitor doesn't flag us as unresponsive mid-iteration.
if let Some(k) = &kernel {
k.touch_agent(&agent_id_str);
}
// Call LLM with retry, error classification, and circuit breaker
let provider_name = manifest.model.provider.as_str();
let mut response = call_with_retry(&*driver, request, Some(provider_name), None, &manifest.fallback_models).await?;
@@ -238,6 +238,12 @@ pub trait KernelHandle: Send + Sync {
Err("Channel file data send not available".to_string())
}
/// Refresh an agent's last_active timestamp without changing any other state.
/// Called by the agent loop before long LLM calls to prevent heartbeat false-positives.
fn touch_agent(&self, agent_id: &str) {
let _ = agent_id;
}
/// Spawn an agent with capability inheritance enforcement.
/// `parent_caps` are the parent's granted capabilities. The kernel MUST verify
/// that every capability in the child manifest is covered by `parent_caps`.