web/api/conversations.py — send_message() routeweb/agent_executor.py — run_agent() async generatorbackends/*/backend.py — command building + JSONL parsingweb/domain_events.py — event dataclasses + SSE serializationweb/database.py — get_db() for persistencemcp_config.py — write MCP configs before agent launchOn the first message, the agent starts fresh. On subsequent messages, the stored backend_session_id
is passed to get_resume_command() which adds --resume {id} to the CLI command,
preserving the full conversation context.
If a resume fails (hung subprocess), a per-read timeout of 300s kills it and reports an error.
Before launching the agent subprocess, _write_mcp_configs_for_conversation() queries the DB
for enabled MCP servers (global + per-conversation overrides) and writes .mcp.json,
.gemini/settings.json, and .codex/config.toml in the project directory.
The CLI automatically discovers these on startup.
POST /api/conversations/{id}/cancel calls cancel_agent() which sends
SIGTERM to the process group. The event generator detects agent.cancelled=True,
emits an error event, and the SSE stream closes. Any still-running tool_calls are marked as cancelled in the DB.