| Age | Commit message (Collapse) | Author |
|
Phase 1 of subagent architecture redesign. Adds Jobs.hs with:
- subagent_jobs table for persistent job queue
- subagent_events table for lifecycle event log
- Job CRUD: create, claim, complete, fail, cancel
- Event logging for started, progress, tool_call, error, completed
- Queries: pending jobs, running jobs, active summary for context
- All tests passing
This enables:
- Jobs survive process restarts
- Workers can claim and execute jobs independently
- Events flow back to Ava's context for collaborative debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- Systemd.hs: add LANG and LC_ALL defaults (en_US.utf8) to all
generated unit files to ensure proper UTF-8 handling
- Systemd.hs: add generateUnitWithLocale that reads LOCALE_ARCHIVE
from the deployer's environment and injects it into generated units
- Telegram.hs: add safePutText wrapper that catches encoding errors
in logging to prevent them from killing message sends
The root cause was NixOS systemd services not inheriting locale
settings from the system, causing emoji characters to fail encoding.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
Wrap processFn in try/catch so exceptions don't kill the batcher thread.
Previously, if a message handler threw an exception, the batcher would
die and subsequent messages would be received but not processed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
Use `cd <path> && direnv exec .` instead of `direnv exec <path>` since
the latter doesn't work correctly with nix-direnv caching.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- Add omniRepoDir constant for the repo path
- Use direnv exec with explicit path instead of "."
- Update ava manifest workingDirectory to /home/ava
This separates Ava's working directory from Coder's repo directory.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
The Coder subagent was ignoring per-spawn guardrails from
subagentGuardrails and always using SubagentConfig defaults.
Now uses getGuardrail helper to check SpawnGuardrails first,
falling back to SubagentConfig defaults if not specified.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- Add SpawnGuardrails type for per-spawn resource limits
- Extend SubagentConfig with toolsOverride, systemPrompt, guardrails
- Add General role with balanced tools (file ops, bash, python, search)
- Update spawn_subagent schema to expose general/custom roles and new params
- Add subagent delegation guidance to Ava's system prompt
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
Only record user's chat_id for private chats, not group chats.
Previously, interacting in a group would overwrite the user's
chat_id, causing personal reminders to be sent to that group.
|
|
- Add subagent completion callback to notify user when subagent finishes
- Show tool name in 'view trace' link (e.g. 'view web_search trace')
- Pretty-print JSON on trace web page using aeson-pretty
Amp-Thread-ID: https://ampcode.com/threads/T-019b3a13-bc75-7368-9ec9-362d462a022c
Co-authored-by: Amp <amp@ampcode.com>
|
|
Tools.hs:
- run_bash now uses mkSuccess (applies truncation)
- read_file requires line ranges for files >500 lines
- read_file rejects ranges >400 lines
Engine.hs:
- Added engine-level truncateToolResult (10k char cap)
- Fixed test detection: bash -> run_bash
|
|
- Rewrote system prompt with TOKEN EFFICIENCY section
- Reduced defaults: timeout 600s, maxCost 50¢, maxTokens 100k
- Added output truncation (8000 char cap) to all tools
- Tightened search limits (30 results, 5 context lines)
|
|
- Add SQLite storage for tool traces (Omni/Ava/Trace.hs)
- Add web server to serve trace viewer (Omni/Ava/Web.hs)
- Add HTML/CSS/JS trace viewer UI (Omni/Ava/Web/trace.html)
- Integrate trace storage into Engine.hs tool execution callback
- Add trace links to Telegram responses when AVA_WEB_URL is set
- Configure Tailscale Funnel for public access
- Fix pre-push hook variable scope bug
- Add direnv, bash, nix to Ava service PATH
- Add mustache dep to Ava.hs for template rendering
Epic: t-272
|
|
- Telegram.hs: add loadTelegramSystemPrompt with fallback
- Subagent.hs: add loadSystemPromptForRole with fallback
- Coder.hs: add loadCoderSystemPrompt with fallback
- Ava.nix: add tmpfiles rules for /home/ava/prompts/
- Prompts.hs: fix test to expect .mustache extension
Templates loaded at runtime from $AVA_DATA_ROOT/prompts/.
Falls back to hardcoded prompts if templates not found.
Amp-Thread-ID: https://ampcode.com/threads/T-019b3878-73be-77ec-97cc-d092a28d211e
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Add promptsDir to Paths.hs for $AVA_DATA_ROOT/prompts/
- Create Omni.Agent.Prompts module with:
- Mustache template loading and rendering
- Automatic partial resolution via automaticCompile
- Frontmatter/metadata parsing for list command
- Create omni-agent-prompt CLI for previewing prompts:
- list: show all available prompts
- render: render prompt with --var and --json context
- Prompts use .mustache extension for automaticCompile compatibility
- Partials referenced with full extension: {{> shared/memory.mustache}}
|
|
- Add AuditLog import to Telegram.hs
- Call writeAvaLog for user messages in both handleEngagement paths
- Call writeAvaLog for assistant responses
- Add logs directories to Ava.nix tmpfiles rules
|
|
- Add chat_history table with embeddings in memory.db
- Add saveChatHistoryEntry for live message ingestion
- Add searchChatHistorySemantic for vector similarity search
- Update search_chat_history tool to use semantic search
- Add backfill command: run.sh Omni/Agent/Memory.hs backfill
- Add stats command: run.sh Omni/Agent/Memory.hs stats
- Change default memory.db path to ~/memory.db
- Wire Telegram message handling to save to chat_history async
|
|
Allows Ava to search her conversation logs for past discussions.
Searches UserMessage/AssistantMessage events with case-insensitive
matching, configurable days_back (default 7) and max_results (default 20).
|
|
|
|
|
|
The coder role no longer requires task_id, only namespace.
|
|
- Strengthen Telegram MarkdownV2 formatting guidance in Ava's system prompt
- Add DNS record beryl.bensima.com -> 100.127.197.132 (Tailscale IP)
- Modify push.sh to detect local deploys and skip SSH
- Add Tailscale hostname fallback when domain is unreachable
|
|
Remove task_id requirement and all jr task CLI calls. The Coder subagent
now only requires namespace and task description - no external task
tracking needed.
Changes:
- Remove coderTaskId from CoderConfig
- Remove jr task show/update/comment calls
- Commit message uses namespace prefix instead of task ID
- Recovery phase just reverts git, no task comment
- Subagent.hs only validates namespace for Coder role
|
|
Security improvement: subagents now require explicit user confirmation via
Telegram inline buttons, preventing the agent from bypassing approval.
Changes:
- Add InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery types
- Add parseCallbackQuery for handling button presses
- Add sendMessageWithKeyboard and answerCallbackQuery API functions
- Add PendingSpawn registry for tracking unconfirmed spawn requests
- Add spawnSubagentToolWithApproval that sends approval buttons
- Add handleCallbackQuery to process approve/reject button clicks
- Add approveAndSpawnSubagent and rejectPendingSpawn functions
Flow:
1. Agent calls spawn_subagent → creates pending request
2. User receives message with ✅ Approve / ❌ Reject buttons
3. Button click (outside agent loop) spawns or cancels
4. Pending requests expire after 10 minutes
|
|
- Add global subagent registry to track running handles by ID
- Modify executeSpawnSubagent to use spawnSubagentAsync and return immediately
- Add check_subagent tool for querying status or getting results
- Export subagentTools convenience function with both tools
- Update Telegram.hs to use subagentTools instead of just spawnSubagentTool
Ava can now spawn subagents in the background and continue
conversations while checking on progress via check_subagent.
|
|
Based on Anthropic's effective harnesses research.
New modules:
- Omni/Agent/AuditLog.hs: JSONL audit logging with SubagentId linking
- Omni/Agent/Tools/AvaLogs.hs: Tool for Ava to query her own logs
- Omni/Agent/Subagent/HARDENING.md: Design documentation
Key features:
- SubagentHandle with TVar status for async execution and polling
- spawnSubagentAsync, querySubagentStatus, waitSubagent, cancelSubagent
- User confirmation: spawn_subagent requires confirmed=true after approval
- Audit logs stored in $AVA_DATA_ROOT/logs/{ava,subagents}/
- CLI: ava logs [--last=N] [<subagent_id>]
- read_ava_logs tool for Ava self-diagnosis
Tasks: t-267, t-268, t-269, t-270, t-271
|
|
- Wrap ava binary with Python (requests, httpx, pandas, etc.)
- Add CLI tools: curl, pandoc, ffmpeg, imagemagick, csvkit
- Add local whisper-cli fallback when OPENAI_API_KEY unavailable
Amp-Thread-ID: https://ampcode.com/threads/T-019b2dc2-36e0-75e1-90c1-622901fc9847
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Add Omni.Agent.Paths module for configurable AVA_DATA_ROOT
- Create ava Linux user in Users.nix with SSH key
- Add systemd service in Beryllium/Ava.nix with graceful shutdown
- Update Skills.hs and Outreach.hs to use configurable paths
- Add startup logging of resolved paths in Telegram.hs
- Create migration script for moving data from _/var/ava to /home/ava
- Add deployment documentation in Beryllium/AVA.md
In dev: AVA_DATA_ROOT unset uses _/var/ava/
In prod: AVA_DATA_ROOT=/home/ava via systemd
Amp-Thread-ID: https://ampcode.com/threads/T-019b2d7e-bd88-7355-8133-275c65157aaf
Co-authored-by: Amp <amp@ampcode.com>
|
|
Enables orchestrator to spawn specialized subagents for focused tasks:
- WebCrawler: web search + page reading (haiku, fast)
- CodeReviewer: code analysis tools (sonnet, thorough)
- DataExtractor: structured data extraction (haiku)
- Researcher: combined web + codebase research (sonnet)
Key features:
- spawn_subagent tool with role-based tool selection
- Per-subagent resource limits (timeout, cost, tokens)
- Structured output with citations (claim, source_url, quote)
- Separate API keys for OpenRouter vs Kagi
- Efficiency-focused system prompts
Defaults: 200k tokens, $1.00 cost cap, 600s timeout, 20 iterations
|
|
- Create Omni/Agent/Skills.hs with skill loader and tools
- Skills follow Claude Skills format (SKILL.md + scripts/references/assets)
- Directory structure: _/var/ava/skills/{shared,<user>}/
- Three tools: skill, list_skills, publish_skill
- Users can publish private skills to shared
- Integrate skills tools into Telegram bot
- Create skill-creator meta-skill at _/var/ava/skills/shared/skill-creator/
|
|
Added retry with backoff, parallel proccessing, editing pages down to main
content, summarization with haiku. It's so much faster and more reliable
now. Plus improved the logging system and distangled the status UI bar from the
logging module.
|
|
- Rename Omni/Bot.hs to Omni/Ava.hs
- Delete Omni/Bot.scm (unused Guile version)
- Remove cost limit (was 10 cents, now 0)
- Increase max iterations from 10 to 50
|
|
python_exec, http_get/post, outreach_*, feedback_list, and read_file
now require isBenAuthorized check, matching email/hledger pattern.
|
|
- Add feedback table with migration in Core.py
- Add FeedbackForm and FeedbackPage UI components
- Add /feedback GET/POST routes and /api/feedback JSON endpoint
- Add admin feedback view at /admin/feedback
- Create Omni/Agent/Tools/Feedback.hs with feedback_list tool
- Wire feedback tool into Telegram agent
|
|
- Add emailSendTool to Email.hs for sending approved drafts
- Add sendApprovedEmail function that checks draft status
- Use Network.Mail.Mime.simpleMail' with SMTP.sendMail
- Integrate with Outreach module to verify approval and mark sent
- Add tests for new tool
|
|
- Import Omni.Agent.Tools in Telegram.hs
- Add readFileTool to Ava's tool list
- Add podcastitlater context section to system prompt with key file paths
|
|
The haiku-based splitting was modifying message content. Replace
with deterministic paragraph-based splitting that preserves the
original text exactly.
|
|
- Create Omni/Agent/Tools/Outreach.hs with tools
- Drafts stored in _/var/ava/outreach/{pending,approved,...}
- Add Telegram commands: /review, /approve, /reject, /queue
- Integrate outreach tools into agent's tool list
Amp-Thread-ID: https://ampcode.com/threads/T-019b202c-2156-74db-aa4a-e0a2f4397fbb
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Create Omni/Agent/Tools/Http.hs with http_get and http_post tools
- Support headers, query params, JSON body, 30s timeout
- Return structured JSON with status, headers, body
- Add 9 unit tests including real HTTP calls to httpbin.org
- Wire tools into Telegram agent's tool list
Completes t-265.2
|
|
- Create Omni/Agent/Tools/Python.hs with python_exec tool
- Execute Python snippets via subprocess with 30s default timeout
- Return structured JSON with stdout, stderr, exit_code
- Add 8 unit tests covering print, imports, errors, timeout
- Wire tool into Telegram agent's tool list
Completes t-265.1
|
|
- Replace openssl s_client with HaskellNet/HaskellNet-SSL for proper
IMAP client support (better protocol handling, no manual parsing)
- Add HaskellNet deps to Haskell.nix with doJailbreak for version bounds
- Fix lost messages: sendMessageReturningId now throws on API errors
instead of returning Nothing (which was incorrectly treated as success)
- Auto-retry markdown parse errors as plain text
- Hardcode benChatId for reliable email check loop startup
|
|
- New Omni/Agent/Tools/Hledger.hs with 5 tools:
- hledger_balance: query account balances
- hledger_register: show transaction history
- hledger_add: create new transactions
- hledger_income_statement: income vs expenses
- hledger_balance_sheet: net worth view
- All tools support currency parameter (default: USD)
- Balance, register, income_statement support period parameter
- Period uses hledger syntax (thismonth, 2024, from X to Y)
- Shell escaping fixed for multi-word period strings
- Authorization: only Ben and Kate get hledger tools
- Max iterations increased from 5 to 10
- Transactions written to ~/fund/telegram-transactions.journal
|
|
|
|
Memory changes:
- Add thread_id column to conversation_messages for topic support
- Add saveGroupMessage/getGroupConversationContext for shared history
- Add storeGroupMemory/recallGroupMemories with 'group:<chat_id>' user
- Fix SQLite busy error: set busy_timeout before journal_mode
Telegram changes:
- Group chats now use shared conversation context (chat_id, thread_id)
- Personal memories stay with user, group memories shared across group
- Memory context shows [Personal] and [Group] prefixes
- Add withTypingIndicator: refreshes typing every 4s while agent thinks
- Fix typing UX: indicator now shows continuously until response sent
|
|
- Parse message_thread_id from incoming messages
- Include thread_id in sendMessage API calls
- Pass thread_id through message queue system
- Replies now go to the correct topic in supergroups
|
|
OpenRouter's chat completion API doesn't properly pass audio to models.
Switched to calling OpenAI's /v1/audio/transcriptions endpoint directly
with the whisper-1 model.
Requires OPENAI_API_KEY environment variable.
|
|
Fixes 'database is locked' errors when multiple threads access the
memory database simultaneously (incoming batcher, message dispatch,
reminder loop, main handler).
|
|
Batches incoming messages by chat_id with a 3-second sliding window
before processing. This prevents confusion when messages arrive
simultaneously from different chats.
- New IncomingQueue module with STM-based in-memory queue
- Messages enqueued immediately, offset acked on enqueue
- 200ms tick loop flushes batches past deadline
- Batch formatting: numbered messages, sender attribution for groups,
media stubs, reply context
- Media from first message in batch still gets full processing
|
|
- Switch from gemini-2.0-flash-001 to gemini-2.5-flash
- Put audio content before text prompt (model was ignoring audio)
- Strengthen prompt to return only transcription
|
|
- Add Messages.hs with scheduled_messages table and dispatcher loop
- All outbound messages now go through the queue (1s polling)
- Disable streaming responses, use runAgentWithProvider instead
- Add send_message tool for delayed messages (up to 30 days)
- Add list_pending_messages and cancel_message tools
- Reminders now queue messages instead of sending directly
- Exponential backoff retry (max 5 attempts) for failed sends
|
|
Amp-Thread-ID: https://ampcode.com/threads/T-019b1894-b431-777d-aba3-65a51e720ef2
Co-authored-by: Amp <amp@ampcode.com>
|