AWS Bedrock
An llm · client with dialect: aws-bedrock sends requests to Amazon Bedrock Runtime. Applications keep using the OpenAI or Anthropic SDK: Zilla Plus converts each request for Bedrock, signs it with AWS Signature Version 4, and returns the reply in the caller's API. An llm · server can also accept requests in the Bedrock Converse API.
Configuration
bedrock_llm_client:
type: llm
kind: client
options:
dialect: aws-bedrock
server: https://bedrock-runtime.us-east-1.amazonaws.com
telemetry:
metrics:
- llm.*
exit: bedrock_http_client
bedrock_http_client:
type: http
kind: client
exit: bedrock_tls_client
bedrock_tls_client:
type: tls
kind: client
options:
sni:
- bedrock-runtime.us-east-1.amazonaws.com
exit: bedrock_tcp_client
bedrock_tcp_client:
type: tcp
kind: client
options:
host: bedrock-runtime.us-east-1.amazonaws.com
port: 443Unlike the OpenAI and Anthropic clients, an aws-bedrock client doesn't connect through sys:http_client. It exits to its own http · client, tls · client, and tcp · client. To use another region, change the host in all three places: server, sni, and host.
Route Bedrock model IDs to it from llm · proxy:
north_llm_proxy:
type: llm
kind: proxy
routes:
- when:
- model:
- anthropic.*
- amazon.*
- us.anthropic.*
- us.amazon.*
exit: bedrock_llm_clientMany Bedrock models are called through a cross-region inference profile, whose ID starts with a geography such as us., for example us.anthropic.claude-haiku-4-5-20251001-v1:0. Add patterns for the profile IDs your callers use.
How Requests Are Sent
Zilla Plus picks the Bedrock API for each request from the API the caller used and the model it asked for:
| Caller's API | Model | Bedrock API |
|---|---|---|
| Anthropic | anthropic.*, with or without a geography prefix such as us.anthropic.* | InvokeModel, with the request in Anthropic's own format |
| OpenAI | openai.* | InvokeModel, with the request in OpenAI's own format |
| OpenAI or Anthropic | Any other model | Converse, converted from the caller's API |
| Bedrock Converse | Any model | Converse |
- InvokeModel sends the caller's request to
/model/{modelId}/invoke, or/model/{modelId}/invoke-with-response-streamfor a streaming request, and returns the model's reply as it is. Zilla Plus removes themodelandstreammembers and adds theanthropic_versionthat Anthropic models require. Foropenai.*models, the reasoning the model returns between<reasoning>tags is removed from the reply. - Converse sends the request to
/model/{modelId}/converse. A streaming request converted from the OpenAI or Anthropic API is also sent to/converse, and the reply is streamed back in the caller's format. Only a caller that uses the Bedrock Converse API itself is sent to/converse-stream.
To call only some of these operations, see Limiting Bedrock Operations.
Model in the Path
Zilla Plus puts each request's model in the Bedrock request path, so one client serves every Bedrock model routed to it. A path in the server URL is ignored.
What Is Converted
When a request is converted to the Converse API, each part of the conversation is converted to its Converse form:
| Section | Converse |
|---|---|
| System instruction | system[].text |
| User and assistant text, refusals | text |
| Images and documents sent inline | image and document, with bytes |
| Audio sent inline, from the OpenAI API | audio, with bytes |
| Reasoning, from the Anthropic API | reasoningContent |
| Tool definitions | toolConfig.tools[].toolSpec |
| Tool calls | toolUse |
| Tool results | toolResult |
The output token limit is carried across as inferenceConfig.maxTokens. Other request settings aren't carried across, as with any translation.
Some content can't be converted:
- Images and documents sent by URL, and tool definitions for tools the provider runs, are rejected with
400 Bad Request, naming the section, such asuser-image cannot be converted from openai to aws-bedrock. - Server tool results and citations are skipped.
- Video, audio, and Amazon S3 references in a Bedrock Converse request can't be sent to OpenAI or Anthropic, and are rejected with
400 Bad Request. - Members only Bedrock has, such as
guardrailConfig,cachePoint, andadditionalModelRequestFields, are kept when the caller uses the Bedrock Converse API, and dropped otherwise.
Credentials
Zilla Plus signs every request itself, so options.authorization is not used with aws-bedrock. It takes credentials from the standard AWS default credentials chain:
- The
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY, andAWS_SESSION_TOKENenvironment variables - An EKS pod's IAM role (IRSA), an ECS task role, or an EC2 instance profile
The identity needs the bedrock:InvokeModel and bedrock:InvokeModelWithResponseStream permissions on the models callers ask for, or only one of them when options.operations limits the client to the operations it allows. When no credentials are available, requests fail with 503 Service Unavailable and the message AWS credentials are not available.
Limiting Bedrock Operations
By default, the client calls all four Bedrock operations, as described in How Requests Are Sent. When the AWS credentials are granted only some of the Bedrock permissions, list the operations they allow in options.operations:
bedrock_llm_client:
type: llm
kind: client
options:
dialect: aws-bedrock
server: https://bedrock-runtime.us-east-1.amazonaws.com
operations:
- converse
- invoke
exit: bedrock_http_client| Operation | Request path | Permission |
|---|---|---|
converse | /model/{modelId}/converse | bedrock:InvokeModel |
converse-stream | /model/{modelId}/converse-stream | bedrock:InvokeModelWithResponseStream |
invoke | /model/{modelId}/invoke | bedrock:InvokeModel |
invoke-with-response-stream | /model/{modelId}/invoke-with-response-stream | bedrock:InvokeModelWithResponseStream |
Zilla Plus works out the operation each request needs, then calls the nearest one that is allowed:
- A streaming request, when only the non-streaming operation is allowed, calls the non-streaming operation. The caller still receives a stream.
- A non-streaming request, when only the streaming operation is allowed, calls the streaming operation. The caller still receives a single reply.
- An Anthropic request for an
anthropic.*model, or an OpenAI request for anopenai.*model, uses Converse when neitherinvokeoperation is allowed. - A request with no allowed operation is rejected with
400 Bad Requestand the typeinvalid_request_error, before anything is sent to Bedrock.
The example above, with only bedrock:InvokeModel granted, serves streaming and non-streaming callers alike.
Region
The signing region comes from the server host, such as us-east-1 for https://bedrock-runtime.us-east-1.amazonaws.com. When the host doesn't contain a region, for example a VPC endpoint, Zilla Plus uses the AWS default region chain, such as the AWS_REGION environment variable.
Accepting the Bedrock Converse API
An llm · server with dialect: aws-bedrock, or with no dialect, also accepts requests in the Bedrock Converse API: POST /model/{modelId}/converse and POST /model/{modelId}/converse-stream. The model is taken from the path, so llm · proxy routes these requests like any other, to Bedrock or to another provider, and the reply comes back as Converse JSON or as a Converse event stream.
north_llm_server:
type: llm
kind: server
options:
dialect: aws-bedrock
exit: north_llm_proxyThe server also accepts the InvokeModel API, POST /model/{modelId}/invoke and POST /model/{modelId}/invoke-with-response-stream, for anthropic.* and openai.* models, with the request in the model's own format. An InvokeModel request for any other model gets 400 with the message InvokeModel is supported for anthropic and openai models.
To expose only some of these operations to callers, list them in options.operations. It needs dialect: aws-bedrock:
north_llm_server:
type: llm
kind: server
options:
dialect: aws-bedrock
operations:
- converse
- converse-stream
exit: north_llm_proxyA request for an operation that isn't listed gets 404 with the error type NotFoundException and the message Unknown operation., the same as any other path the server doesn't serve. The server's operations and the client's operations are independent: one limits what callers can ask for, the other what Zilla Plus calls on Bedrock.
When the server has options.authorization, the request's Authorization header is checked against the guard with the credentials template, and a rejected request gets 403 with the error type UnrecognizedClientException. Zilla Plus doesn't verify AWS Signature Version 4 on incoming requests.
Errors are returned in the Bedrock format, with the error type in the x-amzn-errortype header and a {"message": ...} body:
| Status | Error type |
|---|---|
400 | ValidationException |
401, 403 | AccessDeniedException |
404 | ResourceNotFoundException |
408 | ModelTimeoutException |
429 | ThrottlingException |
503 | ServiceUnavailableException |
Other 4xx | ValidationException |
Other 5xx | InternalServerException |
A request to any other path gets 404 with the error type NotFoundException, and a request whose content type isn't JSON gets 415 with UnsupportedMediaTypeException.
Limits
- A request must fit in one of Zilla's buffer slots, 32 KiB by default. Each event of a reply streamed from Bedrock must also fit in a buffer slot.
- Bedrock doesn't report reasoning tokens.
Next Steps
- AWS SDK: call the gateway with the AWS SDK's Bedrock Runtime client.
- OpenAI Apps on AWS Bedrock: serve OpenAI applications from Bedrock.
- llm · client: the full
llm · clientreference.

