fix: send model-specific OpenAI reasoning formats for Bedrock Converse - #19420
Conversation
Co-authored-by: mmurilo <43329254+mmurilo@users.noreply.github.com>
|
I applied this PR verbatim and tested it against live Bedrock. It fixes the classification but not the failure — the reported request still returns HTTP 400. The unit tests pass because the mocked server accepts any body once What this PR changes vs. what the service acceptsWith this PR applied, I captured the exact {
"us.openai.gpt-5.6-luna": { "reasoning_effort": "high" },
"global.openai.gpt-5.6-luna": { "reasoning_effort": "high" },
"openai.gpt-oss-120b-1:0": { "reasoning_effort": "high" }
}Replaying those exact bodies through
And the shape the GPT-5.x family does accept:
So after this PR the error message changes from Why the two families must divergeThe flat form cannot simply be replaced, because
By contrast GPT-5.6 strictly validates the map: an unknown key returns 400, and Suggested amendmentKeep the classification change in this PR and add the shape selection: } else if (isOpenAIModel) {
- // OpenAI models on Bedrock expect `reasoning_effort` as a flat value
- amazonBedrockOptions.additionalModelRequestFields = {
- ...amazonBedrockOptions.additionalModelRequestFields,
- reasoning_effort: maxReasoningEffort,
- };
+ // gpt-oss models on Bedrock expect `reasoning_effort` as a flat value,
+ // while the GPT-5.x family expects a nested `reasoning.effort` object
+ // and rejects the flat form with `unknown_parameter`.
+ amazonBedrockOptions.additionalModelRequestFields =
+ this.modelId.includes('gpt-oss')
+ ? {
+ ...amazonBedrockOptions.additionalModelRequestFields,
+ reasoning_effort: maxReasoningEffort,
+ }
+ : {
+ ...amazonBedrockOptions.additionalModelRequestFields,
+ reasoning: {
+ ...amazonBedrockOptions.additionalModelRequestFields
+ ?.reasoning,
+ effort: maxReasoningEffort,
+ },
+ };
} else {The new CRIS test should then assert nested expect(requestBody).toMatchObject({
additionalModelRequestFields: {
- reasoning_effort: 'medium',
+ reasoning: { effort: 'medium' },
},
});
+ expect(
+ requestBody.additionalModelRequestFields?.reasoning_effort,
+ ).toBeUndefined();
expect(
requestBody.additionalModelRequestFields?.reasoningConfig,
).toBeUndefined();Verification of the amendment
Since the mocked test server accepts anything, it may be worth having the CRIS mock reject flat Happy to push the amendment to this branch or open a follow-up PR, whichever you prefer. References
All calls were made in |
mmurilo
left a comment
There was a problem hiding this comment.
Suggested changes to make this PR fix the reported failure. As tested against live Bedrock (details in my earlier comment), the classification change here is correct and necessary, but the emitted field still has to differ per OpenAI family:
gpt-oss→ flatreasoning_effort(honored; must be preserved)- GPT-5.x → nested
reasoning.effort(flat form returns 400unknown_parameter: 'reasoning_effort')
The inline suggestions below cover the test assertions. The source change is not in this diff's hunks, so it cannot be offered as an applyable suggestion — it is included here for convenience:
} else if (isOpenAIModel) {
- // OpenAI models on Bedrock expect `reasoning_effort` as a flat value
- amazonBedrockOptions.additionalModelRequestFields = {
- ...amazonBedrockOptions.additionalModelRequestFields,
- reasoning_effort: maxReasoningEffort,
- };
+ // gpt-oss models on Bedrock expect `reasoning_effort` as a flat value,
+ // while the GPT-5.x family expects a nested `reasoning.effort` object
+ // and rejects the flat form with `unknown_parameter`.
+ amazonBedrockOptions.additionalModelRequestFields =
+ this.modelId.includes('gpt-oss')
+ ? {
+ ...amazonBedrockOptions.additionalModelRequestFields,
+ reasoning_effort: maxReasoningEffort,
+ }
+ : {
+ ...amazonBedrockOptions.additionalModelRequestFields,
+ reasoning: {
+ ...amazonBedrockOptions.additionalModelRequestFields
+ ?.reasoning,
+ effort: maxReasoningEffort,
+ },
+ };
} else {(in packages/amazon-bedrock/src/amazon-bedrock-chat-language-model.ts, replacing the existing isOpenAIModel branch around line 331)
With both the source change and these test changes applied: Test Files 19 passed (19), Tests 473 passed (473) in packages/amazon-bedrock, and live Converse calls for us.openai.gpt-5.6-luna / global.openai.gpt-5.6-luna return 200. Without the source change, the suggested assertions fail with reasoning_effort: 'high' received — which is what the live service rejects.
Bugfix reviewOutcome: changes-required Reproduction replayStatus: no-longer-reproduces The exact original reproduction completed successfully and the original bug signal did not appear. Fixes issueStatus: partially-addresses The PR fixes CRIS OpenAI classification, but the resulting request still fails: the OpenAI branch emits flat reasoning_effort, while the issue's corrected live-service evidence shows GPT-5.6 requires nested reasoning.effort and rejects the flat field. Concerns:
Side effectsRisk: low Existing non-prefixed gpt-oss behavior is preserved, but includes('openai.') also reclassifies arbitrary custom or profile IDs containing that substring. Concerns:
PerformanceRisk: none Replacing startsWith with includes adds only a negligible linear substring scan and no allocations or retained state of consequence. Backwards compatibilityRisk: none The changed code only constructs transient Converse request bodies and does not read, write, migrate, or reinterpret stored data. Breaking changesRisk: none No public exports, APIs, types, accepted provider options, return shapes, defaults, configuration schemas, or persisted formats are removed or narrowed. ArchitectureRisk: medium The change remains localized within the Bedrock provider, but the existing provider-wide isOpenAIModel abstraction is too coarse to select a reasoning wire format because gpt-oss and GPT-5.x require different shapes. Concerns:
Change scopeStatus: minimal The production hunk, related regression tests, and patch changeset are all directly scoped to the reported Bedrock reasoning bug, with no unrelated files in the merge-base diff. SecurityRisk: none The PR changes only model-ID classification and request serialization; it introduces no credential, URL, parsing, authorization, or data-exposure path. TestingStatus: needs-more The new tests pass but assert the wrong flat request shape and use a mock that cannot detect the live GPT-5.6 rejection. Concerns:
VerificationInspected the complete origin/main...HEAD diff and the shared request-construction path used by generation and streaming. The focused CRIS tests passed, all 473 Amazon Bedrock Node tests passed, package type checking passed, formatting/lint checks passed, and git diff checks were clean. Source inspection confirmed that the PR serializes reasoning_effort for the new GPT-5.6 cases, matching its tests but not the corrected service contract. Relevant Documentation
|
|
Thanks @mmurilo for help getting this fixed correctly! I'm on it but probably won't be able to finish it up today |
Co-authored-by: mmurilo <43329254+mmurilo@users.noreply.github.com>
|
Revalidated the current head (
No remaining findings. Thanks for incorporating the family-specific mapping. |
…Converse (#19624) ## Background CRIS-prefixed OpenAI Converse requests mapped reasoning effort to Nova-style `reasoningConfig`, causing Bedrock to reject the request with HTTP 400 `unknown_parameter`. ## Root Cause Two model-family assumptions caused the failure: - OpenAI detection used `modelId.startsWith('openai.')`, which excluded `us.` and `global.` CRIS profile IDs. - The OpenAI branch assumed every OpenAI Bedrock model used flat `reasoning_effort`, but GPT-5.x requires nested `reasoning.effort` while gpt-oss requires the flat field. ## Summary - Recognize direct OpenAI model IDs and IDs with one CRIS profile prefix without broadly matching arbitrary custom IDs. - Send nested `reasoning.effort` for GPT-5.x models. - Preserve flat `reasoning_effort` for gpt-oss models. - Add a patch changeset describing the model-specific serialization fix. ## Testing - Added request-body regression coverage for `us.openai.gpt-5.6-luna` and `global.openai.gpt-5.6-luna`, asserting nested `reasoning.effort` and the absence of both rejected fields. - Preserved the existing gpt-oss flat-field regression coverage. - Added coverage ensuring arbitrary custom model IDs containing `openai.` are not reclassified. - `pnpm --filter @ai-sdk/amazon-bedrock test` — 19 Node and 19 Edge test files passed, 474 tests in each runtime. - `pnpm --filter @ai-sdk/amazon-bedrock type-check` - `pnpm check` - `pnpm type-check:full` ## Service Validation Live Bedrock validation reported in #19403 confirmed that `reasoning.effort` succeeds for the `us.` and `global.` GPT-5.6 inference profiles, while flat `reasoning_effort` is rejected. The gpt-oss family continues to honor the flat field. ## Related Issues Fixes #19403 Closes #19621 Backport of #19420 --------- Co-authored-by: ai-sdk-factory[bot] <305873210+ai-sdk-factory[bot]@users.noreply.github.com> Co-authored-by: ai-sdk-factory <308175966+ai-sdk-factory@users.noreply.github.com>
…Converse (#19626) ## Background CRIS-prefixed OpenAI Converse requests mapped reasoning effort to Nova-style `reasoningConfig`, causing Bedrock to reject the request with HTTP 400 `unknown_parameter`. ## Root Cause Two model-family assumptions caused the failure: - OpenAI detection used `modelId.startsWith('openai.')`, which excluded `us.` and `global.` CRIS profile IDs. - The OpenAI branch assumed every OpenAI Bedrock model used flat `reasoning_effort`, but GPT-5.x requires nested `reasoning.effort` while gpt-oss requires the flat field. ## Summary - Recognize direct OpenAI model IDs and IDs with one CRIS profile prefix without broadly matching arbitrary custom IDs. - Send nested `reasoning.effort` for GPT-5.x models. - Preserve flat `reasoning_effort` for gpt-oss models. - Add a patch changeset describing the model-specific serialization fix. ## Testing - Added request-body regression coverage for `us.openai.gpt-5.6-luna` and `global.openai.gpt-5.6-luna`, asserting nested `reasoning.effort` and the absence of both rejected fields. - Preserved the existing gpt-oss flat-field regression coverage. - Added coverage ensuring arbitrary custom model IDs containing `openai.` are not reclassified. - `pnpm --filter @ai-sdk/amazon-bedrock test` — 19 Node and 19 Edge test files passed, 474 tests in each runtime. - `pnpm --filter @ai-sdk/amazon-bedrock type-check` - `pnpm check` - `pnpm type-check:full` ## Service Validation Live Bedrock validation reported in #19403 confirmed that `reasoning.effort` succeeds for the `us.` and `global.` GPT-5.6 inference profiles, while flat `reasoning_effort` is rejected. The gpt-oss family continues to honor the flat field. ## Related Issues Fixes #19403 Closes #19622 Backport of #19420 --------- Co-authored-by: ai-sdk-factory[bot] <305873210+ai-sdk-factory[bot]@users.noreply.github.com> Co-authored-by: ai-sdk-factory <308175966+ai-sdk-factory@users.noreply.github.com> Co-authored-by: Gregor Martynus <39992+gr2m@users.noreply.github.com>
Keep flat reasoning_effort for GPT-OSS and send nested reasoning.effort for other OpenAI models. Recognize the documented in. inference-profile prefix without broad substring matching. Preserve omission, numeric-budget handling, and token defaults. Based on the live GPT-5.6 Converse/ConverseStream findings in vercel/ai#19403 and the merged fix in vercel/ai#19420. Validation: 335 library tests passed; 354 with bedrock-sigv4. Expanded local-only HTTP tests passed 20 signed request cases across both shapes, omission, and budgets. The HTTP test remains uncommitted. Local AWS invocation still returns Error 002; no new live acceptance claim, particularly for Astra.
Background
CRIS-prefixed OpenAI Converse requests mapped reasoning effort to Nova-style
reasoningConfig, causing Bedrock to reject the request with HTTP 400unknown_parameter.Root Cause
Two model-family assumptions caused the failure:
modelId.startsWith('openai.'), which excludedus.andglobal.CRIS profile IDs.reasoning_effort, but GPT-5.x requires nestedreasoning.effortwhile gpt-oss requires the flat field.Summary
reasoning.effortfor GPT-5.x models.reasoning_effortfor gpt-oss models.Testing
us.openai.gpt-5.6-lunaandglobal.openai.gpt-5.6-luna, asserting nestedreasoning.effortand the absence of both rejected fields.openai.are not reclassified.pnpm --filter @ai-sdk/amazon-bedrock test— 19 Node and 19 Edge test files passed, 474 tests in each runtime.pnpm --filter @ai-sdk/amazon-bedrock type-checkpnpm checkpnpm type-check:fullService Validation
Live Bedrock validation reported in #19403 confirmed that
reasoning.effortsucceeds for theus.andglobal.GPT-5.6 inference profiles, while flatreasoning_effortis rejected. The gpt-oss family continues to honor the flat field.Related Issues
Fixes #19403
Closes #19410