# Todo 9 Explicit Runtime Queues Plan **Status:** done ## Result Implemented by subagent and committed as `b2bba51 Add explicit runtime queues`. Main-session verification: ```bash uv run pytest tests/test_debug_runtime.py uv run pytest ``` Results: - runtime queue tests: `5 passed in 0.06s` - full suite: `19 passed, 1 warning in 0.25s` ## Goal Refactor the runtime internals to use explicit input, output, and event queues while preserving the existing WebSocket stream contract. ## Why The MVP works, but the original requirement describes three data-exchange channels: - input queue: WebSocket/user input and EventAgent replies feed ChatAgent; - output queue: ChatAgent stream output feeds WebSocket downlink; - event queue: ChatAgent events feed EventAgent. The current `DebugRuntime.run()` performs these steps directly. This todo introduces the queue structure now, without changing HTTP/WebSocket payloads. ## Scope This todo covers: - Runtime-local `asyncio.Queue` objects for input, output, and events. - A small queue/session abstraction in the application layer. - Tests proving queue ownership and order. - Keeping `DebugRuntime.run()` as the public async generator consumed by FastAPI. This todo does not cover: - Redis/NATS/external queues. - Multiple concurrent browser sessions beyond one runtime instance per WebSocket request. - Tool registry changes. - UI changes. ## Files - Create: `src/agent_lab/application/queues.py` - Modify: `src/agent_lab/application/runtime.py` - Modify/add tests, preferably `tests/test_debug_runtime.py`. - Do not modify: `docs/plans/todos.md`. ## Design Add a `RuntimeQueues` dataclass: ```python @dataclass class RuntimeQueues: input: asyncio.Queue[ChatMessage] output: asyncio.Queue[dict[str, Any]] events: asyncio.Queue[ToolCallEvent] ``` `DebugRuntime.run()` should: 1. Build initial conversation from system prompts and pre-messages. 2. Put the current user message on `input`. 3. Drain input into conversation before each ChatAgent call. 4. Stream ChatAgent items into `output`. 5. Put tool-call events on `events`. 6. Let EventAgent consume `events` and put tool replies back on `input`. 7. Yield only from `output` so the WebSocket contract stays unchanged. Keep the implementation single-process and deterministic. Use sentinel-free sequential draining for this MVP; do not introduce background tasks unless needed by the tests. ## Steps 1. Add failing tests for: - runtime exposes or injects `RuntimeQueues`; - tool-call events are put on the event queue before EventAgent replies return to the input queue; - yielded output message order remains unchanged from current tests. 2. Implement `RuntimeQueues`. 3. Refactor `DebugRuntime.run()` to use the queues internally. 4. Run: ```bash uv run pytest tests/test_debug_runtime.py uv run pytest ``` 5. Evaluate whether Todo 10 still starts with tool registry management or should be adjusted based on the queue abstraction. ## Verification Expected result: - Existing WebSocket/runtime behavior remains compatible. - Tests prove all three queues are part of the runtime flow. - Full suite passes.