- webapp.py lifespan now initializes json_logging, recovery, cost_guard, task_history
- Dispatcher receives cost_guard and task_history dependencies
- ContainerCleaner starts if Docker is available
- Added /health/costs endpoint for API cost monitoring
- Added tests/test_smoke.py with 2 tests for basic health and costs endpoint
- All existing health tests still pass (8 tests)
- Add cost_guard and task_history optional parameters to Dispatcher.__init__
- Check daily cost limit before dequeuing tasks
- Record usage with CostGuard after successful task completion
- Record task history (success and failure) with TaskHistory
- Maintain backward compatibility (cost_guard=None, task_history=None)
- Add tests for cost recording and daily limit blocking
- Add reset_running_to_pending() to PersistentTaskQueue for recovery
- Implement recover_on_startup() to reset interrupted tasks and clean zombies
- Add ContainerCleaner for periodic removal of old sandbox containers
- Add 4 tests covering recovery scenarios and container cleanup logic
Adds three new monitoring endpoints:
- GET /health/gitea — Verifies Gitea API connectivity
- GET /health/discord — Reports Discord bot connection status
- GET /health/queue — Returns pending task count
All endpoints return JSON with status field. The Gitea endpoint
includes the API status code on success or error message on failure.
Discord endpoint returns "not_configured", "connecting", or "ok" with
bot username. Queue endpoint includes pending_tasks count.
Tests use mock lifespan to avoid initializing task queue, message
store, dispatcher, and discord handler during testing.
Adds asynccontextmanager lifespan to webapp.py that:
- Initializes task_queue and message_store on startup
- Starts Dispatcher as background task
- Starts Discord bot gateway if DISCORD_TOKEN is set
- Properly shuts down all resources on application exit
This completes Phase 3 Task 6, enabling the webapp to run Discord bot
and dispatcher concurrently with the webhook server.
Implements discord.py Bot Gateway to receive @agent mentions and enqueue tasks.
Includes deterministic thread ID generation and message parsing for issue numbers,
repo names, and freeform requests. Supports message queuing for running threads.
Files:
- agent/integrations/discord_handler.py: DiscordHandler class with event handling
- tests/test_discord_handler.py: 4 tests for parsing and thread ID generation
All tests pass (95 total).
- Add parse_gitea_event() function to parse issue comments, labels, and PR review requests
- Detect @agent mentions in issue comments and strip them from message
- Implement rate limiting with slowapi (10 requests/minute)
- Integrate with PersistentTaskQueue and MessageStore
- Queue messages if task is already running for the same thread
- Add 6 comprehensive tests for event parsing and signature verification
- Implement SQLite-based MessageStore for follow-up messages
- Replace LangGraph store with MessageStore in check_message_queue middleware
- Preserve all multimodal content parsing logic
- Add comprehensive tests for MessageStore (4 tests, all passing)
- All 85 tests pass
Implemented full async Gitea REST API v1 client using httpx with the following methods:
- create_pull_request: Create PRs with title, head, base, and body
- merge_pull_request: Merge PRs with configurable merge type
- create_issue_comment: Post comments on issues/PRs
- get_issue: Fetch issue/PR details
- get_issue_comments: Retrieve all comments for an issue/PR
- create_branch: Create new branches from existing ones
Added lazy singleton pattern with get_gitea_client() factory function that reads GITEA_URL and GITEA_TOKEN from environment.
All methods properly call raise_for_status() and return JSON responses. Comprehensive test suite with 8 tests covering all methods plus error handling.