Files
bifrost/docs/providers/supported-providers/bedrock.mdx
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

1856 lines
74 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "AWS Bedrock"
description: "AWS Bedrock API conversion guide - model families, parameter mapping, message handling, reasoning/thinking, tool conversion, and AWS authentication"
icon: "aws"
---
## Overview
AWS Bedrock supports multiple model families (Claude, Nova, Mistral, Llama, Cohere, Titan) with significant structural differences from OpenAI's format. Bifrost performs extensive conversion including:
- **Model family detection** - Automatic routing based on model ID to handle family-specific parameters
- **Parameter renaming** - e.g., `max_completion_tokens` → `maxTokens`, `stop` → `stopSequences`
- **Reasoning transformation** - `reasoning` parameters mapped to model-specific thinking/reasoning structures (Anthropic, Nova)
- **Tool restructuring** - Function definitions converted to Bedrock's ToolConfig format
- **Message conversion** - System message extraction, tool message grouping, image format adaptation (base64 only)
- **AWS authentication** - Automatic SigV4 request signing with credential chain support
- **Structured output** - `response_format` converted to specialized tool definitions
- **Service tier & guardrails** - Support for Bedrock-specific performance and safety configurations
### Model Family Support
| Family | Chat | Responses | Text | Embeddings | Image Generation | Image Edit | Image Variation |
| ---------------------- | ---- | --------- | ---- | ---------- | ---------------- | ---------- | --------------- |
| **Claude (Anthropic)** | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| **Nova (Anthropic)** | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
| **Mistral** | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| **Llama** | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Cohere** | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| **Titan** | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| **Stability AI** | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
### Supported Operations
| Operation | Non-Streaming | Streaming | Endpoint |
| -------------------- | ------------- | --------- | ---------------------- |
| Chat Completions | ✅ | ✅ | `converse` |
| Responses API | ✅ | ✅ | `converse` |
| Text Completions | ✅ | ❌ | `invoke` |
| Embeddings | ✅ | - | `invoke` |
| Files | ✅ | - | S3 (via SDK) |
| Batch | ✅ | - | `batch` |
| List Models | ✅ | - | `listFoundationModels` |
| Image Generation | ✅ | ❌ | `invoke` |
| Image Edit | ✅ | ❌ | `invoke` |
| Image Variation | ✅ | ❌ | `invoke` |
| Count Tokens | ✅ | - | `count-tokens` |
| Speech (TTS) | ❌ | ❌ | - |
| Transcriptions (STT) | ❌ | ❌ | - |
<Note>
**Unsupported Operations** (❌): Speech (TTS) and Transcriptions (STT) are not supported by the upstream AWS Bedrock API. These return `UnsupportedOperationError`.
**Limitations**: Images must be in base64 or data URI format (remote URLs not supported). Text completion streaming is not supported.
</Note>
---
## Setup & Configuration
Bedrock supports both SigV4-based authentication and direct API-key authentication. Four authentication flows are supported — choose the one that matches your deployment environment.
<Note>
The `aliases` field (mapping model names to inference profile IDs, ARNs, or
deployment identifiers) requires **v1.5.0-prerelease2 or later**. On v1.4.x,
use `deployments` inside `bedrock_key_config` instead — see the [v1.5.0
Migration
Guide](/migration-guides/v1.5.0#breaking-change-9-provider-deployments-removed-migrate-to-aliases)
for details.
</Note>
### 1. Explicit Credentials
Provide `access_key` and `secret_key` directly. Optionally include `session_token` for temporary credentials.
<Tabs>
<Tab title="Web UI">
<Frame>
<img
src="/media/ui-bedrock-explicit-credentials-auth-setup.png"
alt="AWS Bedrock explicit credentials authentication setup in the Bifrost Web UI showing Access Key, Secret Key, Session Token, and Region fields"
/>
</Frame>
1. Navigate to **"Model Providers"** → **"Configurations"** → **"AWS Bedrock"**
2. Click **"Add Key"** (or edit an existing key)
3. Under **Authentication Method**, select **"Explicit Credentials"**
4. Set **Access Key**: Your AWS access key ID
5. Set **Secret Key**: Your AWS secret access key
6. Set **Session Token** (Optional): For temporary/assumed credentials
7. Set **Region**: e.g., `us-east-1`
8. Configure **Aliases**: Map model names to inference profile IDs
9. Save
</Tab>
<Tab title="API">
```bash
# Step 1: Create the provider
curl -X POST http://localhost:8080/api/providers \
-H "Content-Type: application/json" \
-d '{"provider": "bedrock"}'
# Step 2: Create a key (Explicit Credentials)
curl -X POST http://localhost:8080/api/providers/bedrock/keys \
-H "Content-Type: application/json" \
-d '{
"name": "bedrock-key",
"models": ["*"],
"weight": 1.0,
"aliases": {
"claude-3-5-sonnet": "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
},
"bedrock_key_config": {
"access_key": "env.AWS_ACCESS_KEY_ID",
"secret_key": "env.AWS_SECRET_ACCESS_KEY",
"session_token": "env.AWS_SESSION_TOKEN",
"region": "us-east-1"
}
}'
```
<Note>
**On v1.4.x**, two differences apply:
- Pass `keys` directly in the `POST /api/providers` body — there is no separate `/api/providers/{provider}/keys` endpoint.
- Replace the top-level `aliases` with `"deployments"` inside `bedrock_key_config`:
```json
"bedrock_key_config": {
"access_key": "env.AWS_ACCESS_KEY_ID",
"secret_key": "env.AWS_SECRET_ACCESS_KEY",
"region": "us-east-1",
"deployments": {
"claude-3-5-sonnet": "arn:aws:bedrock:us-east-1::foundation-model/..."
}
}
```
</Note>
</Tab>
<Tab title="config.json">
```json
{
"providers": {
"bedrock": {
"keys": [
{
"name": "bedrock-key",
"models": ["*"],
"weight": 1.0,
"aliases": {
"claude-3-5-sonnet": "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
},
"bedrock_key_config": {
"access_key": "env.AWS_ACCESS_KEY_ID",
"secret_key": "env.AWS_SECRET_ACCESS_KEY",
"session_token": "env.AWS_SESSION_TOKEN",
"region": "us-east-1"
}
}
]
}
}
}
```
<Note>
On **v1.4.x**, use `deployments` inside `bedrock_key_config` instead of the
top-level `aliases` field.
</Note>
</Tab>
<Tab title="Go SDK">
```go
func (a *MyAccount) GetKeysForProvider(ctx *context.Context, provider schemas.ModelProvider) ([]schemas.Key, error) {
switch provider {
case schemas.Bedrock:
return []schemas.Key{
{
Models: []string{"*"},
Weight: 1.0,
Aliases: schemas.KeyAliases{
"claude-3-5-sonnet": "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
},
BedrockKeyConfig: &schemas.BedrockKeyConfig{
AccessKey: *schemas.NewEnvVar("env.AWS_ACCESS_KEY_ID"),
SecretKey: *schemas.NewEnvVar("env.AWS_SECRET_ACCESS_KEY"),
SessionToken: schemas.NewEnvVar("env.AWS_SESSION_TOKEN"),
Region: schemas.NewEnvVar("us-east-1"),
},
},
}, nil
}
return nil, fmt.Errorf("provider %s not supported", provider)
}
```
</Tab>
</Tabs>
### 2. Inherited AWS Credentials / IAM Role
Uses AWS's default credential chain when static credentials are not configured. That includes IAM roles (IRSA in EKS, ECS task role, EC2 instance profile), environment variables (`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`), and shared credential files.
<Tabs>
<Tab title="Web UI">
<Frame>
<img
src="/media/ui-bedrock-sts-assume-role-auth-setup.png"
alt="AWS Bedrock IAM Role authentication setup in the Bifrost Web UI showing optional Assume Role ARN, External ID, and Session Name fields"
/>
</Frame>
1. Navigate to **"Model Providers"** → **"Configurations"** → **"AWS Bedrock"**
2. Click **"Add Key"** (or edit an existing key)
3. Under **Authentication Method**, select **"IAM Role (Inherited)"**
4. Set **Region**: e.g., `us-east-1`
5. Configure **Aliases** if needed
6. _(Optional)_ Set **Assume Role ARN**: to assume an IAM role before signing (e.g., `arn:aws:iam::123456789012:role/BedrockRole`)
7. _(Optional)_ Set **External ID**: required when the role's trust policy demands it
8. _(Optional)_ Set **Session Name**: identifies the session in CloudTrail (default: `bifrost-session`)
9. Save
For system identity, leave steps 68 blank. Ensure your workload has an IAM role with Bedrock permissions attached (via IRSA, ECS task role, or EC2 instance profile), or that `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` are set in the environment.
</Tab>
<Tab title="API">
```bash
# Step 1: Create the provider
curl -X POST http://localhost:8080/api/providers \
-H "Content-Type: application/json" \
-d '{"provider": "bedrock"}'
# Step 2a: System identity — leave credentials empty
curl -X POST http://localhost:8080/api/providers/bedrock/keys \
-H "Content-Type: application/json" \
-d '{
"name": "bedrock-iam",
"models": ["*"],
"weight": 1.0,
"aliases": {
"claude-3-5-sonnet": "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
},
"bedrock_key_config": {
"region": "us-east-1"
}
}'
# Step 2b: AssumeRole — add role_arn on top
curl -X POST http://localhost:8080/api/providers/bedrock/keys \
-H "Content-Type: application/json" \
-d '{
"name": "bedrock-assume-role",
"models": ["*"],
"weight": 1.0,
"bedrock_key_config": {
"region": "us-east-1",
"role_arn": "env.AWS_ROLE_ARN",
"external_id": "env.AWS_EXTERNAL_ID",
"session_name": "bifrost-session"
}
}'
```
<Note>
**On v1.4.x**, two differences apply: - Pass `keys` directly in the `POST
/api/providers` body — there is no separate `/api/providers/{provider}/keys`
endpoint. - Replace the top-level `aliases` with `"deployments"` inside
`bedrock_key_config`.
</Note>
</Tab>
<Tab title="config.json">
```json
{
"providers": {
"bedrock": {
"keys": [
{
"name": "bedrock-iam",
"models": ["*"],
"weight": 1.0,
"aliases": {
"claude-3-5-sonnet": "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
},
"bedrock_key_config": {
"region": "us-east-1",
"role_arn": "env.AWS_ROLE_ARN",
"external_id": "env.AWS_EXTERNAL_ID",
"session_name": "bifrost-session"
}
}
]
}
}
}
```
<Note>
Omit `role_arn`, `external_id`, and `session_name` for plain system identity
with no role assumption.
</Note>
</Tab>
<Tab title="Go SDK">
```go
func (a *MyAccount) GetKeysForProvider(ctx *context.Context, provider schemas.ModelProvider) ([]schemas.Key, error) {
switch provider {
case schemas.Bedrock:
return []schemas.Key{
{
Models: []string{"*"},
Weight: 1.0,
Aliases: schemas.KeyAliases{
"claude-3-5-sonnet": "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
},
BedrockKeyConfig: &schemas.BedrockKeyConfig{
// Leave AccessKey and SecretKey empty — resolved from IRSA/instance profile/env vars
Region: schemas.NewEnvVar("us-east-1"),
RoleARN: schemas.NewEnvVar("env.AWS_ROLE_ARN"), // optional
ExternalID: schemas.NewEnvVar("env.AWS_EXTERNAL_ID"), // optional
RoleSessionName: schemas.NewEnvVar("bifrost-session"), // optional
},
},
}, nil
}
return nil, fmt.Errorf("provider %s not supported", provider)
}
```
</Tab>
</Tabs>
### 3. API Key
Set `value` to a Bearer token for direct API key authentication. This method uses a Bearer token instead of SigV4 signing and does not support STS AssumeRole.
<Tabs>
<Tab title="Web UI">
<Frame>
<img
src="/media/ui-bedrock-api-key-auth-setup.png"
alt="AWS Bedrock API Key authentication setup in the Bifrost Web UI showing the API Key field and Region"
/>
</Frame>
1. Navigate to **"Model Providers"** → **"Configurations"** → **"AWS Bedrock"**
2. Click **"Add Key"** (or edit an existing key)
3. Under **Authentication Method**, select **"API Key"**
4. Set **API Key**: Your Bedrock API key (Bearer token)
5. Set **Region**: e.g., `us-east-1`
6. Configure **Aliases** if needed
7. Save
</Tab>
<Tab title="API">
```bash
# Step 1: Create the provider
curl -X POST http://localhost:8080/api/providers \
-H "Content-Type: application/json" \
-d '{"provider": "bedrock"}'
# Step 2: Create a key (API Key / Bearer token)
curl -X POST http://localhost:8080/api/providers/bedrock/keys \
-H "Content-Type: application/json" \
-d '{
"name": "bedrock-api-key",
"value": "env.BEDROCK_API_KEY",
"models": ["*"],
"weight": 1.0,
"bedrock_key_config": {
"region": "us-east-1"
}
}'
```
</Tab>
<Tab title="config.json">
```json
{
"providers": {
"bedrock": {
"keys": [
{
"name": "bedrock-api-key",
"value": "env.BEDROCK_API_KEY",
"models": ["*"],
"weight": 1.0,
"bedrock_key_config": {
"region": "us-east-1"
}
}
]
}
}
}
```
</Tab>
<Tab title="Go SDK">
```go
func (a *MyAccount) GetKeysForProvider(ctx *context.Context, provider schemas.ModelProvider) ([]schemas.Key, error) {
switch provider {
case schemas.Bedrock:
return []schemas.Key{
{
Value: *schemas.NewEnvVar("env.BEDROCK_API_KEY"),
Models: []string{"*"},
Weight: 1.0,
BedrockKeyConfig: &schemas.BedrockKeyConfig{
Region: schemas.NewEnvVar("us-east-1"),
},
},
}, nil
}
return nil, fmt.Errorf("provider %s not supported", provider)
}
```
</Tab>
</Tabs>
**`bedrock_key_config` fields:**
| Field | Required | Default | Description |
| --------------- | -------- | ----------------- | --------------------------------------------------------------------------------------------------------------------- |
| `region` | Yes | — | AWS region (e.g., `us-east-1`) |
| `access_key` | No | — | AWS access key ID |
| `secret_key` | No | — | AWS secret access key |
| `session_token` | No | — | AWS session token (for temporary credentials) |
| `arn` | No | — | ARN prefix for constructing inference profile URLs (see [Inference Profiles](#inference-profiles--arn-configuration)) |
| `role_arn` | No | — | IAM role ARN for STS AssumeRole |
| `external_id` | No | — | External ID for AssumeRole (when required by trust policy) |
| `session_name` | No | `bifrost-session` | Session name for AssumeRole CloudTrail logs |
**Key-level fields:**
| Field | Required | Description |
| --------- | -------- | ----------------------------------------------------------------------------------- |
| `aliases` | No | Map model names to inference profile IDs or Bedrock model IDs (v1.5.0-prerelease2+) |
| `models` | Yes | Models this key can serve; use `["*"]` to allow all |
---
## Beta Headers
For Claude models on Bedrock, Bifrost validates `anthropic-beta` headers and drops unsupported headers from the request.
**Supported**: `computer-use-*`, `structured-outputs-*`, `compact-*`, `context-management-*`, `interleaved-thinking-*`, `context-1m-*`
**Not supported**: `advanced-tool-use-*`, `mcp-client-*`, `prompt-caching-scope-*`, `files-api-*`, `skills-*`, `fast-mode-*`, `redact-thinking-*`
You can override these defaults per provider via the **Beta Headers** tab in provider configuration or via [`beta_header_overrides`](/quickstart/gateway/provider-configuration#beta-header-overrides). See the full support matrix in the [Anthropic provider docs](/providers/supported-providers/anthropic#beta-headers).
<Frame>
<img
src="/media/aws-bedrock-anthropic-beta-headers.png"
alt="AWS bedrock Beta Headers configuration tab showing supported and unsupported Anthropic beta features with override options"
/>
</Frame>
---
# 1. Chat Completions
## Request Parameters
### Parameter Mapping
| Parameter | Transformation | Notes |
| ----------------------- | --------------------------------------------------------------------------------- | -------------------------- |
| `max_completion_tokens` | → `inferenceConfig.maxTokens` | Required field in Bedrock |
| `temperature`, `top_p` | Direct pass-through to `inferenceConfig` | |
| `stop` | → `inferenceConfig.stopSequences` | Array of strings |
| `response_format` | → Structured output tool (see [Structured Output](#structured-output)) | Creates `bf_so_*` tool |
| `tools` | Schema restructured (see [Tool Conversion](#tool-conversion)) | |
| `tool_choice` | Type mapped (see [Tool Conversion](#tool-conversion)) | |
| `reasoning` | Model-specific thinking config (see [Reasoning / Thinking](#reasoning--thinking)) | |
| `user` | → `metadata.userID` (if provided) | Bedrock-specific metadata |
| `service_tier` | → `serviceModelTier` (if provided) | Performance tier selection |
| `top_k` | Via `extra_params` (model-specific) | Bedrock-specific sampling |
### Dropped Parameters
The following parameters are silently ignored: `frequency_penalty`, `presence_penalty`, `logit_bias`, `logprobs`, `top_logprobs`, `seed`, `parallel_tool_calls`
### Extra Parameters
Use `extra_params` (SDK) or pass directly in request body (Gateway) for Bedrock-specific fields:
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
"messages": [{"role": "user", "content": "Hello"}],
"guardrailConfig": {
"guardrailIdentifier": "guardrail-id",
"guardrailVersion": "1",
"trace": "enabled"
},
"performanceConfig": {
"latency": "optimized"
}
}'
```
</Tab>
<Tab title="Go SDK">
```go
resp, err := client.ChatCompletionRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostChatRequest{
Provider: schemas.Bedrock,
Model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
Input: messages,
Params: &schemas.ChatParameters{
ExtraParams: map[string]interface{}{
"guardrailConfig": map[string]interface{}{
"guardrailIdentifier": "guardrail-id",
"guardrailVersion": "1",
"trace": "enabled",
},
"performanceConfig": map[string]interface{}{
"latency": "optimized",
},
},
},
})
```
</Tab>
</Tabs>
**Available Extra Parameters:**
- `guardrailConfig` - Bedrock guardrail configuration with `guardrailIdentifier`, `guardrailVersion`, `trace`
- `performanceConfig` - Performance optimization with `latency` ("optimized" or "standard")
- `additionalModelRequestFieldPaths` - Pass-through for model-specific fields not in standard schema
- `promptVariables` - Variables for prompt templates (if using prompt caching)
- `requestMetadata` - Custom metadata for request tracking
### Cache Control
Prompt caching is supported via cache control directives:
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "This context will be cached",
"cache_control": {"type": "ephemeral"}
}
]
}
],
"system": [
{
"type": "text",
"text": "You are a helpful assistant",
"cache_control": {"type": "ephemeral"}
}
]
}'
```
</Tab>
<Tab title="Go SDK">
```go
resp, err := client.ChatCompletionRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostChatRequest{
Provider: schemas.Bedrock,
Model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
Input: []schemas.ChatMessage{
{
Role: schemas.ChatMessageRoleUser,
Content: &schemas.ChatMessageContent{
ContentBlocks: []schemas.ChatContentBlock{
{
Text: schemas.Ptr("This context will be cached"),
CacheControl: &schemas.CacheControl{
Type: schemas.Ptr("ephemeral"),
},
},
},
},
},
},
SystemMessages: []schemas.ChatMessage{
{
Role: schemas.ChatMessageRoleSystem,
Content: &schemas.ChatMessageContent{
ContentBlocks: []schemas.ChatContentBlock{
{
Text: schemas.Ptr("You are a helpful assistant"),
CacheControl: &schemas.CacheControl{
Type: schemas.Ptr("ephemeral"),
},
},
},
},
},
},
})
```
</Tab>
</Tabs>
## Reasoning / Thinking
**Documentation**: See [Bifrost Reasoning Reference](/providers/reasoning)
Reasoning/thinking support varies by model family:
### Anthropic Claude Models
**Parameter Mapping:**
- `reasoning.effort` → `thinkingConfig.type = "enabled"` (always enabled when reasoning present)
- `reasoning.max_tokens` → `thinkingConfig.budgetTokens` (token budget for thinking)
**Critical Constraints:**
- **Minimum budget**: 1024 tokens required; requests below this **fail with error**
- **Dynamic budget**: `-1` is converted to `1024` automatically
```json
// Request
{"reasoning": {"effort": "high", "max_tokens": 2048}}
// Bedrock conversion
{"thinkingConfig": {"type": "enabled", "budgetTokens": 2048}}
```
### Anthropic Nova Models
**Parameter Mapping:**
- `reasoning.effort` → `reasoningConfig.thinkingLevel` ("low" → `low`, "high" → `high`)
- `reasoning.max_tokens` → Max reasoning tokens (affects inference configuration)
```json
// Request
{"reasoning": {"effort": "high", "max_tokens": 10000}}
// Bedrock conversion
{"reasoningConfig": {"type": "enabled", "thinkingLevel": "high"}}
```
## Message Conversion
### Critical Caveats
- **System message extraction**: System messages are **removed from messages array** and placed in separate `system` field
- **Tool message grouping**: Consecutive tool messages are **merged into single user message** with tool result content blocks
- **Image format**: **Only base64/data URI supported**; remote image URLs are **not supported** by Bedrock Converse API
- **Document support**: Bifrost's Bedrock conversion path currently supports PDF, CSV, DOC, DOCX, XLS, XLSX, HTML, TXT, MD formats
### Supported Chat Content Blocks
The Chat Completions request format is OpenAI-compatible for standard blocks (`type: "text"`, `type: "image_url"`, `type: "file"`). Bifrost converts these blocks to Bedrock Converse blocks internally. Bedrock-specific extensions (for example, standalone `cachePoint`) are also accepted when using the Bedrock provider.
| Block Type | Request Shape (Bifrost/OpenAI) | Bedrock Handling | Support |
| ---------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------- |
| Text | `{"type":"text","text":"..."}` | Converted to Bedrock `text` block | ✅ |
| Image | `{"type":"image_url","image_url":{"url":"data:image/png;base64,..."}}` | Converted to Bedrock `image.source.bytes` | ✅ (base64/data URI only) |
| File | `{"type":"file","file":{...}}` | Converted to Bedrock `document` block | ✅ |
| Input audio | `{"type":"input_audio",...}` | Returns `audio input not supported in Bedrock Converse API` | ❌ |
| Standalone cache point | `{"cachePoint":{"type":"default"}}` (no outer `type` field) | Converted to Bedrock `cachePoint` marker | ✅ (Bedrock-specific extension) |
### Image Conversion
- **Request shape (client → Bifrost)**: `type: "image_url"` with `image_url.url` set to a data URI/base64 image
- **Internal Bedrock shape (Bifrost → Bedrock)**: Converted to `image: { format, source: { bytes } }`
- **URL images**: ❌ **Not supported** - Will fail if attempted
- **Documents**: Converted to document content blocks with MIME types
### Image Block Example (`image_url`)
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
}
]
}
]
}'
```
</Tab>
<Tab title="Go SDK">
```go
// Note: In the Go SDK, ChatContentBlockTypeImage maps to the OpenAI-compatible "image_url" block.
resp, err := client.ChatCompletionRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostChatRequest{
Provider: schemas.Bedrock,
Model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
Input: []schemas.ChatMessage{
{
Role: schemas.ChatMessageRoleUser,
Content: &schemas.ChatMessageContent{
ContentBlocks: []schemas.ChatContentBlock{
{
Type: schemas.ChatContentBlockTypeText,
Text: schemas.Ptr("What is in this image?"),
},
{
Type: schemas.ChatContentBlockTypeImage,
ImageURLStruct: &schemas.ChatInputImage{
URL: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
},
},
},
},
},
},
})
```
</Tab>
</Tabs>
### File Block Example (`file` → Bedrock `document`)
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Summarize this document."},
{
"type": "file",
"file": {
"file_data": "JVBERi0xLjQKJcfs...",
"filename": "report.pdf",
"file_type": "application/pdf"
}
}
]
}
]
}'
```
</Tab>
<Tab title="Go SDK">
```go
resp, err := client.ChatCompletionRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostChatRequest{
Provider: schemas.Bedrock,
Model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
Input: []schemas.ChatMessage{
{
Role: schemas.ChatMessageRoleUser,
Content: &schemas.ChatMessageContent{
ContentBlocks: []schemas.ChatContentBlock{
{
Type: schemas.ChatContentBlockTypeText,
Text: schemas.Ptr("Summarize this document."),
},
{
Type: schemas.ChatContentBlockTypeFile,
File: &schemas.ChatInputFile{
FileData: schemas.Ptr("JVBERi0xLjQKJcfs..."),
Filename: schemas.Ptr("report.pdf"),
FileType: schemas.Ptr("application/pdf"),
},
},
},
},
},
},
})
```
</Tab>
</Tabs>
Note: `file_data` is raw base64-encoded content (no `data:` URI prefix, unlike `image_url`).
Formats currently supported by Bifrost's Bedrock document conversion path: `pdf`, `txt`, `md`, `html`, `csv`, `doc`, `docx`, `xls`, `xlsx`.
### Standalone Cache Point Example (Bedrock-specific)
```json
{
"role": "system",
"content": [
{ "type": "text", "text": "Long context to cache" },
{ "cachePoint": { "type": "default" } }
]
}
```
This standalone `cachePoint` block is a Bifrost/Bedrock extension (not OpenAI-standard) and should be used only with the Bedrock provider.
### Unsupported Block Notes
- `input_audio` blocks are not supported by Bedrock Converse and return an error.
- For chat content conversion, use `file.file_data` for document payloads. `file_url` and `file_id` are not the documented Bedrock chat-content path here.
### Cache Control Locations
Cache directives supported on:
- System content blocks (entire system message)
- User message content blocks (specific parts)
- Tool definitions within tool configuration
## Tool Conversion
Tool definitions are restructured:
- `function.name` → `name` (preserved)
- `function.parameters` → `inputSchema` (Schema format)
- `function.strict` → Dropped (not supported by Bedrock)
### Tool Choice Mapping
| OpenAI | Bedrock |
| ------------- | ---------------------------------- |
| `"auto"` | `auto` (default) |
| `"none"` | Omitted (not explicitly supported) |
| `"required"` | `any` |
| Specific tool | `{type: "tool", name: "X"}` |
### Tool Call Handling
Tool calls are converted between formats:
- **Bifrost → Bedrock**: Tool call arguments converted from JSON object to `input` field
- **Bedrock → Bifrost**: Tool use results with `toolUseId`, converted back to Bifrost format
- **Tool results**: Merged consecutive tool messages into single user message
## Structured Output
Structured output uses a special tool-based approach:
```json
// Request with structured output
{
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "response",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "number"}
}
}
}
}
}
// Bedrock conversion (internal)
{
"tools": [{
"name": "bf_so_response",
"description": "Structured output tool",
"inputSchema": {
"type": "object",
"properties": {...}
}
}],
"toolChoice": {"type": "tool", "name": "bf_so_response"}
}
// Response extraction
// Tool use input is extracted and returned as contentStr
```
## Response Conversion
### Field Mapping
- `stopReason` → `finish_reason`: `endTurn`/`stopSequence` → `stop`, `maxTokens` → `length`, `toolUse` → `tool_calls`
- `usage.inputTokens + usage.cacheReadInputTokens + usage.cacheWriteInputTokens` → `prompt_tokens` (all cache counts rolled into the total)
- Cache token breakdown surfaced in `prompt_tokens_details`:
- `usage.cacheReadInputTokens` → `prompt_tokens_details.cached_read_tokens`
- `usage.cacheWriteInputTokens` → `prompt_tokens_details.cached_write_tokens`
- `usage.outputTokens` → `completion_tokens`
- `reasoning`/`thinking` blocks → `reasoning_details` with index, type, text, and signature
- Tool call `input` (object) → `arguments` (JSON string)
### Structured Output Response
When structured output is detected:
- Tool call with name `bf_so_*` is treated as structured output
- `input` object is extracted and returned as `contentStr`
- Removed from `toolCalls` array
## Streaming
### Chat Completions Streaming
Event sequence from Bedrock Converse Stream API:
1. **Initial message role**: `contentBlockIndex` and role information
2. **Content block starts**: `toolUse` blocks with `toolUseId`, `name`
3. **Content block deltas**:
- Text delta: Incremental text content
- Tool use delta: Accumulated tool call arguments (JSON)
- Reasoning delta: Reasoning text and optional signature
4. **Message completion**: `stopReason` and final token counts
5. **Usage metrics**: Token counts, cached tokens, performance metrics
**Streaming event conversion**:
- Each Bedrock streaming event → Multiple Bifrost chunks as needed
- Tool arguments accumulated across deltas and emitted on block end
- Reasoning content emitted with signature if present
### Text Completion Streaming
❌ **Not supported** - AWS Bedrock's text completion API does not support streaming.
### Responses API Streaming
Streaming responses use OpenAI-compatible lifecycle events:
- `response.created`
- `response.in_progress`
- `content_part.start`
- `content_part.delta`
- `content_part.done`
- `function_call_arguments.delta`
- `function_call_arguments.done`
- `output_item.done`
Special handling:
- Tool arguments accumulated across deltas
- Content block indices mapped to output indices
- Synthetic events emitted for text/reasoning content
---
# 2. Responses API
The Responses API uses the same underlying `converse` endpoint but converts between OpenAI's Responses format and Bedrock's Messages format.
## Request Parameters
### Parameter Mapping
| Parameter | Transformation |
| ---------------------- | -------------------------------------------------------------------------------------- |
| `max_output_tokens` | Renamed to `maxTokens` (via `inferenceConfig`) |
| `temperature`, `top_p` | Direct pass-through |
| `instructions` | Becomes system message |
| `tools` | Schema restructured (see [Chat Completions](#1-chat-completions)) |
| `tool_choice` | Type mapped (see [Chat Completions](#1-chat-completions)) |
| `reasoning` | Mapped to thinking/reasoning config (see [Reasoning / Thinking](#reasoning--thinking)) |
| `text` | Converted to `output_format` (Bedrock-specific) |
| `include` | Via `extra_params` (Bedrock-specific) |
| `stop` | Via `extra_params`, renamed to `stopSequences` |
| `truncation` | Auto-set to `"auto"` for computer tools |
### Extra Parameters
Use `extra_params` (SDK) or pass directly in request body (Gateway):
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
"input": "Hello, how are you?",
"stop": ["###"]
}'
```
</Tab>
<Tab title="Go SDK">
```go
resp, err := client.ResponsesRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostResponsesRequest{
Provider: schemas.Bedrock,
Model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
Input: messages,
Params: &schemas.ResponsesParameters{
ExtraParams: map[string]interface{}{
"stop": []string{"###"},
},
},
})
```
</Tab>
</Tabs>
## Input & Instructions
- **Input**: String wrapped as user message or array converted to messages
- **Instructions**: Becomes system message (same extraction as [Chat Completions](#1-chat-completions))
- **Cache control**: Supported on instructions (system) and input messages
## Response Conversion
- `stopReason` → `status`: `endTurn`/`stopSequence` → `completed`, `maxTokens` → `incomplete`
- `usage.inputTokens` is aggregated into `input_tokens` (same semantics as [Chat](#1-chat-completions): Bedrock's `inputTokens` + `cacheReadInputTokens` + `cacheWriteInputTokens` rolled up into `input_tokens`); `usage.outputTokens` → `output_tokens` (preserved as-is)
- Cache tokens: `cacheReadInputTokens` → `input_tokens_details.cached_read_tokens` | `cacheWriteInputTokens` → `input_tokens_details.cached_write_tokens`
- Output items: `text` → `message` | `toolUse` → `function_call` | `thinking` → `reasoning`
## Streaming
Event sequence: `response.created` → `response.in_progress` → `content_part.start` → `content_part.delta` → `content_part.done` → `output_item.done`
---
# 3. Text Completions (Legacy)
<Warning>
Legacy API using `invoke` endpoint. Streaming not supported. Only Claude
(Anthropic) and Mistral models supported.
</Warning>
**Request conversion**:
- **Claude models**: Uses Anthropic's `/v1/complete` format with prompt wrapping
- `prompt` auto-wrapped with `\n\nHuman: {prompt}\n\nAssistant:`
- `max_tokens` → `max_tokens_to_sample`
- `temperature`, `top_p` direct pass-through
- `top_k`, `stop` via `extra_params`
- **Mistral models**: Uses standard format
- `max_tokens` → `max_tokens`
- `temperature`, `top_p` direct pass-through
- `stop` → `stop`
**Response conversion**:
- **Claude**: `completion` → `choices[0].text`
- **Mistral**: `outputs[].text` → `choices[]` (supports multiple)
- `stopReason` → `finish_reason`
---
# 4. Embeddings
Supported embedding models: **Titan**, **Cohere**
## Request Parameters
### Parameter Mapping
| Parameter | Transformation | Notes |
| ----------------- | ------------------- | ------------------------------------ |
| `input` | Direct pass-through | Text or array of texts |
| `dimensions` | ⚠️ Not supported | Titan has fixed dimensions per model |
| `encoding_format` | Via `extra_params` | "base64" or "float" |
**Titan-specific**:
- No dimension customization
- Fixed output size per model version
**Cohere-specific**:
- Reuses Cohere format conversion
- Similar parameter mapping to standard Cohere
## Response Conversion
- **Titan**: `embedding` → single embedding vector
- **Cohere**: Reuses Cohere response format with `embeddings` array
- `usage.inputTokens` → `usage.prompt_tokens`
---
# 5. Image Generation
Supported image generation models: **Titan Image Generator v1**, **Titan Image Generator v2**, **Nova Canvas v1**
## Request Conversion
| Parameter(Bifrost) | Transformation (Bedrock) |
| ------------------ | ------------------------------------------------------------------------- |
| `prompt` | `textToImageParams.text` |
| `n` | `imageGenerationConfig.numberOfImages` |
| `negativePrompt` | `textToImageParams.negativeText` |
| `seed` | `imageGenerationConfig.seed` |
| `quality` | `imageGenerationConfig.quality` (see [Quality Mapping](#quality-mapping)) |
| `style` | `textToImageParams.style` |
| `size` | `imageGenerationConfig.width` & `imageGenerationConfig.height` |
### Quality Mapping
The `quality` parameter is automatically mapped to Bedrock's expected format:
| Input Value | Bedrock Value | Notes |
| ----------- | ------------- | --------------------------------- |
| `"low"` | `"standard"` | Mapped automatically |
| `"medium"` | `"standard"` | Mapped automatically |
| `"high"` | `"premium"` | Mapped automatically |
| `"default"` | `"standard"` | Passed through (case-insensitive) |
| `"premium"` | `"premium"` | Passed through (case-insensitive) |
## Response Conversion
| Parameter(Bedrock) | Transformation (Bifrost) |
| ------------------ | ------------------------ |
| `images` | `data.b64_json` |
### Example Request
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/images/generations \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/amazon.nova-canvas-v1:0",
"prompt": "A futuristic cityscape with a flying car",
"size": "1024x1024",
"seed": 123,
"negative_prompt": "bikes",
"n": 2
}'
```
</Tab>
<Tab title="Go SDK">
```go
resp, err := client.ImageGenerationRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostImageGenerationRequest{
Provider: schemas.Bedrock,
Model: "amazon.nova-canvas-v1:0",
Input: &schemas.ImageGenerationInput{
Prompt: "A futuristic cityscape with a flying car",
},
Params: &schemas.ImageGenerationParameters{
N: schemas.Ptr(2),
Seed: schemas.Ptr(123),
NegativePrompt: schemas.Ptr("bikes"),
Quality: schemas.Ptr("auto"),
Style: schemas.Ptr("natural"),
Size: schemas.Ptr("1024x1024"),
},
})
```
</Tab>
</Tabs>
## Stability AI models
Supported generation models: **`stability.stable-image-core-v1:1`**, **`stability.stable-image-ultra-v1:1`**
These models use a flat JSON body (not the nested Bedrock `taskType` structure). Bifrost detects them automatically — any model ID containing `"stability."` is converted via `ToStabilityAIImageGenerationRequest`.
**Request Parameters**
| Parameter | Type | Required | Notes |
| ----------------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
| `prompt` | string | ✅ | Text description of the image |
| `negative_prompt` | string | ❌ | What to exclude |
| `seed` | int | ❌ | Reproducibility seed |
| `aspect_ratio` | string | ❌ | e.g. `"16:9"`, `"1:1"`, `"21:9"` — via `aspect_ratio` param or `ExtraParams["aspect_ratio"]` |
| `output_format` | string | ❌ | `"png"`, `"jpeg"`, `"webp"` — via `output_format` param |
### Example Request
<Tabs>
<Tab title="Gateway">
```bash
curl -X POST http://localhost:8080/v1/images/generations \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/us.stability.stable-image-ultra-v1:1",
"prompt": "A majestic mountain range at golden hour",
"negative_prompt": "blurry, low quality",
"aspect_ratio": "16:9",
"output_format": "png",
"seed": 42
}'
```
</Tab>
<Tab title="Go SDK">
```go
resp, err := client.ImageGenerationRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostImageGenerationRequest{
Provider: schemas.Bedrock,
Model: "us.stability.stable-image-ultra-v1:1",
Input: &schemas.ImageGenerationInput{
Prompt: "A majestic mountain range at golden hour",
},
Params: &schemas.ImageGenerationParameters{
NegativePrompt: schemas.Ptr("blurry, low quality"),
AspectRatio: schemas.Ptr("16:9"),
OutputFormat: schemas.Ptr("png"),
Seed: schemas.Ptr(42),
},
})
```
</Tab>
</Tabs>
---
# 6. Image Edit
<Warning>Requests use **multipart/form-data**, not JSON.</Warning>
Supported image edit models: **Titan Image Generator v1**, **Titan Image Generator v2**, **Nova Canvas v1**
Bedrock supports three image edit task types: **INPAINTING**, **OUTPAINTING**, and **BACKGROUND_REMOVAL**. The `type` field is required and must be one of these values.
**Request Parameters**
| Parameter | Type | Required | Notes |
| ------------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------- |
| `model` | string | ✅ | Model identifier (must be Titan or Nova Canvas model) |
| `type` | string | ✅ | Edit type: `"inpainting"`, `"outpainting"`, or `"background_removal"` |
| `prompt` | string | ❌ | Text description of the edit (required for inpainting/outpainting) |
| `image[]` | binary | ✅ | Image file(s) to edit (only first image used) |
| `mask` | binary | ❌ | Mask image file (for inpainting/outpainting) |
| `n` | int | ❌ | Number of images to generate (1-10, for inpainting/outpainting only) |
| `size` | string | ❌ | Image size: `"WxH"` format (e.g., `"1024x1024"`, for inpainting/outpainting only) |
| `quality` | string | ❌ | Image quality (for inpainting/outpainting only). See [Quality Mapping](#quality-mapping) for supported values. |
| `cfgScale` | float | ❌ | CFG scale (via `ExtraParams["cfgScale"]`, for inpainting/outpainting only) |
| `negative_text` | string | ❌ | Negative prompt (via `ExtraParams["negative_text"]`, for inpainting/outpainting only) |
| `mask_prompt` | string | ❌ | Mask prompt (via `ExtraParams["mask_prompt"]`, for inpainting/outpainting only) |
| `return_mask` | bool | ❌ | Return mask in response (via `ExtraParams["return_mask"]`, for inpainting/outpainting only) |
| `outpainting_mode` | string | ❌ | Outpainting mode (via `ExtraParams["outpainting_mode"]`, outpainting only): `"DEFAULT"` or `"PRECISE"` |
---
**Request Conversion**
- **Task Type Mapping**: `Params.Type` is mapped to `taskType`:
- `"inpainting"` → `"INPAINTING"`
- `"outpainting"` → `"OUTPAINTING"`
- `"background_removal"` → `"BACKGROUND_REMOVAL"`
- Any other value returns an error: `"unsupported type for Bedrock"`
- **Image Conversion**: First image in `Input.Images` is converted to base64: `image.Image` → base64 string
- **Task-Specific Parameters**:
- **INPAINTING**: Uses `inPaintingParams`:
- `prompt` → `inPaintingParams.text`
- `image` (base64) → `inPaintingParams.image`
- `mask` (if present) → `inPaintingParams.maskImage` (base64)
- `negative_text` (via `ExtraParams`) → `inPaintingParams.negativeText`
- `mask_prompt` (via `ExtraParams`) → `inPaintingParams.maskPrompt`
- `return_mask` (via `ExtraParams`) → `inPaintingParams.returnMask`
- **OUTPAINTING**: Uses `outPaintingParams`:
- `prompt` → `outPaintingParams.text`
- `image` (base64) → `outPaintingParams.image`
- `mask` (if present) → `outPaintingParams.maskImage` (base64)
- `negative_text` (via `ExtraParams`) → `outPaintingParams.negativeText`
- `mask_prompt` (via `ExtraParams`) → `outPaintingParams.maskPrompt`
- `return_mask` (via `ExtraParams`) → `outPaintingParams.returnMask`
- `outpainting_mode` (via `ExtraParams`, validated to `"DEFAULT"` or `"PRECISE"`) → `outPaintingParams.outPaintingMode`
- **BACKGROUND_REMOVAL**: Uses `backgroundRemovalParams`:
- `image` (base64) → `backgroundRemovalParams.image`
- No other parameters supported
- **Image Generation Config** (for INPAINTING and OUTPAINTING only):
- `n` → `imageGenerationConfig.numberOfImages`
- `size` → `imageGenerationConfig.width` and `imageGenerationConfig.height` (parsed from `"WxH"` format)
- `quality` → `imageGenerationConfig.quality` (see [Quality Mapping](#quality-mapping))
- `cfgScale` (via `ExtraParams["cfgScale"]`) → `imageGenerationConfig.cfgScale`
**Response Conversion**
- Uses the same response structure as image generation: `BedrockImageGenerationResponse` → `BifrostImageGenerationResponse`
- Response includes:
- `images[]`: Array of base64-encoded images
- `maskImage`: Base64-encoded mask image (if `return_mask` was true)
- `error`: Error message (if present)
**Endpoint**: Same as image generation: `invoke` endpoint
**Streaming**: Image edit streaming is not supported by Bedrock.
---
## Stability AI models
<Warning>Requests use **multipart/form-data**, not JSON.</Warning>
Stability AI edit models are automatically detected by their model ID (contains `"stability."`). The **task type is inferred from the model name** by default, but you can also set the `type` field explicitly — useful when using deployment aliases. See [Type values for explicit task selection](#type-values-for-explicit-task-selection) below.
### Supported models
| Model ID | Task | Images required | Prompt |
| ----------------------------------------------- | -------------------- | ----------------- | ------ |
| `stability.stable-image-inpaint-v1:0` | inpaint | 1 + mask | ✅ |
| `stability.stable-outpaint-v1:0` | outpaint | 1 (optional mask) | ✅ |
| `stability.stable-image-search-recolor-v1:0` | recolor | 1 | ✅ |
| `stability.stable-image-search-replace-v1:0` | search-replace | 1 | ✅ |
| `stability.stable-image-erase-object-v1:0` | erase-object | 1 + mask | ❌ |
| `stability.stable-image-remove-background-v1:0` | remove-bg | 1 | ❌ |
| `stability.stable-image-control-sketch-v1:0` | control-sketch | 1 | ✅ |
| `stability.stable-image-control-structure-v1:0` | control-structure | 1 | ✅ |
| `stability.stable-image-style-guide-v1:0` | style-guide | 1 | ✅ |
| `stability.stable-style-transfer-v1:0` | style-transfer | **2 required** | ✅ |
| `stability.stable-creative-upscale-v1:0` | upscale-creative | 1 | ✅ |
| `stability.stable-conservative-upscale-v1:0` | upscale-conservative | 1 | ✅ |
| `stability.stable-fast-upscale-v1:0` | upscale-fast | 1 | ❌ |
### Common parameters
| Parameter | Type | Required | Notes |
| ----------------- | ------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model` | string | ✅ | Stability AI model ID (see table above) |
| `image[]` | binary | ✅ | Input image(s). `style-transfer` requires exactly 2. |
| `prompt` | string | task-dependent | Required for all tasks except `remove-bg`, `upscale-fast`, and `erase-object`. For these no-prompt operations, set `type` to `remove_background`, `upscale_fast`, or `erase_object` to skip prompt validation at the gateway level. |
| `negative_prompt` | string | ❌ | Not applied for: `remove-bg`, `upscale-fast`, `erase-object` |
| `seed` | int | ❌ | Not applied for: `remove-bg`, `upscale-fast` |
| `mask` | binary | task-dependent | Required for: `inpaint`, `erase-object`; ignored for others |
### Task-specific extra parameters
Pass these via `extra_params` (Go SDK) or as top-level form fields (Gateway).
| Extra parameter | Type | Task(s) |
| ----------------------------- | ------ | ------------------------------------------------------------------------------------------------------------ |
| `output_format` | string | All — `"png"`, `"jpeg"`, `"webp"` |
| `style_preset` | string | inpaint, outpaint, recolor, search-replace, control-sketch, control-structure, style-guide, upscale-creative |
| `grow_mask` | int | inpaint, recolor, search-replace, erase-object |
| `left`, `right`, `up`, `down` | int | outpaint — pixels to expand in each direction |
| `creativity` | float | upscale-creative, upscale-conservative, outpaint |
| `select_prompt` | string | recolor — which region to recolor |
| `search_prompt` | string | search-replace — what object to find and replace |
| `control_strength` | float | control-sketch, control-structure — 0.01.0 |
| `aspect_ratio` | string | style-guide — output aspect ratio |
| `fidelity` | float | style-guide — 0.01.0 |
| `style_strength` | float | style-transfer — 0.01.0 |
| `composition_fidelity` | float | style-transfer — 0.01.0 |
| `change_strength` | float | style-transfer — 0.01.0 |
<Note>
**Style-transfer image order matters.** The first image (`image[0]`) becomes
`init_image` (the content to transform) and the second (`image[1]`) becomes
`style_image` (the artistic reference). Both images must be non-empty.
</Note>
### Type values for explicit task selection
You can set the `type` field to override model-name inference. This is especially useful with deployment aliases where the alias name may not contain the Stability AI model pattern.
| `type` value | Stability AI task |
| ---------------------------------------------------------- | -------------------- |
| `inpainting` or `inpaint` | inpaint |
| `outpainting` or `outpaint` | outpaint |
| `background_removal` or `remove_background` or `remove_bg` | remove-bg |
| `erase_object` | erase-object |
| `upscale_fast` | upscale-fast |
| `upscale_creative` | upscale-creative |
| `upscale_conservative` | upscale-conservative |
| `recolor` | recolor |
| `search_replace` | search-replace |
| `control_sketch` | control-sketch |
| `control_structure` | control-structure |
| `style_guide` | style-guide |
| `style_transfer` | style-transfer |
### Example requests
<Tabs>
<Tab title="Inpaint">
```bash
curl -X POST http://localhost:8080/v1/images/edits \
-F "model=bedrock/us.stability.stable-image-inpaint-v1:0" \
-F "image[]=@photo.png;type=image/png" \
-F "mask=@mask.png;type=image/png" \
-F "prompt=A beautiful garden replacing the masked area" \
-F "negative_prompt=ugly, blurry" \
-F "output_format=png"
```
</Tab>
<Tab title="Style transfer">
```bash
curl -X POST http://localhost:8080/v1/images/edits \
-F "model=bedrock/us.stability.stable-style-transfer-v1:0" \
-F "image[]=@content.png;type=image/png" \
-F "image[]=@style.png;type=image/png" \
-F "prompt=Apply the artistic style to the content image" \
-F "style_strength=0.8" \
-F "composition_fidelity=0.5" \
-F "change_strength=0.4" \
-F "output_format=png"
```
</Tab>
<Tab title="Outpaint">
```bash
curl -X POST http://localhost:8080/v1/images/edits \
-F "model=bedrock/us.stability.stable-outpaint-v1:0" \
-F "image[]=@photo.png;type=image/png" \
-F "prompt=Extend the scene naturally" \
-F "left=200" \
-F "right=200" \
-F "output_format=png"
```
</Tab>
<Tab title="Remove background">
```bash
curl -X POST http://localhost:8080/v1/images/edits \
-F "model=bedrock/us.stability.stable-image-remove-background-v1:0" \
-F "image[]=@photo.png;type=image/png" \
-F "output_format=png"
```
</Tab>
<Tab title="Erase object">
No prompt required. Set `type=erase_object` to skip gateway prompt validation.
```bash
curl -X POST http://localhost:8080/v1/images/edits \
-F "model=bedrock/us.stability.stable-image-erase-object-v1:0" \
-F "image[]=@photo.png;type=image/png" \
-F "mask=@mask.png;type=image/png" \
-F "type=erase_object" \
-F "output_format=png"
```
</Tab>
<Tab title="Fast upscale">
No prompt required. Set `type=upscale_fast` to skip gateway prompt validation.
```bash
curl -X POST http://localhost:8080/v1/images/edits \
-F "model=bedrock/us.stability.stable-fast-upscale-v1:0" \
-F "image[]=@photo.png;type=image/png" \
-F "type=upscale_fast" \
-F "output_format=png"
```
</Tab>
</Tabs>
**Endpoint**: `invoke` endpoint (same as all other Bedrock image operations)
**Streaming**: Not supported.
---
# 7. Image Variation
<Warning>Requests use **multipart/form-data**, not JSON.</Warning>
Supported image variation models: **Titan Image Generator v1**, **Titan Image Generator v2**, **Nova Canvas v1**
**Request Parameters**
| Parameter | Type | Required | Notes |
| -------------------- | ------ | -------- | ------------------------------------------------------------------------------- |
| `model` | string | ✅ | Model identifier (must be Titan or Nova Canvas model) |
| `image` | binary | ✅ | Image file to create variations from (supports multiple images via `image[]`) |
| `n` | int | ❌ | Number of images to generate (1-10) |
| `size` | string | ❌ | Image size: `"WxH"` format (e.g., `"1024x1024"`) |
| `quality` | string | ❌ | Image quality. See [Quality Mapping](#quality-mapping) for supported values. |
| `cfgScale` | float | ❌ | CFG scale (via `ExtraParams["cfgScale"]`) |
| `prompt` | string | ❌ | Prompt/text for variation (via `ExtraParams["prompt"]`) |
| `negativeText` | string | ❌ | Negative prompt (via `ExtraParams["negativeText"]`) |
| `similarityStrength` | float | ❌ | Similarity strength (via `ExtraParams["similarityStrength"]`): Range 0.2 to 1.0 |
---
**Request Conversion**
- **Task Type**: `taskType` is set to `"IMAGE_VARIATION"`
- **Image Conversion**: All images are converted to base64 strings:
- Primary image: `Input.Image.Image` → base64 string → `imageVariationParams.images[0]`
- Additional images: `ExtraParams["images"]` (stored as `[][]byte` by HTTP handler) → base64 strings → appended to `imageVariationParams.images[]`
- **Image Variation Parameters**:
- `prompt` (via `ExtraParams["prompt"]`) → `imageVariationParams.text`
- `negativeText` (via `ExtraParams["negativeText"]`) → `imageVariationParams.negativeText`
- `similarityStrength` (via `ExtraParams["similarityStrength"]`) → `imageVariationParams.similarityStrength` (validated to range [0.2, 1.0])
- **Image Generation Config**:
- `n` → `imageGenerationConfig.numberOfImages`
- `size` → `imageGenerationConfig.width` and `imageGenerationConfig.height` (parsed from `"WxH"` format)
- `quality` (via `ExtraParams["quality"]`) → `imageGenerationConfig.quality` (see [Quality Mapping](#quality-mapping))
- `cfgScale` (via `ExtraParams["cfgScale"]`) → `imageGenerationConfig.cfgScale`
**Response Conversion**
- Uses the same response structure as image generation: `BedrockImageGenerationResponse` → `BifrostImageGenerationResponse`
- Response includes:
- `images[]`: Array of base64-encoded image variations
- `error`: Error message (if present)
**Endpoint**: Same as image generation: `invoke` endpoint
**Streaming**: Image variation streaming is not supported by Bedrock.
---
# 8. Batch API
**Request formats**: `requests` array (CustomID + Params) or `input_file_id`
**Pagination**: Cursor-based with `afterId`, `beforeId`, `limit`
**Endpoints**:
- POST `/batch` - Create batch
- GET `/batch` - List batches
- GET `/batch/{batch_id}` - Retrieve batch
- POST `/batch/{batch_id}/cancel` - Cancel batch
**Response**: JSONL format with `{recordId, modelOutput: {...}}` or `{recordId, error: {...}}`
**Status mapping**:
| Bedrock Status | Bifrost Mapping |
|---|---|
| `Submitted`, `Validating` | `Validating` |
| `InProgress` | `InProgress` |
| `Completed` | `Completed` |
| `Failed`, `PartiallyCompleted` | `Failed` |
| `Stopping` | `Cancelling` |
| `Stopped` | `Cancelled` |
| `Expired` | `Expired` |
**Note**: RFC3339Nano timestamps converted to Unix timestamps, multi-key retry supported
---
# 9. Files API
<Note>
S3-backed file operations. Files are stored in S3 buckets integrated with
Bedrock.
</Note>
**Upload**: Multipart/form-data with `file` (required) and `filename` (optional)
**Field mapping**:
- `id` (file ID)
- `filename`
- `size_bytes` (from S3 object size)
- `created_at` (Unix timestamp from S3 LastModified)
- `mime_type` (derived from content or explicitly set)
**Endpoints**:
- POST `/v1/files` - Upload
- GET `/v1/files` - List (cursor pagination)
- GET `/v1/files/{file_id}` - Retrieve metadata
- DELETE `/v1/files/{file_id}` - Delete
- GET `/v1/files/{file_id}/content` - Download content
**Note**: File purpose always `"batch"`, status always `"processed"`
---
# 10. List Models
**Request**: GET `/v1/models` (no body)
**Field mapping**:
- `id` (model name with deployment prefix if applicable)
- `display_name` → `name`
- `created_at` (Unix timestamp)
**Pagination**: Token-based with `NextPageToken`, `FirstID`, `LastID`
**Filtering**:
- Region-based model filtering
- Deployment mapping from configuration
- Model allowlist support (`allowed_models` config)
**Multi-key support**: Results aggregated from all keys, filtered by the key-level `models` allowlist if configured
---
# 11. AWS Authentication & Configuration
Bifrost signs every Bedrock request with AWS Signature Version 4 (SigV4). Credentials are resolved in the following priority order, and STS AssumeRole can be layered on top of any of them.
## Authentication Methods
### 1. Explicit Credentials
Provide `access_key` and `secret_key` directly in `bedrock_key_config`. Optionally include a `session_token` for pre-obtained temporary credentials.
```json
{
"bedrock_key_config": {
"access_key": "your-aws-access-key",
"secret_key": "your-aws-secret-key",
"session_token": "optional-session-token",
"region": "us-east-1"
}
}
```
### 2. Default Credential Chain (IAM Role / Instance Profile)
Leave `access_key` and `secret_key` empty (or omit them). Bifrost calls AWS `LoadDefaultConfig` which automatically resolves credentials from the environment in this order:
- Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`)
- EKS IRSA (`AWS_WEB_IDENTITY_TOKEN_FILE` + `AWS_ROLE_ARN`)
- ECS task role
- EC2 instance profile (IMDS)
- `~/.aws/credentials` default profile
```json
{
"bedrock_key_config": {
"region": "us-east-1"
}
}
```
### 3. STS AssumeRole
Set `role_arn` to assume an IAM role before signing requests. AssumeRole requires a valid source identity — it works when credentials are available either via explicit `access_key`/`secret_key` in key config, or via the default credential chain (environment variables, EC2 instance profile, ECS task role, EKS IRSA, etc.). **If no credentials are available from either source, AssumeRole will fail.**
```json
{
"bedrock_key_config": {
"role_arn": "arn:aws:iam::123456789012:role/BedrockRole",
"external_id": "optional-external-id",
"session_name": "my-session",
"region": "us-east-1"
}
}
```
| Field | Required | Default | Notes |
| -------------- | ------------- | ----------------- | ------------------------------------------------ |
| `role_arn` | Yes (for STS) | - | IAM role ARN to assume |
| `external_id` | No | - | Required when the role's trust policy demands it |
| `session_name` | No | `bifrost-session` | Identifies the session in CloudTrail logs |
## Inference Profiles & ARN Configuration
### How to Use ARNs and Application Inference Profiles
When using AWS Bedrock inference profiles or application inference profiles, you must split the configuration correctly to avoid `UnknownOperationException`:
| Field | Purpose |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`arn`** | The ARN prefix (everything before the final `/resource-id`). Required for URL formation when using inference profiles. |
| **`aliases`** | Map logical model names to the **model ID or inference profile resource ID only** — not the full ARN. Set at the key level, not inside `bedrock_key_config`. |
<Warning>
**Do not** put the full ARN in the aliases mapping. The resource ID (e.g.,
`abc12xyz`) goes in `aliases`; the ARN prefix goes in the dedicated `arn`
field inside `bedrock_key_config`. Putting the full ARN in `aliases` causes
malformed URLs and `UnknownOperationException`.
</Warning>
**Application inference profiles** — use the resource ID (short alphanumeric suffix) in aliases:
```json
{
"aliases": {
"claude-opus-4-6": "ghi56rst",
"claude-sonnet-4-5": "jkl78mno"
},
"bedrock_key_config": {
"access_key": "your-aws-access-key",
"secret_key": "your-aws-secret-key",
"session_token": "optional-session-token",
"region": "eu-west-1",
"arn": "arn:aws:bedrock:eu-west-1:123456789012:application-inference-profile"
}
}
```
**Cross-region inference profiles** — use the model identifier (e.g., `us.anthropic.claude-3-5-sonnet-v1:0`) in aliases:
```json
{
"aliases": {
"claude-sonnet": "us.anthropic.claude-3-5-sonnet-v1:0"
},
"bedrock_key_config": {
"access_key": "your-aws-access-key",
"secret_key": "your-aws-secret-key",
"session_token": "optional-session-token",
"region": "us-east-1",
"arn": "arn:aws:bedrock:us-east-1:123456789012:inference-profile"
}
}
```
### Endpoints
- **Runtime API**: `bedrock-runtime.{region}.amazonaws.com/model/{path}`
- **Control Plane**: `bedrock.{region}.amazonaws.com` (list models)
- **Batch API**: Via bedrock-runtime
---
# 12. Error Handling
**HTTP Status Mapping**:
| Status | Bifrost Error Type | Notes |
| ------ | ------------------------- | ------------------------------- |
| 400 | `invalid_request_error` | Bad request parameters |
| 401 | `authentication_error` | Invalid/expired credentials |
| 403 | `permission_denied_error` | Access denied to model/resource |
| 404 | `not_found_error` | Model or resource not found |
| 429 | `rate_limit_error` | Rate limit exceeded |
| 500 | `api_error` | Server error |
| 529 | `overloaded_error` | Service overloaded |
**Error Response Structure**:
```go
type BifrostError struct {
IsBifrostError bool
StatusCode *int
Error: {
Type: string // Error classification
Message: string // Human-readable message
Error: error // Underlying error
}
}
```
**Special Cases**:
- Context cancellation → `RequestCancelled`
- Request timeout → `ErrProviderRequestTimedOut`
- Streaming errors → Sent via channel with stream end indicator
- Response unmarshalling → `ErrProviderResponseUnmarshal`
---
## Caveats
<Accordion title="Image Format Restriction">
**Severity**: High **Behavior**: Only base64/data URI images supported; remote
URLs not supported **Impact**: Requests with URL-based images fail **Code**:
`chat.go:image handling`
</Accordion>
<Accordion title="Minimum Reasoning Budget (Claude)">
**Severity**: High
**Behavior**: `reasoning.max_tokens` must be >= 1024
**Impact**: Requests with lower values fail with error
**Code**: `chat.go:reasoning validation`
</Accordion>
<Accordion title="System Message Extraction">
**Severity**: High **Behavior**: System messages removed from array, placed in
separate `system` field **Impact**: Message array structure differs from input
**Code**: `chat.go:message conversion`
</Accordion>
<Accordion title="Tool Message Grouping">
**Severity**: High **Behavior**: Consecutive tool messages merged into single
user message **Impact**: Message count and structure changes **Code**:
`chat.go:tool message handling`
</Accordion>
<Accordion title="Model Family-Specific Parameters">
**Severity**: Medium **Behavior**: Reasoning/thinking config varies
significantly by model family **Impact**: Parameter mapping differs for Claude
vs Nova vs other families **Code**: `chat.go, utils.go:model detection`
</Accordion>
<Accordion title="Text Completion Streaming Not Supported">
**Severity**: Medium **Behavior**: Text completion streaming returns error
**Impact**: Streaming not available for legacy completions API **Code**:
`text.go:streaming`
</Accordion>
<Accordion title="Structured Output via Tool">
**Severity**: Low **Behavior**: `response_format` converted to special
`bf_so_*` tool **Impact**: Tool call count and structure changes internally
**Code**: `chat.go:structured output handling`
</Accordion>
<Accordion title="Deployment Region Prefix Handling">
**Severity**: Low **Behavior**: Model IDs with region prefixes matched against
deployment config **Impact**: Model availability depends on deployment
configuration **Code**: `models.go:deployment matching`
</Accordion>