- #962: WebSocket auth now URL-decodes token before comparison. API keys with +/=/
characters (base64-derived) now work correctly for WS streaming.
- #939: Clippy bool_comparison lint fixed in web_fetch.rs test.
- #983: Dockerfile adds perl and make for openssl-sys compilation on slim-bookworm.
- #987: Nextcloud chat poll endpoint corrected from api/v4/room/{token}/chat to
api/v1/chat/{token}/ matching the send endpoint.
- #970: Moonshot Kimi K2/K2.5 models now redirect to api.moonshot.cn/v1 instead of
api.moonshot.ai/v1. The .ai domain only serves legacy moonshot-v1-* models.
- #882: Closed as resolved by v0.5.7 custom hand persistence fix (#984).
- #926: Verified already fixed (rmcp builder API from previous session).
All tests passing. 8 files changed, 75 insertions.
Bug: in activate_hand(), kill_agent() is called on the existing agent
BEFORE the new agent is spawned. kill_agent() invokes
cron_scheduler.remove_agent_jobs() which deletes all cron jobs from memory
AND persists [] to cron_jobs.json. The reassign_agent_jobs() call further
down was meant to migrate jobs from old to new (per #461), but it always
runs as a no-op because the jobs are already gone — the order of
operations defeats the fix.
Symptom: every daemon restart silently destroys cron jobs for hand-style
agents. cron_jobs.json is rewritten as []. /api/cron/jobs returns empty.
No error message.
Fix: snapshot the cron jobs into a local Vec BEFORE kill_agent (same
pattern as saved_triggers above), then re-add them under the new agent_id
AFTER spawn_agent_with_parent. Runtime state (next_run, last_run) is
reset so jobs get a fresh start. The existing reassign_agent_jobs()
block is kept as a defensive safety net but is now redundant in the
common path.
Verified with cargo check -p openfang-kernel --lib (clean compile, no
warnings).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When an LLM produces text alongside tool_use blocks (e.g., a chat
message followed by memory_store calls), the text was lost if the
final EndTurn iteration returned empty text. The empty-response guard
would activate and return "[Task completed — the agent executed tools
but did not produce a text summary.]" even though the agent DID
produce text in an earlier iteration.
This is a common pattern when agents are instructed to respond to
users AND persist state via memory_store in the same turn.
Fix: accumulate text content from all ToolUse iterations. When the
final EndTurn has empty text, use accumulated text as fallback before
triggering the empty-response guard.
Applied to both sync and streaming agent loop paths.
Built-in templates and the spawn wizard both hardcoded
provider = "groq" / model = "llama-3.3-70b-versatile" in the
manifest TOML sent to the API. The kernel's default_model overlay
only activates when provider/model are empty or "default", so
hardcoded values bypassed the user's configured default entirely.
Fixes#967
The agent config reload logic was missing skills and mcp_servers from
the change detection, so edits to these fields in agent.toml weren't
being picked up when loading agents from SQLite.
Added both fields to the comparison to ensure proper hot-reload.
The previous commit accidentally included a complete MCP module rewrite
that removed Http transport and headers support, breaking compilation
against upstream kernel.rs tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>