- Add dedicated "heartbeat" target in memory_write tool so the LLM
routes HEARTBEAT.md writes to the database instead of the filesystem
- Update tool description to clarify it's database-backed storage
- Broadcast heartbeat notifications to all channels when no explicit
notify target is configured, instead of silently logging them
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The heartbeat feature was dead on arrival: nothing ever created HEARTBEAT.md,
so the runner silently skipped every cycle. Now the workspace returns an
in-memory seed template when the file doesn't exist in the database (no DB
write), and the runner detects "effectively empty" content (headers, HTML
comments, bare list markers) to avoid wasting LLM API calls on placeholder
templates. The user creates the real DB entry via memory_write when they
actually want periodic checks.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Thread message metadata through Channel::send_status so WASM channels
can route status updates (like typing indicators) to the correct chat.
The WasmChannel spawns a background task that repeats on_status every
4 seconds to keep Telegram's typing bubble alive until the response
is sent.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add escape_telegram_markdown() to handle underscores in tool names
(e.g., build_software was breaking Telegram's Markdown parser)
- Use Telegram-compatible *bold* syntax instead of **bold**
- Clarify workspace memory vs filesystem tool descriptions to prevent
LLM from using read_file on memory_tree paths
- Update build_software to strongly prefer Rust WASM for agent tools
- Rewrite WASM tool template to use Component Model with wit_bindgen
instead of outdated extern "C" approach
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove the brittle natural language pattern matching from the router
and add job management tools to the normal tool registry instead.
- Add job tools: create_job, list_jobs, job_status, cancel_job
- Router now only handles explicit /commands
- Natural language goes through agentic loop with all tools
- LLM naturally picks appropriate tools based on user intent
- Share ContextManager between job tools and Agent
Co-Authored-By: Claude Opus 4.5 <[email protected]>
The test expected "Can you create a website for me?" to route as CreateJob,
but the extract_intent logic intentionally requires explicit job creation
patterns (containing both "create" and "job") to avoid capturing general
conversation as job requests.
Updated test to verify:
- "create job: ..." routes to CreateJob
- Messages with both "create" and "job" route to CreateJob
- General requests without explicit "job" fall through to Chat
Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit addresses three critical issues from code review:
1. Tool approval enforcement: Tools declaring requires_approval() (shell,
http, file write/patch, build_software) now gate execution. Adds
PendingApproval struct, session-scoped auto-approved tools set, and
approval flow with yes/no/always commands.
2. Tool definition refresh: Tool definitions now refresh each iteration
in both chat and job loops, so newly built tools become visible
immediately within the same session.
3. Worker tool call handling: Changed respond() to respond_with_tools()
when select_tools returns empty, properly executing tool calls instead
of formatting them as text.
Also includes prior work from the plan:
- Wire embeddings provider (OpenAI + NEAR AI) to workspace
- Load workspace system prompt (identity files) into LLM context
- Route heartbeat notifications through channel manager
- Enable auto-context compaction when threshold exceeded
- Refactor to config structs (AgentDeps, WorkerDeps, LlmCallRecord)
- Fix clippy warnings (saturating_sub, too_many_arguments)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add HeartbeatConfig for proactive periodic execution with channel notifications
- Add use_planning option to Worker for ActionPlan generation before tool execution
- Implement tool failure tracking in database (V3 migration)
- Add auto-repair via Builder for broken WASM tools in self_repair.rs
- Record tool failures in Worker for self-repair tracking
- Update .env.example with new configuration options
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add StatusUpdate enum with Thinking, ToolStarted, ToolCompleted, StreamChunk, Status variants
- Add send_status method to Channel trait (default no-op)
- Implement send_status in TuiChannel to show status in UI
- Add send_status to ChannelManager for routing to specific channels
- Update handle_message to send "Processing..." status for Chat/CreateJob
- Update handle_chat to send "Generating response..." and show errors
Now when a user sends a message, they see feedback that the agent is working.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
When the TUI quits (Ctrl+D twice), it now:
1. Sends a "/shutdown" message through the channel before closing
2. Explicitly drops msg_tx to ensure channel closure
The agent loop now:
1. Returns Option<String> from handle_message (None = shutdown)
2. Handles /quit, /exit, /shutdown commands by returning None
3. Breaks out of the main loop on shutdown signal
4. Lists /quit in help menu
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Persist jobs and actions to PostgreSQL using fire-and-forget pattern:
- Scheduler passes store to Worker, persists cancellations
- Worker persists job status changes and tool execution actions
- Agent persists new jobs on creation
- All DB writes use tokio::spawn to avoid blocking execution
Store remains optional to preserve --no-db mode.
Co-Authored-By: Claude Opus 4.5 <[email protected]>