@ai-sdk/amazon-bedrock
Version:
The **[Amazon Bedrock provider](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for the Amazon Bedrock [converse API](https://docs.aws.amazon.com/bedrock/latest/APIR
440 lines (429 loc) • 16 kB
JavaScript
// src/anthropic/amazon-bedrock-anthropic-provider.ts
import {
NoSuchModelError
} from "@ai-sdk/provider";
import {
loadOptionalSetting,
loadSetting,
resolve,
withoutTrailingSlash,
withUserAgentSuffix as withUserAgentSuffix2
} from "@ai-sdk/provider-utils";
import {
anthropicTools,
AnthropicLanguageModel
} from "@ai-sdk/anthropic/internal";
// src/amazon-bedrock-sigv4-fetch.ts
import {
combineHeaders,
normalizeHeaders,
withUserAgentSuffix,
getRuntimeEnvironmentUserAgent
} from "@ai-sdk/provider-utils";
import { AwsV4Signer } from "aws4fetch";
// src/version.ts
var VERSION = true ? "5.0.10" : "0.0.0-test";
// src/amazon-bedrock-sigv4-fetch.ts
function createSigV4FetchFunction(getCredentials, fetch, service = "bedrock") {
return async (input, init) => {
var _a, _b;
const effectiveFetch = fetch != null ? fetch : globalThis.fetch;
const request = input instanceof Request ? input : void 0;
const originalHeaders = combineHeaders(
normalizeHeaders(request == null ? void 0 : request.headers),
normalizeHeaders(init == null ? void 0 : init.headers)
);
const headersWithUserAgent = withUserAgentSuffix(
originalHeaders,
`ai-sdk/amazon-bedrock/${VERSION}`,
getRuntimeEnvironmentUserAgent()
);
let effectiveBody = (_a = init == null ? void 0 : init.body) != null ? _a : void 0;
if (effectiveBody === void 0 && request && request.body !== null) {
try {
effectiveBody = await request.clone().text();
} catch (e) {
}
}
const effectiveMethod = (_b = init == null ? void 0 : init.method) != null ? _b : request == null ? void 0 : request.method;
if ((effectiveMethod == null ? void 0 : effectiveMethod.toUpperCase()) !== "POST" || !effectiveBody) {
return effectiveFetch(input, {
...init,
headers: headersWithUserAgent
});
}
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
const body = prepareBodyString(effectiveBody);
const credentials = await getCredentials();
const signer = new AwsV4Signer({
url,
method: "POST",
headers: Object.entries(headersWithUserAgent),
body,
region: credentials.region,
accessKeyId: credentials.accessKeyId,
secretAccessKey: credentials.secretAccessKey,
sessionToken: credentials.sessionToken,
service
});
const signingResult = await signer.sign();
const signedHeaders = normalizeHeaders(signingResult.headers);
const combinedHeaders = combineHeaders(headersWithUserAgent, signedHeaders);
return effectiveFetch(input, {
...init,
body,
headers: combinedHeaders
});
};
}
function prepareBodyString(body) {
if (typeof body === "string") {
return body;
} else if (body instanceof Uint8Array) {
return new TextDecoder().decode(body);
} else if (body instanceof ArrayBuffer) {
return new TextDecoder().decode(new Uint8Array(body));
} else {
return JSON.stringify(body);
}
}
function createApiKeyFetchFunction(apiKey, fetch) {
return async (input, init) => {
const effectiveFetch = fetch != null ? fetch : globalThis.fetch;
const originalHeaders = normalizeHeaders(init == null ? void 0 : init.headers);
const headersWithUserAgent = withUserAgentSuffix(
originalHeaders,
`ai-sdk/amazon-bedrock/${VERSION}`,
getRuntimeEnvironmentUserAgent()
);
const finalHeaders = combineHeaders(headersWithUserAgent, {
Authorization: `Bearer ${apiKey}`
});
return effectiveFetch(input, {
...init,
headers: finalHeaders
});
};
}
// src/anthropic/amazon-bedrock-anthropic-fetch.ts
import {
convertBase64ToUint8Array,
safeParseJSON
} from "@ai-sdk/provider-utils";
import { z } from "zod/v4";
// src/amazon-bedrock-event-stream-decoder.ts
import { EventStreamCodec } from "@smithy/eventstream-codec";
import { toUtf8, fromUtf8 } from "@smithy/util-utf8";
function createAmazonBedrockEventStreamDecoder(body, processEvent) {
const codec = new EventStreamCodec(toUtf8, fromUtf8);
let buffer = new Uint8Array(0);
const textDecoder = new TextDecoder();
return body.pipeThrough(
new TransformStream({
async transform(chunk, controller) {
var _a, _b;
const newBuffer = new Uint8Array(buffer.length + chunk.length);
newBuffer.set(buffer);
newBuffer.set(chunk, buffer.length);
buffer = newBuffer;
while (buffer.length >= 4) {
const totalLength = new DataView(
buffer.buffer,
buffer.byteOffset,
buffer.byteLength
).getUint32(0, false);
if (buffer.length < totalLength) {
break;
}
try {
const subView = buffer.subarray(0, totalLength);
const decoded = codec.decode(subView);
buffer = buffer.slice(totalLength);
const messageType = (_a = decoded.headers[":message-type"]) == null ? void 0 : _a.value;
const eventType = (_b = decoded.headers[":event-type"]) == null ? void 0 : _b.value;
const data = textDecoder.decode(decoded.body);
await processEvent({ messageType, eventType, data }, controller);
} catch (e) {
break;
}
}
}
})
);
}
// src/anthropic/amazon-bedrock-anthropic-fetch.ts
var amazonBedrockErrorSchema = z.looseObject({
message: z.string().optional()
});
function createAmazonBedrockAnthropicFetch(baseFetch) {
return async (url, options) => {
const response = await baseFetch(url, options);
if (!response.ok) {
const text = await response.text();
const parsed = await safeParseJSON({
text,
schema: amazonBedrockErrorSchema
});
const message = parsed.success && parsed.value.message ? parsed.value.message : text;
const anthropicError = JSON.stringify({
type: "error",
error: { type: "error", message }
});
return new Response(anthropicError, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
}
const contentType = response.headers.get("content-type");
if ((contentType == null ? void 0 : contentType.includes("application/vnd.amazon.eventstream")) && response.body != null) {
const transformedBody = transformAmazonBedrockEventStreamToSSE(
response.body
);
return new Response(transformedBody, {
status: response.status,
statusText: response.statusText,
headers: new Headers({
...Object.fromEntries(response.headers.entries()),
"content-type": "text/event-stream"
})
});
}
return response;
};
}
function transformAmazonBedrockEventStreamToSSE(body) {
const textEncoder = new TextEncoder();
return createAmazonBedrockEventStreamDecoder(
body,
async (event, controller) => {
if (event.messageType === "event") {
if (event.eventType === "chunk") {
const parsed = await safeParseJSON({ text: event.data });
if (!parsed.success) {
controller.enqueue(textEncoder.encode(`data: ${event.data}
`));
return;
}
const bytes = parsed.value.bytes;
if (bytes) {
const anthropicEvent = new TextDecoder().decode(
convertBase64ToUint8Array(bytes)
);
controller.enqueue(
textEncoder.encode(`data: ${anthropicEvent}
`)
);
} else {
controller.enqueue(textEncoder.encode(`data: ${event.data}
`));
}
} else if (event.eventType === "messageStop") {
controller.enqueue(textEncoder.encode("data: [DONE]\n\n"));
}
} else if (event.messageType === "exception") {
controller.enqueue(
textEncoder.encode(
`data: ${JSON.stringify({ type: "error", error: event.data })}
`
)
);
}
}
);
}
// src/anthropic/amazon-bedrock-anthropic-provider.ts
var BEDROCK_TOOL_VERSION_MAP = {
bash_20241022: "bash_20250124",
text_editor_20241022: "text_editor_20250728",
computer_20241022: "computer_20250124"
};
var BEDROCK_TOOL_NAME_MAP = {
text_editor_20250728: "str_replace_based_edit_tool"
};
var BEDROCK_TOOL_BETA_MAP = {
bash_20250124: "computer-use-2025-01-24",
bash_20241022: "computer-use-2024-10-22",
text_editor_20250124: "computer-use-2025-01-24",
text_editor_20241022: "computer-use-2024-10-22",
text_editor_20250429: "computer-use-2025-01-24",
text_editor_20250728: "computer-use-2025-01-24",
computer_20250124: "computer-use-2025-01-24",
computer_20241022: "computer-use-2024-10-22",
tool_search_tool_regex_20251119: "tool-search-tool-2025-10-19",
// BM25 is not currently supported on Bedrock, but including the beta flag
// so that Bedrock returns a more useful error message if it's used.
tool_search_tool_bm25_20251119: "tool-search-tool-2025-10-19"
};
function createAmazonBedrockAnthropic(options = {}) {
const rawApiKey = loadOptionalSetting({
settingValue: options.apiKey,
environmentVariableName: "AWS_BEARER_TOKEN_BEDROCK"
});
const apiKey = rawApiKey && rawApiKey.trim().length > 0 ? rawApiKey.trim() : void 0;
const baseFetchFunction = apiKey ? createApiKeyFetchFunction(apiKey, options.fetch) : createSigV4FetchFunction(async () => {
const region = loadSetting({
settingValue: options.region,
settingName: "region",
environmentVariableName: "AWS_REGION",
description: "AWS region"
});
if (options.credentialProvider) {
try {
return {
...await options.credentialProvider(),
region
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(
`AWS credential provider failed: ${errorMessage}. Please ensure your credential provider returns valid AWS credentials with accessKeyId and secretAccessKey properties.`
);
}
}
try {
return {
region,
accessKeyId: loadSetting({
settingValue: options.accessKeyId,
settingName: "accessKeyId",
environmentVariableName: "AWS_ACCESS_KEY_ID",
description: "AWS access key ID"
}),
secretAccessKey: loadSetting({
settingValue: options.secretAccessKey,
settingName: "secretAccessKey",
environmentVariableName: "AWS_SECRET_ACCESS_KEY",
description: "AWS secret access key"
}),
sessionToken: loadOptionalSetting({
settingValue: options.sessionToken,
environmentVariableName: "AWS_SESSION_TOKEN"
})
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
if (errorMessage.includes("AWS_ACCESS_KEY_ID") || errorMessage.includes("accessKeyId")) {
throw new Error(
`AWS SigV4 authentication requires AWS credentials. Please provide either:
1. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables
2. Provide accessKeyId and secretAccessKey in options
3. Use a credentialProvider function
4. Use API key authentication with AWS_BEARER_TOKEN_BEDROCK or apiKey option
Original error: ${errorMessage}`
);
}
if (errorMessage.includes("AWS_SECRET_ACCESS_KEY") || errorMessage.includes("secretAccessKey")) {
throw new Error(
`AWS SigV4 authentication requires both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Please ensure both credentials are provided.
Original error: ${errorMessage}`
);
}
throw error;
}
}, options.fetch);
const fetchFunction = createAmazonBedrockAnthropicFetch(baseFetchFunction);
const getBaseURL = () => {
var _a, _b;
return (_b = withoutTrailingSlash(
(_a = options.baseURL) != null ? _a : `https://bedrock-runtime.${loadSetting({
settingValue: options.region,
settingName: "region",
environmentVariableName: "AWS_REGION",
description: "AWS region"
})}.amazonaws.com`
)) != null ? _b : "https://bedrock-runtime.us-east-1.amazonaws.com";
};
const getHeaders = async () => {
var _a;
const baseHeaders = (_a = await resolve(options.headers)) != null ? _a : {};
return withUserAgentSuffix2(baseHeaders, `ai-sdk/amazon-bedrock/${VERSION}`);
};
const createChatModel = (modelId) => new AnthropicLanguageModel(modelId, {
provider: "bedrock.anthropic.messages",
baseURL: getBaseURL(),
headers: getHeaders,
fetch: fetchFunction,
buildRequestUrl: (baseURL, isStreaming) => `${baseURL}/model/${encodeURIComponent(modelId)}/${isStreaming ? "invoke-with-response-stream" : "invoke"}`,
transformRequestBody: (args, betas) => {
const {
model: _model,
stream: _stream,
tool_choice,
tools,
...rest
} = args;
const transformedToolChoice = tool_choice != null ? {
type: tool_choice.type,
...tool_choice.name != null ? { name: tool_choice.name } : {}
} : void 0;
const requiredBetas = new Set(betas);
const transformedTools = tools == null ? void 0 : tools.map((tool) => {
const toolType = tool.type;
if (toolType && toolType in BEDROCK_TOOL_VERSION_MAP) {
const newType = BEDROCK_TOOL_VERSION_MAP[toolType];
if (newType in BEDROCK_TOOL_BETA_MAP) {
requiredBetas.add(BEDROCK_TOOL_BETA_MAP[newType]);
}
const newName = newType in BEDROCK_TOOL_NAME_MAP ? BEDROCK_TOOL_NAME_MAP[newType] : tool.name;
return {
...tool,
type: newType,
name: newName
};
}
if (toolType && toolType in BEDROCK_TOOL_BETA_MAP) {
requiredBetas.add(BEDROCK_TOOL_BETA_MAP[toolType]);
}
if (toolType && toolType in BEDROCK_TOOL_NAME_MAP) {
return {
...tool,
name: BEDROCK_TOOL_NAME_MAP[toolType]
};
}
return tool;
});
return {
...rest,
...transformedTools != null ? { tools: transformedTools } : {},
...transformedToolChoice != null ? { tool_choice: transformedToolChoice } : {},
...requiredBetas.size > 0 ? { anthropic_beta: Array.from(requiredBetas) } : {},
anthropic_version: "bedrock-2023-05-31"
};
},
// Bedrock Anthropic doesn't support URL sources, force download and base64 conversion
supportedUrls: () => ({}),
// native structured output via output_config.format is supported on Bedrock
// Bedrock rejects `output_config.format` for `claude-opus-4-7`, `claude-opus-4-8`, `claude-fable-5`, and `claude-sonnet-5`
supportsNativeStructuredOutput: !modelId.includes("claude-opus-4-7") && !modelId.includes("claude-opus-4-8") && !modelId.includes("claude-fable-5") && !modelId.includes("claude-sonnet-5")
});
const provider = function(modelId) {
if (new.target) {
throw new Error(
"The Bedrock Anthropic model function cannot be called with the new keyword."
);
}
return createChatModel(modelId);
};
provider.specificationVersion = "v4";
provider.languageModel = createChatModel;
provider.chat = createChatModel;
provider.messages = createChatModel;
provider.embeddingModel = (modelId) => {
throw new NoSuchModelError({ modelId, modelType: "embeddingModel" });
};
provider.textEmbeddingModel = provider.embeddingModel;
provider.imageModel = (modelId) => {
throw new NoSuchModelError({ modelId, modelType: "imageModel" });
};
provider.tools = anthropicTools;
return provider;
}
var amazonBedrockAnthropic = createAmazonBedrockAnthropic();
export {
amazonBedrockAnthropic,
amazonBedrockAnthropic as bedrockAnthropic,
createAmazonBedrockAnthropic,
createAmazonBedrockAnthropic as createBedrockAnthropic
};
//# sourceMappingURL=index.js.map