Skip to content

Python: [Feature]: Python: BedrockChatClient — support Converse API outputConfig.textFormat for structured output #5966

@ankit-singh16

Description

@ankit-singh16

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_config

4. Populate ChatResponse.value by passing response_format through to _build_response, same as the Anthropic client does.

Compatibility notes

  • When response_format is omitted, nothing changes. No outputConfig gets sent.
  • Models that don't support outputConfig.textFormat will return a ValidationException from 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.schema is serialized as a JSON string (not a dict)
  • additionalProperties: false is set recursively on all object schemas
  • No outputConfig in the request when response_format is not provided
  • Clear error when a model doesn't support it (no silent downgrade)
  • ChatResponse.value is populated with a parsed Pydantic model
  • Unit tests covering request shape, string serialization, and the no-op path

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions