Skip to content

fix(drivers-prompt): don't force tool_choice for Claude Opus 5.5 on Bedrock and Anthropic - #2352

Closed
kimnamu wants to merge 2 commits into
griptape-ai:mainfrom
kimnamu:fix/bedrock-opus-5-5
Closed

kimnamu wants to merge 2 commits into
griptape-ai:mainfrom
kimnamu:fix/bedrock-opus-5-5

Conversation

@kimnamu

@kimnamu kimnamu commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for the version-keyed gate in anthropic_utils from #2251 and #2261; it made this a small change.

Describe your changes

Claude Opus 5.5 and Sonnet 5.5 reject a forced tool_choice (any or a named tool), which the default structured_output_strategy="tool" sends. This adds supports_forced_tool_choice() next to supports_sampling_params(), backed by a FORCED_TOOL_CHOICE_UNSUPPORTED_MIN_VERSIONS table ({"opus": (5, 5), "sonnet": (5, 5)}). Both use the same version parsing, now in a shared _is_at_or_above(). Both drivers skip the any override when it returns False, so the configured tool_choice (default auto) is sent. Sonnet 5.5 reached Bedrock on 2026-09-28 with the same 400, so c2dfddb adds its row.

case (live, us-east-1) Before After
AmazonBedrockPromptDriver + output_schema, us./global.anthropic.claude-opus-5-5, stream on/off ❌ ValidationException ✅ {'answer': 'OK'}
AmazonBedrockPromptDriver + output_schema, us./global.anthropic.claude-sonnet-5-5, stream on/off ❌ ValidationException ✅ {'answer': 'OK'}
AnthropicPromptDriver (AnthropicBedrock client) + output_schema, Opus 5.5 and Sonnet 5.5 ❌ 400 ✅ {'answer': 'OK'}
Opus 5, Sonnet 5: forced any still sent ✅ ✅ unchanged
Non-Claude models (ai21.j2), rule strategy ✅ ✅ unchanged (existing tests pass)
supports_sampling_params() results ✅ ✅ unchanged (existing tests pass)
$ uv run pytest tests/unit/utils/test_anthropic_utils.py tests/unit/drivers/prompt/test_amazon_bedrock_prompt_driver.py tests/unit/drivers/prompt/test_anthropic_prompt_driver.py
207 passed
$ uv run pytest -n auto tests/unit/drivers/prompt tests/unit/utils tests/unit/structures tests/unit/tasks
1446 passed, 1 skipped
$ uv run ruff format --check . && uv run ruff check . && uv run typos
1236 files already formatted
All checks passed!
$ uv run pyright <changed source files>
0 errors, 0 warnings, 0 informations
RED: source files reset to main, new tests kept

12 of the 16 failures are the helper tests; the 4 driver cases still send any.

E       AttributeError: module 'griptape.utils.anthropic_utils' has no attribute 'supports_forced_tool_choice'
E       AssertionError: assert {'any': {}} == {'auto': {}}
E       AssertionError: assert {'type': 'any'} == {'type': 'auto'}
16 failed, 187 passed

Sonnet 5.5 rows (c2dfddb), anthropic_utils.py reset to 98f3e64, new rows kept:

FAILED tests/unit/utils/test_anthropic_utils.py::TestAnthropicUtils::test_supports_forced_tool_choice[us.anthropic.claude-sonnet-5-5-False]
FAILED tests/unit/drivers/prompt/test_amazon_bedrock_prompt_driver.py::TestAmazonBedrockPromptDriver::test_base_params_structured_output_tool_choice[us.anthropic.claude-sonnet-5-5-expected_tool_choice5]
FAILED tests/unit/drivers/prompt/test_anthropic_prompt_driver.py::TestAnthropicPromptDriver::test_try_run_structured_output_tool_choice[True-claude-sonnet-5-5-expected_tool_choice3]
FAILED tests/unit/drivers/prompt/test_anthropic_prompt_driver.py::TestAnthropicPromptDriver::test_try_run_structured_output_tool_choice[False-claude-sonnet-5-5-expected_tool_choice3]
4 failed, 23 passed

Live, Agent(output_schema=Schema({"answer": str})).run("Reply with answer=OK"), before (main):

us.anthropic.claude-opus-5-5       stream=False -> ErrorArtifact: An error occurred (ValidationException) when calling the Converse operation: The model returned the following errors: tool_choice: type "tool" and "any" are not supported for this model.
us.anthropic.claude-opus-5-5       stream=True  -> ErrorArtifact: An error occurred (ValidationException) when calling the ConverseStream operation: The model returned the following errors: tool_choice: type "tool" and "any" are not supported for this model.
global.anthropic.claude-opus-5-5   stream=False -> ErrorArtifact: An error occurred (ValidationException) when calling the Converse operation: The model returned the following errors: tool_choice: type "tool" and "any" are not supported for this model.
global.anthropic.claude-opus-5-5   stream=True  -> ErrorArtifact: An error occurred (ValidationException) when calling the ConverseStream operation: The model returned the following errors: tool_choice: type "tool" and "any" are not supported for this model.
us.anthropic.claude-opus-5         stream=False -> JsonArtifact: {'answer': 'OK'}
us.anthropic.claude-opus-5         stream=True  -> JsonArtifact: {'answer': 'OK'}
AnthropicPromptDriver us.anthropic.claude-opus-5-5   -> ErrorArtifact: Error code: 400 - {'message': 'tool_choice: type "tool" and "any" are not supported for this model.'}
AnthropicPromptDriver us.anthropic.claude-opus-5     -> JsonArtifact: {'answer': 'OK'}

After (this branch):

us.anthropic.claude-opus-5-5       stream=False -> JsonArtifact: {'answer': 'OK'}
us.anthropic.claude-opus-5-5       stream=True  -> JsonArtifact: {'answer': 'OK'}
global.anthropic.claude-opus-5-5   stream=False -> JsonArtifact: {'answer': 'OK'}
global.anthropic.claude-opus-5-5   stream=True  -> JsonArtifact: {'answer': 'OK'}
us.anthropic.claude-opus-5         stream=False -> JsonArtifact: {'answer': 'OK'}
us.anthropic.claude-opus-5         stream=True  -> JsonArtifact: {'answer': 'OK'}
global.anthropic.claude-sonnet-5   stream=False -> JsonArtifact: {'answer': 'OK'}
global.anthropic.claude-sonnet-5   stream=True  -> JsonArtifact: {'answer': 'OK'}
AnthropicPromptDriver us.anthropic.claude-opus-5-5   -> JsonArtifact: {'answer': 'OK'}
AnthropicPromptDriver us.anthropic.claude-opus-5     -> JsonArtifact: {'answer': 'OK'}

Sonnet 5.5, before (98f3e64) and after (c2dfddb):

before us.anthropic.claude-sonnet-5-5       stream=False -> ErrorArtifact: An error occurred (ValidationException) when calling the Converse operation: The model returned the following errors: tool_choice: type "tool" and "any" are not supported for this model.
before us.anthropic.claude-sonnet-5-5       stream=True  -> ErrorArtifact: An error occurred (ValidationException) when calling the ConverseStream operation: The model returned the following errors: tool_choice: type "tool" and "any" are not supported for this model.
before global.anthropic.claude-sonnet-5-5   stream=False/True -> same ValidationException
before AnthropicPromptDriver us.anthropic.claude-sonnet-5-5 -> ErrorArtifact: Error code: 400 - {'message': 'tool_choice: type "tool" and "any" are not supported for this model.'}
after  us.anthropic.claude-sonnet-5-5       stream=False -> JsonArtifact: {'answer': 'OK'}
after  us.anthropic.claude-sonnet-5-5       stream=True  -> JsonArtifact: {'answer': 'OK'}
after  global.anthropic.claude-sonnet-5-5   stream=False -> JsonArtifact: {'answer': 'OK'}
after  global.anthropic.claude-sonnet-5-5   stream=True  -> JsonArtifact: {'answer': 'OK'}
after  us.anthropic.claude-sonnet-5         stream=False -> JsonArtifact: {'answer': 'OK'}
after  us.anthropic.claude-sonnet-5         stream=True  -> JsonArtifact: {'answer': 'OK'}
after  AnthropicPromptDriver us.anthropic.claude-sonnet-5-5 -> JsonArtifact: {'answer': 'OK'}

With auto the model could answer without calling the tool. Opus 5.5 and Sonnet 5.5 each called it for all 5 prompts I tried, so I left that alone here.

Issue ticket number and link

Fixes #2351

References: announcement · migration guide

…edrock and Anthropic

Claude Opus 5.5 rejects a forced tool_choice ("any" or a named tool) with
`tool_choice: type "tool" and "any" are not supported for this model.`
The default structured_output_strategy="tool" forces "any" in both
AmazonBedrockPromptDriver and AnthropicPromptDriver, so every Agent with an
output_schema fails on Opus 5.5.

Add supports_forced_tool_choice() next to supports_sampling_params(),
backed by a FORCED_TOOL_CHOICE_UNSUPPORTED_MIN_VERSIONS table ({"opus":
(5, 5)}) and the same version parsing (extracted into _is_at_or_above()).
Both drivers skip the "any" override when it returns False, so the
configured tool_choice (default auto) is sent. Opus 5 and earlier, other
Claude families, and non-Claude models are unchanged.
@codecov

codecov Bot commented Sep 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@collindutter
collindutter self-requested a review September 23, 2026 20:18
Claude Sonnet 5.5 (anthropic.claude-sonnet-5-5, on Bedrock since
2026-09-28) rejects a forced tool_choice with the same
`tool_choice: type "tool" and "any" are not supported for this model.`
as Opus 5.5. Add "sonnet": (5, 5) to FORCED_TOOL_CHOICE_UNSUPPORTED_MIN_VERSIONS.
Sonnet 5 still accepts the forced "any" and keeps it.

Co-Authored-By: Claude <noreply@anthropic.com>
@collindutter

Copy link
Copy Markdown
Member

Thanks for the PR @kimnamu! Opened #2370 which adds on a few more fixes. I preserved your commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Claude Opus 5.5 structured output fails on Bedrock: forced tool_choice rejected with ValidationException

2 participants