# Todo 8 Tool Pre-Message Guard Plan **Status:** done ## Result Implemented by subagent and locally verified by the main session. Commands: ```bash uv run pytest tests/test_websocket_api.py uv run pytest ``` Results: - focused WebSocket/API tests: `10 passed, 1 warning in 0.22s` - full suite: `16 passed, 1 warning in 0.22s` ## Goal Prevent the debug UI and provider serializer from generating invalid Chat Completions `tool` messages without `tool_call_id`. ## Problem The pre-message editor exposes `tool` as a role, but the UI does not collect `tool_call_id`. A manual `tool` pre-message can therefore reach the provider as `{role: "tool", content: "..."}`, which strict compatible providers reject. ## Scope This todo covers: - Removing `tool` from the static pre-message role selector for MVP. - Adding provider-client validation that raises a clear error if a `tool` message lacks `tool_call_id`. - Tests for the validation and UI markup. This todo does not cover: - Adding full manual tool-call transcript editing. - New EventAgent tools. - Live LLM smoke. ## Files - Modify: `src/agent_lab/presentation/static/index.html` - Modify: `src/agent_lab/infrastructure/chat_client.py` - Modify/add tests, preferably `tests/test_websocket_api.py`. - Do not modify: `docs/plans/todos.md`. ## Steps 1. Add a failing test that `OpenAICompatibleChatClient` rejects a `ChatMessage(role="tool", content="...")` without `tool_call_id`. 2. Add a failing test or assertion that the static pre-message role selector does not offer `tool`. 3. Implement the minimal fix: - remove `` from the pre-message template. - in `_serialize_message`, raise `ValueError("tool messages require tool_call_id")` when role is `tool` and no `tool_call_id` is present. 4. Run: ```bash uv run pytest tests/test_websocket_api.py uv run pytest ``` ## Verification Expected result: - Invalid manual tool messages fail before network I/O. - UI no longer exposes invalid manual tool pre-message creation. - Full suite passes.