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
- Add failing negative tests for every review finding.
- Verify failures are caused by current acceptance/override behavior, not test setup.
- Implement the smallest domain/client/history/request-boundary hardening.
- 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