UNPKG

@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
// 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