Repository navigation
Description
Description
BedrockChatClient hard-codes response_format: None in BedrockChatOptions, which blocks structured output entirely. The Converse API now supports outputConfig.textFormat with a jsonSchema type for API-enforced structured output (GA since February 2026, works with Converse, ConverseStream, InvokeModel, and InvokeModelWithResponseStream). The Anthropic, Gemini, and OpenAI clients in MAF all support response_format already. Bedrock is the odd one out.
What needs to change
1. Remove the response_format: None override so ChatOptions.response_format can flow through naturally.
2. Add a _prepare_output_config() helper that converts Pydantic models or dict schemas into the Bedrock wire format:
def _prepare_output_config(self, response_format):
if response_format is None:
return None
if isinstance(response_format, dict):
schema = response_format.get("json_schema", {}).get("schema", response_format)
name = response_format.get("json_schema", {}).get("name", "output_schema")
else:
schema = response_format.model_json_schema()
name = response_format.__name__
self._set_additional_properties_false(schema)
return {
"textFormat": {
"type": "jsonSchema",
"jsonSchema": {
"name": name,
"schema": json.dumps(schema), # Bedrock wants a JSON string, not a dict
},
}
}The recursive _set_additional_properties_false helper mirrors what AnthropicChatClient._prepare_response_format() does (lines 659-693).
3. Wire it into _prepare_options() after the toolConfig block:
if output_config := self._prepare_output_config(options.get("response_format")):
run_options["outputConfig"] = output_config4. Populate ChatResponse.value by passing response_format through to _build_response, same as the Anthropic client does.
Compatibility notes
- When
response_formatis omitted, nothing changes. NooutputConfiggets sent. - Models that don't support
outputConfig.textFormatwill return aValidationExceptionfrom Bedrock. Surface that clearly rather than silently falling back to unstructured text. Agent.run(response_format=...)might need a separate follow-up to pass the option down to the client layer.
Acceptance criteria
-
outputConfig.textFormat.jsonSchema.schemais serialized as a JSON string (not a dict) -
additionalProperties: falseis set recursively on all object schemas - No
outputConfigin the request whenresponse_formatis not provided - Clear error when a model doesn't support it (no silent downgrade)
-
ChatResponse.valueis populated with a parsed Pydantic model - Unit tests covering request shape, string serialization, and the no-op path
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
[-][Feature]: Python: BedrockChatClient — support Converse API outputConfig.textFormat for structured output[/-][+][Feature]: Python: BedrockChatClient support Converse API outputConfig.textFormat for structured output[/+][-][Feature]: Python: BedrockChatClient support Converse API outputConfig.textFormat for structured output[/-][+]Python: [Feature]: Python: BedrockChatClient — support Converse API outputConfig.textFormat for structured output[/+]karthik-0306 commentedon May 23, 2026
I've now verified the correct wire format against the AWS CLI reference and the Feb 4, 2026 Bedrock API changelog.
The issue description's proposed
_prepare_output_config()has two problems in the generated shape:Missing structure wrapper — the correct nesting is
textFormat -> structure -> jsonSchema, nottextFormat -> jsonSchema.Wrong type string — the correct value is
"json_schema"(underscore), not"jsonSchema"(camelCase).The correct wire format is:
{ "outputConfig": { "textFormat": { "type": "json_schema", "structure": { "jsonSchema": { "name": "output_schema", "schema": "{...}" } } } } }My implementation plan accounts for both of these. I'll follow the 4-step approach:
response_format: Noneoverride_prepare_output_config()with the correct structure_prepare_options()ChatResponse.valuein_build_response()I’ll also add unit tests covering:
Happy to open a draft PR shortly.
Python: feat(bedrock): implement native structured output support via…