improvement: Map response_format to Bedrock Converse outputConfig#1547
improvement: Map response_format to Bedrock Converse outputConfig#1547austin-engle wants to merge 3 commits intoPortkey-AI:2.0.0from
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes Bedrock Converse structured output support by correctly mapping OpenAI-style response_format: { type: "json_schema", ... } into Bedrock’s outputConfig.textFormat, instead of incorrectly placing it in additionalModelRequestFields (which Bedrock ignores).
Changes:
- Remove
response_formatpass-through fromtransformAdditionalModelRequestFields()(previously ineffective for Bedrock). - Add
transformOutputConfig()to translate OpenAIjson_schemastructured output into BedrockoutputConfig.textFormat, including schema stringification and sensible defaults. - Add Bedrock unit tests validating the mapping and ensuring
response_formatis no longer included inadditionalModelRequestFields.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/providers/bedrock/utils.ts |
Adds transformOutputConfig() and removes ineffective response_format placement under additionalModelRequestFields. |
src/providers/bedrock/chatComplete.ts |
Wires response_format into Bedrock Converse request body as outputConfig via transformOutputConfig(). |
src/providers/bedrock/utils.test.ts |
Adds unit coverage for json_schema mapping behavior and guards. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Bedrock Converse API supports structured output via outputConfig.textFormat (added Feb 2026), but the gateway currently puts response_format into additionalModelRequestFields where Bedrock silently ignores it. This change: - Adds transformOutputConfig() to map OpenAI's response_format (json_schema) to Bedrock's outputConfig.textFormat parameter - Adds response_format entry to BedrockConverseChatCompleteConfig - Removes response_format from transformAdditionalModelRequestFields (where it was a no-op) - Handles schema stringification (OpenAI sends object, Bedrock expects string) - Only maps type=json_schema; json_object is not supported by Bedrock - Includes unit tests for all transform cases Ref: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_OutputConfig.html
…ocument strict - Pass through json_schema.description to Bedrock's jsonSchema.description when present (Bedrock's JsonSchemaDefinition supports it) - Guard against undefined/missing schema to prevent JSON.stringify(undefined) - Document that OpenAI's strict field is intentionally dropped (no Bedrock equivalent) - Add 3 new test cases: description present, description absent, schema missing
The 2.0.0 branch restructured utils.ts imports (added apm, awsAuth, cacheService). Update jest mocks to match the new import chain.
25baa65 to
0b6578e
Compare
|
Done — rebased onto I noticed The Anthropic variant's override takes precedence via the spread pattern, so Anthropic models are unaffected. Updated the PR description with a table showing the two paths. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
itsthusharashenoi
left a comment
There was a problem hiding this comment.
Changes have been verified and tested.
The concept of structured outputs in bedrock is working via PortKey.
Changes may be merged.
Regards,
Thushara.
Summary
Bedrock's Converse API supports native structured JSON output via
outputConfig.textFormat(launched February 2025 for Claude 3.5+, Llama, Mistral, and others). However, the gateway currently placesresponse_formatintoadditionalModelRequestFieldson the baseBedrockConverseChatCompleteConfig, where Bedrock silently ignores it — structured output never actually takes effect for non-Anthropic models.This PR adds proper mapping from OpenAI's
response_format: { type: "json_schema", ... }to Bedrock's native Converse APIoutputConfig.textFormatparameter on the base config.What changed
src/providers/bedrock/utils.tsresponse_formatfromtransformAdditionalModelRequestFields()(was a no-op — Bedrock ignores unknown keys inadditionalModelRequestFields)transformOutputConfig()function that maps:schemaas a JSON object, Bedrock expects a JSON stringname(defaults to"response") anddescription(omitted when not provided)schemato prevent malformed requestsstrictis intentionally dropped — Bedrock has no equivalentsrc/providers/bedrock/chatComplete.tsresponse_format→outputConfigentry toBedrockConverseChatCompleteConfigtransformOutputConfigfrom utilssrc/providers/bedrock/utils.test.ts(new)How it interacts with the Anthropic variant
The
BedrockConverseAnthropicChatCompleteConfigin2.0.0already overridesresponse_formatto route throughtransformAnthropicAdditionalModelRequestFields, which maps it toadditionalModelRequestFields.output_config. Since the spread + override pattern means the Anthropic-specific entry takes precedence, Anthropic models are unaffected by this change. This PR only affects the base Converse config used by non-Anthropic models.additionalModelRequestFields.output_configoutputConfig.textFormatDesign decisions
Only
json_schematype is mapped — Bedrock Converse does not supportjson_object. Forjson_objectandtexttypes,transformOutputConfigreturnsundefinedso nooutputConfigis set (same behavior as before).strictis intentionally dropped — OpenAI'sstrictfield has no Bedrock equivalent. Documented in the JSDoc.No model filtering — Rather than maintaining a list of which Bedrock models support structured output, we let Bedrock return a
400 ValidationExceptionfor unsupported models. This matches how other unsupported features (e.g., tool use on models without it) are handled.No streaming changes needed — The same
chatCompleteconfig is used for bothConverseandConverseStreamAPI calls, so structured output works for both.Scoped to Bedrock only — All changes are within
src/providers/bedrock/. Zero impact on any other provider.Context
We discovered this issue while building a Terraform PR review agent that uses Portkey to route structured output calls to Bedrock (Claude Sonnet via Converse API). The model returned correct decisions but empty arrays in the structured response — because without
outputConfig, Bedrock has no schema to enforce and the model was free to minimize output. Switching to tool-use (tools+tool_choice) as a workaround confirmed the model was capable; the gateway translation was the gap.Bedrock API Reference
outputConfigparametertextFormatstructurejson_schematype withJsonSchemaFormatschema(string),name,descriptionTest plan
npx jest src/providers/bedrock/utils.test.ts)2.0.0— no conflictsresponse_format: { type: "json_schema" }