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:

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:

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.