todo-44.1-tool-transcript-hardening.md 3.2 KB

Todo 44.1 Tool Transcript Hardening Plan

Status: done

Result

  • Rejected duplicate call IDs within and across assistant messages.
  • Protected provider request fields from extra_body overrides and validated forced choices locally.
  • Projected EventAgent history without unresolved provider protocol state.
  • Kept public pre-messages user-facing by rejecting internal tool protocol messages.
  • Completed role-field and test-double validation; full suite passes (108 passed).

Goal

Close identity, payload-precedence, history-projection, and request-boundary gaps found by Todo 44 code review before direct Runtime tool mode builds on the transcript layer.

Scope

  • Reject duplicate assistant tool-call IDs before serialization.
  • Prevent extra_body from overriding reserved provider request fields, especially explicit tool_choice.
  • Validate forced tool choices locally against the supplied tools.
  • Project EventAgent conversation history without unresolved assistant tool-call protocol state.
  • Keep public pre_messages user-facing only by rejecting both tool replies and assistant tool calls.
  • Complete role-specific field validation and update all affected fakes.

Files

  • Modify: src/agent_lab/domain/messages.py
  • Modify: src/agent_lab/application/contracts.py
  • Modify: src/agent_lab/application/event_agent.py
  • Modify: src/agent_lab/infrastructure/chat_client.py
  • Modify: tests/test_websocket_api.py
  • Modify: tests/test_event_agent.py
  • Modify: tests/test_debug_runtime.py

Plan

Plan

  1. Add failing negative tests for every review finding.
  2. Verify failures are caused by current acceptance/override behavior, not test setup.
  3. Implement the smallest domain/client/history/request-boundary hardening.
  4. Run focused and full regressions.

Act

  • Add tests rejecting duplicate tool-call IDs within one assistant message and across a transcript.
  • Add tests proving extra_body cannot override messages, tools, tool_choice, model, streaming, or token/sampling controls.
  • Add tests rejecting forced tool choice with no tools or a function name absent from the supplied list.
  • Add an EventAgent test with a prior complete assistant/tool round and assert its argument prompt contains visible assistant content without unresolved tool_calls.
  • Add request-contract tests rejecting pre_messages that contain either tool replies or assistant tool calls.
  • Update ChatMessage role-field tests so irrelevant tool_call_id/tool_calls fields fail instead of being ignored.
  • Update all fake stream_chat signatures and assertions for optional tool_choice.
  • Run RED, apply minimum fixes, then run focused/full verification.

Observe

Confirm transcript identity is unique, explicit controlled fields win over provider extras, EventAgent receives a provider-valid projected history, and public pre-messages cannot inject partial internal protocol state.

Update

  • Mark 44 and 44.1 done only after spec and quality re-review.
  • Commit separately with the malformed transcript and provider override risks in the body.

Verification

  • uv run pytest tests/test_websocket_api.py tests/test_event_agent.py tests/test_debug_runtime.py -q
  • uv run pytest
  • git diff --check