@warlock.js/ai-bedrock 5.2.2 → 5.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/cjs/index.cjs.map +1 -1
- package/esm/embedder.mjs.map +1 -1
- package/esm/model.mjs.map +1 -1
- package/esm/utils/to-bedrock-messages.mjs.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `@warlock.js/ai-bedrock` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.2.3 - 2026-09-02
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Released in exact lockstep with Core's Web generator repairs so every family dependency remains installable at 5.2.3.
|
|
12
|
+
|
|
7
13
|
## 5.2.2
|
|
8
14
|
|
|
9
15
|
### Maintenance
|
package/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["InvalidRequestError","AIError","ProviderTimeoutError","ProviderAuthError","QuotaExceededError","ProviderRateLimitError","ContextLengthExceededError","InvalidRequestError","ProviderError","LOG_MODULE","log","InvokeModelCommand","log","ConverseCommand","ConverseStreamCommand","BedrockRuntimeClient"],"sources":["../../../../../../ai-bedrock/src/utils/map-stop-reason.ts","../../../../../../ai-bedrock/src/utils/to-bedrock-messages.ts","../../../../../../ai-bedrock/src/utils/to-bedrock-tools.ts","../../../../../../ai-bedrock/src/utils/wrap-bedrock-error.ts","../../../../../../ai-bedrock/src/embedder.ts","../../../../../../ai-bedrock/src/known-capabilities.ts","../../../../../../ai-bedrock/src/known-vision-models.ts","../../../../../../ai-bedrock/src/model.ts","../../../../../../ai-bedrock/src/sdk.ts"],"sourcesContent":["import type { FinishReason } from \"@warlock.js/ai\";\n\nconst stopReasonMap: Record<string, FinishReason> = {\n end_turn: \"stop\",\n stop_sequence: \"stop\",\n max_tokens: \"length\",\n tool_use: \"tool_calls\",\n};\n\n/**\n * Map Bedrock Converse's `stopReason` to the normalized `FinishReason`\n * union.\n *\n * `end_turn` / `stop_sequence` are natural stops. `max_tokens` maps to\n * `length`. `tool_use` maps to `tool_calls`. Everything else —\n * `content_filtered`, `guardrail_intervened`, `malformed_tool_use`,\n * `malformed_model_output`, `model_context_window_exceeded`, `null`,\n * or any future value — falls through to `\"error\"`: none produced a\n * clean terminal answer, so the agent must not treat them as success.\n *\n * @example\n * mapStopReason(\"end_turn\"); // \"stop\"\n * mapStopReason(\"tool_use\"); // \"tool_calls\"\n * mapStopReason(\"guardrail_intervened\"); // \"error\"\n * mapStopReason(undefined); // \"error\"\n */\nexport function mapStopReason(raw: string | null | undefined): FinishReason {\n return stopReasonMap[raw ?? \"\"] ?? \"error\";\n}\n","import { InvalidRequestError, type ContentPart, type Message } from \"@warlock.js/ai\";\nimport type {\n ContentBlock,\n ImageFormat,\n Message as BedrockMessage,\n SystemContentBlock,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Result of splitting a vendor-neutral `Message[]` for the Bedrock\n * Converse API: system prompts hoist to a separate `SystemContentBlock[]`\n * (Converse has no `\"system\"` role inside `messages`), and the\n * remaining turns map to Bedrock `Message[]`.\n */\nexport type BedrockMessages = {\n system: SystemContentBlock[] | undefined;\n messages: BedrockMessage[];\n};\n\nconst MEDIA_TYPE_TO_FORMAT: Record<string, ImageFormat> = {\n \"image/jpeg\": \"jpeg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"image/webp\": \"webp\",\n};\n\n/**\n * Convert vendor-neutral `Message[]` into Bedrock Converse's request\n * shape.\n *\n * Converse differs from the OpenAI Chat protocol in three ways this\n * function absorbs:\n *\n * 1. **No `system` role.** System messages become a separate\n * `SystemContentBlock[]` (one `{ text }` block each).\n * 2. **Tool results are `user` turns.** A neutral `tool` message\n * becomes a `user` message carrying a single `toolResult` block.\n * 3. **Tool calls are `toolUse` content blocks.** An assistant message\n * with `toolCalls` becomes an `assistant` message: an optional\n * leading `text` block followed by one `toolUse` block per call.\n *\n * @example\n * const { system, messages } = toBedrockMessages([\n * { role: \"system\", content: \"Be concise.\" },\n * { role: \"user\", content: \"Hi\" },\n * ]);\n */\nexport function toBedrockMessages(messages: Message[]): BedrockMessages {\n const system: SystemContentBlock[] = [];\n const mapped: BedrockMessage[] = [];\n\n for (const message of messages) {\n if (message.role === \"system\") {\n system.push({ text: stringifyContent(message.content) });\n\n continue;\n }\n\n if (message.role === \"tool\") {\n mapped.push({\n role: \"user\",\n content: [\n {\n toolResult: {\n toolUseId: message.toolCallId ?? \"\",\n content: [{ text: stringifyContent(message.content) }],\n },\n },\n ],\n });\n\n continue;\n }\n\n if (message.role === \"assistant\" && message.toolCalls && message.toolCalls.length > 0) {\n const blocks: ContentBlock[] = [];\n const text = stringifyContent(message.content);\n\n if (text) {\n blocks.push({ text });\n }\n\n for (const toolCall of message.toolCalls) {\n blocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.input ?? {},\n },\n } as ContentBlock);\n }\n\n mapped.push({ role: \"assistant\", content: blocks });\n\n continue;\n }\n\n if (message.role === \"user\" && Array.isArray(message.content)) {\n mapped.push({\n role: \"user\",\n content: message.content.map(toBedrockContentBlock),\n });\n\n continue;\n }\n\n mapped.push({\n role: message.role === \"assistant\" ? \"assistant\" : \"user\",\n content: [{ text: stringifyContent(message.content) }],\n });\n }\n\n return {\n system: system.length > 0 ? system : undefined,\n messages: mapped,\n };\n}\n\n/**\n * Multipart content is only meaningful on user messages — for any other\n * role collapse a `ContentPart[]` to its concatenated text. Plain\n * strings pass through unchanged.\n */\nfunction stringifyContent(content: string | ContentPart[]): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n return content\n .filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n}\n\n/**\n * Map a resolved `ContentPart` to a Bedrock `ContentBlock`. Bedrock's\n * `ImageSource` only accepts raw bytes or an S3 location — there is no\n * remote-URL source. A neutral `{ url }` image therefore cannot be\n * sent and surfaces a typed `InvalidRequestError` upfront rather than\n * a downstream Bedrock validation fault. The agent has already\n * resolved attachments, so this never fetches or reads anything.\n */\nfunction toBedrockContentBlock(part: ContentPart): ContentBlock {\n if (part.type === \"text\") {\n return { text: part.text };\n }\n\n if (\"url\" in part.source) {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support remote-URL sources; supply base64 bytes instead.\",\n );\n }\n\n // PDF → Bedrock `document` content block (A2). Converse accepts a\n // document block with raw bytes; the agent gates this on the model's\n // `pdf` capability before it reaches here.\n if (part.type === \"pdf\") {\n return {\n document: {\n format: \"pdf\",\n name: \"attachment\",\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n } as unknown as ContentBlock;\n }\n\n // Bedrock Converse has no audio content block (capability stays false).\n if (part.type === \"audio\") {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support audio attachments.\",\n );\n }\n\n const format = MEDIA_TYPE_TO_FORMAT[part.source.mediaType];\n\n if (!format) {\n throw new InvalidRequestError(\n `Unsupported image media type for Bedrock: \"${part.source.mediaType}\" (expected image/jpeg, image/png, image/gif, or image/webp).`,\n );\n }\n\n return {\n image: {\n format,\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n };\n}\n","import { extractJsonSchema, type ToolConfig } from \"@warlock.js/ai\";\nimport type { Tool, ToolConfiguration, ToolInputSchema } from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Convert vendor-neutral `ToolConfig[]` into Bedrock Converse's\n * `ToolConfiguration`. Each tool becomes a `toolSpec` with a JSON\n * `inputSchema`. Bedrock requires the schema root to be an object —\n * a non-object extraction degrades to a parameterless object schema\n * so registration never fails.\n *\n * Returns `undefined` when there are no tools so the caller can omit\n * `toolConfig` from the request entirely (Bedrock rejects an empty\n * `tools` array).\n *\n * @example\n * const toolConfig = toBedrockToolConfig([weatherTool]);\n * await client.send(new ConverseCommand({ modelId, messages, toolConfig }));\n */\nexport function toBedrockToolConfig(\n tools: ToolConfig<unknown, unknown>[] | undefined,\n): ToolConfiguration | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return {\n tools: tools.map(\n (tool): Tool => ({\n toolSpec: {\n name: tool.name,\n description: tool.description,\n inputSchema: { json: toJsonSchema(tool.input) } as ToolInputSchema,\n },\n }),\n ),\n };\n}\n\n/**\n * Resolve a tool's input schema to a JSON-Schema object. Bedrock's\n * `ToolInputSchema.json` requires an object root; anything else (or a\n * failed extraction) degrades to a parameterless object so the tool\n * still registers.\n */\nfunction toJsonSchema(input: ToolConfig<unknown, unknown>[\"input\"]): Record<string, unknown> {\n const schema = extractJsonSchema(input);\n\n if (schema && schema.type === \"object\") {\n return schema;\n }\n\n return { type: \"object\" };\n}\n","import {\n AIError,\n ContextLengthExceededError,\n InvalidRequestError,\n ProviderAuthError,\n ProviderError,\n ProviderRateLimitError,\n ProviderTimeoutError,\n QuotaExceededError,\n} from \"@warlock.js/ai\";\n\n/**\n * Raw-error fields the wrapper reads off an AWS SDK exception. Every\n * Bedrock error is a Smithy `__BaseException` with a stable `name`\n * (`\"ThrottlingException\"`, `\"ValidationException\"`, …) and a\n * `$metadata` carrying `httpStatusCode` + `requestId`. We duck-type\n * because retries and proxies sometimes flatten the prototype chain.\n */\ntype BedrockErrorShape = {\n name?: string;\n message?: string;\n httpStatusCode?: number;\n requestId?: string;\n code?: string;\n};\n\nconst TIMEOUT_NAMES = new Set([\n \"ModelTimeoutException\",\n \"TimeoutError\",\n \"RequestTimeout\",\n \"RequestTimeoutException\",\n]);\n\n/**\n * Wrap any thrown value caught inside the Bedrock adapter into the\n * appropriate `@warlock.js/ai` `AIError` subclass.\n *\n * **Dispatch strategy.** AWS errors carry no provider machine `code`;\n * the stable identifier is the Smithy exception `name`. Dispatch keys\n * on `name`, falls back to `$metadata.httpStatusCode` when the name is\n * missing (flattened/proxied errors). `ValidationException` is split:\n * the \"input is too long / exceeds context window\" phrasing maps to\n * `ContextLengthExceededError`, everything else to\n * `InvalidRequestError`.\n *\n * `AIError` instances pass through unchanged so `catch/throw wrap(e)`\n * pipelines never double-wrap.\n *\n * @example\n * try {\n * return await this.client.send(new ConverseCommand(...));\n * } catch (thrown) {\n * throw wrapBedrockError(thrown);\n * }\n */\nexport function wrapBedrockError(thrown: unknown): AIError {\n if (thrown instanceof AIError) {\n return thrown;\n }\n\n const shape = toShape(thrown);\n const context = buildContext(shape);\n const message = shape.message ?? (thrown instanceof Error ? thrown.message : String(thrown));\n\n if (isTimeout(shape)) {\n return new ProviderTimeoutError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"AccessDeniedException\" || shape.httpStatusCode === 403) {\n return new ProviderAuthError(message, { cause: thrown, context });\n }\n\n if (shape.httpStatusCode === 401) {\n return new ProviderAuthError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"ServiceQuotaExceededException\") {\n return new QuotaExceededError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"ThrottlingException\" || shape.httpStatusCode === 429) {\n return new ProviderRateLimitError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"ValidationException\") {\n if (/too long|context window|maximum context|exceeds the maximum/i.test(message)) {\n return new ContextLengthExceededError(message, { cause: thrown, context });\n }\n\n return new InvalidRequestError(message, { cause: thrown, context });\n }\n\n if (\n shape.name === \"ResourceNotFoundException\" ||\n shape.name === \"ConflictException\" ||\n isClientStatus(shape.httpStatusCode)\n ) {\n return new InvalidRequestError(message, { cause: thrown, context });\n }\n\n return new ProviderError(message, { cause: thrown, context });\n}\n\n/**\n * Read the raw error shape without depending on `instanceof`. AWS\n * exceptions expose `$metadata`; plain/proxied errors may carry\n * `status` / `code` instead.\n */\nfunction toShape(thrown: unknown): BedrockErrorShape {\n if (typeof thrown !== \"object\" || thrown === null) {\n return {};\n }\n\n const raw = thrown as Record<string, unknown>;\n const metadata = raw.$metadata as { httpStatusCode?: number; requestId?: string } | undefined;\n\n return {\n name: typeof raw.name === \"string\" ? raw.name : undefined,\n message: typeof raw.message === \"string\" ? raw.message : undefined,\n httpStatusCode:\n metadata && typeof metadata.httpStatusCode === \"number\"\n ? metadata.httpStatusCode\n : typeof raw.status === \"number\"\n ? (raw.status as number)\n : undefined,\n requestId: metadata && typeof metadata.requestId === \"string\" ? metadata.requestId : undefined,\n code: typeof raw.code === \"string\" ? raw.code : undefined,\n };\n}\n\n/**\n * Decide whether the error is a timeout. Bedrock surfaces\n * `ModelTimeoutException`; the AWS transport layer surfaces\n * `TimeoutError` / `ETIMEDOUT` / `ECONNABORTED`.\n */\nfunction isTimeout(shape: BedrockErrorShape): boolean {\n if (shape.name && TIMEOUT_NAMES.has(shape.name)) {\n return true;\n }\n\n return shape.code === \"ETIMEDOUT\" || shape.code === \"ECONNABORTED\";\n}\n\n/** True for HTTP 4xx — a client-side request problem, not a server fault. */\nfunction isClientStatus(status: number | undefined): boolean {\n return typeof status === \"number\" && status >= 400 && status < 500;\n}\n\n/**\n * Attach the raw diagnostic fields to `error.context`. The Smithy\n * exception `name` is the closest thing Bedrock has to a stable error\n * code, so it lands on `context.code`.\n */\nfunction buildContext(shape: BedrockErrorShape): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n\n if (shape.httpStatusCode !== undefined) {\n context.status = shape.httpStatusCode;\n }\n\n if (shape.name) {\n context.code = shape.name;\n }\n\n if (shape.requestId) {\n context.requestId = shape.requestId;\n }\n\n return context;\n}\n","import {\n type EmbeddingBatchResult,\n type EmbeddingResult,\n type EmbeddingUsage,\n type EmbedderContract,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport { InvokeModelCommand, type BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockEmbedderConfig } from \"./config.type\";\nimport { wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/** Shape of the Amazon Titan Text Embeddings response body. */\ntype TitanEmbeddingResponse = {\n embedding: number[];\n inputTextTokenCount: number;\n};\n\n/**\n * Bedrock-backed implementation of `EmbedderContract`, targeting the\n * Amazon Titan Text Embeddings family\n * (`amazon.titan-embed-text-v2:0` / v1) via `InvokeModel`.\n *\n * **Role.** Converts text into floating-point vectors. Standalone\n * primitive — unrelated to Converse / tools / the agent loop.\n *\n * **Single-input only upstream.** Titan's `InvokeModel` body accepts\n * one `inputText` per call — there is no batch endpoint. `embedMany`\n * therefore issues one request per input sequentially and aggregates\n * token usage. This is a deliberate, documented trade-off: a real\n * batch API does not exist for Titan on Bedrock, so the alternative\n * (failing `embedMany`) would be worse. Cohere embeddings on Bedrock\n * *do* batch but use an incompatible body shape — out of scope; use\n * the OpenAI adapter or a future Cohere adapter when batch throughput\n * matters.\n *\n * **Dimensions.** When no `dimensions` override is given,\n * `this.dimensions` starts at `0` and is populated from the first\n * response's vector length, then cached. Passing `dimensions` forwards\n * Titan v2's truncation hint (256 / 512 / 1024) and sets the initial\n * value immediately.\n *\n * @example\n * const embedder = new BedrockEmbedder(client, { name: \"amazon.titan-embed-text-v2:0\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n * const { vectors } = await embedder.embedMany([\"doc 1\", \"doc 2\"]);\n */\nexport class BedrockEmbedder implements EmbedderContract {\n public readonly name: string;\n public readonly provider: string;\n public dimensions: number;\n\n private readonly client: BedrockRuntimeClient;\n private readonly configuredDimensions: number | undefined;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockEmbedderConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.name = config.name;\n this.provider = provider;\n this.configuredDimensions = config.dimensions;\n this.dimensions = config.dimensions ?? 0;\n }\n\n public async embed(input: string): Promise<EmbeddingResult> {\n const { vector, tokens } = await this.invoke(input);\n\n return {\n vector,\n dimensions: this.dimensions,\n usage: { promptTokens: tokens, totalTokens: tokens },\n };\n }\n\n public async embedMany(inputs: string[]): Promise<EmbeddingBatchResult> {\n const vectors: number[][] = [];\n let tokens = 0;\n\n for (const input of inputs) {\n const result = await this.invoke(input);\n\n vectors.push(result.vector);\n tokens += result.tokens;\n }\n\n const usage: EmbeddingUsage = { promptTokens: tokens, totalTokens: tokens };\n\n return { vectors, dimensions: this.dimensions, usage };\n }\n\n /**\n * Issue a single Titan `InvokeModel` embedding request: encode the\n * JSON body, send, wrap provider errors, decode the response, and\n * cache `dimensions` on the first successful call.\n */\n private async invoke(input: string): Promise<{ vector: number[]; tokens: number }> {\n this.logger.debug(LOG_MODULE, \"embedder.request\", \"InvokeModel embeddings\", {\n model: this.name,\n });\n\n const body = JSON.stringify({\n inputText: input,\n ...(this.configuredDimensions !== undefined\n ? { dimensions: this.configuredDimensions }\n : {}),\n });\n\n let raw;\n\n try {\n raw = await this.client.send(\n new InvokeModelCommand({\n modelId: this.name,\n contentType: \"application/json\",\n accept: \"application/json\",\n body: new TextEncoder().encode(body),\n }),\n );\n } catch (thrown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"embedder.error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n throw wrapped;\n }\n\n const decoded = JSON.parse(new TextDecoder().decode(raw.body)) as TitanEmbeddingResponse;\n\n if (this.dimensions === 0) {\n this.dimensions = decoded.embedding.length;\n }\n\n this.logger.debug(LOG_MODULE, \"embedder.response\", \"InvokeModel embeddings returned\", {\n dimensions: decoded.embedding.length,\n tokens: decoded.inputTextTokenCount,\n });\n\n return { vector: decoded.embedding, tokens: decoded.inputTextTokenCount };\n }\n}\n","/**\n * Cost-truth capability inference for Bedrock Converse model ids.\n *\n * Bedrock model ids are provider-prefixed and version-suffixed\n * (`anthropic.claude-3-7-sonnet-20250219-v1:0`, `us.amazon.nova-pro-v1:0`),\n * so — exactly like `known-vision-models.ts` — a lowercase substring scan\n * is the only robust check across cross-region inference-profile prefixes\n * (`us.`, `eu.`, `apac.`) and date/version tags.\n *\n * Each predicate answers a single `ModelCapabilities` flag the agent reads\n * to decide whether to forward a cost-truth option (`reasoning`,\n * `cacheControl`) or up-front-reject an attachment (`pdf`). Unknown ids\n * default to `false` so an unsupported request fails fast with a clear\n * capability error instead of an opaque Bedrock `ValidationException`.\n * Every inference is overridable per-model via `bedrock.model({ name, … })`.\n */\n\n/**\n * Families that expose Anthropic-style extended thinking on Bedrock\n * Converse via `additionalModelRequestFields.thinking`. Only Claude 3.7\n * and the Claude 4 line (Sonnet / Opus / Haiku) support a configurable\n * thinking budget; earlier Claude, Nova, Llama, Mistral and Cohere do\n * not, so they are intentionally absent.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\n \"claude-3-7\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n];\n\n/**\n * Families that honor Converse `cachePoint` prompt-cache breakpoints.\n * Anthropic Claude 3.5+ / 3.7 / 4 and the Amazon Nova line support\n * cache points; text-only legacy families do not.\n */\nconst PROMPT_CACHING_CAPABLE_SUBSTRINGS = [\n \"claude-3-5\",\n \"claude-3-7\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n \"nova-lite\",\n \"nova-pro\",\n \"nova-premier\",\n \"nova-micro\",\n];\n\n/**\n * Families that accept Converse `document` content blocks (PDF / docx /\n * txt input). The multimodal Claude 3+ and Nova families support\n * document blocks; the substring set mirrors the vision-capable list\n * minus the image-only Llama entries (Llama on Bedrock takes images but\n * not document blocks via Converse).\n */\nconst PDF_CAPABLE_SUBSTRINGS = [\n \"claude-3\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n \"nova-lite\",\n \"nova-pro\",\n \"nova-premier\",\n];\n\nfunction matchesAny(modelId: string, fragments: string[]): boolean {\n const normalized = modelId.toLowerCase();\n\n return fragments.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Infer whether a Bedrock model id exposes extended-thinking / reasoning\n * (Claude 3.7 + Claude 4). When true the adapter forwards\n * `ModelCallOptions.reasoning` as Converse\n * `additionalModelRequestFields.thinking`.\n *\n * @example\n * inferReasoningCapability(\"anthropic.claude-3-7-sonnet-20250219-v1:0\"); // → true\n * inferReasoningCapability(\"us.amazon.nova-pro-v1:0\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n return matchesAny(modelId, REASONING_CAPABLE_SUBSTRINGS);\n}\n\n/**\n * Infer whether a Bedrock model id honors Converse `cachePoint`\n * breakpoints (Claude 3.5+ / Nova). When true the adapter both maps\n * `ModelCallOptions.cacheControl` write breakpoints to cache points and\n * reports `Usage.cachedTokens` / `Usage.cacheWriteTokens`.\n *\n * @example\n * inferPromptCachingCapability(\"us.amazon.nova-pro-v1:0\"); // → true\n * inferPromptCachingCapability(\"meta.llama3-1-8b-instruct-v1:0\"); // → false\n */\nexport function inferPromptCachingCapability(modelId: string): boolean {\n return matchesAny(modelId, PROMPT_CACHING_CAPABLE_SUBSTRINGS);\n}\n\n/**\n * Infer whether a Bedrock model id accepts Converse `document` content\n * blocks (PDF / document input — Claude 3+ / Nova). When false the agent\n * rejects a PDF attachment up front instead of dropping it at the wire.\n *\n * @example\n * inferPdfCapability(\"anthropic.claude-3-5-sonnet-20240620-v1:0\"); // → true\n * inferPdfCapability(\"meta.llama3-2-90b-instruct-v1:0\"); // → false\n */\nexport function inferPdfCapability(modelId: string): boolean {\n return matchesAny(modelId, PDF_CAPABLE_SUBSTRINGS);\n}\n","/**\n * Substrings that identify Bedrock model ids whose family accepts image\n * input on the Converse API.\n *\n * Bedrock model ids are provider-prefixed and version-suffixed\n * (`anthropic.claude-3-5-sonnet-20240620-v1:0`, `us.amazon.nova-pro-v1:0`,\n * `meta.llama3-2-90b-instruct-v1:0`), so a substring match is the only\n * robust check across the cross-region inference-profile prefixes\n * (`us.`, `eu.`, `apac.`) and date/version tags.\n *\n * Multimodal families covered: Anthropic Claude 3 / 3.5 / 3.7 / 4,\n * Amazon Nova Lite/Pro/Premier, Meta Llama 3.2 (11B/90B) and Llama 4.\n * Text-only families (Llama 3/3.1, Titan Text, Mistral 7B, Cohere\n * Command) are intentionally absent. Override per-model via\n * `bedrock.model({ name, vision: true | false })`.\n */\nconst VISION_CAPABLE_SUBSTRINGS = [\n \"claude-3\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n \"nova-lite\",\n \"nova-pro\",\n \"nova-premier\",\n \"llama3-2-11b\",\n \"llama3-2-90b\",\n \"llama4\",\n];\n\n/**\n * Infer whether a Bedrock model id supports vision based on the known\n * multimodal-family substrings. Unknown ids default to `false` so that\n * passing an image attachment to an unsupported model surfaces a clear,\n * agent-side capability error instead of an opaque Bedrock validation\n * fault.\n *\n * @example\n * inferVisionCapability(\"anthropic.claude-3-5-sonnet-20240620-v1:0\"); // → true\n * inferVisionCapability(\"us.amazon.nova-pro-v1:0\"); // → true\n * inferVisionCapability(\"meta.llama3-1-8b-instruct-v1:0\"); // → false\n * inferVisionCapability(\"amazon.titan-text-express-v1\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n","import {\n safeJsonParse,\n type Message,\n type ModelCallOptions,\n type ModelCapabilities,\n type ModelContract,\n type ModelPricing,\n type ModelResponse,\n type ModelStreamChunk,\n type ModelToolCallRequest,\n type Usage,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport {\n ConverseCommand,\n ConverseStreamCommand,\n type BedrockRuntimeClient,\n type ContentBlock,\n type ConverseRequest,\n type TokenUsage,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockModelConfig } from \"./config.type\";\nimport {\n inferPdfCapability,\n inferPromptCachingCapability,\n inferReasoningCapability,\n} from \"./known-capabilities\";\nimport { inferVisionCapability } from \"./known-vision-models\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/**\n * Conventional extended-thinking token budgets for the neutral\n * `reasoning.effort` levels, used when the caller asks for an effort\n * tier without naming an explicit `reasoning.maxTokens` budget. Mirrors\n * the low / medium / high spread other reasoning adapters expose so the\n * vendor-neutral option behaves consistently across providers.\n */\nconst EFFORT_THINKING_BUDGET: Record<string, number | undefined> = {\n low: 1024,\n medium: 4096,\n high: 16384,\n};\n\n/**\n * Bedrock-backed implementation of `ModelContract`.\n *\n * **Role.** The provider-facing bridge between the vendor-neutral\n * `@warlock.js/ai` agent runtime and AWS Bedrock's Converse /\n * ConverseStream API. Converse is the model-agnostic surface — one\n * wire mapping covers every Bedrock-hosted family (Anthropic Claude,\n * Amazon Nova, Meta Llama, Mistral, Cohere) instead of per-family\n * `InvokeModel` body shapes.\n *\n * **Responsibility.**\n * - Owns: a long-lived `BedrockRuntimeClient` + frozen `ModelConfig`\n * (modelId, temperature, maxTokens) used as per-call defaults.\n * - Owns: translating vendor-neutral `Message[]` / `ToolConfig[]` into\n * Converse shapes (system hoisting, `toolUse` / `toolResult` blocks,\n * image bytes) on the way out, and Converse's content-block response\n * (text, tool calls, stop reason, token usage) back into the neutral\n * shapes on the way in.\n * - Does NOT own: dispatching tools, looping, history, retries — those\n * are agent concerns. The model is a per-call protocol adapter.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across calls\"): the AWS client is heavy to construct and reused for\n * the SDK's lifetime.\n *\n * @example\n * import { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\n * const client = new BedrockRuntimeClient({ region: \"us-east-1\" });\n * const model = new BedrockModel(client, {\n * name: \"anthropic.claude-sonnet-4-5-20250929-v1:0\",\n * });\n *\n * const myAgent = agent({ model, tools: [searchTool] });\n * const result = await myAgent.execute(\"Summarize today's news.\");\n */\nexport class BedrockModel implements ModelContract {\n public readonly name: string;\n public readonly provider: string;\n public readonly capabilities: ModelCapabilities;\n public readonly pricing?: ModelPricing;\n\n private readonly client: BedrockRuntimeClient;\n private readonly config: BedrockModelConfig;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockModelConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.config = config;\n this.name = config.name;\n this.provider = provider;\n this.pricing = config.pricing;\n this.capabilities = {\n structuredOutput: config.structuredOutput ?? true,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n promptCaching: config.promptCaching ?? inferPromptCachingCapability(config.name),\n pdf: config.pdf ?? inferPdfCapability(config.name),\n audio: config.audio ?? false,\n };\n }\n\n /**\n * Single-shot completion via the Converse API. Sends the full\n * message list, waits for the terminal response, and reshapes it\n * into a vendor-neutral `ModelResponse`. Per-call `options` override\n * the instance defaults for this call only.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting Converse call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: false,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const blocks = response.output?.message?.content ?? [];\n const finishReason = mapStopReason(response.stopReason);\n const usage = this.extractUsage(response.usage);\n const toolCalls = this.extractToolCalls(blocks);\n\n this.logger.debug(LOG_MODULE, \"response\", \"Converse call succeeded\", { finishReason, usage });\n\n return {\n content: this.extractText(blocks),\n finishReason,\n usage,\n toolCalls,\n };\n }\n\n /**\n * Incremental streaming completion via ConverseStream. Yields neutral\n * `ModelStreamChunk`s — `delta` for text, `tool-call` once a\n * `toolUse` block's accumulated input JSON is complete, and a\n * terminal `done` with the final finish reason + usage totals.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting ConverseStream call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: true,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseStreamCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n let rawStopReason: string | undefined;\n const usage: Usage = { input: 0, output: 0, total: 0 };\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n try {\n for await (const event of response.stream ?? []) {\n if (event.contentBlockStart?.start?.toolUse) {\n const start = event.contentBlockStart.start.toolUse;\n\n toolBlocks.set(event.contentBlockStart.contentBlockIndex ?? 0, {\n id: start.toolUseId ?? \"\",\n name: start.name ?? \"\",\n json: \"\",\n });\n\n continue;\n }\n\n if (event.contentBlockDelta?.delta) {\n const delta = event.contentBlockDelta.delta;\n\n if (delta.text) {\n yield { type: \"delta\", content: delta.text };\n } else if (delta.toolUse) {\n const accumulator = toolBlocks.get(event.contentBlockDelta.contentBlockIndex ?? 0);\n\n if (accumulator) {\n accumulator.json += delta.toolUse.input ?? \"\";\n }\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const accumulator = toolBlocks.get(event.contentBlockStop.contentBlockIndex ?? 0);\n\n if (accumulator) {\n yield {\n type: \"tool-call\",\n id: accumulator.id,\n name: accumulator.name,\n input: safeJsonParse<Record<string, unknown>>(accumulator.json, {}),\n };\n\n toolBlocks.delete(event.contentBlockStop.contentBlockIndex ?? 0);\n }\n\n continue;\n }\n\n if (event.messageStop) {\n rawStopReason = event.messageStop.stopReason;\n }\n\n if (event.metadata?.usage) {\n const raw = event.metadata.usage;\n\n usage.input = raw.inputTokens ?? 0;\n usage.output = raw.outputTokens ?? 0;\n usage.total = raw.totalTokens ?? usage.input + usage.output;\n\n if (raw.cacheReadInputTokens && raw.cacheReadInputTokens > 0) {\n usage.cachedTokens = raw.cacheReadInputTokens;\n }\n\n if (raw.cacheWriteInputTokens && raw.cacheWriteInputTokens > 0) {\n usage.cacheWriteTokens = raw.cacheWriteInputTokens;\n }\n }\n }\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const finishReason = mapStopReason(rawStopReason);\n\n this.logger.debug(LOG_MODULE, \"response\", \"ConverseStream call succeeded\", {\n finishReason,\n usage,\n });\n\n yield { type: \"done\", finishReason, usage };\n }\n\n /**\n * Assemble the Converse request shared by `complete()` and\n * `stream()` (both command shapes take the same input). Hoists the\n * system prompt, maps inference params, and conditionally attaches\n * tools and native structured output.\n */\n private buildRequest(\n messages: Message[],\n options: ModelCallOptions | undefined,\n ): ConverseRequest {\n const { system, messages: bedrockMessages } = toBedrockMessages(messages);\n const maxTokens = options?.maxTokens ?? this.config.maxTokens;\n const temperature = options?.temperature ?? this.config.temperature;\n const cachedMessages = this.applyCacheBreakpoints(bedrockMessages, options?.cacheControl);\n\n return {\n modelId: this.name,\n messages: cachedMessages,\n ...(system ? { system } : {}),\n inferenceConfig: {\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n },\n ...this.buildToolConfig(options?.tools),\n ...this.buildOutputConfig(options?.responseSchema),\n ...this.buildReasoningConfig(options?.reasoning),\n };\n }\n\n /**\n * Append a Converse `cachePoint` block to the LAST message when the\n * caller supplies a `cacheControl` write breakpoint and the model is\n * `promptCaching`-capable. A cache point tells Bedrock to cache the\n * whole prefix up to that block, so subsequent calls reusing the same\n * prefix bill the cached portion at the discounted read rate\n * (surfaced as `Usage.cachedTokens`). No-ops gracefully when caching\n * is unsupported, no breakpoint was requested, or there are no\n * messages to mark — Bedrock then prices the call normally.\n *\n * Bedrock only honors `CachePointType.DEFAULT`; the neutral\n * `breakpoints` count is a presence hint (one trailing breakpoint is\n * the only placement Converse supports without manual block surgery),\n * so any positive value marks the trailing message.\n */\n private applyCacheBreakpoints(\n messages: ConverseRequest[\"messages\"],\n cacheControl: ModelCallOptions[\"cacheControl\"],\n ): ConverseRequest[\"messages\"] {\n const breakpoints = cacheControl?.breakpoints ?? 0;\n\n if (!this.capabilities.promptCaching || breakpoints <= 0 || !messages || messages.length === 0) {\n return messages;\n }\n\n const last = messages.length - 1;\n const lastMessage = messages[last];\n\n return [\n ...messages.slice(0, last),\n {\n ...lastMessage,\n content: [...(lastMessage.content ?? []), { cachePoint: { type: \"default\" } }],\n },\n ];\n }\n\n /**\n * Translate the neutral `reasoning` option into Claude-on-Bedrock's\n * extended-thinking control, carried in Converse's escape hatch\n * `additionalModelRequestFields.thinking`. Emitted only when the model\n * is `reasoning`-capable and a budget can be resolved — `maxTokens`\n * (explicit thinking budget) wins, otherwise `effort` maps to a\n * conventional token budget so callers can opt in without picking a\n * number. Returns an empty object (no-op) for non-reasoning models or\n * when no reasoning option was supplied, so unsupported params never\n * reach the wire.\n */\n private buildReasoningConfig(\n reasoning: ModelCallOptions[\"reasoning\"],\n ): Pick<ConverseRequest, \"additionalModelRequestFields\"> {\n if (!this.capabilities.reasoning || !reasoning) {\n return {};\n }\n\n const budgetTokens = reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[reasoning.effort ?? \"\"];\n\n if (budgetTokens === undefined) {\n return {};\n }\n\n return {\n additionalModelRequestFields: {\n thinking: { type: \"enabled\", budget_tokens: budgetTokens },\n },\n };\n }\n\n /**\n * Spread-friendly tool fragment. Returns an empty object when no\n * tools were supplied (Bedrock rejects an empty `tools` array).\n */\n private buildToolConfig(tools: ModelCallOptions[\"tools\"]): Pick<ConverseRequest, \"toolConfig\"> {\n const toolConfig = toBedrockToolConfig(tools);\n\n return toolConfig ? { toolConfig } : {};\n }\n\n /**\n * Translate the neutral `responseSchema` into Converse's native\n * `outputConfig.textFormat` (JSON-schema structured output). Bedrock\n * requires the schema as a stringified JSON document and only\n * accepts an object root. Emitted only when the model is\n * `structuredOutput`-capable and the schema is an object — otherwise\n * the agent's soft system-prompt hint + client-side `validate()`\n * carry shape (same degradation philosophy as the OpenAI adapter).\n */\n private buildOutputConfig(\n responseSchema: Record<string, unknown> | undefined,\n ): Pick<ConverseRequest, \"outputConfig\"> {\n if (!responseSchema || !this.capabilities.structuredOutput) {\n return {};\n }\n\n if (responseSchema.type !== \"object\" || typeof responseSchema.properties !== \"object\") {\n return {};\n }\n\n return {\n outputConfig: {\n textFormat: {\n type: \"json_schema\",\n structure: {\n jsonSchema: { name: \"response\", schema: JSON.stringify(responseSchema) },\n },\n },\n },\n };\n }\n\n /**\n * Concatenate every `text` content block into the single neutral\n * `content` string. `toolUse` and other block types are surfaced\n * separately via `extractToolCalls`.\n */\n private extractText(blocks: ContentBlock[]): string {\n return blocks\n .map((block) => (\"text\" in block && typeof block.text === \"string\" ? block.text : \"\"))\n .join(\"\");\n }\n\n /**\n * Reshape Converse `toolUse` content blocks into the neutral\n * `ModelToolCallRequest[]`. Returns `undefined` when no tools were\n * requested so callers can branch on presence.\n */\n private extractToolCalls(blocks: ContentBlock[]): ModelToolCallRequest[] | undefined {\n const toolCalls: ModelToolCallRequest[] = [];\n\n for (const block of blocks) {\n if (\"toolUse\" in block && block.toolUse) {\n toolCalls.push({\n id: block.toolUse.toolUseId ?? \"\",\n name: block.toolUse.name ?? \"\",\n input: (block.toolUse.input ?? {}) as Record<string, unknown>,\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /**\n * Normalize Converse's `TokenUsage` into the neutral `Usage` shape.\n * Bedrock supplies a pre-summed `totalTokens`; cache-read and\n * cache-write tokens are surfaced as `cachedTokens` /\n * `cacheWriteTokens` only when non-zero so callers can price the\n * discounted read rate and the one-time write cost separately.\n * Bedrock's Converse `TokenUsage` carries no reasoning-token channel,\n * so `Usage.reasoningTokens` is intentionally left unset here.\n */\n private extractUsage(raw: TokenUsage | undefined): Usage {\n if (!raw) {\n return { input: 0, output: 0, total: 0 };\n }\n\n const input = raw.inputTokens ?? 0;\n const output = raw.outputTokens ?? 0;\n const cached = raw.cacheReadInputTokens;\n const cacheWrite = raw.cacheWriteInputTokens;\n\n return {\n input,\n output,\n total: raw.totalTokens ?? input + output,\n ...(cached && cached > 0 ? { cachedTokens: cached } : {}),\n ...(cacheWrite && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n };\n }\n\n /**\n * Wrap a thrown provider error into the typed `AIError` hierarchy\n * and emit the standard error log line before it propagates. Shared\n * by every catch site so the log shape stays identical.\n */\n private logAndWrap(thrown: unknown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n return wrapped;\n }\n}\n","import { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\nimport type {\n EmbedderContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { approximateTokenCount } from \"@warlock.js/ai\";\nimport type {\n BedrockEmbedderConfig,\n BedrockModelConfig,\n BedrockSDKConfig,\n} from \"./config.type\";\nimport { BedrockEmbedder } from \"./embedder\";\nimport { BedrockModel } from \"./model\";\n\n/**\n * AWS Bedrock-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for any Bedrock-hosted model via\n * the Converse API. A single `BedrockSDK` holds one live\n * `BedrockRuntimeClient`, shared by every `ModelContract` and\n * `EmbedderContract` it produces. Construct one SDK per AWS\n * account/region and reuse it everywhere.\n *\n * **Responsibility.**\n * - Owns: a long-lived `BedrockRuntimeClient` (region, credential\n * chain) and its lifetime. Factory for `BedrockModel` /\n * `BedrockEmbedder` instances sharing that client.\n * - Does NOT own: anything per-call — those live in `BedrockModel` /\n * `BedrockEmbedder` and the agent runtime.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): the AWS client is heavy to construct and\n * designed for reuse; keeping it on `this` aligns with the\n * `new BedrockRuntimeClient(...)` upstream convention.\n *\n * @example\n * const bedrock = new BedrockSDK({ region: \"us-east-1\" });\n * const model = bedrock.model({ name: \"anthropic.claude-sonnet-4-5-20250929-v1:0\" });\n * const embedder = bedrock.embedder({ name: \"amazon.titan-embed-text-v2:0\" });\n */\nexport class BedrockSDK implements SDKAdapterContract {\n private readonly client: BedrockRuntimeClient;\n private readonly provider: string;\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: BedrockSDKConfig) {\n const { provider, pricing, ...clientConfig } = config;\n\n this.client = new BedrockRuntimeClient(clientConfig);\n this.provider = provider ?? \"bedrock\";\n this.pricing = pricing;\n }\n\n /**\n * Build a `BedrockModel` bound to this SDK's client. Each call\n * returns a fresh instance; all instances share the underlying AWS\n * client so connection pools, credential refresh, and retry config\n * stay unified. The SDK's `provider` label is forwarded.\n *\n * Pricing resolution: per-model `config.pricing` wins; otherwise the\n * SDK-level registry entry keyed by `config.name`; otherwise\n * `undefined` (no cost computed).\n */\n public model(config: BedrockModelConfig): ModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: BedrockModelConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new BedrockModel(this.client, resolvedConfig, this.provider);\n }\n\n /**\n * Rough token-count estimate. Uses the character-heuristic\n * (`approximateTokenCount`) from the core package — Bedrock has no\n * offline tokenizer and the per-model tokenizers differ; good enough\n * for budgeting and quota guards, not for billing.\n */\n public async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n }\n\n /**\n * Build a `BedrockEmbedder` (Amazon Titan Text Embeddings) bound to\n * this SDK's client.\n *\n * @example\n * const embedder = bedrock.embedder({ name: \"amazon.titan-embed-text-v2:0\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: BedrockEmbedderConfig): EmbedderContract {\n return new BedrockEmbedder(this.client, config, this.provider);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["InvalidRequestError","AIError","ProviderTimeoutError","ProviderAuthError","QuotaExceededError","ProviderRateLimitError","ContextLengthExceededError","InvalidRequestError","ProviderError","LOG_MODULE","log","InvokeModelCommand","log","ConverseCommand","ConverseStreamCommand","BedrockRuntimeClient"],"sources":["../../../../../../ai-bedrock/src/utils/map-stop-reason.ts","../../../../../../ai-bedrock/src/utils/to-bedrock-messages.ts","../../../../../../ai-bedrock/src/utils/to-bedrock-tools.ts","../../../../../../ai-bedrock/src/utils/wrap-bedrock-error.ts","../../../../../../ai-bedrock/src/embedder.ts","../../../../../../ai-bedrock/src/known-capabilities.ts","../../../../../../ai-bedrock/src/known-vision-models.ts","../../../../../../ai-bedrock/src/model.ts","../../../../../../ai-bedrock/src/sdk.ts"],"sourcesContent":["import type { FinishReason } from \"@warlock.js/ai\";\n\nconst stopReasonMap: Record<string, FinishReason> = {\n end_turn: \"stop\",\n stop_sequence: \"stop\",\n max_tokens: \"length\",\n tool_use: \"tool_calls\",\n};\n\n/**\n * Map Bedrock Converse's `stopReason` to the normalized `FinishReason`\n * union.\n *\n * `end_turn` / `stop_sequence` are natural stops. `max_tokens` maps to\n * `length`. `tool_use` maps to `tool_calls`. Everything else —\n * `content_filtered`, `guardrail_intervened`, `malformed_tool_use`,\n * `malformed_model_output`, `model_context_window_exceeded`, `null`,\n * or any future value — falls through to `\"error\"`: none produced a\n * clean terminal answer, so the agent must not treat them as success.\n *\n * @example\n * mapStopReason(\"end_turn\"); // \"stop\"\n * mapStopReason(\"tool_use\"); // \"tool_calls\"\n * mapStopReason(\"guardrail_intervened\"); // \"error\"\n * mapStopReason(undefined); // \"error\"\n */\nexport function mapStopReason(raw: string | null | undefined): FinishReason {\n return stopReasonMap[raw ?? \"\"] ?? \"error\";\n}\n","import { InvalidRequestError, type ContentPart, type Message } from \"@warlock.js/ai\";\nimport type {\n ContentBlock,\n ImageFormat,\n Message as BedrockMessage,\n SystemContentBlock,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Result of splitting a vendor-neutral `Message[]` for the Bedrock\n * Converse API: system prompts hoist to a separate `SystemContentBlock[]`\n * (Converse has no `\"system\"` role inside `messages`), and the\n * remaining turns map to Bedrock `Message[]`.\n */\nexport type BedrockMessages = {\n system: SystemContentBlock[] | undefined;\n messages: BedrockMessage[];\n};\n\nconst MEDIA_TYPE_TO_FORMAT: Record<string, ImageFormat> = {\n \"image/jpeg\": \"jpeg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"image/webp\": \"webp\",\n};\n\n/**\n * Convert vendor-neutral `Message[]` into Bedrock Converse's request\n * shape.\n *\n * Converse differs from the OpenAI Chat protocol in three ways this\n * function absorbs:\n *\n * 1. **No `system` role.** System messages become a separate\n * `SystemContentBlock[]` (one `{ text }` block each).\n * 2. **Tool results are `user` turns.** A neutral `tool` message\n * becomes a `user` message carrying a single `toolResult` block.\n * 3. **Tool calls are `toolUse` content blocks.** An assistant message\n * with `toolCalls` becomes an `assistant` message: an optional\n * leading `text` block followed by one `toolUse` block per call.\n *\n * @example\n * const { system, messages } = toBedrockMessages([\n * { role: \"system\", content: \"Be concise.\" },\n * { role: \"user\", content: \"Hi\" },\n * ]);\n */\nexport function toBedrockMessages(messages: Message[]): BedrockMessages {\n const system: SystemContentBlock[] = [];\n const mapped: BedrockMessage[] = [];\n\n for (const message of messages) {\n if (message.role === \"system\") {\n system.push({ text: stringifyContent(message.content) });\n\n continue;\n }\n\n if (message.role === \"tool\") {\n mapped.push({\n role: \"user\",\n content: [\n {\n toolResult: {\n toolUseId: message.toolCallId ?? \"\",\n content: [{ text: stringifyContent(message.content) }],\n },\n },\n ],\n });\n\n continue;\n }\n\n if (message.role === \"assistant\" && message.toolCalls && message.toolCalls.length > 0) {\n const blocks: ContentBlock[] = [];\n const text = stringifyContent(message.content);\n\n if (text) {\n blocks.push({ text });\n }\n\n for (const toolCall of message.toolCalls) {\n blocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.input ?? {},\n },\n } as ContentBlock);\n }\n\n mapped.push({ role: \"assistant\", content: blocks });\n\n continue;\n }\n\n if (message.role === \"user\" && Array.isArray(message.content)) {\n mapped.push({\n role: \"user\",\n content: message.content.map(toBedrockContentBlock),\n });\n\n continue;\n }\n\n mapped.push({\n role: message.role === \"assistant\" ? \"assistant\" : \"user\",\n content: [{ text: stringifyContent(message.content) }],\n });\n }\n\n return {\n system: system.length > 0 ? system : undefined,\n messages: mapped,\n };\n}\n\n/**\n * Multipart content is only meaningful on user messages — for any other\n * role collapse a `ContentPart[]` to its concatenated text. Plain\n * strings pass through unchanged.\n */\nfunction stringifyContent(content: string | ContentPart[]): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n return content\n .filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n}\n\n/**\n * Map a resolved `ContentPart` to a Bedrock `ContentBlock`. Bedrock's\n * `ImageSource` only accepts raw bytes or an S3 location — there is no\n * remote-URL source. A neutral `{ url }` image therefore cannot be\n * sent and surfaces a typed `InvalidRequestError` upfront rather than\n * a downstream Bedrock validation fault. The agent has already\n * resolved attachments, so this never fetches or reads anything.\n */\nfunction toBedrockContentBlock(part: ContentPart): ContentBlock {\n if (part.type === \"text\") {\n return { text: part.text };\n }\n\n if (\"url\" in part.source) {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support remote-URL sources; supply base64 bytes instead.\",\n );\n }\n\n // PDF → Bedrock `document` content block (A2). Converse accepts a\n // document block with raw bytes; the agent gates this on the model's\n // `pdf` capability before it reaches here.\n if (part.type === \"pdf\") {\n return {\n document: {\n format: \"pdf\",\n name: \"attachment\",\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n } as unknown as ContentBlock;\n }\n\n // Bedrock Converse has no audio content block (capability stays false).\n if (part.type === \"audio\") {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support audio attachments.\",\n );\n }\n\n const format = MEDIA_TYPE_TO_FORMAT[part.source.mediaType];\n\n if (!format) {\n throw new InvalidRequestError(\n `Unsupported image media type for Bedrock: \"${part.source.mediaType}\" (expected image/jpeg, image/png, image/gif, or image/webp).`,\n );\n }\n\n return {\n image: {\n format,\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n };\n}\n","import { extractJsonSchema, type ToolConfig } from \"@warlock.js/ai\";\nimport type { Tool, ToolConfiguration, ToolInputSchema } from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Convert vendor-neutral `ToolConfig[]` into Bedrock Converse's\n * `ToolConfiguration`. Each tool becomes a `toolSpec` with a JSON\n * `inputSchema`. Bedrock requires the schema root to be an object —\n * a non-object extraction degrades to a parameterless object schema\n * so registration never fails.\n *\n * Returns `undefined` when there are no tools so the caller can omit\n * `toolConfig` from the request entirely (Bedrock rejects an empty\n * `tools` array).\n *\n * @example\n * const toolConfig = toBedrockToolConfig([weatherTool]);\n * await client.send(new ConverseCommand({ modelId, messages, toolConfig }));\n */\nexport function toBedrockToolConfig(\n tools: ToolConfig<unknown, unknown>[] | undefined,\n): ToolConfiguration | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return {\n tools: tools.map(\n (tool): Tool => ({\n toolSpec: {\n name: tool.name,\n description: tool.description,\n inputSchema: { json: toJsonSchema(tool.input) } as ToolInputSchema,\n },\n }),\n ),\n };\n}\n\n/**\n * Resolve a tool's input schema to a JSON-Schema object. Bedrock's\n * `ToolInputSchema.json` requires an object root; anything else (or a\n * failed extraction) degrades to a parameterless object so the tool\n * still registers.\n */\nfunction toJsonSchema(input: ToolConfig<unknown, unknown>[\"input\"]): Record<string, unknown> {\n const schema = extractJsonSchema(input);\n\n if (schema && schema.type === \"object\") {\n return schema;\n }\n\n return { type: \"object\" };\n}\n","import {\n AIError,\n ContextLengthExceededError,\n InvalidRequestError,\n ProviderAuthError,\n ProviderError,\n ProviderRateLimitError,\n ProviderTimeoutError,\n QuotaExceededError,\n} from \"@warlock.js/ai\";\n\n/**\n * Raw-error fields the wrapper reads off an AWS SDK exception. Every\n * Bedrock error is a Smithy `__BaseException` with a stable `name`\n * (`\"ThrottlingException\"`, `\"ValidationException\"`, …) and a\n * `$metadata` carrying `httpStatusCode` + `requestId`. We duck-type\n * because retries and proxies sometimes flatten the prototype chain.\n */\ntype BedrockErrorShape = {\n name?: string;\n message?: string;\n httpStatusCode?: number;\n requestId?: string;\n code?: string;\n};\n\nconst TIMEOUT_NAMES = new Set([\n \"ModelTimeoutException\",\n \"TimeoutError\",\n \"RequestTimeout\",\n \"RequestTimeoutException\",\n]);\n\n/**\n * Wrap any thrown value caught inside the Bedrock adapter into the\n * appropriate `@warlock.js/ai` `AIError` subclass.\n *\n * **Dispatch strategy.** AWS errors carry no provider machine `code`;\n * the stable identifier is the Smithy exception `name`. Dispatch keys\n * on `name`, falls back to `$metadata.httpStatusCode` when the name is\n * missing (flattened/proxied errors). `ValidationException` is split:\n * the \"input is too long / exceeds context window\" phrasing maps to\n * `ContextLengthExceededError`, everything else to\n * `InvalidRequestError`.\n *\n * `AIError` instances pass through unchanged so `catch/throw wrap(e)`\n * pipelines never double-wrap.\n *\n * @example\n * try {\n * return await this.client.send(new ConverseCommand(...));\n * } catch (thrown) {\n * throw wrapBedrockError(thrown);\n * }\n */\nexport function wrapBedrockError(thrown: unknown): AIError {\n if (thrown instanceof AIError) {\n return thrown;\n }\n\n const shape = toShape(thrown);\n const context = buildContext(shape);\n const message = shape.message ?? (thrown instanceof Error ? thrown.message : String(thrown));\n\n if (isTimeout(shape)) {\n return new ProviderTimeoutError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"AccessDeniedException\" || shape.httpStatusCode === 403) {\n return new ProviderAuthError(message, { cause: thrown, context });\n }\n\n if (shape.httpStatusCode === 401) {\n return new ProviderAuthError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"ServiceQuotaExceededException\") {\n return new QuotaExceededError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"ThrottlingException\" || shape.httpStatusCode === 429) {\n return new ProviderRateLimitError(message, { cause: thrown, context });\n }\n\n if (shape.name === \"ValidationException\") {\n if (/too long|context window|maximum context|exceeds the maximum/i.test(message)) {\n return new ContextLengthExceededError(message, { cause: thrown, context });\n }\n\n return new InvalidRequestError(message, { cause: thrown, context });\n }\n\n if (\n shape.name === \"ResourceNotFoundException\" ||\n shape.name === \"ConflictException\" ||\n isClientStatus(shape.httpStatusCode)\n ) {\n return new InvalidRequestError(message, { cause: thrown, context });\n }\n\n return new ProviderError(message, { cause: thrown, context });\n}\n\n/**\n * Read the raw error shape without depending on `instanceof`. AWS\n * exceptions expose `$metadata`; plain/proxied errors may carry\n * `status` / `code` instead.\n */\nfunction toShape(thrown: unknown): BedrockErrorShape {\n if (typeof thrown !== \"object\" || thrown === null) {\n return {};\n }\n\n const raw = thrown as Record<string, unknown>;\n const metadata = raw.$metadata as { httpStatusCode?: number; requestId?: string } | undefined;\n\n return {\n name: typeof raw.name === \"string\" ? raw.name : undefined,\n message: typeof raw.message === \"string\" ? raw.message : undefined,\n httpStatusCode:\n metadata && typeof metadata.httpStatusCode === \"number\"\n ? metadata.httpStatusCode\n : typeof raw.status === \"number\"\n ? (raw.status as number)\n : undefined,\n requestId: metadata && typeof metadata.requestId === \"string\" ? metadata.requestId : undefined,\n code: typeof raw.code === \"string\" ? raw.code : undefined,\n };\n}\n\n/**\n * Decide whether the error is a timeout. Bedrock surfaces\n * `ModelTimeoutException`; the AWS transport layer surfaces\n * `TimeoutError` / `ETIMEDOUT` / `ECONNABORTED`.\n */\nfunction isTimeout(shape: BedrockErrorShape): boolean {\n if (shape.name && TIMEOUT_NAMES.has(shape.name)) {\n return true;\n }\n\n return shape.code === \"ETIMEDOUT\" || shape.code === \"ECONNABORTED\";\n}\n\n/** True for HTTP 4xx — a client-side request problem, not a server fault. */\nfunction isClientStatus(status: number | undefined): boolean {\n return typeof status === \"number\" && status >= 400 && status < 500;\n}\n\n/**\n * Attach the raw diagnostic fields to `error.context`. The Smithy\n * exception `name` is the closest thing Bedrock has to a stable error\n * code, so it lands on `context.code`.\n */\nfunction buildContext(shape: BedrockErrorShape): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n\n if (shape.httpStatusCode !== undefined) {\n context.status = shape.httpStatusCode;\n }\n\n if (shape.name) {\n context.code = shape.name;\n }\n\n if (shape.requestId) {\n context.requestId = shape.requestId;\n }\n\n return context;\n}\n","import {\n type EmbeddingBatchResult,\n type EmbeddingResult,\n type EmbeddingUsage,\n type EmbedderContract,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport { InvokeModelCommand, type BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockEmbedderConfig } from \"./config.type\";\nimport { wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/** Shape of the Amazon Titan Text Embeddings response body. */\ntype TitanEmbeddingResponse = {\n embedding: number[];\n inputTextTokenCount: number;\n};\n\n/**\n * Bedrock-backed implementation of `EmbedderContract`, targeting the\n * Amazon Titan Text Embeddings family\n * (`amazon.titan-embed-text-v2:0` / v1) via `InvokeModel`.\n *\n * **Role.** Converts text into floating-point vectors. Standalone\n * primitive — unrelated to Converse / tools / the agent loop.\n *\n * **Single-input only upstream.** Titan's `InvokeModel` body accepts\n * one `inputText` per call — there is no batch endpoint. `embedMany`\n * therefore issues one request per input sequentially and aggregates\n * token usage. This is a deliberate, documented trade-off: a real\n * batch API does not exist for Titan on Bedrock, so the alternative\n * (failing `embedMany`) would be worse. Cohere embeddings on Bedrock\n * *do* batch but use an incompatible body shape — out of scope; use\n * the OpenAI adapter or a future Cohere adapter when batch throughput\n * matters.\n *\n * **Dimensions.** When no `dimensions` override is given,\n * `this.dimensions` starts at `0` and is populated from the first\n * response's vector length, then cached. Passing `dimensions` forwards\n * Titan v2's truncation hint (256 / 512 / 1024) and sets the initial\n * value immediately.\n *\n * @example\n * const embedder = new BedrockEmbedder(client, { name: \"amazon.titan-embed-text-v2:0\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n * const { vectors } = await embedder.embedMany([\"doc 1\", \"doc 2\"]);\n */\nexport class BedrockEmbedder implements EmbedderContract {\n public readonly name: string;\n public readonly provider: string;\n public dimensions: number;\n\n private readonly client: BedrockRuntimeClient;\n private readonly configuredDimensions: number | undefined;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockEmbedderConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.name = config.name;\n this.provider = provider;\n this.configuredDimensions = config.dimensions;\n this.dimensions = config.dimensions ?? 0;\n }\n\n public async embed(input: string): Promise<EmbeddingResult> {\n const { vector, tokens } = await this.invoke(input);\n\n return {\n vector,\n dimensions: this.dimensions,\n usage: { promptTokens: tokens, totalTokens: tokens },\n };\n }\n\n public async embedMany(inputs: string[]): Promise<EmbeddingBatchResult> {\n const vectors: number[][] = [];\n let tokens = 0;\n\n for (const input of inputs) {\n const result = await this.invoke(input);\n\n vectors.push(result.vector);\n tokens += result.tokens;\n }\n\n const usage: EmbeddingUsage = { promptTokens: tokens, totalTokens: tokens };\n\n return { vectors, dimensions: this.dimensions, usage };\n }\n\n /**\n * Issue a single Titan `InvokeModel` embedding request: encode the\n * JSON body, send, wrap provider errors, decode the response, and\n * cache `dimensions` on the first successful call.\n */\n private async invoke(input: string): Promise<{ vector: number[]; tokens: number }> {\n this.logger.debug(LOG_MODULE, \"embedder.request\", \"InvokeModel embeddings\", {\n model: this.name,\n });\n\n const body = JSON.stringify({\n inputText: input,\n ...(this.configuredDimensions !== undefined\n ? { dimensions: this.configuredDimensions }\n : {}),\n });\n\n let raw;\n\n try {\n raw = await this.client.send(\n new InvokeModelCommand({\n modelId: this.name,\n contentType: \"application/json\",\n accept: \"application/json\",\n body: new TextEncoder().encode(body),\n }),\n );\n } catch (thrown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"embedder.error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n throw wrapped;\n }\n\n const decoded = JSON.parse(new TextDecoder().decode(raw.body)) as TitanEmbeddingResponse;\n\n if (this.dimensions === 0) {\n this.dimensions = decoded.embedding.length;\n }\n\n this.logger.debug(LOG_MODULE, \"embedder.response\", \"InvokeModel embeddings returned\", {\n dimensions: decoded.embedding.length,\n tokens: decoded.inputTextTokenCount,\n });\n\n return { vector: decoded.embedding, tokens: decoded.inputTextTokenCount };\n }\n}\n","/**\n * Cost-truth capability inference for Bedrock Converse model ids.\n *\n * Bedrock model ids are provider-prefixed and version-suffixed\n * (`anthropic.claude-3-7-sonnet-20250219-v1:0`, `us.amazon.nova-pro-v1:0`),\n * so — exactly like `known-vision-models.ts` — a lowercase substring scan\n * is the only robust check across cross-region inference-profile prefixes\n * (`us.`, `eu.`, `apac.`) and date/version tags.\n *\n * Each predicate answers a single `ModelCapabilities` flag the agent reads\n * to decide whether to forward a cost-truth option (`reasoning`,\n * `cacheControl`) or up-front-reject an attachment (`pdf`). Unknown ids\n * default to `false` so an unsupported request fails fast with a clear\n * capability error instead of an opaque Bedrock `ValidationException`.\n * Every inference is overridable per-model via `bedrock.model({ name, … })`.\n */\n\n/**\n * Families that expose Anthropic-style extended thinking on Bedrock\n * Converse via `additionalModelRequestFields.thinking`. Only Claude 3.7\n * and the Claude 4 line (Sonnet / Opus / Haiku) support a configurable\n * thinking budget; earlier Claude, Nova, Llama, Mistral and Cohere do\n * not, so they are intentionally absent.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\n \"claude-3-7\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n];\n\n/**\n * Families that honor Converse `cachePoint` prompt-cache breakpoints.\n * Anthropic Claude 3.5+ / 3.7 / 4 and the Amazon Nova line support\n * cache points; text-only legacy families do not.\n */\nconst PROMPT_CACHING_CAPABLE_SUBSTRINGS = [\n \"claude-3-5\",\n \"claude-3-7\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n \"nova-lite\",\n \"nova-pro\",\n \"nova-premier\",\n \"nova-micro\",\n];\n\n/**\n * Families that accept Converse `document` content blocks (PDF / docx /\n * txt input). The multimodal Claude 3+ and Nova families support\n * document blocks; the substring set mirrors the vision-capable list\n * minus the image-only Llama entries (Llama on Bedrock takes images but\n * not document blocks via Converse).\n */\nconst PDF_CAPABLE_SUBSTRINGS = [\n \"claude-3\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n \"nova-lite\",\n \"nova-pro\",\n \"nova-premier\",\n];\n\nfunction matchesAny(modelId: string, fragments: string[]): boolean {\n const normalized = modelId.toLowerCase();\n\n return fragments.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Infer whether a Bedrock model id exposes extended-thinking / reasoning\n * (Claude 3.7 + Claude 4). When true the adapter forwards\n * `ModelCallOptions.reasoning` as Converse\n * `additionalModelRequestFields.thinking`.\n *\n * @example\n * inferReasoningCapability(\"anthropic.claude-3-7-sonnet-20250219-v1:0\"); // → true\n * inferReasoningCapability(\"us.amazon.nova-pro-v1:0\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n return matchesAny(modelId, REASONING_CAPABLE_SUBSTRINGS);\n}\n\n/**\n * Infer whether a Bedrock model id honors Converse `cachePoint`\n * breakpoints (Claude 3.5+ / Nova). When true the adapter both maps\n * `ModelCallOptions.cacheControl` write breakpoints to cache points and\n * reports `Usage.cachedTokens` / `Usage.cacheWriteTokens`.\n *\n * @example\n * inferPromptCachingCapability(\"us.amazon.nova-pro-v1:0\"); // → true\n * inferPromptCachingCapability(\"meta.llama3-1-8b-instruct-v1:0\"); // → false\n */\nexport function inferPromptCachingCapability(modelId: string): boolean {\n return matchesAny(modelId, PROMPT_CACHING_CAPABLE_SUBSTRINGS);\n}\n\n/**\n * Infer whether a Bedrock model id accepts Converse `document` content\n * blocks (PDF / document input — Claude 3+ / Nova). When false the agent\n * rejects a PDF attachment up front instead of dropping it at the wire.\n *\n * @example\n * inferPdfCapability(\"anthropic.claude-3-5-sonnet-20240620-v1:0\"); // → true\n * inferPdfCapability(\"meta.llama3-2-90b-instruct-v1:0\"); // → false\n */\nexport function inferPdfCapability(modelId: string): boolean {\n return matchesAny(modelId, PDF_CAPABLE_SUBSTRINGS);\n}\n","/**\n * Substrings that identify Bedrock model ids whose family accepts image\n * input on the Converse API.\n *\n * Bedrock model ids are provider-prefixed and version-suffixed\n * (`anthropic.claude-3-5-sonnet-20240620-v1:0`, `us.amazon.nova-pro-v1:0`,\n * `meta.llama3-2-90b-instruct-v1:0`), so a substring match is the only\n * robust check across the cross-region inference-profile prefixes\n * (`us.`, `eu.`, `apac.`) and date/version tags.\n *\n * Multimodal families covered: Anthropic Claude 3 / 3.5 / 3.7 / 4,\n * Amazon Nova Lite/Pro/Premier, Meta Llama 3.2 (11B/90B) and Llama 4.\n * Text-only families (Llama 3/3.1, Titan Text, Mistral 7B, Cohere\n * Command) are intentionally absent. Override per-model via\n * `bedrock.model({ name, vision: true | false })`.\n */\nconst VISION_CAPABLE_SUBSTRINGS = [\n \"claude-3\",\n \"claude-sonnet-4\",\n \"claude-opus-4\",\n \"claude-haiku-4\",\n \"nova-lite\",\n \"nova-pro\",\n \"nova-premier\",\n \"llama3-2-11b\",\n \"llama3-2-90b\",\n \"llama4\",\n];\n\n/**\n * Infer whether a Bedrock model id supports vision based on the known\n * multimodal-family substrings. Unknown ids default to `false` so that\n * passing an image attachment to an unsupported model surfaces a clear,\n * agent-side capability error instead of an opaque Bedrock validation\n * fault.\n *\n * @example\n * inferVisionCapability(\"anthropic.claude-3-5-sonnet-20240620-v1:0\"); // → true\n * inferVisionCapability(\"us.amazon.nova-pro-v1:0\"); // → true\n * inferVisionCapability(\"meta.llama3-1-8b-instruct-v1:0\"); // → false\n * inferVisionCapability(\"amazon.titan-text-express-v1\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n","import {\n safeJsonParse,\n type Message,\n type ModelCallOptions,\n type ModelCapabilities,\n type ModelContract,\n type ModelPricing,\n type ModelResponse,\n type ModelStreamChunk,\n type ModelToolCallRequest,\n type Usage,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport {\n ConverseCommand,\n ConverseStreamCommand,\n type BedrockRuntimeClient,\n type ContentBlock,\n type ConverseRequest,\n type TokenUsage,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockModelConfig } from \"./config.type\";\nimport {\n inferPdfCapability,\n inferPromptCachingCapability,\n inferReasoningCapability,\n} from \"./known-capabilities\";\nimport { inferVisionCapability } from \"./known-vision-models\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/**\n * Conventional extended-thinking token budgets for the neutral\n * `reasoning.effort` levels, used when the caller asks for an effort\n * tier without naming an explicit `reasoning.maxTokens` budget. Mirrors\n * the low / medium / high spread other reasoning adapters expose so the\n * vendor-neutral option behaves consistently across providers.\n */\nconst EFFORT_THINKING_BUDGET: Record<string, number | undefined> = {\n low: 1024,\n medium: 4096,\n high: 16384,\n};\n\n/**\n * Bedrock-backed implementation of `ModelContract`.\n *\n * **Role.** The provider-facing bridge between the vendor-neutral\n * `@warlock.js/ai` agent runtime and AWS Bedrock's Converse /\n * ConverseStream API. Converse is the model-agnostic surface — one\n * wire mapping covers every Bedrock-hosted family (Anthropic Claude,\n * Amazon Nova, Meta Llama, Mistral, Cohere) instead of per-family\n * `InvokeModel` body shapes.\n *\n * **Responsibility.**\n * - Owns: a long-lived `BedrockRuntimeClient` + frozen `ModelConfig`\n * (modelId, temperature, maxTokens) used as per-call defaults.\n * - Owns: translating vendor-neutral `Message[]` / `ToolConfig[]` into\n * Converse shapes (system hoisting, `toolUse` / `toolResult` blocks,\n * image bytes) on the way out, and Converse's content-block response\n * (text, tool calls, stop reason, token usage) back into the neutral\n * shapes on the way in.\n * - Does NOT own: dispatching tools, looping, history, retries — those\n * are agent concerns. The model is a per-call protocol adapter.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across calls\"): the AWS client is heavy to construct and reused for\n * the SDK's lifetime.\n *\n * @example\n * import { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\n * const client = new BedrockRuntimeClient({ region: \"us-east-1\" });\n * const model = new BedrockModel(client, {\n * name: \"anthropic.claude-sonnet-4-5-20250929-v1:0\",\n * });\n *\n * const myAgent = agent({ model, tools: [searchTool] });\n * const result = await myAgent.execute(\"Summarize today's news.\");\n */\nexport class BedrockModel implements ModelContract {\n public readonly name: string;\n public readonly provider: string;\n public readonly capabilities: ModelCapabilities;\n public readonly pricing?: ModelPricing;\n\n private readonly client: BedrockRuntimeClient;\n private readonly config: BedrockModelConfig;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockModelConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.config = config;\n this.name = config.name;\n this.provider = provider;\n this.pricing = config.pricing;\n this.capabilities = {\n structuredOutput: config.structuredOutput ?? true,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n promptCaching: config.promptCaching ?? inferPromptCachingCapability(config.name),\n pdf: config.pdf ?? inferPdfCapability(config.name),\n audio: config.audio ?? false,\n };\n }\n\n /**\n * Single-shot completion via the Converse API. Sends the full\n * message list, waits for the terminal response, and reshapes it\n * into a vendor-neutral `ModelResponse`. Per-call `options` override\n * the instance defaults for this call only.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting Converse call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: false,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const blocks = response.output?.message?.content ?? [];\n const finishReason = mapStopReason(response.stopReason);\n const usage = this.extractUsage(response.usage);\n const toolCalls = this.extractToolCalls(blocks);\n\n this.logger.debug(LOG_MODULE, \"response\", \"Converse call succeeded\", { finishReason, usage });\n\n return {\n content: this.extractText(blocks),\n finishReason,\n usage,\n toolCalls,\n };\n }\n\n /**\n * Incremental streaming completion via ConverseStream. Yields neutral\n * `ModelStreamChunk`s — `delta` for text, `tool-call` once a\n * `toolUse` block's accumulated input JSON is complete, and a\n * terminal `done` with the final finish reason + usage totals.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting ConverseStream call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: true,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseStreamCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n let rawStopReason: string | undefined;\n const usage: Usage = { input: 0, output: 0, total: 0 };\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n try {\n for await (const event of response.stream ?? []) {\n if (event.contentBlockStart?.start?.toolUse) {\n const start = event.contentBlockStart.start.toolUse;\n\n toolBlocks.set(event.contentBlockStart.contentBlockIndex ?? 0, {\n id: start.toolUseId ?? \"\",\n name: start.name ?? \"\",\n json: \"\",\n });\n\n continue;\n }\n\n if (event.contentBlockDelta?.delta) {\n const delta = event.contentBlockDelta.delta;\n\n if (delta.text) {\n yield { type: \"delta\", content: delta.text };\n } else if (delta.toolUse) {\n const accumulator = toolBlocks.get(event.contentBlockDelta.contentBlockIndex ?? 0);\n\n if (accumulator) {\n accumulator.json += delta.toolUse.input ?? \"\";\n }\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const accumulator = toolBlocks.get(event.contentBlockStop.contentBlockIndex ?? 0);\n\n if (accumulator) {\n yield {\n type: \"tool-call\",\n id: accumulator.id,\n name: accumulator.name,\n input: safeJsonParse<Record<string, unknown>>(accumulator.json, {}),\n };\n\n toolBlocks.delete(event.contentBlockStop.contentBlockIndex ?? 0);\n }\n\n continue;\n }\n\n if (event.messageStop) {\n rawStopReason = event.messageStop.stopReason;\n }\n\n if (event.metadata?.usage) {\n const raw = event.metadata.usage;\n\n usage.input = raw.inputTokens ?? 0;\n usage.output = raw.outputTokens ?? 0;\n usage.total = raw.totalTokens ?? usage.input + usage.output;\n\n if (raw.cacheReadInputTokens && raw.cacheReadInputTokens > 0) {\n usage.cachedTokens = raw.cacheReadInputTokens;\n }\n\n if (raw.cacheWriteInputTokens && raw.cacheWriteInputTokens > 0) {\n usage.cacheWriteTokens = raw.cacheWriteInputTokens;\n }\n }\n }\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const finishReason = mapStopReason(rawStopReason);\n\n this.logger.debug(LOG_MODULE, \"response\", \"ConverseStream call succeeded\", {\n finishReason,\n usage,\n });\n\n yield { type: \"done\", finishReason, usage };\n }\n\n /**\n * Assemble the Converse request shared by `complete()` and\n * `stream()` (both command shapes take the same input). Hoists the\n * system prompt, maps inference params, and conditionally attaches\n * tools and native structured output.\n */\n private buildRequest(\n messages: Message[],\n options: ModelCallOptions | undefined,\n ): ConverseRequest {\n const { system, messages: bedrockMessages } = toBedrockMessages(messages);\n const maxTokens = options?.maxTokens ?? this.config.maxTokens;\n const temperature = options?.temperature ?? this.config.temperature;\n const cachedMessages = this.applyCacheBreakpoints(bedrockMessages, options?.cacheControl);\n\n return {\n modelId: this.name,\n messages: cachedMessages,\n ...(system ? { system } : {}),\n inferenceConfig: {\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n },\n ...this.buildToolConfig(options?.tools),\n ...this.buildOutputConfig(options?.responseSchema),\n ...this.buildReasoningConfig(options?.reasoning),\n };\n }\n\n /**\n * Append a Converse `cachePoint` block to the LAST message when the\n * caller supplies a `cacheControl` write breakpoint and the model is\n * `promptCaching`-capable. A cache point tells Bedrock to cache the\n * whole prefix up to that block, so subsequent calls reusing the same\n * prefix bill the cached portion at the discounted read rate\n * (surfaced as `Usage.cachedTokens`). No-ops gracefully when caching\n * is unsupported, no breakpoint was requested, or there are no\n * messages to mark — Bedrock then prices the call normally.\n *\n * Bedrock only honors `CachePointType.DEFAULT`; the neutral\n * `breakpoints` count is a presence hint (one trailing breakpoint is\n * the only placement Converse supports without manual block surgery),\n * so any positive value marks the trailing message.\n */\n private applyCacheBreakpoints(\n messages: ConverseRequest[\"messages\"],\n cacheControl: ModelCallOptions[\"cacheControl\"],\n ): ConverseRequest[\"messages\"] {\n const breakpoints = cacheControl?.breakpoints ?? 0;\n\n if (!this.capabilities.promptCaching || breakpoints <= 0 || !messages || messages.length === 0) {\n return messages;\n }\n\n const last = messages.length - 1;\n const lastMessage = messages[last];\n\n return [\n ...messages.slice(0, last),\n {\n ...lastMessage,\n content: [...(lastMessage.content ?? []), { cachePoint: { type: \"default\" } }],\n },\n ];\n }\n\n /**\n * Translate the neutral `reasoning` option into Claude-on-Bedrock's\n * extended-thinking control, carried in Converse's escape hatch\n * `additionalModelRequestFields.thinking`. Emitted only when the model\n * is `reasoning`-capable and a budget can be resolved — `maxTokens`\n * (explicit thinking budget) wins, otherwise `effort` maps to a\n * conventional token budget so callers can opt in without picking a\n * number. Returns an empty object (no-op) for non-reasoning models or\n * when no reasoning option was supplied, so unsupported params never\n * reach the wire.\n */\n private buildReasoningConfig(\n reasoning: ModelCallOptions[\"reasoning\"],\n ): Pick<ConverseRequest, \"additionalModelRequestFields\"> {\n if (!this.capabilities.reasoning || !reasoning) {\n return {};\n }\n\n const budgetTokens = reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[reasoning.effort ?? \"\"];\n\n if (budgetTokens === undefined) {\n return {};\n }\n\n return {\n additionalModelRequestFields: {\n thinking: { type: \"enabled\", budget_tokens: budgetTokens },\n },\n };\n }\n\n /**\n * Spread-friendly tool fragment. Returns an empty object when no\n * tools were supplied (Bedrock rejects an empty `tools` array).\n */\n private buildToolConfig(tools: ModelCallOptions[\"tools\"]): Pick<ConverseRequest, \"toolConfig\"> {\n const toolConfig = toBedrockToolConfig(tools);\n\n return toolConfig ? { toolConfig } : {};\n }\n\n /**\n * Translate the neutral `responseSchema` into Converse's native\n * `outputConfig.textFormat` (JSON-schema structured output). Bedrock\n * requires the schema as a stringified JSON document and only\n * accepts an object root. Emitted only when the model is\n * `structuredOutput`-capable and the schema is an object — otherwise\n * the agent's soft system-prompt hint + client-side `validate()`\n * carry shape (same degradation philosophy as the OpenAI adapter).\n */\n private buildOutputConfig(\n responseSchema: Record<string, unknown> | undefined,\n ): Pick<ConverseRequest, \"outputConfig\"> {\n if (!responseSchema || !this.capabilities.structuredOutput) {\n return {};\n }\n\n if (responseSchema.type !== \"object\" || typeof responseSchema.properties !== \"object\") {\n return {};\n }\n\n return {\n outputConfig: {\n textFormat: {\n type: \"json_schema\",\n structure: {\n jsonSchema: { name: \"response\", schema: JSON.stringify(responseSchema) },\n },\n },\n },\n };\n }\n\n /**\n * Concatenate every `text` content block into the single neutral\n * `content` string. `toolUse` and other block types are surfaced\n * separately via `extractToolCalls`.\n */\n private extractText(blocks: ContentBlock[]): string {\n return blocks\n .map((block) => (\"text\" in block && typeof block.text === \"string\" ? block.text : \"\"))\n .join(\"\");\n }\n\n /**\n * Reshape Converse `toolUse` content blocks into the neutral\n * `ModelToolCallRequest[]`. Returns `undefined` when no tools were\n * requested so callers can branch on presence.\n */\n private extractToolCalls(blocks: ContentBlock[]): ModelToolCallRequest[] | undefined {\n const toolCalls: ModelToolCallRequest[] = [];\n\n for (const block of blocks) {\n if (\"toolUse\" in block && block.toolUse) {\n toolCalls.push({\n id: block.toolUse.toolUseId ?? \"\",\n name: block.toolUse.name ?? \"\",\n input: (block.toolUse.input ?? {}) as Record<string, unknown>,\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /**\n * Normalize Converse's `TokenUsage` into the neutral `Usage` shape.\n * Bedrock supplies a pre-summed `totalTokens`; cache-read and\n * cache-write tokens are surfaced as `cachedTokens` /\n * `cacheWriteTokens` only when non-zero so callers can price the\n * discounted read rate and the one-time write cost separately.\n * Bedrock's Converse `TokenUsage` carries no reasoning-token channel,\n * so `Usage.reasoningTokens` is intentionally left unset here.\n */\n private extractUsage(raw: TokenUsage | undefined): Usage {\n if (!raw) {\n return { input: 0, output: 0, total: 0 };\n }\n\n const input = raw.inputTokens ?? 0;\n const output = raw.outputTokens ?? 0;\n const cached = raw.cacheReadInputTokens;\n const cacheWrite = raw.cacheWriteInputTokens;\n\n return {\n input,\n output,\n total: raw.totalTokens ?? input + output,\n ...(cached && cached > 0 ? { cachedTokens: cached } : {}),\n ...(cacheWrite && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n };\n }\n\n /**\n * Wrap a thrown provider error into the typed `AIError` hierarchy\n * and emit the standard error log line before it propagates. Shared\n * by every catch site so the log shape stays identical.\n */\n private logAndWrap(thrown: unknown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n return wrapped;\n }\n}\n","import { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\nimport type {\n EmbedderContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { approximateTokenCount } from \"@warlock.js/ai\";\nimport type {\n BedrockEmbedderConfig,\n BedrockModelConfig,\n BedrockSDKConfig,\n} from \"./config.type\";\nimport { BedrockEmbedder } from \"./embedder\";\nimport { BedrockModel } from \"./model\";\n\n/**\n * AWS Bedrock-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for any Bedrock-hosted model via\n * the Converse API. A single `BedrockSDK` holds one live\n * `BedrockRuntimeClient`, shared by every `ModelContract` and\n * `EmbedderContract` it produces. Construct one SDK per AWS\n * account/region and reuse it everywhere.\n *\n * **Responsibility.**\n * - Owns: a long-lived `BedrockRuntimeClient` (region, credential\n * chain) and its lifetime. Factory for `BedrockModel` /\n * `BedrockEmbedder` instances sharing that client.\n * - Does NOT own: anything per-call — those live in `BedrockModel` /\n * `BedrockEmbedder` and the agent runtime.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): the AWS client is heavy to construct and\n * designed for reuse; keeping it on `this` aligns with the\n * `new BedrockRuntimeClient(...)` upstream convention.\n *\n * @example\n * const bedrock = new BedrockSDK({ region: \"us-east-1\" });\n * const model = bedrock.model({ name: \"anthropic.claude-sonnet-4-5-20250929-v1:0\" });\n * const embedder = bedrock.embedder({ name: \"amazon.titan-embed-text-v2:0\" });\n */\nexport class BedrockSDK implements SDKAdapterContract {\n private readonly client: BedrockRuntimeClient;\n private readonly provider: string;\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: BedrockSDKConfig) {\n const { provider, pricing, ...clientConfig } = config;\n\n this.client = new BedrockRuntimeClient(clientConfig);\n this.provider = provider ?? \"bedrock\";\n this.pricing = pricing;\n }\n\n /**\n * Build a `BedrockModel` bound to this SDK's client. Each call\n * returns a fresh instance; all instances share the underlying AWS\n * client so connection pools, credential refresh, and retry config\n * stay unified. The SDK's `provider` label is forwarded.\n *\n * Pricing resolution: per-model `config.pricing` wins; otherwise the\n * SDK-level registry entry keyed by `config.name`; otherwise\n * `undefined` (no cost computed).\n */\n public model(config: BedrockModelConfig): ModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: BedrockModelConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new BedrockModel(this.client, resolvedConfig, this.provider);\n }\n\n /**\n * Rough token-count estimate. Uses the character-heuristic\n * (`approximateTokenCount`) from the core package — Bedrock has no\n * offline tokenizer and the per-model tokenizers differ; good enough\n * for budgeting and quota guards, not for billing.\n */\n public async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n }\n\n /**\n * Build a `BedrockEmbedder` (Amazon Titan Text Embeddings) bound to\n * this SDK's client.\n *\n * @example\n * const embedder = bedrock.embedder({ name: \"amazon.titan-embed-text-v2:0\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: BedrockEmbedderConfig): EmbedderContract {\n return new BedrockEmbedder(this.client, config, this.provider);\n }\n}\n"],"mappings":"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"}
|
package/esm/embedder.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedder.mjs","names":[],"sources":["../../../../../../ai-bedrock/src/embedder.ts"],"sourcesContent":["import {\n type EmbeddingBatchResult,\n type EmbeddingResult,\n type EmbeddingUsage,\n type EmbedderContract,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport { InvokeModelCommand, type BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockEmbedderConfig } from \"./config.type\";\nimport { wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/** Shape of the Amazon Titan Text Embeddings response body. */\ntype TitanEmbeddingResponse = {\n embedding: number[];\n inputTextTokenCount: number;\n};\n\n/**\n * Bedrock-backed implementation of `EmbedderContract`, targeting the\n * Amazon Titan Text Embeddings family\n * (`amazon.titan-embed-text-v2:0` / v1) via `InvokeModel`.\n *\n * **Role.** Converts text into floating-point vectors. Standalone\n * primitive — unrelated to Converse / tools / the agent loop.\n *\n * **Single-input only upstream.** Titan's `InvokeModel` body accepts\n * one `inputText` per call — there is no batch endpoint. `embedMany`\n * therefore issues one request per input sequentially and aggregates\n * token usage. This is a deliberate, documented trade-off: a real\n * batch API does not exist for Titan on Bedrock, so the alternative\n * (failing `embedMany`) would be worse. Cohere embeddings on Bedrock\n * *do* batch but use an incompatible body shape — out of scope; use\n * the OpenAI adapter or a future Cohere adapter when batch throughput\n * matters.\n *\n * **Dimensions.** When no `dimensions` override is given,\n * `this.dimensions` starts at `0` and is populated from the first\n * response's vector length, then cached. Passing `dimensions` forwards\n * Titan v2's truncation hint (256 / 512 / 1024) and sets the initial\n * value immediately.\n *\n * @example\n * const embedder = new BedrockEmbedder(client, { name: \"amazon.titan-embed-text-v2:0\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n * const { vectors } = await embedder.embedMany([\"doc 1\", \"doc 2\"]);\n */\nexport class BedrockEmbedder implements EmbedderContract {\n public readonly name: string;\n public readonly provider: string;\n public dimensions: number;\n\n private readonly client: BedrockRuntimeClient;\n private readonly configuredDimensions: number | undefined;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockEmbedderConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.name = config.name;\n this.provider = provider;\n this.configuredDimensions = config.dimensions;\n this.dimensions = config.dimensions ?? 0;\n }\n\n public async embed(input: string): Promise<EmbeddingResult> {\n const { vector, tokens } = await this.invoke(input);\n\n return {\n vector,\n dimensions: this.dimensions,\n usage: { promptTokens: tokens, totalTokens: tokens },\n };\n }\n\n public async embedMany(inputs: string[]): Promise<EmbeddingBatchResult> {\n const vectors: number[][] = [];\n let tokens = 0;\n\n for (const input of inputs) {\n const result = await this.invoke(input);\n\n vectors.push(result.vector);\n tokens += result.tokens;\n }\n\n const usage: EmbeddingUsage = { promptTokens: tokens, totalTokens: tokens };\n\n return { vectors, dimensions: this.dimensions, usage };\n }\n\n /**\n * Issue a single Titan `InvokeModel` embedding request: encode the\n * JSON body, send, wrap provider errors, decode the response, and\n * cache `dimensions` on the first successful call.\n */\n private async invoke(input: string): Promise<{ vector: number[]; tokens: number }> {\n this.logger.debug(LOG_MODULE, \"embedder.request\", \"InvokeModel embeddings\", {\n model: this.name,\n });\n\n const body = JSON.stringify({\n inputText: input,\n ...(this.configuredDimensions !== undefined\n ? { dimensions: this.configuredDimensions }\n : {}),\n });\n\n let raw;\n\n try {\n raw = await this.client.send(\n new InvokeModelCommand({\n modelId: this.name,\n contentType: \"application/json\",\n accept: \"application/json\",\n body: new TextEncoder().encode(body),\n }),\n );\n } catch (thrown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"embedder.error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n throw wrapped;\n }\n\n const decoded = JSON.parse(new TextDecoder().decode(raw.body)) as TitanEmbeddingResponse;\n\n if (this.dimensions === 0) {\n this.dimensions = decoded.embedding.length;\n }\n\n this.logger.debug(LOG_MODULE, \"embedder.response\", \"InvokeModel embeddings returned\", {\n dimensions: decoded.embedding.length,\n tokens: decoded.inputTextTokenCount,\n });\n\n return { vector: decoded.embedding, tokens: decoded.inputTextTokenCount };\n }\n}\n"],"mappings":";;;;;;AAWA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCnB,IAAa,kBAAb,MAAyD;CASvD,AAAO,YACL,QACA,QACA,WAAmB,WACnB;gBANgC;EAOhC,KAAK,SAAS;EACd,KAAK,OAAO,OAAO;EACnB,KAAK,WAAW;EAChB,KAAK,uBAAuB,OAAO;EACnC,KAAK,aAAa,OAAO,cAAc;CACzC;CAEA,MAAa,MAAM,OAAyC;EAC1D,MAAM,EAAE,QAAQ,WAAW,MAAM,KAAK,OAAO,KAAK;EAElD,OAAO;GACL;GACA,YAAY,KAAK;GACjB,OAAO;IAAE,cAAc;IAAQ,aAAa;GAAO;EACrD;CACF;CAEA,MAAa,UAAU,QAAiD;EACtE,MAAM,UAAsB,CAAC;EAC7B,IAAI,SAAS;EAEb,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK;GAEtC,QAAQ,KAAK,OAAO,MAAM;GAC1B,UAAU,OAAO;EACnB;EAEA,MAAM,QAAwB;GAAE,cAAc;GAAQ,aAAa;EAAO;EAE1E,OAAO;GAAE;GAAS,YAAY,KAAK;GAAY;EAAM;CACvD;;;;;;CAOA,MAAc,OAAO,OAA8D;EACjF,KAAK,OAAO,MAAM,YAAY,oBAAoB,0BAA0B,EAC1E,OAAO,KAAK,KACd,CAAC;EAED,MAAM,OAAO,KAAK,UAAU;GAC1B,WAAW;GACX,GAAI,KAAK,yBAAyB,SAC9B,EAAE,YAAY,KAAK,qBAAqB,IACxC,CAAC;EACP,CAAC;EAED,IAAI;EAEJ,IAAI;GACF,MAAM,MAAM,KAAK,OAAO,KACtB,IAAI,mBAAmB;IACrB,SAAS,KAAK;IACd,aAAa;IACb,QAAQ;IACR,MAAM,IAAI,YAAY,
|
|
1
|
+
{"version":3,"file":"embedder.mjs","names":[],"sources":["../../../../../../ai-bedrock/src/embedder.ts"],"sourcesContent":["import {\n type EmbeddingBatchResult,\n type EmbeddingResult,\n type EmbeddingUsage,\n type EmbedderContract,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport { InvokeModelCommand, type BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockEmbedderConfig } from \"./config.type\";\nimport { wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/** Shape of the Amazon Titan Text Embeddings response body. */\ntype TitanEmbeddingResponse = {\n embedding: number[];\n inputTextTokenCount: number;\n};\n\n/**\n * Bedrock-backed implementation of `EmbedderContract`, targeting the\n * Amazon Titan Text Embeddings family\n * (`amazon.titan-embed-text-v2:0` / v1) via `InvokeModel`.\n *\n * **Role.** Converts text into floating-point vectors. Standalone\n * primitive — unrelated to Converse / tools / the agent loop.\n *\n * **Single-input only upstream.** Titan's `InvokeModel` body accepts\n * one `inputText` per call — there is no batch endpoint. `embedMany`\n * therefore issues one request per input sequentially and aggregates\n * token usage. This is a deliberate, documented trade-off: a real\n * batch API does not exist for Titan on Bedrock, so the alternative\n * (failing `embedMany`) would be worse. Cohere embeddings on Bedrock\n * *do* batch but use an incompatible body shape — out of scope; use\n * the OpenAI adapter or a future Cohere adapter when batch throughput\n * matters.\n *\n * **Dimensions.** When no `dimensions` override is given,\n * `this.dimensions` starts at `0` and is populated from the first\n * response's vector length, then cached. Passing `dimensions` forwards\n * Titan v2's truncation hint (256 / 512 / 1024) and sets the initial\n * value immediately.\n *\n * @example\n * const embedder = new BedrockEmbedder(client, { name: \"amazon.titan-embed-text-v2:0\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n * const { vectors } = await embedder.embedMany([\"doc 1\", \"doc 2\"]);\n */\nexport class BedrockEmbedder implements EmbedderContract {\n public readonly name: string;\n public readonly provider: string;\n public dimensions: number;\n\n private readonly client: BedrockRuntimeClient;\n private readonly configuredDimensions: number | undefined;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockEmbedderConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.name = config.name;\n this.provider = provider;\n this.configuredDimensions = config.dimensions;\n this.dimensions = config.dimensions ?? 0;\n }\n\n public async embed(input: string): Promise<EmbeddingResult> {\n const { vector, tokens } = await this.invoke(input);\n\n return {\n vector,\n dimensions: this.dimensions,\n usage: { promptTokens: tokens, totalTokens: tokens },\n };\n }\n\n public async embedMany(inputs: string[]): Promise<EmbeddingBatchResult> {\n const vectors: number[][] = [];\n let tokens = 0;\n\n for (const input of inputs) {\n const result = await this.invoke(input);\n\n vectors.push(result.vector);\n tokens += result.tokens;\n }\n\n const usage: EmbeddingUsage = { promptTokens: tokens, totalTokens: tokens };\n\n return { vectors, dimensions: this.dimensions, usage };\n }\n\n /**\n * Issue a single Titan `InvokeModel` embedding request: encode the\n * JSON body, send, wrap provider errors, decode the response, and\n * cache `dimensions` on the first successful call.\n */\n private async invoke(input: string): Promise<{ vector: number[]; tokens: number }> {\n this.logger.debug(LOG_MODULE, \"embedder.request\", \"InvokeModel embeddings\", {\n model: this.name,\n });\n\n const body = JSON.stringify({\n inputText: input,\n ...(this.configuredDimensions !== undefined\n ? { dimensions: this.configuredDimensions }\n : {}),\n });\n\n let raw;\n\n try {\n raw = await this.client.send(\n new InvokeModelCommand({\n modelId: this.name,\n contentType: \"application/json\",\n accept: \"application/json\",\n body: new TextEncoder().encode(body),\n }),\n );\n } catch (thrown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"embedder.error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n throw wrapped;\n }\n\n const decoded = JSON.parse(new TextDecoder().decode(raw.body)) as TitanEmbeddingResponse;\n\n if (this.dimensions === 0) {\n this.dimensions = decoded.embedding.length;\n }\n\n this.logger.debug(LOG_MODULE, \"embedder.response\", \"InvokeModel embeddings returned\", {\n dimensions: decoded.embedding.length,\n tokens: decoded.inputTextTokenCount,\n });\n\n return { vector: decoded.embedding, tokens: decoded.inputTextTokenCount };\n }\n}\n"],"mappings":";;;;;;AAWA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCnB,IAAa,kBAAb,MAAyD;CASvD,AAAO,YACL,QACA,QACA,WAAmB,WACnB;gBANgC;EAOhC,KAAK,SAAS;EACd,KAAK,OAAO,OAAO;EACnB,KAAK,WAAW;EAChB,KAAK,uBAAuB,OAAO;EACnC,KAAK,aAAa,OAAO,cAAc;CACzC;CAEA,MAAa,MAAM,OAAyC;EAC1D,MAAM,EAAE,QAAQ,WAAW,MAAM,KAAK,OAAO,KAAK;EAElD,OAAO;GACL;GACA,YAAY,KAAK;GACjB,OAAO;IAAE,cAAc;IAAQ,aAAa;GAAO;EACrD;CACF;CAEA,MAAa,UAAU,QAAiD;EACtE,MAAM,UAAsB,CAAC;EAC7B,IAAI,SAAS;EAEb,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,SAAS,MAAM,KAAK,OAAO,KAAK;GAEtC,QAAQ,KAAK,OAAO,MAAM;GAC1B,UAAU,OAAO;EACnB;EAEA,MAAM,QAAwB;GAAE,cAAc;GAAQ,aAAa;EAAO;EAE1E,OAAO;GAAE;GAAS,YAAY,KAAK;GAAY;EAAM;CACvD;;;;;;CAOA,MAAc,OAAO,OAA8D;EACjF,KAAK,OAAO,MAAM,YAAY,oBAAoB,0BAA0B,EAC1E,OAAO,KAAK,KACd,CAAC;EAED,MAAM,OAAO,KAAK,UAAU;GAC1B,WAAW;GACX,GAAI,KAAK,yBAAyB,SAC9B,EAAE,YAAY,KAAK,qBAAqB,IACxC,CAAC;EACP,CAAC;EAED,IAAI;EAEJ,IAAI;GACF,MAAM,MAAM,KAAK,OAAO,KACtB,IAAI,mBAAmB;IACrB,SAAS,KAAK;IACd,aAAa;IACb,QAAQ;IACR,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,IAAI;GACrC,CAAC,CACH;EACF,SAAS,QAAQ;GACf,MAAM,UAAU,iBAAiB,MAAM;GAEvC,KAAK,OAAO,MAAM,YAAY,kBAAkB,QAAQ,SAAS;IAC/D,MAAM,QAAQ;IACd,SAAS,QAAQ;GACnB,CAAC;GAED,MAAM;EACR;EAEA,MAAM,UAAU,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC;EAE7D,IAAI,KAAK,eAAe,GACtB,KAAK,aAAa,QAAQ,UAAU;EAGtC,KAAK,OAAO,MAAM,YAAY,qBAAqB,mCAAmC;GACpF,YAAY,QAAQ,UAAU;GAC9B,QAAQ,QAAQ;EAClB,CAAC;EAED,OAAO;GAAE,QAAQ,QAAQ;GAAW,QAAQ,QAAQ;EAAoB;CAC1E;AACF"}
|
package/esm/model.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.mjs","names":[],"sources":["../../../../../../ai-bedrock/src/model.ts"],"sourcesContent":["import {\n safeJsonParse,\n type Message,\n type ModelCallOptions,\n type ModelCapabilities,\n type ModelContract,\n type ModelPricing,\n type ModelResponse,\n type ModelStreamChunk,\n type ModelToolCallRequest,\n type Usage,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport {\n ConverseCommand,\n ConverseStreamCommand,\n type BedrockRuntimeClient,\n type ContentBlock,\n type ConverseRequest,\n type TokenUsage,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockModelConfig } from \"./config.type\";\nimport {\n inferPdfCapability,\n inferPromptCachingCapability,\n inferReasoningCapability,\n} from \"./known-capabilities\";\nimport { inferVisionCapability } from \"./known-vision-models\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/**\n * Conventional extended-thinking token budgets for the neutral\n * `reasoning.effort` levels, used when the caller asks for an effort\n * tier without naming an explicit `reasoning.maxTokens` budget. Mirrors\n * the low / medium / high spread other reasoning adapters expose so the\n * vendor-neutral option behaves consistently across providers.\n */\nconst EFFORT_THINKING_BUDGET: Record<string, number | undefined> = {\n low: 1024,\n medium: 4096,\n high: 16384,\n};\n\n/**\n * Bedrock-backed implementation of `ModelContract`.\n *\n * **Role.** The provider-facing bridge between the vendor-neutral\n * `@warlock.js/ai` agent runtime and AWS Bedrock's Converse /\n * ConverseStream API. Converse is the model-agnostic surface — one\n * wire mapping covers every Bedrock-hosted family (Anthropic Claude,\n * Amazon Nova, Meta Llama, Mistral, Cohere) instead of per-family\n * `InvokeModel` body shapes.\n *\n * **Responsibility.**\n * - Owns: a long-lived `BedrockRuntimeClient` + frozen `ModelConfig`\n * (modelId, temperature, maxTokens) used as per-call defaults.\n * - Owns: translating vendor-neutral `Message[]` / `ToolConfig[]` into\n * Converse shapes (system hoisting, `toolUse` / `toolResult` blocks,\n * image bytes) on the way out, and Converse's content-block response\n * (text, tool calls, stop reason, token usage) back into the neutral\n * shapes on the way in.\n * - Does NOT own: dispatching tools, looping, history, retries — those\n * are agent concerns. The model is a per-call protocol adapter.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across calls\"): the AWS client is heavy to construct and reused for\n * the SDK's lifetime.\n *\n * @example\n * import { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\n * const client = new BedrockRuntimeClient({ region: \"us-east-1\" });\n * const model = new BedrockModel(client, {\n * name: \"anthropic.claude-sonnet-4-5-20250929-v1:0\",\n * });\n *\n * const myAgent = agent({ model, tools: [searchTool] });\n * const result = await myAgent.execute(\"Summarize today's news.\");\n */\nexport class BedrockModel implements ModelContract {\n public readonly name: string;\n public readonly provider: string;\n public readonly capabilities: ModelCapabilities;\n public readonly pricing?: ModelPricing;\n\n private readonly client: BedrockRuntimeClient;\n private readonly config: BedrockModelConfig;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockModelConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.config = config;\n this.name = config.name;\n this.provider = provider;\n this.pricing = config.pricing;\n this.capabilities = {\n structuredOutput: config.structuredOutput ?? true,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n promptCaching: config.promptCaching ?? inferPromptCachingCapability(config.name),\n pdf: config.pdf ?? inferPdfCapability(config.name),\n audio: config.audio ?? false,\n };\n }\n\n /**\n * Single-shot completion via the Converse API. Sends the full\n * message list, waits for the terminal response, and reshapes it\n * into a vendor-neutral `ModelResponse`. Per-call `options` override\n * the instance defaults for this call only.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting Converse call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: false,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const blocks = response.output?.message?.content ?? [];\n const finishReason = mapStopReason(response.stopReason);\n const usage = this.extractUsage(response.usage);\n const toolCalls = this.extractToolCalls(blocks);\n\n this.logger.debug(LOG_MODULE, \"response\", \"Converse call succeeded\", { finishReason, usage });\n\n return {\n content: this.extractText(blocks),\n finishReason,\n usage,\n toolCalls,\n };\n }\n\n /**\n * Incremental streaming completion via ConverseStream. Yields neutral\n * `ModelStreamChunk`s — `delta` for text, `tool-call` once a\n * `toolUse` block's accumulated input JSON is complete, and a\n * terminal `done` with the final finish reason + usage totals.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting ConverseStream call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: true,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseStreamCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n let rawStopReason: string | undefined;\n const usage: Usage = { input: 0, output: 0, total: 0 };\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n try {\n for await (const event of response.stream ?? []) {\n if (event.contentBlockStart?.start?.toolUse) {\n const start = event.contentBlockStart.start.toolUse;\n\n toolBlocks.set(event.contentBlockStart.contentBlockIndex ?? 0, {\n id: start.toolUseId ?? \"\",\n name: start.name ?? \"\",\n json: \"\",\n });\n\n continue;\n }\n\n if (event.contentBlockDelta?.delta) {\n const delta = event.contentBlockDelta.delta;\n\n if (delta.text) {\n yield { type: \"delta\", content: delta.text };\n } else if (delta.toolUse) {\n const accumulator = toolBlocks.get(event.contentBlockDelta.contentBlockIndex ?? 0);\n\n if (accumulator) {\n accumulator.json += delta.toolUse.input ?? \"\";\n }\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const accumulator = toolBlocks.get(event.contentBlockStop.contentBlockIndex ?? 0);\n\n if (accumulator) {\n yield {\n type: \"tool-call\",\n id: accumulator.id,\n name: accumulator.name,\n input: safeJsonParse<Record<string, unknown>>(accumulator.json, {}),\n };\n\n toolBlocks.delete(event.contentBlockStop.contentBlockIndex ?? 0);\n }\n\n continue;\n }\n\n if (event.messageStop) {\n rawStopReason = event.messageStop.stopReason;\n }\n\n if (event.metadata?.usage) {\n const raw = event.metadata.usage;\n\n usage.input = raw.inputTokens ?? 0;\n usage.output = raw.outputTokens ?? 0;\n usage.total = raw.totalTokens ?? usage.input + usage.output;\n\n if (raw.cacheReadInputTokens && raw.cacheReadInputTokens > 0) {\n usage.cachedTokens = raw.cacheReadInputTokens;\n }\n\n if (raw.cacheWriteInputTokens && raw.cacheWriteInputTokens > 0) {\n usage.cacheWriteTokens = raw.cacheWriteInputTokens;\n }\n }\n }\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const finishReason = mapStopReason(rawStopReason);\n\n this.logger.debug(LOG_MODULE, \"response\", \"ConverseStream call succeeded\", {\n finishReason,\n usage,\n });\n\n yield { type: \"done\", finishReason, usage };\n }\n\n /**\n * Assemble the Converse request shared by `complete()` and\n * `stream()` (both command shapes take the same input). Hoists the\n * system prompt, maps inference params, and conditionally attaches\n * tools and native structured output.\n */\n private buildRequest(\n messages: Message[],\n options: ModelCallOptions | undefined,\n ): ConverseRequest {\n const { system, messages: bedrockMessages } = toBedrockMessages(messages);\n const maxTokens = options?.maxTokens ?? this.config.maxTokens;\n const temperature = options?.temperature ?? this.config.temperature;\n const cachedMessages = this.applyCacheBreakpoints(bedrockMessages, options?.cacheControl);\n\n return {\n modelId: this.name,\n messages: cachedMessages,\n ...(system ? { system } : {}),\n inferenceConfig: {\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n },\n ...this.buildToolConfig(options?.tools),\n ...this.buildOutputConfig(options?.responseSchema),\n ...this.buildReasoningConfig(options?.reasoning),\n };\n }\n\n /**\n * Append a Converse `cachePoint` block to the LAST message when the\n * caller supplies a `cacheControl` write breakpoint and the model is\n * `promptCaching`-capable. A cache point tells Bedrock to cache the\n * whole prefix up to that block, so subsequent calls reusing the same\n * prefix bill the cached portion at the discounted read rate\n * (surfaced as `Usage.cachedTokens`). No-ops gracefully when caching\n * is unsupported, no breakpoint was requested, or there are no\n * messages to mark — Bedrock then prices the call normally.\n *\n * Bedrock only honors `CachePointType.DEFAULT`; the neutral\n * `breakpoints` count is a presence hint (one trailing breakpoint is\n * the only placement Converse supports without manual block surgery),\n * so any positive value marks the trailing message.\n */\n private applyCacheBreakpoints(\n messages: ConverseRequest[\"messages\"],\n cacheControl: ModelCallOptions[\"cacheControl\"],\n ): ConverseRequest[\"messages\"] {\n const breakpoints = cacheControl?.breakpoints ?? 0;\n\n if (!this.capabilities.promptCaching || breakpoints <= 0 || !messages || messages.length === 0) {\n return messages;\n }\n\n const last = messages.length - 1;\n const lastMessage = messages[last];\n\n return [\n ...messages.slice(0, last),\n {\n ...lastMessage,\n content: [...(lastMessage.content ?? []), { cachePoint: { type: \"default\" } }],\n },\n ];\n }\n\n /**\n * Translate the neutral `reasoning` option into Claude-on-Bedrock's\n * extended-thinking control, carried in Converse's escape hatch\n * `additionalModelRequestFields.thinking`. Emitted only when the model\n * is `reasoning`-capable and a budget can be resolved — `maxTokens`\n * (explicit thinking budget) wins, otherwise `effort` maps to a\n * conventional token budget so callers can opt in without picking a\n * number. Returns an empty object (no-op) for non-reasoning models or\n * when no reasoning option was supplied, so unsupported params never\n * reach the wire.\n */\n private buildReasoningConfig(\n reasoning: ModelCallOptions[\"reasoning\"],\n ): Pick<ConverseRequest, \"additionalModelRequestFields\"> {\n if (!this.capabilities.reasoning || !reasoning) {\n return {};\n }\n\n const budgetTokens = reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[reasoning.effort ?? \"\"];\n\n if (budgetTokens === undefined) {\n return {};\n }\n\n return {\n additionalModelRequestFields: {\n thinking: { type: \"enabled\", budget_tokens: budgetTokens },\n },\n };\n }\n\n /**\n * Spread-friendly tool fragment. Returns an empty object when no\n * tools were supplied (Bedrock rejects an empty `tools` array).\n */\n private buildToolConfig(tools: ModelCallOptions[\"tools\"]): Pick<ConverseRequest, \"toolConfig\"> {\n const toolConfig = toBedrockToolConfig(tools);\n\n return toolConfig ? { toolConfig } : {};\n }\n\n /**\n * Translate the neutral `responseSchema` into Converse's native\n * `outputConfig.textFormat` (JSON-schema structured output). Bedrock\n * requires the schema as a stringified JSON document and only\n * accepts an object root. Emitted only when the model is\n * `structuredOutput`-capable and the schema is an object — otherwise\n * the agent's soft system-prompt hint + client-side `validate()`\n * carry shape (same degradation philosophy as the OpenAI adapter).\n */\n private buildOutputConfig(\n responseSchema: Record<string, unknown> | undefined,\n ): Pick<ConverseRequest, \"outputConfig\"> {\n if (!responseSchema || !this.capabilities.structuredOutput) {\n return {};\n }\n\n if (responseSchema.type !== \"object\" || typeof responseSchema.properties !== \"object\") {\n return {};\n }\n\n return {\n outputConfig: {\n textFormat: {\n type: \"json_schema\",\n structure: {\n jsonSchema: { name: \"response\", schema: JSON.stringify(responseSchema) },\n },\n },\n },\n };\n }\n\n /**\n * Concatenate every `text` content block into the single neutral\n * `content` string. `toolUse` and other block types are surfaced\n * separately via `extractToolCalls`.\n */\n private extractText(blocks: ContentBlock[]): string {\n return blocks\n .map((block) => (\"text\" in block && typeof block.text === \"string\" ? block.text : \"\"))\n .join(\"\");\n }\n\n /**\n * Reshape Converse `toolUse` content blocks into the neutral\n * `ModelToolCallRequest[]`. Returns `undefined` when no tools were\n * requested so callers can branch on presence.\n */\n private extractToolCalls(blocks: ContentBlock[]): ModelToolCallRequest[] | undefined {\n const toolCalls: ModelToolCallRequest[] = [];\n\n for (const block of blocks) {\n if (\"toolUse\" in block && block.toolUse) {\n toolCalls.push({\n id: block.toolUse.toolUseId ?? \"\",\n name: block.toolUse.name ?? \"\",\n input: (block.toolUse.input ?? {}) as Record<string, unknown>,\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /**\n * Normalize Converse's `TokenUsage` into the neutral `Usage` shape.\n * Bedrock supplies a pre-summed `totalTokens`; cache-read and\n * cache-write tokens are surfaced as `cachedTokens` /\n * `cacheWriteTokens` only when non-zero so callers can price the\n * discounted read rate and the one-time write cost separately.\n * Bedrock's Converse `TokenUsage` carries no reasoning-token channel,\n * so `Usage.reasoningTokens` is intentionally left unset here.\n */\n private extractUsage(raw: TokenUsage | undefined): Usage {\n if (!raw) {\n return { input: 0, output: 0, total: 0 };\n }\n\n const input = raw.inputTokens ?? 0;\n const output = raw.outputTokens ?? 0;\n const cached = raw.cacheReadInputTokens;\n const cacheWrite = raw.cacheWriteInputTokens;\n\n return {\n input,\n output,\n total: raw.totalTokens ?? input + output,\n ...(cached && cached > 0 ? { cachedTokens: cached } : {}),\n ...(cacheWrite && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n };\n }\n\n /**\n * Wrap a thrown provider error into the typed `AIError` hierarchy\n * and emit the standard error log line before it propagates. Shared\n * by every catch site so the log shape stays identical.\n */\n private logAndWrap(thrown: unknown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n return wrapped;\n }\n}\n"],"mappings":";;;;;;;;;;;;AA8BA,MAAM,aAAa;;;;;;;;AASnB,MAAM,yBAA6D;CACjE,KAAK;CACL,QAAQ;CACR,MAAM;AACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,IAAa,eAAb,MAAmD;CAUjD,AAAO,YACL,QACA,QACA,WAAmB,WACnB;gBANgC;EAOhC,KAAK,SAAS;EACd,KAAK,SAAS;EACd,KAAK,OAAO,OAAO;EACnB,KAAK,WAAW;EAChB,KAAK,UAAU,OAAO;EACtB,KAAK,eAAe;GAClB,kBAAkB,OAAO,oBAAoB;GAC7C,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;GACnE,eAAe,OAAO,iBAAiB,6BAA6B,OAAO,IAAI;GAC/E,KAAK,OAAO,OAAO,mBAAmB,OAAO,IAAI;GACjD,OAAO,OAAO,SAAS;EACzB;CACF;;;;;;;CAQA,MAAa,SAAS,UAAqB,SAAoD;EAC7F,KAAK,OAAO,MAAM,YAAY,WAAW,0BAA0B;GACjE,OAAO,KAAK;GACZ,cAAc,SAAS;GACvB,WAAW;GACX,WAAW,SAAS,OAAO,UAAU;EACvC,CAAC;EAED,IAAI;EAEJ,IAAI;GACF,WAAW,MAAM,KAAK,OAAO,KAC3B,IAAI,gBAAgB,KAAK,aAAa,UAAU,OAAO,CAAC,GACxD,SAAS,SAAS,EAAE,aAAa,QAAQ,OAAO,IAAI,MACtD;EACF,SAAS,QAAQ;GACf,MAAM,KAAK,WAAW,MAAM;EAC9B;EAEA,MAAM,SAAS,SAAS,QAAQ,SAAS,WAAW,CAAC;EACrD,MAAM,eAAe,cAAc,SAAS,UAAU;EACtD,MAAM,QAAQ,KAAK,aAAa,SAAS,KAAK;EAC9C,MAAM,YAAY,KAAK,iBAAiB,MAAM;EAE9C,KAAK,OAAO,MAAM,YAAY,YAAY,2BAA2B;GAAE;GAAc;EAAM,CAAC;EAE5F,OAAO;GACL,SAAS,KAAK,YAAY,MAAM;GAChC;GACA;GACA;EACF;CACF;;;;;;;CAQA,OAAc,OACZ,UACA,SACiC;EACjC,KAAK,OAAO,MAAM,YAAY,WAAW,gCAAgC;GACvE,OAAO,KAAK;GACZ,cAAc,SAAS;GACvB,WAAW;GACX,WAAW,SAAS,OAAO,UAAU;EACvC,CAAC;EAED,IAAI;EAEJ,IAAI;GACF,WAAW,MAAM,KAAK,OAAO,KAC3B,IAAI,sBAAsB,KAAK,aAAa,UAAU,OAAO,CAAC,GAC9D,SAAS,SAAS,EAAE,aAAa,QAAQ,OAAO,IAAI,MACtD;EACF,SAAS,QAAQ;GACf,MAAM,KAAK,WAAW,MAAM;EAC9B;EAEA,IAAI;EACJ,MAAM,QAAe;GAAE,OAAO;GAAG,QAAQ;GAAG,OAAO;EAAE;EACrD,MAAM,6BAAa,IAAI,IAAwD;EAE/E,IAAI;GACF,WAAW,MAAM,SAAS,SAAS,UAAU,CAAC,GAAG;IAC/C,IAAI,MAAM,mBAAmB,OAAO,SAAS;KAC3C,MAAM,QAAQ,MAAM,kBAAkB,MAAM;KAE5C,WAAW,IAAI,MAAM,kBAAkB,qBAAqB,GAAG;MAC7D,IAAI,MAAM,aAAa;MACvB,MAAM,MAAM,QAAQ;MACpB,MAAM;KACR,CAAC;KAED;IACF;IAEA,IAAI,MAAM,mBAAmB,OAAO;KAClC,MAAM,QAAQ,MAAM,kBAAkB;KAEtC,IAAI,MAAM,MACR,MAAM;MAAE,MAAM;MAAS,SAAS,MAAM;KAAK;UACtC,IAAI,MAAM,SAAS;MACxB,MAAM,cAAc,WAAW,IAAI,MAAM,kBAAkB,qBAAqB,CAAC;MAEjF,IAAI,aACF,YAAY,QAAQ,MAAM,QAAQ,SAAS;KAE/C;KAEA;IACF;IAEA,IAAI,MAAM,kBAAkB;KAC1B,MAAM,cAAc,WAAW,IAAI,MAAM,iBAAiB,qBAAqB,CAAC;KAEhF,IAAI,aAAa;MACf,MAAM;OACJ,MAAM;OACN,IAAI,YAAY;OAChB,MAAM,YAAY;OAClB,OAAO,cAAuC,YAAY,MAAM,CAAC,CAAC;MACpE;MAEA,WAAW,OAAO,MAAM,iBAAiB,qBAAqB,CAAC;KACjE;KAEA;IACF;IAEA,IAAI,MAAM,aACR,gBAAgB,MAAM,YAAY;IAGpC,IAAI,MAAM,UAAU,OAAO;KACzB,MAAM,MAAM,MAAM,SAAS;KAE3B,MAAM,QAAQ,IAAI,eAAe;KACjC,MAAM,SAAS,IAAI,gBAAgB;KACnC,MAAM,QAAQ,IAAI,eAAe,MAAM,QAAQ,MAAM;KAErD,IAAI,IAAI,wBAAwB,IAAI,uBAAuB,GACzD,MAAM,eAAe,IAAI;KAG3B,IAAI,IAAI,yBAAyB,IAAI,wBAAwB,GAC3D,MAAM,mBAAmB,IAAI;IAEjC;GACF;EACF,SAAS,QAAQ;GACf,MAAM,KAAK,WAAW,MAAM;EAC9B;EAEA,MAAM,eAAe,cAAc,aAAa;EAEhD,KAAK,OAAO,MAAM,YAAY,YAAY,iCAAiC;GACzE;GACA;EACF,CAAC;EAED,MAAM;GAAE,MAAM;GAAQ;GAAc;EAAM;CAC5C;;;;;;;CAQA,AAAQ,aACN,UACA,SACiB;EACjB,MAAM,EAAE,QAAQ,UAAU,oBAAoB,kBAAkB,QAAQ;EACxE,MAAM,YAAY,SAAS,aAAa,KAAK,OAAO;EACpD,MAAM,cAAc,SAAS,eAAe,KAAK,OAAO;EACxD,MAAM,iBAAiB,KAAK,sBAAsB,iBAAiB,SAAS,YAAY;EAExF,OAAO;GACL,SAAS,KAAK;GACd,UAAU;GACV,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAC3B,iBAAiB;IACf,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;IAC/C,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;GACrD;GACA,GAAG,KAAK,gBAAgB,SAAS,KAAK;GACtC,GAAG,KAAK,kBAAkB,SAAS,cAAc;GACjD,GAAG,KAAK,qBAAqB,SAAS,SAAS;EACjD;CACF;;;;;;;;;;;;;;;;CAiBA,AAAQ,sBACN,UACA,cAC6B;EAC7B,MAAM,cAAc,cAAc,eAAe;EAEjD,IAAI,CAAC,KAAK,aAAa,iBAAiB,eAAe,KAAK,CAAC,YAAY,SAAS,WAAW,GAC3F,OAAO;EAGT,MAAM,OAAO,SAAS,SAAS;EAC/B,MAAM,cAAc,SAAS;EAE7B,OAAO,CACL,GAAG,SAAS,MAAM,GAAG,IAAI,GACzB;GACE,GAAG;GACH,SAAS,CAAC,GAAI,YAAY,WAAW,CAAC,GAAI,EAAE,YAAY,EAAE,MAAM,UAAU,EAAE,CAAC;EAC/E,CACF;CACF;;;;;;;;;;;;CAaA,AAAQ,qBACN,WACuD;EACvD,IAAI,CAAC,KAAK,aAAa,aAAa,CAAC,WACnC,OAAO,CAAC;EAGV,MAAM,eAAe,UAAU,aAAa,uBAAuB,UAAU,UAAU;EAEvF,IAAI,iBAAiB,QACnB,OAAO,CAAC;EAGV,OAAO,EACL,8BAA8B,EAC5B,UAAU;GAAE,MAAM;GAAW,eAAe;EAAa,EAC3D,EACF;CACF;;;;;CAMA,AAAQ,gBAAgB,OAAuE;EAC7F,MAAM,aAAa,oBAAoB,KAAK;EAE5C,OAAO,aAAa,EAAE,WAAW,IAAI,CAAC;CACxC;;;;;;;;;;CAWA,AAAQ,kBACN,gBACuC;EACvC,IAAI,CAAC,kBAAkB,CAAC,KAAK,aAAa,kBACxC,OAAO,CAAC;EAGV,IAAI,eAAe,SAAS,YAAY,OAAO,eAAe,eAAe,UAC3E,OAAO,CAAC;EAGV,OAAO,EACL,cAAc,EACZ,YAAY;GACV,MAAM;GACN,WAAW,EACT,YAAY;IAAE,MAAM;IAAY,QAAQ,KAAK,UAAU,cAAc;GAAE,EACzE;EACF,EACF,EACF;CACF;;;;;;CAOA,AAAQ,YAAY,QAAgC;EAClD,OAAO,OACJ,KAAK,UAAW,UAAU,SAAS,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,EAAG,EACpF,KAAK,EAAE;CACZ;;;;;;CAOA,AAAQ,iBAAiB,QAA4D;EACnF,MAAM,YAAoC,CAAC;EAE3C,KAAK,MAAM,SAAS,QAClB,IAAI,aAAa,SAAS,MAAM,SAC9B,UAAU,KAAK;GACb,IAAI,MAAM,QAAQ,aAAa;GAC/B,MAAM,MAAM,QAAQ,QAAQ;GAC5B,OAAQ,MAAM,QAAQ,SAAS,CAAC;EAClC,CAAC;EAIL,OAAO,UAAU,SAAS,IAAI,YAAY;CAC5C;;;;;;;;;;CAWA,AAAQ,aAAa,KAAoC;EACvD,IAAI,CAAC,KACH,OAAO;GAAE,OAAO;GAAG,QAAQ;GAAG,OAAO;EAAE;EAGzC,MAAM,QAAQ,IAAI,eAAe;EACjC,MAAM,SAAS,IAAI,gBAAgB;EACnC,MAAM,SAAS,IAAI;EACnB,MAAM,aAAa,IAAI;EAEvB,OAAO;GACL;GACA;GACA,OAAO,IAAI,eAAe,QAAQ;GAClC,GAAI,UAAU,SAAS,IAAI,EAAE,cAAc,OAAO,IAAI,CAAC;GACvD,GAAI,cAAc,aAAa,IAAI,EAAE,kBAAkB,WAAW,IAAI,CAAC;EACzE;CACF;;;;;;CAOA,AAAQ,WAAW,QAAiB;EAClC,MAAM,UAAU,iBAAiB,MAAM;EAEvC,KAAK,OAAO,MAAM,YAAY,SAAS,QAAQ,SAAS;GACtD,MAAM,QAAQ;GACd,SAAS,QAAQ;EACnB,CAAC;EAED,OAAO;CACT;AACF"}
|
|
1
|
+
{"version":3,"file":"model.mjs","names":[],"sources":["../../../../../../ai-bedrock/src/model.ts"],"sourcesContent":["import {\n safeJsonParse,\n type Message,\n type ModelCallOptions,\n type ModelCapabilities,\n type ModelContract,\n type ModelPricing,\n type ModelResponse,\n type ModelStreamChunk,\n type ModelToolCallRequest,\n type Usage,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport {\n ConverseCommand,\n ConverseStreamCommand,\n type BedrockRuntimeClient,\n type ContentBlock,\n type ConverseRequest,\n type TokenUsage,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport type { BedrockModelConfig } from \"./config.type\";\nimport {\n inferPdfCapability,\n inferPromptCachingCapability,\n inferReasoningCapability,\n} from \"./known-capabilities\";\nimport { inferVisionCapability } from \"./known-vision-models\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/**\n * Conventional extended-thinking token budgets for the neutral\n * `reasoning.effort` levels, used when the caller asks for an effort\n * tier without naming an explicit `reasoning.maxTokens` budget. Mirrors\n * the low / medium / high spread other reasoning adapters expose so the\n * vendor-neutral option behaves consistently across providers.\n */\nconst EFFORT_THINKING_BUDGET: Record<string, number | undefined> = {\n low: 1024,\n medium: 4096,\n high: 16384,\n};\n\n/**\n * Bedrock-backed implementation of `ModelContract`.\n *\n * **Role.** The provider-facing bridge between the vendor-neutral\n * `@warlock.js/ai` agent runtime and AWS Bedrock's Converse /\n * ConverseStream API. Converse is the model-agnostic surface — one\n * wire mapping covers every Bedrock-hosted family (Anthropic Claude,\n * Amazon Nova, Meta Llama, Mistral, Cohere) instead of per-family\n * `InvokeModel` body shapes.\n *\n * **Responsibility.**\n * - Owns: a long-lived `BedrockRuntimeClient` + frozen `ModelConfig`\n * (modelId, temperature, maxTokens) used as per-call defaults.\n * - Owns: translating vendor-neutral `Message[]` / `ToolConfig[]` into\n * Converse shapes (system hoisting, `toolUse` / `toolResult` blocks,\n * image bytes) on the way out, and Converse's content-block response\n * (text, tool calls, stop reason, token usage) back into the neutral\n * shapes on the way in.\n * - Does NOT own: dispatching tools, looping, history, retries — those\n * are agent concerns. The model is a per-call protocol adapter.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across calls\"): the AWS client is heavy to construct and reused for\n * the SDK's lifetime.\n *\n * @example\n * import { BedrockRuntimeClient } from \"@aws-sdk/client-bedrock-runtime\";\n * const client = new BedrockRuntimeClient({ region: \"us-east-1\" });\n * const model = new BedrockModel(client, {\n * name: \"anthropic.claude-sonnet-4-5-20250929-v1:0\",\n * });\n *\n * const myAgent = agent({ model, tools: [searchTool] });\n * const result = await myAgent.execute(\"Summarize today's news.\");\n */\nexport class BedrockModel implements ModelContract {\n public readonly name: string;\n public readonly provider: string;\n public readonly capabilities: ModelCapabilities;\n public readonly pricing?: ModelPricing;\n\n private readonly client: BedrockRuntimeClient;\n private readonly config: BedrockModelConfig;\n private readonly logger: Logger = log;\n\n public constructor(\n client: BedrockRuntimeClient,\n config: BedrockModelConfig,\n provider: string = \"bedrock\",\n ) {\n this.client = client;\n this.config = config;\n this.name = config.name;\n this.provider = provider;\n this.pricing = config.pricing;\n this.capabilities = {\n structuredOutput: config.structuredOutput ?? true,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n promptCaching: config.promptCaching ?? inferPromptCachingCapability(config.name),\n pdf: config.pdf ?? inferPdfCapability(config.name),\n audio: config.audio ?? false,\n };\n }\n\n /**\n * Single-shot completion via the Converse API. Sends the full\n * message list, waits for the terminal response, and reshapes it\n * into a vendor-neutral `ModelResponse`. Per-call `options` override\n * the instance defaults for this call only.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting Converse call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: false,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const blocks = response.output?.message?.content ?? [];\n const finishReason = mapStopReason(response.stopReason);\n const usage = this.extractUsage(response.usage);\n const toolCalls = this.extractToolCalls(blocks);\n\n this.logger.debug(LOG_MODULE, \"response\", \"Converse call succeeded\", { finishReason, usage });\n\n return {\n content: this.extractText(blocks),\n finishReason,\n usage,\n toolCalls,\n };\n }\n\n /**\n * Incremental streaming completion via ConverseStream. Yields neutral\n * `ModelStreamChunk`s — `delta` for text, `tool-call` once a\n * `toolUse` block's accumulated input JSON is complete, and a\n * terminal `done` with the final finish reason + usage totals.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting ConverseStream call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: true,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseStreamCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n let rawStopReason: string | undefined;\n const usage: Usage = { input: 0, output: 0, total: 0 };\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n try {\n for await (const event of response.stream ?? []) {\n if (event.contentBlockStart?.start?.toolUse) {\n const start = event.contentBlockStart.start.toolUse;\n\n toolBlocks.set(event.contentBlockStart.contentBlockIndex ?? 0, {\n id: start.toolUseId ?? \"\",\n name: start.name ?? \"\",\n json: \"\",\n });\n\n continue;\n }\n\n if (event.contentBlockDelta?.delta) {\n const delta = event.contentBlockDelta.delta;\n\n if (delta.text) {\n yield { type: \"delta\", content: delta.text };\n } else if (delta.toolUse) {\n const accumulator = toolBlocks.get(event.contentBlockDelta.contentBlockIndex ?? 0);\n\n if (accumulator) {\n accumulator.json += delta.toolUse.input ?? \"\";\n }\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const accumulator = toolBlocks.get(event.contentBlockStop.contentBlockIndex ?? 0);\n\n if (accumulator) {\n yield {\n type: \"tool-call\",\n id: accumulator.id,\n name: accumulator.name,\n input: safeJsonParse<Record<string, unknown>>(accumulator.json, {}),\n };\n\n toolBlocks.delete(event.contentBlockStop.contentBlockIndex ?? 0);\n }\n\n continue;\n }\n\n if (event.messageStop) {\n rawStopReason = event.messageStop.stopReason;\n }\n\n if (event.metadata?.usage) {\n const raw = event.metadata.usage;\n\n usage.input = raw.inputTokens ?? 0;\n usage.output = raw.outputTokens ?? 0;\n usage.total = raw.totalTokens ?? usage.input + usage.output;\n\n if (raw.cacheReadInputTokens && raw.cacheReadInputTokens > 0) {\n usage.cachedTokens = raw.cacheReadInputTokens;\n }\n\n if (raw.cacheWriteInputTokens && raw.cacheWriteInputTokens > 0) {\n usage.cacheWriteTokens = raw.cacheWriteInputTokens;\n }\n }\n }\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const finishReason = mapStopReason(rawStopReason);\n\n this.logger.debug(LOG_MODULE, \"response\", \"ConverseStream call succeeded\", {\n finishReason,\n usage,\n });\n\n yield { type: \"done\", finishReason, usage };\n }\n\n /**\n * Assemble the Converse request shared by `complete()` and\n * `stream()` (both command shapes take the same input). Hoists the\n * system prompt, maps inference params, and conditionally attaches\n * tools and native structured output.\n */\n private buildRequest(\n messages: Message[],\n options: ModelCallOptions | undefined,\n ): ConverseRequest {\n const { system, messages: bedrockMessages } = toBedrockMessages(messages);\n const maxTokens = options?.maxTokens ?? this.config.maxTokens;\n const temperature = options?.temperature ?? this.config.temperature;\n const cachedMessages = this.applyCacheBreakpoints(bedrockMessages, options?.cacheControl);\n\n return {\n modelId: this.name,\n messages: cachedMessages,\n ...(system ? { system } : {}),\n inferenceConfig: {\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n },\n ...this.buildToolConfig(options?.tools),\n ...this.buildOutputConfig(options?.responseSchema),\n ...this.buildReasoningConfig(options?.reasoning),\n };\n }\n\n /**\n * Append a Converse `cachePoint` block to the LAST message when the\n * caller supplies a `cacheControl` write breakpoint and the model is\n * `promptCaching`-capable. A cache point tells Bedrock to cache the\n * whole prefix up to that block, so subsequent calls reusing the same\n * prefix bill the cached portion at the discounted read rate\n * (surfaced as `Usage.cachedTokens`). No-ops gracefully when caching\n * is unsupported, no breakpoint was requested, or there are no\n * messages to mark — Bedrock then prices the call normally.\n *\n * Bedrock only honors `CachePointType.DEFAULT`; the neutral\n * `breakpoints` count is a presence hint (one trailing breakpoint is\n * the only placement Converse supports without manual block surgery),\n * so any positive value marks the trailing message.\n */\n private applyCacheBreakpoints(\n messages: ConverseRequest[\"messages\"],\n cacheControl: ModelCallOptions[\"cacheControl\"],\n ): ConverseRequest[\"messages\"] {\n const breakpoints = cacheControl?.breakpoints ?? 0;\n\n if (!this.capabilities.promptCaching || breakpoints <= 0 || !messages || messages.length === 0) {\n return messages;\n }\n\n const last = messages.length - 1;\n const lastMessage = messages[last];\n\n return [\n ...messages.slice(0, last),\n {\n ...lastMessage,\n content: [...(lastMessage.content ?? []), { cachePoint: { type: \"default\" } }],\n },\n ];\n }\n\n /**\n * Translate the neutral `reasoning` option into Claude-on-Bedrock's\n * extended-thinking control, carried in Converse's escape hatch\n * `additionalModelRequestFields.thinking`. Emitted only when the model\n * is `reasoning`-capable and a budget can be resolved — `maxTokens`\n * (explicit thinking budget) wins, otherwise `effort` maps to a\n * conventional token budget so callers can opt in without picking a\n * number. Returns an empty object (no-op) for non-reasoning models or\n * when no reasoning option was supplied, so unsupported params never\n * reach the wire.\n */\n private buildReasoningConfig(\n reasoning: ModelCallOptions[\"reasoning\"],\n ): Pick<ConverseRequest, \"additionalModelRequestFields\"> {\n if (!this.capabilities.reasoning || !reasoning) {\n return {};\n }\n\n const budgetTokens = reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[reasoning.effort ?? \"\"];\n\n if (budgetTokens === undefined) {\n return {};\n }\n\n return {\n additionalModelRequestFields: {\n thinking: { type: \"enabled\", budget_tokens: budgetTokens },\n },\n };\n }\n\n /**\n * Spread-friendly tool fragment. Returns an empty object when no\n * tools were supplied (Bedrock rejects an empty `tools` array).\n */\n private buildToolConfig(tools: ModelCallOptions[\"tools\"]): Pick<ConverseRequest, \"toolConfig\"> {\n const toolConfig = toBedrockToolConfig(tools);\n\n return toolConfig ? { toolConfig } : {};\n }\n\n /**\n * Translate the neutral `responseSchema` into Converse's native\n * `outputConfig.textFormat` (JSON-schema structured output). Bedrock\n * requires the schema as a stringified JSON document and only\n * accepts an object root. Emitted only when the model is\n * `structuredOutput`-capable and the schema is an object — otherwise\n * the agent's soft system-prompt hint + client-side `validate()`\n * carry shape (same degradation philosophy as the OpenAI adapter).\n */\n private buildOutputConfig(\n responseSchema: Record<string, unknown> | undefined,\n ): Pick<ConverseRequest, \"outputConfig\"> {\n if (!responseSchema || !this.capabilities.structuredOutput) {\n return {};\n }\n\n if (responseSchema.type !== \"object\" || typeof responseSchema.properties !== \"object\") {\n return {};\n }\n\n return {\n outputConfig: {\n textFormat: {\n type: \"json_schema\",\n structure: {\n jsonSchema: { name: \"response\", schema: JSON.stringify(responseSchema) },\n },\n },\n },\n };\n }\n\n /**\n * Concatenate every `text` content block into the single neutral\n * `content` string. `toolUse` and other block types are surfaced\n * separately via `extractToolCalls`.\n */\n private extractText(blocks: ContentBlock[]): string {\n return blocks\n .map((block) => (\"text\" in block && typeof block.text === \"string\" ? block.text : \"\"))\n .join(\"\");\n }\n\n /**\n * Reshape Converse `toolUse` content blocks into the neutral\n * `ModelToolCallRequest[]`. Returns `undefined` when no tools were\n * requested so callers can branch on presence.\n */\n private extractToolCalls(blocks: ContentBlock[]): ModelToolCallRequest[] | undefined {\n const toolCalls: ModelToolCallRequest[] = [];\n\n for (const block of blocks) {\n if (\"toolUse\" in block && block.toolUse) {\n toolCalls.push({\n id: block.toolUse.toolUseId ?? \"\",\n name: block.toolUse.name ?? \"\",\n input: (block.toolUse.input ?? {}) as Record<string, unknown>,\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /**\n * Normalize Converse's `TokenUsage` into the neutral `Usage` shape.\n * Bedrock supplies a pre-summed `totalTokens`; cache-read and\n * cache-write tokens are surfaced as `cachedTokens` /\n * `cacheWriteTokens` only when non-zero so callers can price the\n * discounted read rate and the one-time write cost separately.\n * Bedrock's Converse `TokenUsage` carries no reasoning-token channel,\n * so `Usage.reasoningTokens` is intentionally left unset here.\n */\n private extractUsage(raw: TokenUsage | undefined): Usage {\n if (!raw) {\n return { input: 0, output: 0, total: 0 };\n }\n\n const input = raw.inputTokens ?? 0;\n const output = raw.outputTokens ?? 0;\n const cached = raw.cacheReadInputTokens;\n const cacheWrite = raw.cacheWriteInputTokens;\n\n return {\n input,\n output,\n total: raw.totalTokens ?? input + output,\n ...(cached && cached > 0 ? { cachedTokens: cached } : {}),\n ...(cacheWrite && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n };\n }\n\n /**\n * Wrap a thrown provider error into the typed `AIError` hierarchy\n * and emit the standard error log line before it propagates. Shared\n * by every catch site so the log shape stays identical.\n */\n private logAndWrap(thrown: unknown) {\n const wrapped = wrapBedrockError(thrown);\n\n this.logger.error(LOG_MODULE, \"error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n\n return wrapped;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to-bedrock-messages.mjs","names":[],"sources":["../../../../../../../ai-bedrock/src/utils/to-bedrock-messages.ts"],"sourcesContent":["import { InvalidRequestError, type ContentPart, type Message } from \"@warlock.js/ai\";\nimport type {\n ContentBlock,\n ImageFormat,\n Message as BedrockMessage,\n SystemContentBlock,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Result of splitting a vendor-neutral `Message[]` for the Bedrock\n * Converse API: system prompts hoist to a separate `SystemContentBlock[]`\n * (Converse has no `\"system\"` role inside `messages`), and the\n * remaining turns map to Bedrock `Message[]`.\n */\nexport type BedrockMessages = {\n system: SystemContentBlock[] | undefined;\n messages: BedrockMessage[];\n};\n\nconst MEDIA_TYPE_TO_FORMAT: Record<string, ImageFormat> = {\n \"image/jpeg\": \"jpeg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"image/webp\": \"webp\",\n};\n\n/**\n * Convert vendor-neutral `Message[]` into Bedrock Converse's request\n * shape.\n *\n * Converse differs from the OpenAI Chat protocol in three ways this\n * function absorbs:\n *\n * 1. **No `system` role.** System messages become a separate\n * `SystemContentBlock[]` (one `{ text }` block each).\n * 2. **Tool results are `user` turns.** A neutral `tool` message\n * becomes a `user` message carrying a single `toolResult` block.\n * 3. **Tool calls are `toolUse` content blocks.** An assistant message\n * with `toolCalls` becomes an `assistant` message: an optional\n * leading `text` block followed by one `toolUse` block per call.\n *\n * @example\n * const { system, messages } = toBedrockMessages([\n * { role: \"system\", content: \"Be concise.\" },\n * { role: \"user\", content: \"Hi\" },\n * ]);\n */\nexport function toBedrockMessages(messages: Message[]): BedrockMessages {\n const system: SystemContentBlock[] = [];\n const mapped: BedrockMessage[] = [];\n\n for (const message of messages) {\n if (message.role === \"system\") {\n system.push({ text: stringifyContent(message.content) });\n\n continue;\n }\n\n if (message.role === \"tool\") {\n mapped.push({\n role: \"user\",\n content: [\n {\n toolResult: {\n toolUseId: message.toolCallId ?? \"\",\n content: [{ text: stringifyContent(message.content) }],\n },\n },\n ],\n });\n\n continue;\n }\n\n if (message.role === \"assistant\" && message.toolCalls && message.toolCalls.length > 0) {\n const blocks: ContentBlock[] = [];\n const text = stringifyContent(message.content);\n\n if (text) {\n blocks.push({ text });\n }\n\n for (const toolCall of message.toolCalls) {\n blocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.input ?? {},\n },\n } as ContentBlock);\n }\n\n mapped.push({ role: \"assistant\", content: blocks });\n\n continue;\n }\n\n if (message.role === \"user\" && Array.isArray(message.content)) {\n mapped.push({\n role: \"user\",\n content: message.content.map(toBedrockContentBlock),\n });\n\n continue;\n }\n\n mapped.push({\n role: message.role === \"assistant\" ? \"assistant\" : \"user\",\n content: [{ text: stringifyContent(message.content) }],\n });\n }\n\n return {\n system: system.length > 0 ? system : undefined,\n messages: mapped,\n };\n}\n\n/**\n * Multipart content is only meaningful on user messages — for any other\n * role collapse a `ContentPart[]` to its concatenated text. Plain\n * strings pass through unchanged.\n */\nfunction stringifyContent(content: string | ContentPart[]): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n return content\n .filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n}\n\n/**\n * Map a resolved `ContentPart` to a Bedrock `ContentBlock`. Bedrock's\n * `ImageSource` only accepts raw bytes or an S3 location — there is no\n * remote-URL source. A neutral `{ url }` image therefore cannot be\n * sent and surfaces a typed `InvalidRequestError` upfront rather than\n * a downstream Bedrock validation fault. The agent has already\n * resolved attachments, so this never fetches or reads anything.\n */\nfunction toBedrockContentBlock(part: ContentPart): ContentBlock {\n if (part.type === \"text\") {\n return { text: part.text };\n }\n\n if (\"url\" in part.source) {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support remote-URL sources; supply base64 bytes instead.\",\n );\n }\n\n // PDF → Bedrock `document` content block (A2). Converse accepts a\n // document block with raw bytes; the agent gates this on the model's\n // `pdf` capability before it reaches here.\n if (part.type === \"pdf\") {\n return {\n document: {\n format: \"pdf\",\n name: \"attachment\",\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n } as unknown as ContentBlock;\n }\n\n // Bedrock Converse has no audio content block (capability stays false).\n if (part.type === \"audio\") {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support audio attachments.\",\n );\n }\n\n const format = MEDIA_TYPE_TO_FORMAT[part.source.mediaType];\n\n if (!format) {\n throw new InvalidRequestError(\n `Unsupported image media type for Bedrock: \"${part.source.mediaType}\" (expected image/jpeg, image/png, image/gif, or image/webp).`,\n );\n }\n\n return {\n image: {\n format,\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n };\n}\n"],"mappings":";;;AAmBA,MAAM,uBAAoD;CACxD,cAAc;CACd,aAAa;CACb,aAAa;CACb,cAAc;AAChB;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,UAAsC;CACtE,MAAM,SAA+B,CAAC;CACtC,MAAM,SAA2B,CAAC;CAElC,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,QAAQ,SAAS,UAAU;GAC7B,OAAO,KAAK,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;GAEvD;EACF;EAEA,IAAI,QAAQ,SAAS,QAAQ;GAC3B,OAAO,KAAK;IACV,MAAM;IACN,SAAS,CACP,EACE,YAAY;KACV,WAAW,QAAQ,cAAc;KACjC,SAAS,CAAC,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;IACvD,EACF,CACF;GACF,CAAC;GAED;EACF;EAEA,IAAI,QAAQ,SAAS,eAAe,QAAQ,aAAa,QAAQ,UAAU,SAAS,GAAG;GACrF,MAAM,SAAyB,CAAC;GAChC,MAAM,OAAO,iBAAiB,QAAQ,OAAO;GAE7C,IAAI,MACF,OAAO,KAAK,EAAE,KAAK,CAAC;GAGtB,KAAK,MAAM,YAAY,QAAQ,WAC7B,OAAO,KAAK,EACV,SAAS;IACP,WAAW,SAAS;IACpB,MAAM,SAAS;IACf,OAAO,SAAS,SAAS,CAAC;GAC5B,EACF,CAAiB;GAGnB,OAAO,KAAK;IAAE,MAAM;IAAa,SAAS;GAAO,CAAC;GAElD;EACF;EAEA,IAAI,QAAQ,SAAS,UAAU,MAAM,QAAQ,QAAQ,OAAO,GAAG;GAC7D,OAAO,KAAK;IACV,MAAM;IACN,SAAS,QAAQ,QAAQ,IAAI,qBAAqB;GACpD,CAAC;GAED;EACF;EAEA,OAAO,KAAK;GACV,MAAM,QAAQ,SAAS,cAAc,cAAc;GACnD,SAAS,CAAC,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;EACvD,CAAC;CACH;CAEA,OAAO;EACL,QAAQ,OAAO,SAAS,IAAI,SAAS;EACrC,UAAU;CACZ;AACF;;;;;;AAOA,SAAS,iBAAiB,SAAyC;CACjE,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,OAAO,QACJ,QAAQ,SAAiD,KAAK,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"to-bedrock-messages.mjs","names":[],"sources":["../../../../../../../ai-bedrock/src/utils/to-bedrock-messages.ts"],"sourcesContent":["import { InvalidRequestError, type ContentPart, type Message } from \"@warlock.js/ai\";\nimport type {\n ContentBlock,\n ImageFormat,\n Message as BedrockMessage,\n SystemContentBlock,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Result of splitting a vendor-neutral `Message[]` for the Bedrock\n * Converse API: system prompts hoist to a separate `SystemContentBlock[]`\n * (Converse has no `\"system\"` role inside `messages`), and the\n * remaining turns map to Bedrock `Message[]`.\n */\nexport type BedrockMessages = {\n system: SystemContentBlock[] | undefined;\n messages: BedrockMessage[];\n};\n\nconst MEDIA_TYPE_TO_FORMAT: Record<string, ImageFormat> = {\n \"image/jpeg\": \"jpeg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"image/webp\": \"webp\",\n};\n\n/**\n * Convert vendor-neutral `Message[]` into Bedrock Converse's request\n * shape.\n *\n * Converse differs from the OpenAI Chat protocol in three ways this\n * function absorbs:\n *\n * 1. **No `system` role.** System messages become a separate\n * `SystemContentBlock[]` (one `{ text }` block each).\n * 2. **Tool results are `user` turns.** A neutral `tool` message\n * becomes a `user` message carrying a single `toolResult` block.\n * 3. **Tool calls are `toolUse` content blocks.** An assistant message\n * with `toolCalls` becomes an `assistant` message: an optional\n * leading `text` block followed by one `toolUse` block per call.\n *\n * @example\n * const { system, messages } = toBedrockMessages([\n * { role: \"system\", content: \"Be concise.\" },\n * { role: \"user\", content: \"Hi\" },\n * ]);\n */\nexport function toBedrockMessages(messages: Message[]): BedrockMessages {\n const system: SystemContentBlock[] = [];\n const mapped: BedrockMessage[] = [];\n\n for (const message of messages) {\n if (message.role === \"system\") {\n system.push({ text: stringifyContent(message.content) });\n\n continue;\n }\n\n if (message.role === \"tool\") {\n mapped.push({\n role: \"user\",\n content: [\n {\n toolResult: {\n toolUseId: message.toolCallId ?? \"\",\n content: [{ text: stringifyContent(message.content) }],\n },\n },\n ],\n });\n\n continue;\n }\n\n if (message.role === \"assistant\" && message.toolCalls && message.toolCalls.length > 0) {\n const blocks: ContentBlock[] = [];\n const text = stringifyContent(message.content);\n\n if (text) {\n blocks.push({ text });\n }\n\n for (const toolCall of message.toolCalls) {\n blocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.input ?? {},\n },\n } as ContentBlock);\n }\n\n mapped.push({ role: \"assistant\", content: blocks });\n\n continue;\n }\n\n if (message.role === \"user\" && Array.isArray(message.content)) {\n mapped.push({\n role: \"user\",\n content: message.content.map(toBedrockContentBlock),\n });\n\n continue;\n }\n\n mapped.push({\n role: message.role === \"assistant\" ? \"assistant\" : \"user\",\n content: [{ text: stringifyContent(message.content) }],\n });\n }\n\n return {\n system: system.length > 0 ? system : undefined,\n messages: mapped,\n };\n}\n\n/**\n * Multipart content is only meaningful on user messages — for any other\n * role collapse a `ContentPart[]` to its concatenated text. Plain\n * strings pass through unchanged.\n */\nfunction stringifyContent(content: string | ContentPart[]): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n return content\n .filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n}\n\n/**\n * Map a resolved `ContentPart` to a Bedrock `ContentBlock`. Bedrock's\n * `ImageSource` only accepts raw bytes or an S3 location — there is no\n * remote-URL source. A neutral `{ url }` image therefore cannot be\n * sent and surfaces a typed `InvalidRequestError` upfront rather than\n * a downstream Bedrock validation fault. The agent has already\n * resolved attachments, so this never fetches or reads anything.\n */\nfunction toBedrockContentBlock(part: ContentPart): ContentBlock {\n if (part.type === \"text\") {\n return { text: part.text };\n }\n\n if (\"url\" in part.source) {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support remote-URL sources; supply base64 bytes instead.\",\n );\n }\n\n // PDF → Bedrock `document` content block (A2). Converse accepts a\n // document block with raw bytes; the agent gates this on the model's\n // `pdf` capability before it reaches here.\n if (part.type === \"pdf\") {\n return {\n document: {\n format: \"pdf\",\n name: \"attachment\",\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n } as unknown as ContentBlock;\n }\n\n // Bedrock Converse has no audio content block (capability stays false).\n if (part.type === \"audio\") {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support audio attachments.\",\n );\n }\n\n const format = MEDIA_TYPE_TO_FORMAT[part.source.mediaType];\n\n if (!format) {\n throw new InvalidRequestError(\n `Unsupported image media type for Bedrock: \"${part.source.mediaType}\" (expected image/jpeg, image/png, image/gif, or image/webp).`,\n );\n }\n\n return {\n image: {\n format,\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n };\n}\n"],"mappings":";;;AAmBA,MAAM,uBAAoD;CACxD,cAAc;CACd,aAAa;CACb,aAAa;CACb,cAAc;AAChB;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,UAAsC;CACtE,MAAM,SAA+B,CAAC;CACtC,MAAM,SAA2B,CAAC;CAElC,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,QAAQ,SAAS,UAAU;GAC7B,OAAO,KAAK,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;GAEvD;EACF;EAEA,IAAI,QAAQ,SAAS,QAAQ;GAC3B,OAAO,KAAK;IACV,MAAM;IACN,SAAS,CACP,EACE,YAAY;KACV,WAAW,QAAQ,cAAc;KACjC,SAAS,CAAC,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;IACvD,EACF,CACF;GACF,CAAC;GAED;EACF;EAEA,IAAI,QAAQ,SAAS,eAAe,QAAQ,aAAa,QAAQ,UAAU,SAAS,GAAG;GACrF,MAAM,SAAyB,CAAC;GAChC,MAAM,OAAO,iBAAiB,QAAQ,OAAO;GAE7C,IAAI,MACF,OAAO,KAAK,EAAE,KAAK,CAAC;GAGtB,KAAK,MAAM,YAAY,QAAQ,WAC7B,OAAO,KAAK,EACV,SAAS;IACP,WAAW,SAAS;IACpB,MAAM,SAAS;IACf,OAAO,SAAS,SAAS,CAAC;GAC5B,EACF,CAAiB;GAGnB,OAAO,KAAK;IAAE,MAAM;IAAa,SAAS;GAAO,CAAC;GAElD;EACF;EAEA,IAAI,QAAQ,SAAS,UAAU,MAAM,QAAQ,QAAQ,OAAO,GAAG;GAC7D,OAAO,KAAK;IACV,MAAM;IACN,SAAS,QAAQ,QAAQ,IAAI,qBAAqB;GACpD,CAAC;GAED;EACF;EAEA,OAAO,KAAK;GACV,MAAM,QAAQ,SAAS,cAAc,cAAc;GACnD,SAAS,CAAC,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;EACvD,CAAC;CACH;CAEA,OAAO;EACL,QAAQ,OAAO,SAAS,IAAI,SAAS;EACrC,UAAU;CACZ;AACF;;;;;;AAOA,SAAS,iBAAiB,SAAyC;CACjE,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,OAAO,QACJ,QAAQ,SAAiD,KAAK,SAAS,MAAM,CAAC,CAC9E,KAAK,SAAS,KAAK,IAAI,CAAC,CACxB,KAAK,EAAE;AACZ;;;;;;;;;AAUA,SAAS,sBAAsB,MAAiC;CAC9D,IAAI,KAAK,SAAS,QAChB,OAAO,EAAE,MAAM,KAAK,KAAK;CAG3B,IAAI,SAAS,KAAK,QAChB,MAAM,IAAI,oBACR,oFACF;CAMF,IAAI,KAAK,SAAS,OAChB,OAAO,EACL,UAAU;EACR,QAAQ;EACR,MAAM;EACN,QAAQ,EAAE,OAAO,OAAO,KAAK,KAAK,OAAO,QAAQ,QAAQ,EAAE;CAC7D,EACF;CAIF,IAAI,KAAK,SAAS,SAChB,MAAM,IAAI,oBACR,sDACF;CAGF,MAAM,SAAS,qBAAqB,KAAK,OAAO;CAEhD,IAAI,CAAC,QACH,MAAM,IAAI,oBACR,8CAA8C,KAAK,OAAO,UAAU,8DACtE;CAGF,OAAO,EACL,OAAO;EACL;EACA,QAAQ,EAAE,OAAO,OAAO,KAAK,KAAK,OAAO,QAAQ,QAAQ,EAAE;CAC7D,EACF;AACF"}
|
package/package.json
CHANGED
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"url": "https://github.com/warlockjs/ai-bedrock"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@warlock.js/ai": "5.2.
|
|
17
|
+
"@warlock.js/ai": "5.2.4"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@aws-sdk/client-bedrock-runtime": "^3.1048.0",
|
|
21
|
-
"@warlock.js/logger": "5.2.
|
|
21
|
+
"@warlock.js/logger": "5.2.4"
|
|
22
22
|
},
|
|
23
|
-
"version": "5.2.
|
|
23
|
+
"version": "5.2.4",
|
|
24
24
|
"main": "./cjs/index.cjs",
|
|
25
25
|
"module": "./esm/index.mjs",
|
|
26
26
|
"types": "./esm/index.d.mts",
|