fix(anthropic): handle thinking response blocks - #1976
Conversation
ErenAta16
left a comment
There was a problem hiding this comment.
The fix is right and the problem is broader than the title suggests, which is an argument for merging it rather than against.
completion.content[0].text assumes the first block is text. Thinking is the case that prompted this, but the SDK now defines a lot of block types that can legitimately lead a response:
anthropic 0.117.0, types ending in "Block": 29 of them, including
ThinkingBlock, RedactedThinkingBlock, ToolUseBlock, ServerToolUseBlock,
WebSearchToolResultBlock, CodeExecutionResultBlock, DocumentBlock, ...
Any of those in position zero produces AttributeError: 'ThinkingBlock' object has no attribute 'text' today. Scanning for the first type == "text" block handles the whole family rather than special-casing thinking, so it will not need revisiting the next time a server-side tool block type is added.
Raising rather than returning "" when there is no text block is the right call for a generation library. An empty string would flow into whatever the caller does next and fail somewhere less obvious, and a response with no text block genuinely is not a completion.
One thing worth a look before merge: anthropic.types also exports ParsedTextBlock. If that is what comes back on the structured-output path and its discriminator is not literally "text", this loop would skip it and raise on a response that does contain text. I could not confirm the discriminator value without constructing one, since these models have no default on the type field, so it may be fine. Worth a one-line check given the loop is now the only way text is found.
On the test, using real ThinkingBlock and TextBlock instances rather than mocks is the right choice here. A MagicMock would answer to .type and .text for anything and would pass regardless of whether the loop worked.
Summary
content[0].This preserves ordinary responses and supports extended-thinking replies whose first block is reasoning.
Tests
uv run --with anthropic --with pytest pytest tests/models/test_anthropic.py -m 'not api_call' -qpre-commit run ruff --files src/outlines/models/anthropic.py tests/models/test_anthropic.pymypy --allow-redefinition src/outlines/models/anthropic.py tests/models/test_anthropic.py