fix: remove unsupported fields from requests to Bedrock#225
Merged
Conversation
This was referenced Mar 19, 2026
Merged
Contributor
Author
This was referenced Mar 19, 2026
7d8c1ae to
dcc3668
Compare
39ebebb to
20254b5
Compare
dannykopping
approved these changes
Mar 26, 2026
41fbe48 to
6f57430
Compare
20254b5 to
61e7146
Compare
Contributor
Author
61e7146 to
6987152
Compare
pawbana
added a commit
that referenced
this pull request
Mar 27, 2026
This PR removes unsupported fields from requests to Bedrock. Adaptive thinking field is replaced for models that don't support with `type: enabled` + `budget_tokens: N` combination. `budget_tokens` value is calculated as a ratio of `max_tokens`. Ratio depends on `output_config.effort` value, used the same ratio values as OpenRouter does: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens#reasoning-effort-level Fixes: #219
pawbana
added a commit
that referenced
this pull request
Mar 30, 2026
* chore: remove SDK struct usage from requests in messages API (#218) Replaces MessageNewParamsWrapper that wrapped anthropic.MessageNewParams with MessagesRequestPayload that operates on raw bytes. * fix: remove unsupported fields from requests to Bedrock (#225) This PR removes unsupported fields from requests to Bedrock. Adaptive thinking field is replaced for models that don't support with `type: enabled` + `budget_tokens: N` combination. `budget_tokens` value is calculated as a ratio of `max_tokens`. Ratio depends on `output_config.effort` value, used the same ratio values as OpenRouter does: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens#reasoning-effort-level Fixes: #219 * fix: filter unsupported Anthropic-Beta headers from Bedrock (#226) Removes headers from requests to Bedrock that are unsupported. Fixes: #221
dannykopping
added a commit
to coder/coder
that referenced
this pull request
May 14, 2026
…e for Bedrock Opus 4.7+ Claude Opus 4.7 (and future adaptive-only Bedrock models) reject the legacy thinking.type "enabled" + budget_tokens shape with a 400. Claude Code falls back to that shape when it cannot read the upstream model's capability metadata, which is exactly the case when AI Bridge sits between the client and Bedrock. This is the symmetric counterpart to the adaptive -> enabled conversion added in coder/aibridge#225 for older Bedrock models. The new conversion is gated on a bedrockModelRequiresAdaptiveThinking helper that matches Opus 4.7 model IDs (and ARN-style application inference profile names that include the model ID). The effort level is derived from the original budget_tokens / max_tokens ratio using the midpoints of the forward mapping's anchor ratios, so a payload that round-trips through both conversions lands on the same effort level it started with. An explicit output_config.effort already present in the request is preserved. Adaptive-only models support output_config natively (no beta flag), so the field-strip pass is updated to exempt output_config for those models via a new variadic exemptFields parameter on removeUnsupportedBedrockFields. Fixes coder/aibridge#280
dannykopping
added a commit
to coder/coder
that referenced
this pull request
May 14, 2026
…e for Bedrock Opus 4.7+ Claude Opus 4.7 (and future adaptive-only Bedrock models) reject the legacy thinking.type "enabled" + budget_tokens shape with a 400. Claude Code falls back to that shape when it cannot read the upstream model's capability metadata, which is exactly the case when AI Bridge sits between the client and Bedrock. This is the symmetric counterpart to the adaptive -> enabled conversion added in coder/aibridge#225 for older Bedrock models. The new conversion is gated on a bedrockModelRequiresAdaptiveThinking helper that matches Opus 4.7 model IDs (and ARN-style application inference profile names that include the model ID). The effort level is derived from the original budget_tokens / max_tokens ratio using the midpoints of the forward mapping's anchor ratios, so a payload that round-trips through both conversions lands on the same effort level it started with. An explicit output_config.effort already present in the request is preserved. Adaptive-only models support output_config natively (no beta flag), so the field-strip pass is updated to exempt output_config for those models via a new variadic exemptFields parameter on removeUnsupportedBedrockFields. Fixes coder/aibridge#280
dannykopping
added a commit
to coder/coder
that referenced
this pull request
May 15, 2026
…e for Bedrock Opus 4.7+ (#25335) *Disclaimer: implemented by a Coder Agent using Claude Opus 4.6/4.7* Fixes [coder/aibridge#280](coder/aibridge#280). Claude Opus 4.7 (and future adaptive-only Bedrock models) reject the legacy `thinking.type: "enabled"` + `budget_tokens` shape with a 400. Claude Code falls back to that shape when it cannot read the upstream model's capability metadata, which is exactly the case when AI Bridge sits between the client and Bedrock. Pinning back to Opus 4.6 is the only operator workaround today. This is the counterpart to the `adaptive -> enabled` conversion added in [coder/aibridge#225](coder/aibridge#225) for older Bedrock models. ## Behavior - New `bedrockModelRequiresAdaptiveThinking()` helper matches Opus 4.7 (covers `us.anthropic.claude-opus-4-7`, ARN-style application inference profile names that include the model ID, etc.). - New `RequestPayload.convertEnabledThinkingForBedrock()` rewrites `thinking: {type: enabled, budget_tokens: N}` to `thinking: {type: adaptive}`. The budget hint is dropped; an explicit `output_config.effort` from the caller is preserved naturally because we never touch that field. We deliberately do **not** derive an effort label from the budget (see decision log). - `removeUnsupportedBedrockFields` learns a variadic `exemptFields` parameter. Adaptive-only models support `output_config` natively (no beta flag required), so `augmentRequestForBedrock` exempts that field for those models. - Bedrock Opus 4.7 accepts `output_config.effort` but rejects `output_config.format` (structured outputs) with the same "Extra inputs are not permitted" 400. The generic strip pass operates at top-level granularity only, so a small targeted pass drops `output_config.format` after the top-level strip for adaptive-only models. The whole Bedrock thinking-type shim block carries a header comment flagging it as temporary; a planned native Bedrock provider removes the impedance mismatch and lets us delete it. ## Out of scope The issue calls out a possible follow-up around `Anthropic-Beta: interleaved-thinking-2025-05-14` for adaptive-only models; best evidence is that Opus 4.7 still accepts those flags, so this PR is a no-op there. <details> <summary>Decision log</summary> - `bedrockModelSupportsAdaptiveThinking` now also returns `true` for adaptive-only models. That keeps the existing `convertAdaptiveThinkingForBedrock` branch from running on Opus 4.7 (which would otherwise be incorrect; `adaptive` is the supported native type there), and the new `convertEnabledThinkingForBedrock` runs only for adaptive-only models via the explicit `bedrockModelRequiresAdaptiveThinking` switch case. The two model sets are disjoint by construction. - The reverse conversion does **not** derive `output_config.effort` from `budget_tokens / max_tokens`. The two thinking shapes encode different intents (`enabled+budget` is "give me exactly N tokens," `adaptive[+effort]` is "model, pick a budget, optionally biased") and there is no canonical mapping between them. An earlier draft of this PR derived effort via midpoints of an invented anchor table; it was symmetric-looking but lossy and required a lot of scaffolding (sorted anchors, init-time invariant guard, round-trip tests) to keep two halves consistent. The reverse direction now just rewrites the shape, which is honest about the information loss and matches platform-defined adaptive behavior when no effort hint is present. - `output_config.format` is stripped only for adaptive-only models. Other Bedrock models either don't get `output_config` through at all (top-level strip handles them) or accept it via a beta flag that may imply broader feature support. Easy to widen if the same 400 shows up elsewhere. - I chose `variadic exemptFields ...string` over passing the model down to `removeUnsupportedBedrockFields`, to keep that function focused on stripping and to localise the model-aware policy in `augmentRequestForBedrock`. </details>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

This PR removes unsupported fields from requests to Bedrock.
Adaptive thinking field is replaced for models that don't support with
type: enabled+budget_tokens: Ncombination.budget_tokensvalue is calculated as a ratio ofmax_tokens.Ratio depends on
output_config.effortvalue, used the same ratio values as OpenRouter does: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens#reasoning-effort-levelFixes: #219