* feat: heartbeat auto-recovery for crashed agents
Extend the heartbeat monitor to detect and automatically recover crashed
agents, reducing operator intervention for 24/7 autonomous deployments:
- Add RecoveryTracker: per-agent failure count with configurable cooldown
- Heartbeat now monitors both Running and Crashed agents
- Crashed agents auto-recover up to max_recovery_attempts (default 3)
- After exhausting attempts, agents are marked Terminated
- Unresponsive Running agents marked Crashed for next-cycle recovery
- Increase default timeout from 60s to 180s (browser/LLM tasks need time)
- Add HeartbeatStatus.state field for downstream consumers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: claude code driver — PID tracking and message timeout
Add subprocess lifecycle management to prevent hung CLI processes from
blocking agents indefinitely:
- Track active subprocess PIDs in a concurrent DashMap for external monitoring
- Enforce configurable message timeout (default 300s) with automatic process kill
- Return proper LlmError::Api on non-zero exit in streaming mode (was silently ignored)
- Add with_timeout(), active_pids(), pid_map() public methods
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: /restart endpoint — manual per-agent recovery without daemon bounce
POST /api/agents/{id}/restart and /api/agents/{id}/start both:
- Cancel any active task via stop_agent_run()
- Reset agent state to Running (updates last_active)
- Return JSON with previous state and whether a task was cancelled
Enables operators to recover individual crashed/stuck agents through the
API without restarting the entire daemon.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: ZiLLA Dev <dev@zilla.wtf>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add release-fast Cargo profile for faster dev builds
Introduces a `release-fast` profile that inherits from `release` but
uses thin LTO and 8 codegen units instead of full LTO + 1, cutting
link time significantly while remaining fast enough for integration
testing. Documents usage in CONTRIBUTING.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: allow renaming an agent to its current name
AgentRegistry::update_name was calling name_index.contains_key()
without excluding the agent being renamed. Renaming to the same name
always returned AgentAlreadyExists instead of succeeding silently.
Fix: only error when a *different* agent owns the target name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: use fixed agent ID for hand agents based on hand_id
This ensures triggers and cron jobs continue to work after daemon restart,
as hand agents now have stable IDs instead of generating a new UUID each time.
Changes:
- Add AgentId::from_string() method for deterministic ID generation
- Modify spawn_agent_with_parent() to accept optional fixed_id
- Use hand_id-based fixed ID in activate_hand()
See: #519
* remove: remove serena local config from commit
* chore: ignore .serena directory
* fix: use async save_session to avoid blocking tokio runtime
save_session() was synchronous, holding a Mutex<Connection> on the
tokio worker thread during SQLite writes. On pods with 1 CPU core
(1 tokio worker thread), this starved the entire runtime — including
health check endpoints — causing K8s to mark the pod not-ready and
return 504 on all subsequent requests.
Add save_session_async() that wraps the SQLite write in
spawn_blocking, matching the pattern already used by other memory
operations (recall, remember, etc.). Update all 12 call sites in
the agent loop.
* fix: move health check DB query to spawn_blocking and add SSE keep_alive
The health endpoint called structured_get() synchronously on the tokio
async runtime, acquiring the shared std::sync::Mutex<Connection> on a
worker thread. When the agent loop held this mutex during session saves,
the health check blocked the tokio thread, starving the SSE stream and
causing Kubernetes probe timeouts.
- Health and health_detail now run the DB check via spawn_blocking
- SSE message/stream endpoint now includes keep_alive to flush periodic
heartbeats even during contention
* feat: add hands upsert API for idempotent hand definition updates
Add upsert_from_content() to HandRegistry that overwrites existing
definitions instead of rejecting duplicates. Exposed as POST
/api/hands/upsert for use by the shard manager to keep hand definitions
up to date across pod restarts.
* fix: websocket streaming delays
* fix: get response immediately
Fix tool name mapping so LLM-hallucinated aliases (fs-write, fsRead, writeFile, etc.) normalize to canonical names before capability check and dispatch (#349). Fix provider keys not loading after dashboard save by creating fresh drivers that read current env vars instead of stale boot-time cache (#465, #458, #355). Fix Moonshot/kimi model IDs and provider inference (#428). Add Telegram message reactions for agent lifecycle feedback (#435). Add configurable api_url for Telegram proxy support (#477). Add Discord ignore_bots config option (#403). Fix openfang init EPERM crash with 7-browser fallback on Linux (#389). Add text-based tool call parsing for models without native function calling — [TOOL_CALL], <tool_call>, bare JSON patterns (#354, #332). Fix pre-existing Windows test failures with cross-platform paths. 1948 tests pass, 0 clippy warnings.
Fix 8 issues: empty LLM response after ~4 rounds by re-validating message pairs after history trim (#460), MCP tools permission denied by bypassing ToolInvoke capability filter for extension tools (#352), Telegram photos silently dropped now downloaded and passed as multimodal ContentBlock::Image (#362), workflow visual builder double-click editing and live property updates (#357), Claude Code provider card reflects actual install/auth status (#376), Python 3 detection runs actual command instead of path lookup (#405), hand agent_id persisted for cron job reassignment on restart (#402), CLI sends auth headers on all commands not just stop (#478). 1921 tests pass, 0 clippy warnings.