# Todo 3 WebSocket API and Static UI Plan **Status:** done ## Result Implemented by subagent and locally verified. Commands: ```bash uv run pytest uv run python -c "from agent_lab.main import app; print(app.title)" ``` Results: - `uv run pytest`: `8 passed, 1 warning in 0.24s` - import smoke: `Agent Lab` Evaluation note: real LLM configuration already exists through `Settings`, so Todo 4 should focus on documentation and a minimal manual smoke helper rather than adding another runtime layer. ## Goal Expose the domain runtime through FastAPI WebSocket and serve a usable static debug console. ## Scope This todo covers: - FastAPI app factory and HTTP index route. - WebSocket endpoint for one debug run per request. - OpenAI Chat Completions compatible HTTP client for streaming completions. - Assistant message transcript persistence during runtime loops. - Static HTML/CSS/JS page without a frontend build chain. - Contract tests using FastAPI `TestClient` and a fake runtime/client where possible. This todo does not cover: - Production auth. - Multi-user session storage. - Redis/NATS/external queues. - Full visual polish. - Final README/env docs; those stay in Todo 4. ## Files - Modify: `src/agent_lab/application/runtime.py` - Create: `src/agent_lab/infrastructure/chat_client.py` - Create: `src/agent_lab/settings.py` - Create: `src/agent_lab/main.py` - Create: `src/agent_lab/presentation/web.py` - Create: `src/agent_lab/presentation/static/index.html` - Create: `src/agent_lab/presentation/static/app.js` - Create: `src/agent_lab/presentation/static/styles.css` - Create: `tests/test_websocket_api.py` - Update: `docs/plans/todos.md` after evaluation only. ## Protocol Frontend sends one JSON object to `/ws/debug`: ```json { "user_message": "debug this", "system_prompts": ["You are a debugger."], "pre_messages": [], "chat_agent": { "model": "gpt-4.1-mini", "temperature": 0.2, "max_tokens": 800 }, "event_agent": { "enabled_tools": ["handoff_note"], "max_event_loops": 3 } } ``` Server sends newline-independent JSON WebSocket messages already produced by `DebugRuntime.run()`, plus an `error` message on validation/runtime failures. ## Steps 1. Add tests for `/health` and `/ws/debug` with a fake runtime or fake chat client. 2. Update `DebugRuntime` to aggregate streamed assistant content and append assistant messages to history when a model turn completes. 3. Implement `Settings` with pydantic-settings fields: - `openai_api_key` - `openai_base_url` - `openai_default_model` - `request_timeout_seconds` 4. Implement `OpenAICompatibleChatClient` using `httpx.AsyncClient.stream()` against `/chat/completions`, with `stream: true`, configured model params, tool definitions, and `ChatCompletionStreamParser`. 5. Implement FastAPI app factory and routes: - `GET /health` - `GET /` - `WebSocket /ws/debug` 6. Implement static page controls: - multiple system prompts. - pre-message editor. - chat input and streamed output. - ChatAgent/EventAgent parameter inputs. - EventAgent tool toggles. - round stats area for tokens, cached tokens, TTFT, and elapsed time. 7. Run focused tests: ```bash uv run pytest tests/test_websocket_api.py tests/test_debug_runtime.py ``` 8. Run full tests: ```bash uv run pytest ``` ## Verification Expected result: - WebSocket contract test passes without a real LLM key. - Existing Todo 2 tests still pass. - App imports with `uv run python -c "from agent_lab.main import app; print(app.title)"`.