test(e2e): check the tool input on the messages path too

The /v1/messages validator checked a tool_use block's name and id but not its
input, so a block whose location came back empty or wrong still passed, while
the chat side rejected the same damage. That gap predates this branch; it is
worth closing here because the point of the change is that every parallel call
is checked rather than counted.

AnthropicContentBlock now declares input as a typed field. It already survived
on extra="allow", but reaching it from a test needs a real field to keep the
e2e basedpyright gate at zero. Serialization is unchanged: bodies are dumped
with exclude_none, so a block without an input still replays exactly as before.
This commit is contained in:
Yuneng Jiang 2026-08-27 13:34:09 -07:00
parent 474fbea81f
commit 2cab010c73
No known key found for this signature in database
2 changed files with 4 additions and 0 deletions

View file

@ -483,6 +483,9 @@ def _tool_use_blocks(content: list[AnthropicContentBlock] | None) -> list[Anthro
def _validated_tool_use_id(block: AnthropicContentBlock) -> str:
assert block.name == "get_weather", f"wrong tool called: {block}"
assert block.id, f"tool_use block carries no id, so a tool_result cannot answer it: {block}"
assert block.input is not None, f"tool_use block carries no input: {block}"
args = _WeatherArgs.model_validate(block.input)
assert "paris" in args.location.lower(), f"tool input lost the location: {args}"
return block.id

View file

@ -421,6 +421,7 @@ class AnthropicContentBlock(BaseModel):
text: str | None = None
id: str | None = None
name: str | None = None
input: dict[str, object] | None = None
class AnthropicToolResultBlock(BaseModel):