todo-14-message-role-validation.md 2.3 KB

Todo 14 Message Role Validation Plan

Status: done

Goal

Reject provider-invalid API message roles and malformed tool replies before runtime work or network calls.

Why

The UI no longer exposes tool pre-messages, and the OpenAI client rejects tool messages without tool_call_id. API callers can still send arbitrary role values in pre_messages, which can fail later at the provider boundary. The request contract should fail fast.

Scope

This todo covers:

  • Constrain ChatMessage.role to Chat Completions-compatible roles.
  • Reject pre_messages with role="tool" in DebugRunRequest, because request pre-messages cannot provide a matching assistant tool_calls context safely.
  • Preserve internally generated EventAgent tool replies.
  • Keep OpenAI client payload serialization tests passing.

This todo does not cover:

  • Full arbitrary conversation transcript validation.
  • UI changes.
  • Tool handler exception isolation.

Files

  • Modify: src/agent_lab/domain/messages.py
  • Modify: src/agent_lab/application/contracts.py
  • Modify: tests/test_websocket_api.py or add focused contract tests.

Steps

  1. Add failing tests:
    • invalid pre-message role is rejected by DebugRunRequest.model_validate();
    • pre_messages with role="tool" is rejected before runtime;
    • internally created ChatMessage(role="tool", tool_call_id="...") remains valid.
  2. Implement a Literal role type in ChatMessage.
  3. Add a DebugRunRequest validator that rejects tool pre-messages.
  4. Run:

    uv run pytest tests/test_websocket_api.py tests/test_event_agent.py
    uv run pytest
    
  5. Update this plan and docs/plans/todos.md, then commit.

Verification

Result:

  • Red run passed as expected: invalid role and tool pre-message tests failed before implementation.
  • uv run pytest tests/test_websocket_api.py tests/test_event_agent.py passed: 21 tests, 1 existing Starlette deprecation warning.
  • uv run pytest passed: 34 tests, 1 existing Starlette deprecation warning.

Evaluation

  • ChatMessage.role now accepts only system, user, assistant, or tool.
  • DebugRunRequest rejects tool entries in pre_messages, so API callers cannot send orphan tool replies as front-loaded context.
  • Internally generated EventAgent tool replies still validate and serialize correctly.