Skip to content

adds structredoutput fallback for bedrock converse api#3184

Merged
akshaydeo merged 1 commit intomainfrom
05-02-adds_structredoutput_fallback_for_bedrock_converse_api
May 1, 2026
Merged

adds structredoutput fallback for bedrock converse api#3184
akshaydeo merged 1 commit intomainfrom
05-02-adds_structredoutput_fallback_for_bedrock_converse_api

Conversation

@akshaydeo
Copy link
Copy Markdown
Contributor

@akshaydeo akshaydeo commented May 1, 2026

Summary

Fixes a user-reported regression where Claude Opus 4.7 structured output requests on Bedrock Converse failed with output_config.format: Extra inputs are not permitted. The root cause was that PR #3053 routed Anthropic-on-Bedrock structured outputs through output_config.format + anthropic_beta: structured-outputs-2025-11-13 in additionalModelRequestFields, which Bedrock Converse rejects for certain Claude variants (including Opus 4.7). The fix routes all Bedrock + Anthropic structured output requests through the synthetic bf_so_* tool path (the same path used by non-Anthropic Bedrock models), which is a standard Converse tool call accepted by all Claude variants.

Changes

  • convertResponseFormatToTool and convertTextFormatToTool in core/providers/bedrock/utils.go no longer branch on IsAnthropicModel to emit output_config.format; both functions now fall through to the bf_so_* synthetic-tool synthesis for all Bedrock models.
  • ToBedrockResponsesRequest in core/providers/bedrock/responses.go drops the output_config.format + anthropic_beta injection block that was added in bedrock cli compatibility changes #3053.
  • convertChatParameters in core/providers/bedrock/utils.go similarly drops the output_config.format + anthropic_beta injection block.
  • Added TestBedrockAnthropicChatStructuredOutputUsesSyntheticTool and TestToBedrockResponsesRequest_AnthropicStructuredOutputUsesSyntheticTool unit tests that assert output_config and the structured-outputs beta header are absent, and that the bf_so_* tool is injected and forced via tool_choice.
  • Added a live end-to-end regression repro test BedrockOpus47Tests/TestBedrockOpus47StructuredOutputRegression (skipped unless BEDROCK_OPUS_47_MODEL_ID is set) that mirrors the exact user-reported Python snippet through the same wire path.
  • Helm chart bumped to 2.1.13; enforceAuthOnInference surfaced as a commented default in values.yaml; enforceGovernanceHeader marked deprecated.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

# Unit tests covering the synthetic-tool routing fix
go test ./core/providers/bedrock/... -run TestBedrockAnthropicChatStructuredOutputUsesSyntheticTool
go test ./core/providers/bedrock/... -run TestToBedrockResponsesRequest_AnthropicStructuredOutputUsesSyntheticTool

# Live Opus 4.7 regression repro (requires AWS credentials + Bedrock entitlement)
export BEDROCK_OPUS_47_MODEL_ID=anthropic.claude-opus-4-7-v1:0   # or your inference-profile id
make test-core PROVIDER=bedrock TESTCASE=TestBedrockOpus47StructuredOutputRegression

The live repro test sends a structured output request with output_config.format (json_schema with anyOf-style nullable fields) and no outer anthropic-beta header — the exact shape of the user's failing request. A passing run logs Bedrock Opus 4.7 structured-output request SUCCEEDED.

Breaking changes

  • Yes
  • No

Related issues

Regression introduced in #3053 (commit 7df13ab45).

Security considerations

No auth, secrets, or PII changes. The .infisical directory is now gitignored to prevent accidental credential leakage.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 84807056-ea0e-4fae-afff-203c77265612

📥 Commits

Reviewing files that changed from the base of the PR and between 6237130 and 46c7ef2.

📒 Files selected for processing (9)
  • .gitignore
  • .infisical.json
  • core/providers/bedrock/bedrock_test.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/utils.go
  • helm-charts/bifrost/Chart.yaml
  • helm-charts/bifrost/README.md
  • helm-charts/bifrost/values.yaml
  • helm-charts/index.yaml

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added enforceAuthOnInference configuration option to require authentication on inference endpoints.
  • Deprecations

    • enforceGovernanceHeader is now deprecated; use enforceAuthOnInference instead.
  • Chores

    • Helm chart version updated to 2.1.13.

Walkthrough

This PR refactors Bedrock-Anthropic structured output handling to use a unified synthetic tool-based approach instead of provider-native output configuration, adds comprehensive test coverage for this behavior, and bumps the Helm chart version with new authentication configuration options.

Changes

Cohort / File(s) Summary
Bedrock Structured Output Refactoring
core/providers/bedrock/responses.go, core/providers/bedrock/utils.go
Removes native Anthropic output_config generation from Bedrock request conversion; shifts structured output handling to rely on the synthetic bf_so_* tool injection path for all models, with unified tool-forcing logic.
Bedrock Structured Output Testing
core/providers/bedrock/bedrock_test.go
Adds 272 lines of new test coverage for Claude Opus 4.7 structured outputs, including deterministic unit assertions for synthetic tool injection, live model-ID-gated regression tests, and a betaListContains helper for robust anthropic_beta header detection.
Infisical Configuration
.infisical.json
Introduces new Infisical project configuration file defining workspace ID and branch-to-environment mappings.
Git Configuration
.gitignore
Updates .gitignore to include .infisical path and ensures proper newline termination.
Helm Chart Version Bump
helm-charts/bifrost/Chart.yaml, helm-charts/index.yaml
Updates Helm chart version from 2.1.12 to 2.1.13 and adds corresponding repository index entry with metadata.
Helm Chart Documentation & Configuration
helm-charts/bifrost/README.md, helm-charts/bifrost/values.yaml
Adds new bifrost.client.enforceAuthOnInference configuration option (default true); marks enforceGovernanceHeader as deprecated; updates changelog and documentation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hops through Bedrock with glee,
Synthetic tools dance wild and free,
No native config clouds the way,
Unified paths now lead the day! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title contains a typo ('structredoutput' instead of 'structuredoutput') and is unclear; while it partially relates to the Bedrock structured output fix, it lacks specificity about the regression and the synthetic-tool fallback solution. Consider revising to 'Fix Bedrock Anthropic structured output regression by using synthetic-tool fallback' to be more descriptive and correct the spelling.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, changes, type, affected areas, testing instructions, breaking changes, related issues, and security considerations, with most checklist items addressed.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-02-adds_structredoutput_fallback_for_bedrock_converse_api

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Review rate limit: 3/5 reviews remaining, refill in 19 minutes and 13 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@akshaydeo akshaydeo marked this pull request as ready for review May 1, 2026 19:55
@akshaydeo akshaydeo requested a review from a team as a code owner May 1, 2026 19:55
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 1, 2026

Confidence Score: 4/5

Core fix is correct and well-tested; the open Helm values.yaml behavioral change (enforceAuthOnInference: true) from a prior thread is the remaining concern before merging.

No new P0/P1 issues found in this pass. The previously flagged P1 (enforceAuthOnInference: true rendering a live config change on Helm upgrade) is still unresolved, which keeps the ceiling at 4/5.

helm-charts/bifrost/values.yaml — the enforceAuthOnInference: true field is active and will render into deployed configs on chart upgrade.

Important Files Changed

Filename Overview
core/providers/bedrock/utils.go Removes IsAnthropicModel branch from convertResponseFormatToTool and convertTextFormatToTool; all Bedrock models now use the bf_so_* synthetic-tool path for structured output. Logic is clean and correct.
core/providers/bedrock/responses.go Drops the output_config.format + anthropic_beta injection block in ToBedrockResponsesRequest; structured output for Anthropic-on-Bedrock now defers to the synthetic bf_so_* tool path, consistent with the utils.go change.
core/providers/bedrock/bedrock_test.go Adds two unit tests asserting absence of output_config/beta header and presence of bf_so_* tool, plus a live E2E regression repro test (skipped without BEDROCK_OPUS_47_MODEL_ID). Coverage is thorough.
helm-charts/bifrost/values.yaml Adds enforceAuthOnInference: true as an active (uncommented) value; this will render enforce_auth_on_inference: true into the config on Helm upgrade and may silently change behavior for existing deployments. Previously flagged in review thread.
.infisical.json New file committing the Infisical project config (workspaceId, branch mapping). The workspace ID is a non-secret project identifier; actual credential files are now gitignored via .infisical entry in .gitignore.
helm-charts/bifrost/Chart.yaml Bumps chart version to 2.1.13. Straightforward version increment.
helm-charts/index.yaml Adds 2.1.13 index entry with an empty digest, consistent with all other existing entries in the file.

Reviews (2): Last reviewed commit: "framework: bump core to v1.5.7 --skip-ci" | Re-trigger Greptile

Comment thread helm-charts/bifrost/values.yaml
Comment thread core/providers/bedrock/utils.go Outdated
Comment thread core/providers/bedrock/responses.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/providers/bedrock/bedrock_test.go`:
- Around line 3444-3565: The test suite now enforces Route A (Anthropic on
Bedrock must use the synthetic bf_so_* tool and must NOT set output_config), but
several legacy tests still assert the old behavior; update or remove those tests
so they match Route A: locate the legacy tests
TestToBedrockResponsesRequest_AnthropicTextFormatUsesOutputConfig,
TestAnthropicStructuredOutputUsesOutputConfigWithoutForcedToolChoice,
TestAnthropicStructuredOutputAcceptsOrderedMaps, and
TestAnthropicStructuredOutputMergesAdditionalModelRequestFieldPaths and change
their assertions to the Route A contract — i.e., assert
AdditionalModelRequestFields does NOT contain "output_config" or the
structured-outputs beta tunnel and assert ToolConfig contains a bf_so_* tool
with ToolChoice forcing the specific tool (e.g., "bf_so_classification") — or
remove the obsolete tests entirely if they duplicate coverage already provided
by TestBedrockAnthropicChatStructuredOutputUsesSyntheticTool and
TestToBedrockResponsesRequest_AnthropicStructuredOutputUsesSyntheticTool.

In `@core/providers/bedrock/responses.go`:
- Around line 1842-1847: Update the outdated comment to reflect the new
behavior: note that convertTextFormatToTool can return a synthetic "bf_so_*"
tool for Anthropic (and non-Anthropic) models, that this value is captured in
responseFormatTool, and that the code later injects it via a forced tool_choice
rather than dropping it; mention that output_config.format is still handled
accordingly and that streaming-json-parser enforces JSON shape when no synthetic
tool is present. Reference convertTextFormatToTool, responseFormatTool, and the
synthetic bf_so_* tool in the comment so future readers don't assume a (nil,
nil) return for Anthropic.

In `@core/providers/bedrock/utils.go`:
- Around line 80-86: Update the outdated helper comment around the
convertResponseFormatToTool call: remove references to the old Anthropic path
that returned (nil, nil) and to dropping output_config.format, and instead state
that convertResponseFormatToTool now consistently synthesizes a bf_so_* tool for
all models (so responseFormatTool is always used) and that downstream JSON-shape
guidance/validation is handled by the streaming-json-parser plugin; update the
same wording at the other occurrences referenced (around lines where
responseFormatTool is used with bifrostReq.Model and bifrostReq.Params).

In `@helm-charts/bifrost/values.yaml`:
- Around line 205-209: The values file is actively setting
enforceAuthOnInference: true which forces rendering due to the template's hasKey
logic and changes upgrade behavior; remove or comment out the
enforceAuthOnInference key (leave enforceGovernanceHeader comment as-is or
adjust its note) so the key is absent and the template falls back to
authConfig.disableAuthOnInference as intended; ensure references to
enforceAuthOnInference in the Helm templates that use hasKey continue to rely on
absence rather than a default true value.

In `@helm-charts/index.yaml`:
- Around line 6-8: The index.yaml entry for the helm-charts repository contains
stale/missing metadata (empty digest for version 2.1.13 and a future created
timestamp), so regenerate the chart index using the standard Helm workflow:
re-package any changed charts (helm package) then run helm repo index . with
--merge to update the existing index (and --url set to the chart hosting URL) so
that the generated fields "digest", "created" (per-release), and top-level
"generated" are recomputed consistently; verify the 2.1.13 entry now has a
non-empty digest and no future timestamp, then commit the updated
helm-charts/index.yaml.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c06c528c-9ecd-48e4-9f80-9c59b09542d7

📥 Commits

Reviewing files that changed from the base of the PR and between f7a83d4 and 6237130.

📒 Files selected for processing (10)
  • .gitignore
  • .infisical.json
  • core/changelog.md
  • core/providers/bedrock/bedrock_test.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/utils.go
  • helm-charts/bifrost/Chart.yaml
  • helm-charts/bifrost/README.md
  • helm-charts/bifrost/values.yaml
  • helm-charts/index.yaml

Comment thread core/providers/bedrock/bedrock_test.go
Comment thread core/providers/bedrock/responses.go Outdated
Comment thread core/providers/bedrock/utils.go Outdated
Comment thread helm-charts/bifrost/values.yaml
Comment thread helm-charts/index.yaml
@akshaydeo akshaydeo force-pushed the 05-02-adds_structredoutput_fallback_for_bedrock_converse_api branch from 6237130 to 46c7ef2 Compare May 1, 2026 20:12
Copy link
Copy Markdown
Contributor Author

akshaydeo commented May 1, 2026

Merge activity

  • May 1, 8:12 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 1, 8:13 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo akshaydeo merged commit 734f02d into main May 1, 2026
15 of 17 checks passed
@akshaydeo akshaydeo deleted the 05-02-adds_structredoutput_fallback_for_bedrock_converse_api branch May 1, 2026 20:13
ryan-orphic added a commit to Orphic-AI/bifrost that referenced this pull request May 4, 2026
…output tool

Bedrock Converse rejects toolConfig.toolChoice.tool on Meta Llama variants
with HTTP 400 ("This model doesn't support the toolConfig.toolChoice.tool
field. Remove toolConfig.toolChoice.tool and try again."). The synthetic
bf_so_* tool path used for structured output unconditionally pinned the
synthetic tool via toolChoice.tool, which broke every with_structured_output
caller against Llama 4 Maverick / Scout / Llama 3.x on Bedrock.

This patch adds an IsLlamaModel helper next to the existing IsNovaModel /
IsAnthropicModel family and gates the forced-tool emission off it in three
places:

  1. core/providers/bedrock/utils.go: ChatCompletions synthetic-tool injection
     (response_format=json_schema -> bf_so_* tool path).
  2. core/providers/bedrock/responses.go: OpenAI Responses API mirror path
     (text.format=json_schema -> bf_so_* tool path).
  3. core/providers/bedrock/utils.go: convertToolConfigFromFiltered's explicit
     tool_choice path (defense-in-depth for callers using bind_tools(tool_choice=
     {"type": "function", "function": {"name": "X"}}) directly).

With one synthetic tool bound and Bedrock's default "auto" behavior, omitting
tool_choice yields the same outcome on Llama because there's exactly one tool
the model can call. This mirrors the gate langchain-aws ships
(supports_tool_choice_values for llama4 / llama3-1 / llama3-3 sets only
"auto", causing with_structured_output to emit no tool_choice at all).

Tests added (mirroring PR maximhq#3184's TestBedrockAnthropicChatStructuredOutputUsesSyntheticTool
naming and structure):

  - TestBedrockLlamaChatStructuredOutputOmitsForcedToolChoice — synthetic tool
    present, ToolChoice nil for Llama on the ChatCompletions path.
  - TestBedrockNonLlamaChatStructuredOutputForcesToolChoice — regression guard:
    Nova / Anthropic still get the forced tool_choice (gate doesn't over-fire).
  - TestToBedrockResponsesRequest_LlamaStructuredOutputOmitsForcedToolChoice —
    same negative+positive on the Responses API path.
  - TestBedrockLlamaConvertToolConfigOmitsForcedToolChoice — defense-in-depth
    coverage for explicit tool_choice struct callers.

Refs:
  - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html
  - https://github.com/langchain-ai/langchain-aws (bedrock_converse.py
    supports_tool_choice_values family-detection lines 678-711).
  - PR maximhq#3184 (Anthropic structured-output fallback to synthetic tool path) —
    immediate predecessor; this PR completes the per-family gating story.
ryan-orphic added a commit to Orphic-AI/bifrost that referenced this pull request May 4, 2026
…output tool

Bedrock Converse rejects toolConfig.toolChoice.tool on Meta Llama variants
with HTTP 400 ("This model doesn't support the toolConfig.toolChoice.tool
field. Remove toolConfig.toolChoice.tool and try again."). The synthetic
bf_so_* tool path used for structured output unconditionally pinned the
synthetic tool via toolChoice.tool, which broke every with_structured_output
caller against Llama 4 Maverick / Scout / Llama 3.x on Bedrock.

This patch adds an IsLlamaModel helper next to the existing IsNovaModel /
IsAnthropicModel family and gates the forced-tool emission off it in four
places (covering both API surfaces and both the synthetic and explicit
tool_choice paths on each):

  1. core/providers/bedrock/utils.go: ChatCompletions synthetic-tool injection
     (response_format=json_schema -> bf_so_* tool path).
  2. core/providers/bedrock/responses.go: OpenAI Responses API mirror of maximhq#1
     (text.format=json_schema -> bf_so_* tool path).
  3. core/providers/bedrock/utils.go: convertToolConfigFromFiltered's explicit
     tool_choice path (defense-in-depth for ChatCompletions callers using
     bind_tools(tool_choice={"type": "function", "function": {"name": "X"}})
     directly).
  4. core/providers/bedrock/responses.go: Responses API mirror of maximhq#3 — the
     explicit tool_choice path runs convertResponsesToolChoice and writes
     BedrockToolChoice{Tool: ...} straight onto the request, which trips the
     same Llama 400 without the gate.

With one synthetic tool bound and Bedrock's default "auto" behavior, omitting
tool_choice yields the same outcome on Llama because there's exactly one tool
the model can call. This mirrors the gate langchain-aws ships
(supports_tool_choice_values for llama4 / llama3-1 / llama3-3 sets only
"auto", causing with_structured_output to emit no tool_choice at all).

Tests added (mirroring PR maximhq#3184's TestBedrockAnthropicChatStructuredOutputUsesSyntheticTool
naming and structure):

  - TestBedrockLlamaChatStructuredOutputOmitsForcedToolChoice — synthetic tool
    present, ToolChoice nil for Llama on the ChatCompletions path.
  - TestBedrockNonLlamaChatStructuredOutputForcesToolChoice — regression guard:
    Nova / Anthropic still get the forced tool_choice (gate doesn't over-fire).
  - TestToBedrockResponsesRequest_LlamaStructuredOutputOmitsForcedToolChoice —
    same negative+positive on the Responses API synthetic-tool path.
  - TestBedrockLlamaConvertToolConfigOmitsForcedToolChoice — defense-in-depth
    coverage for ChatCompletions explicit tool_choice struct callers.
  - TestToBedrockResponsesRequest_LlamaConvertResponsesToolChoiceOmitsForcedToolChoice
    — defense-in-depth coverage for Responses API explicit tool_choice
    (function-typed) struct callers — the gap surfaced in code review.
  - TestToBedrockResponsesRequest_NonLlamaConvertResponsesToolChoiceForcesToolChoice
    — Anthropic regression guard for maximhq#5 so the Responses-side Llama gate
    doesn't over-fire.

Refs:
  - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html
  - https://github.com/langchain-ai/langchain-aws (bedrock_converse.py
    supports_tool_choice_values family-detection lines 678-711).
  - PR maximhq#3184 (Anthropic structured-output fallback to synthetic tool path) —
    immediate predecessor; this PR completes the per-family gating story.
akshaydeo pushed a commit that referenced this pull request May 4, 2026
…output tool (#3196)

Bedrock Converse rejects toolConfig.toolChoice.tool on Meta Llama variants
with HTTP 400 ("This model doesn't support the toolConfig.toolChoice.tool
field. Remove toolConfig.toolChoice.tool and try again."). The synthetic
bf_so_* tool path used for structured output unconditionally pinned the
synthetic tool via toolChoice.tool, which broke every with_structured_output
caller against Llama 4 Maverick / Scout / Llama 3.x on Bedrock.

This patch adds an IsLlamaModel helper next to the existing IsNovaModel /
IsAnthropicModel family and gates the forced-tool emission off it in four
places (covering both API surfaces and both the synthetic and explicit
tool_choice paths on each):

  1. core/providers/bedrock/utils.go: ChatCompletions synthetic-tool injection
     (response_format=json_schema -> bf_so_* tool path).
  2. core/providers/bedrock/responses.go: OpenAI Responses API mirror of #1
     (text.format=json_schema -> bf_so_* tool path).
  3. core/providers/bedrock/utils.go: convertToolConfigFromFiltered's explicit
     tool_choice path (defense-in-depth for ChatCompletions callers using
     bind_tools(tool_choice={"type": "function", "function": {"name": "X"}})
     directly).
  4. core/providers/bedrock/responses.go: Responses API mirror of #3 — the
     explicit tool_choice path runs convertResponsesToolChoice and writes
     BedrockToolChoice{Tool: ...} straight onto the request, which trips the
     same Llama 400 without the gate.

With one synthetic tool bound and Bedrock's default "auto" behavior, omitting
tool_choice yields the same outcome on Llama because there's exactly one tool
the model can call. This mirrors the gate langchain-aws ships
(supports_tool_choice_values for llama4 / llama3-1 / llama3-3 sets only
"auto", causing with_structured_output to emit no tool_choice at all).

Tests added (mirroring PR #3184's TestBedrockAnthropicChatStructuredOutputUsesSyntheticTool
naming and structure):

  - TestBedrockLlamaChatStructuredOutputOmitsForcedToolChoice — synthetic tool
    present, ToolChoice nil for Llama on the ChatCompletions path.
  - TestBedrockNonLlamaChatStructuredOutputForcesToolChoice — regression guard:
    Nova / Anthropic still get the forced tool_choice (gate doesn't over-fire).
  - TestToBedrockResponsesRequest_LlamaStructuredOutputOmitsForcedToolChoice —
    same negative+positive on the Responses API synthetic-tool path.
  - TestBedrockLlamaConvertToolConfigOmitsForcedToolChoice — defense-in-depth
    coverage for ChatCompletions explicit tool_choice struct callers.
  - TestToBedrockResponsesRequest_LlamaConvertResponsesToolChoiceOmitsForcedToolChoice
    — defense-in-depth coverage for Responses API explicit tool_choice
    (function-typed) struct callers — the gap surfaced in code review.
  - TestToBedrockResponsesRequest_NonLlamaConvertResponsesToolChoiceForcesToolChoice
    — Anthropic regression guard for #5 so the Responses-side Llama gate
    doesn't over-fire.

Refs:
  - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html
  - https://github.com/langchain-ai/langchain-aws (bedrock_converse.py
    supports_tool_choice_values family-detection lines 678-711).
  - PR #3184 (Anthropic structured-output fallback to synthetic tool path) —
    immediate predecessor; this PR completes the per-family gating story.
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.

2 participants