# AWS Bedrock

aimock supports the AWS Bedrock Claude invoke and Converse API endpoints — both streaming and non-streaming. Point the AWS SDK at your aimock instance and fixtures match against the Bedrock-format requests, returning responses in the authentic Bedrock format including AWS Event Stream binary framing for streaming.

## How It Works

AWS Bedrock uses URL patterns like `/model/{modelId}/invoke` and `/model/{modelId}/invoke-with-response-stream` to call foundation models. The request body uses the Anthropic Messages format with an additional `anthropic_version` field, and does not include a `model` field in the body (the model is in the URL).

aimock detects the Bedrock URL pattern, extracts the model ID, translates the request to the internal fixture-matching format, and returns the response in the Anthropic Messages API format — which is identical to the Bedrock Claude response format. For streaming, responses use the AWS Event Stream binary framing protocol.

aimock also supports the Converse API (`/model/{modelId}/converse` and `/model/{modelId}/converse-stream`), which uses a different request/response format with camelCase field names.

## URL Patterns

Bedrock URL | Description
--- | ---
`POST /model/{modelId}/invoke` | Non-streaming Claude invoke
`POST /model/{modelId}/invoke-with-response-stream` | Streaming Claude invoke (AWS Event Stream binary)
`POST /model/{modelId}/converse` | Converse API (non-streaming)
`POST /model/{modelId}/converse-stream` | Converse API (streaming, AWS Event Stream binary)

## Request Format

Bedrock Claude requests use the Anthropic Messages format. The `anthropic_version` field is accepted but not validated. The model is taken from the URL path, not the request body.

bedrock request body json

    {
      "anthropic_version": "bedrock-2023-05-31",
      "max_tokens": 512,
      "messages": [
        { "role": "user", "content": "Hello" }
      ],
      "system": "You are helpful"
    }

## Response Format

Bedrock Claude responses are identical to the Anthropic Messages API non-streaming responses:

text response json

    {
      "id": "msg_...",
      "type": "message",
      "role": "assistant",
      "content": [{ "type": "text", "text": "Hello!" }],
      "stop_reason": "end_turn",
      "stop_sequence": null,
      "usage": { "input_tokens": 10, "output_tokens": 5 }
    }

## Model Resolution

The model ID is extracted from the URL path. This is used both for fixture matching and included in the response body. Bedrock model IDs typically look like:

- `anthropic.claude-3-5-sonnet-20241022-v2:0`
- `anthropic.claude-3-haiku-20240307-v1:0`
- `anthropic.claude-3-opus-20240229-v1:0`

Write fixtures that match by Bedrock model ID:

fixture matching by Bedrock model ID json

    {
      "match": {
        "model": "anthropic.claude-3-5-sonnet-20241022-v2:0",
        "userMessage": "hello"
      },
      "response": {
        "content": "Hello from Bedrock!"
      }
    }

## SDK Configuration

To point the AWS SDK Bedrock Runtime client at aimock, configure the endpoint URL:

bedrock-sdk.ts ts

    import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";

    const client = new BedrockRuntimeClient({
      region: "us-east-1",
      endpoint: "http://localhost:4005",  // aimock URL
      credentials: { accessKeyId: "mock", secretAccessKey: "mock" },
    });

    const response = await client.send(new InvokeModelCommand({
      modelId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
      contentType: "application/json",
      body: JSON.stringify({
        anthropic_version: "bedrock-2023-05-31",
        max_tokens: 512,
        messages: [{ role: "user", content: "Hello" }],
      }),
    }));

## Fixture Examples

text response fixture json

    {
      "fixtures": [
        {
          "match": { "userMessage": "hello" },
          "response": { "content": "Hi there!" }
        },
        {
          "match": { "userMessage": "weather" },
          "response": {
            "toolCalls": [{
              "name": "get_weather",
              "arguments": { "city": "SF" }
            }]
          }
        }
      ]
    }

Fixtures are shared across all providers. The same fixture file works for OpenAI, Claude Messages, Gemini, Azure, and Bedrock endpoints — aimock translates each provider's request format to a common internal format before matching.

## Streaming (invoke-with-response-stream)

The `invoke-with-response-stream` endpoint returns responses using the AWS Event Stream binary protocol. aimock implements this protocol natively — each response chunk is encoded as a binary frame with CRC32 checksums, headers, and a JSON payload, exactly as the real Bedrock service sends them.

Streaming events follow the Bedrock Claude streaming sequence:

- `messageStart` — opens the message with `role: "assistant"`
- `contentBlockStart` — begins a content block
- `contentBlockDelta` — delivers text chunks (`text_delta`) or tool input (`input_json_delta`)
- `contentBlockStop` — closes the content block
- `messageStop` — closes the message with a `stopReason`

streaming SDK usage ts

    import { BedrockRuntimeClient, InvokeModelWithResponseStreamCommand } from "@aws-sdk/client-bedrock-runtime";

    const client = new BedrockRuntimeClient({
      region: "us-east-1",
      endpoint: "http://localhost:4005",
      credentials: { accessKeyId: "mock", secretAccessKey: "mock" },
    });

    const response = await client.send(new InvokeModelWithResponseStreamCommand({
      modelId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
      contentType: "application/json",
      body: JSON.stringify({
        anthropic_version: "bedrock-2023-05-31",
        max_tokens: 512,
        messages: [{ role: "user", content: "Hello" }],
      }),
    }));

## AWS Event Stream Binary Format

Unlike SSE-based streaming used by OpenAI and Claude, AWS Bedrock streaming uses a binary event stream protocol. Each frame has the following layout:

binary frame layout text

    [total_length: 4B uint32-BE]
    [headers_length: 4B uint32-BE]
    [prelude_crc32: 4B CRC32 of first 8 bytes]
    [headers: variable-length string key-value pairs]
    [payload: raw JSON bytes]
    [message_crc32: 4B CRC32 of entire frame minus last 4 bytes]

aimock encodes these frames with proper CRC32 checksums, so the AWS SDK can decode them natively. The `:event-type` header in each frame carries the event name (e.g. `chunk`), and the `:content-type` header is set to `application/json`.

## Converse API

The Converse API is AWS Bedrock's provider-agnostic conversation interface. It uses camelCase field names and a different request structure than the Claude-native invoke endpoints. aimock supports both `/model/{modelId}/converse` (non-streaming) and `/model/{modelId}/converse-stream` (streaming via Event Stream binary).

converse request body json

    {
      "messages": [
        {
          "role": "user",
          "content": [{ "text": "Hello" }]
        }
      ],
      "system": [{ "text": "You are helpful" }],
      "inferenceConfig": { "maxTokens": 512 }
    }

converse response json

    {
      "output": {
        "message": {
          "role": "assistant",
          "content": [{ "text": "Hello!" }]
        }
      },
      "stopReason": "end_turn",
      "usage": { "inputTokens": 0, "outputTokens": 0, "totalTokens": 0 }
    }

The Converse API also supports tool calls via `toolUse` and `toolResult` content blocks, and tool definitions via the `toolConfig` field. aimock translates all of these to the unified internal format for fixture matching.