@warlock.js/ai-bedrock 5.29.0 → 5.31.0

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/cjs/index.cjs +350 -57
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/config.type.d.mts +31 -6
  5. package/esm/config.type.d.mts.map +1 -1
  6. package/esm/embedder.mjs +1 -1
  7. package/esm/embedder.mjs.map +1 -1
  8. package/esm/index.d.mts +3 -1
  9. package/esm/index.mjs +2 -1
  10. package/esm/known-capabilities.mjs +42 -4
  11. package/esm/known-capabilities.mjs.map +1 -1
  12. package/esm/known-pricing.d.mts +48 -0
  13. package/esm/known-pricing.d.mts.map +1 -0
  14. package/esm/known-pricing.mjs +99 -0
  15. package/esm/known-pricing.mjs.map +1 -0
  16. package/esm/known-vision-models.mjs +1 -1
  17. package/esm/known-vision-models.mjs.map +1 -1
  18. package/esm/model.mjs +122 -46
  19. package/esm/model.mjs.map +1 -1
  20. package/esm/provider-options.d.mts +8 -0
  21. package/esm/provider-options.d.mts.map +1 -0
  22. package/esm/provider-options.mjs +36 -0
  23. package/esm/provider-options.mjs.map +1 -0
  24. package/esm/sdk.d.mts +5 -1
  25. package/esm/sdk.d.mts.map +1 -1
  26. package/esm/sdk.mjs +35 -4
  27. package/esm/sdk.mjs.map +1 -1
  28. package/esm/utils/map-stop-reason.mjs +1 -1
  29. package/esm/utils/map-stop-reason.mjs.map +1 -1
  30. package/esm/utils/reasoning-blocks.mjs +1 -1
  31. package/esm/utils/reasoning-blocks.mjs.map +1 -1
  32. package/esm/utils/to-bedrock-messages.mjs +15 -2
  33. package/esm/utils/to-bedrock-messages.mjs.map +1 -1
  34. package/esm/utils/to-bedrock-tools.mjs +1 -1
  35. package/esm/utils/to-bedrock-tools.mjs.map +1 -1
  36. package/esm/utils/wrap-bedrock-error.mjs +6 -2
  37. package/esm/utils/wrap-bedrock-error.mjs.map +1 -1
  38. package/llms-full.txt +152 -38
  39. package/llms.txt +1 -1
  40. package/package.json +5 -4
  41. package/skills/setup-bedrock/SKILL.md +152 -38
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 { toReasoningMetadata, type BedrockReasoningBlock } from \"./utils/reasoning-blocks\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/** Default output allowance added to a thinking budget when maxTokens is unset. */\nconst DEFAULT_MAX_TOKENS = 4096;\nconst MIN_THINKING_BUDGET = 1024;\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 minimal: 1024,\n low: 1024,\n medium: 4096,\n high: 16384,\n xhigh: 24000,\n max: 32000,\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 const reasoningBlocks = new Map<number, { text?: string; signature?: string; redactedContent?: Uint8Array }>();\n const completedReasoningBlocks: BedrockReasoningBlock[] = [];\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 } else if (delta.reasoningContent) {\n const index = event.contentBlockDelta.contentBlockIndex ?? 0;\n const accumulator = reasoningBlocks.get(index) ?? {};\n\n if (delta.reasoningContent.text !== undefined) {\n accumulator.text = (accumulator.text ?? \"\") + delta.reasoningContent.text;\n }\n\n if (delta.reasoningContent.signature !== undefined) {\n accumulator.signature = delta.reasoningContent.signature;\n }\n\n if (delta.reasoningContent.redactedContent !== undefined) {\n accumulator.redactedContent = delta.reasoningContent.redactedContent;\n }\n\n reasoningBlocks.set(index, accumulator);\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const index = event.contentBlockStop.contentBlockIndex ?? 0;\n const accumulator = toolBlocks.get(index);\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 ...(completedReasoningBlocks.length > 0\n ? { providerMetadata: { bedrock: { reasoningBlocks: completedReasoningBlocks } } }\n : {}),\n };\n\n toolBlocks.delete(index);\n }\n\n const reasoningAccumulator = reasoningBlocks.get(index);\n\n if (reasoningAccumulator) {\n const reasoningBlock = this.toReasoningMetadata(reasoningAccumulator);\n\n if (reasoningBlock) {\n completedReasoningBlocks.push(reasoningBlock);\n }\n reasoningBlocks.delete(index);\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 thinkingBudget = this.resolveThinkingBudget(options?.reasoning);\n const configuredMaxTokens = options?.maxTokens ?? this.config.maxTokens;\n const maxTokens = this.resolveMaxTokens(configuredMaxTokens, thinkingBudget);\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(thinkingBudget),\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 if (!lastMessage) {\n return messages;\n }\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 resolveThinkingBudget(reasoning: ModelCallOptions[\"reasoning\"]): number | undefined {\n if (!this.capabilities.reasoning || !reasoning || reasoning.effort === \"none\") {\n return undefined;\n }\n\n const budgetTokens = reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[reasoning.effort ?? \"\"];\n\n if (budgetTokens !== undefined && budgetTokens < MIN_THINKING_BUDGET) {\n throw new Error(`thinking budget (${budgetTokens}) must be at least ${MIN_THINKING_BUDGET}`);\n }\n\n return budgetTokens;\n }\n\n /** Resolve Bedrock's output ceiling while reserving room for extended thinking. */\n private resolveMaxTokens(maxTokens: number | undefined, thinkingBudget: number | undefined): number | undefined {\n if (thinkingBudget === undefined) {\n return maxTokens;\n }\n\n if (maxTokens === undefined) {\n return thinkingBudget + DEFAULT_MAX_TOKENS;\n }\n\n if (maxTokens <= thinkingBudget) {\n throw new Error(`maxTokens (${maxTokens}) must be greater than thinking budget (${thinkingBudget})`);\n }\n\n return maxTokens;\n }\n\n private buildReasoningConfig(\n budgetTokens: number | undefined,\n ): Pick<ConverseRequest, \"additionalModelRequestFields\"> {\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 const reasoningBlocks = blocks.map(toReasoningMetadata).filter(\n (block): block is BedrockReasoningBlock => block !== undefined,\n );\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 ...(reasoningBlocks.length > 0\n ? { providerMetadata: { bedrock: { reasoningBlocks } } }\n : {}),\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /** Encode accumulated stream deltas as persistence-safe reasoning metadata. */\n private toReasoningMetadata(block: {\n text?: string;\n signature?: string;\n redactedContent?: Uint8Array;\n }): BedrockReasoningBlock | undefined {\n if (block.redactedContent !== undefined) {\n return toReasoningMetadata({ reasoningContent: { redactedContent: block.redactedContent } });\n }\n\n return toReasoningMetadata({\n reasoningContent: {\n reasoningText: { text: block.text ?? \"\", ...(block.signature ? { signature: block.signature } : {}) },\n },\n });\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
+ {"version":3,"file":"model.mjs","names":[],"sources":["../../../../../../../packages/ai-bedrock/src/model.ts"],"sourcesContent":["import {\n attachCost,\n InvalidRequestError,\n resolveStreamChunks,\n safeJsonParse,\n selectProviderTools,\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 CountTokensCommand,\n ConverseCommand,\n ConverseStreamCommand,\n type Tool,\n type BedrockRuntimeClient,\n type ContentBlock,\n type ConverseRequest,\n type TokenUsage,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport { mergeProviderBody } from \"./provider-options\";\nimport type { BedrockModelConfig } from \"./config.type\";\nimport {\n inferPdfCapability,\n inferPromptCachingCapability,\n inferReasoningCapability,\n supportsOneHourCacheTtl,\n supportsToolCachePoint,\n} from \"./known-capabilities\";\nimport { bedrockPricingFor, withClaudeCacheWriteRates } from \"./known-pricing\";\nimport { inferVisionCapability } from \"./known-vision-models\";\nimport { toReasoningMetadata, type BedrockReasoningBlock } from \"./utils/reasoning-blocks\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\n/** A Converse cache point as this adapter emits it. */\ntype BedrockCachePoint = { type: \"default\"; ttl?: \"1h\" };\n\nconst LOG_MODULE = \"ai.bedrock\";\n\n/** `provider` value of `ai.providerTool()` entries this adapter sends verbatim. */\nconst BEDROCK_WIRE_FORMAT = \"bedrock\";\n\n/** Converse `ToolUseBlock.type` of a tool use run by Bedrock itself (SDK `ToolUseType`). */\nconst SERVER_TOOL_USE = \"server_tool_use\";\n\n/** Default output allowance added to a thinking budget when maxTokens is unset. */\nconst DEFAULT_MAX_TOKENS = 4096;\nconst MIN_THINKING_BUDGET = 1024;\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 minimal: 1024,\n low: 1024,\n medium: 4096,\n high: 16384,\n xhigh: 24000,\n max: 32000,\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 // Explicit pricing wins over the built-in `global.` / `us.` profile\n // prices; Claude entries get the 1.25x / 2x cache-write rates filled.\n this.pricing = withClaudeCacheWriteRates(\n config.name,\n config.pricing ?? bedrockPricingFor(config.name),\n );\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 = attachCost(this.extractUsage(response.usage), this.pricing);\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 /** Count native input tokens from the same Converse conversation and tool configuration. */\n public async countTokens(messages: Message[], options?: ModelCallOptions): Promise<number> {\n const request = this.buildRequest(messages, options);\n try {\n const response = await this.client.send(\n new CountTokensCommand({\n modelId: request.modelId,\n input: {\n converse: {\n messages: request.messages,\n system: request.system,\n toolConfig: request.toolConfig,\n additionalModelRequestFields: request.additionalModelRequestFields,\n },\n },\n }),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n if (response.inputTokens === undefined)\n throw new InvalidRequestError(\"Bedrock countTokens returned no inputTokens.\");\n return response.inputTokens;\n } catch (thrown) {\n throw this.logAndWrap(thrown);\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 * With `options.streamChunks` it also yields `reasoning` for each\n * `reasoningContent.text` delta and `tool-args` for each client\n * `toolUse.input` delta. Usage arrives once, in the final `metadata`\n * event, so no `usage` chunk is emitted. A system tool's\n * `server_tool_use` block never becomes a `tool-call`.\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 let usage: Usage = { input: 0, output: 0, total: 0 };\n const want = resolveStreamChunks(options);\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n const reasoningBlocks = new Map<\n number,\n { text?: string; signature?: string; redactedContent?: Uint8Array }\n >();\n const completedReasoningBlocks: BedrockReasoningBlock[] = [];\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 // A system tool's `server_tool_use` runs on Bedrock's side.\n if (start.type === SERVER_TOOL_USE) {\n continue;\n }\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 if (want.toolArgs && delta.toolUse.input) {\n yield {\n type: \"tool-args\",\n callId: accumulator.id,\n name: accumulator.name,\n delta: delta.toolUse.input,\n };\n }\n }\n } else if (delta.reasoningContent) {\n const index = event.contentBlockDelta.contentBlockIndex ?? 0;\n const accumulator = reasoningBlocks.get(index) ?? {};\n\n if (delta.reasoningContent.text !== undefined) {\n accumulator.text = (accumulator.text ?? \"\") + delta.reasoningContent.text;\n\n if (want.reasoning && delta.reasoningContent.text !== \"\") {\n yield { type: \"reasoning\", delta: delta.reasoningContent.text };\n }\n }\n\n if (delta.reasoningContent.signature !== undefined) {\n accumulator.signature = delta.reasoningContent.signature;\n }\n\n if (delta.reasoningContent.redactedContent !== undefined) {\n accumulator.redactedContent = delta.reasoningContent.redactedContent;\n }\n\n reasoningBlocks.set(index, accumulator);\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const index = event.contentBlockStop.contentBlockIndex ?? 0;\n const accumulator = toolBlocks.get(index);\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 ...(completedReasoningBlocks.length > 0\n ? { providerMetadata: { bedrock: { reasoningBlocks: completedReasoningBlocks } } }\n : {}),\n };\n\n toolBlocks.delete(index);\n }\n\n const reasoningAccumulator = reasoningBlocks.get(index);\n\n if (reasoningAccumulator) {\n const reasoningBlock = this.toReasoningMetadata(reasoningAccumulator);\n\n if (reasoningBlock) {\n completedReasoningBlocks.push(reasoningBlock);\n }\n reasoningBlocks.delete(index);\n }\n\n continue;\n }\n\n if (event.messageStop) {\n rawStopReason = event.messageStop.stopReason;\n }\n\n if (event.metadata?.usage) {\n usage = this.extractUsage(event.metadata.usage);\n }\n }\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const finishReason = mapStopReason(rawStopReason);\n\n attachCost(usage, this.pricing);\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 thinkingBudget = this.resolveThinkingBudget(options?.reasoning);\n const configuredMaxTokens = options?.maxTokens ?? this.config.maxTokens;\n const maxTokens = this.resolveMaxTokens(configuredMaxTokens, thinkingBudget);\n const temperature = options?.temperature ?? this.config.temperature;\n const cachePoint = this.resolveCachePoint(options?.cacheControl);\n const cachedMessages = this.applyCacheBreakpoints(bedrockMessages, cachePoint);\n const cachedSystem = system && cachePoint ? [...system, { cachePoint }] : system;\n\n return mergeProviderBody<ConverseRequest>(\n {\n modelId: this.name,\n messages: cachedMessages,\n ...(cachedSystem ? { system: cachedSystem } : {}),\n inferenceConfig: {\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n },\n ...this.buildToolConfig(options, cachePoint),\n ...this.buildOutputConfig(options?.responseSchema),\n ...this.buildReasoningConfig(thinkingBudget),\n },\n options,\n );\n }\n\n /**\n * Resolve the Converse `cachePoint` to place for this call, or\n * `undefined` when no cache point applies (the model is not\n * `promptCaching`-capable or no `cacheControl` breakpoint was asked\n * for). Bedrock only honors `type: \"default\"`; the neutral\n * `breakpoints` count is a presence hint.\n *\n * The lifetime is the per-call `cacheControl.ttl`, else the model's\n * `promptCacheTtl`. `ttl: \"1h\"` is sent only to models that accept it\n * ({@link supportsOneHourCacheTtl}); any other model gets the 5-minute\n * default, because AWS rejects the field there.\n */\n private resolveCachePoint(\n cacheControl: ModelCallOptions[\"cacheControl\"],\n ): BedrockCachePoint | undefined {\n const breakpoints = cacheControl?.breakpoints ?? 0;\n\n if (!this.capabilities.promptCaching || breakpoints <= 0) {\n return undefined;\n }\n\n const ttl = cacheControl?.ttl ?? this.config.promptCacheTtl;\n\n return ttl === \"1h\" && supportsOneHourCacheTtl(this.name)\n ? { type: \"default\", ttl: \"1h\" }\n : { type: \"default\" };\n }\n\n /**\n * Append the call's `cachePoint` to the LAST message. Together with the\n * `system` and `tools` cache points (see `buildRequest` /\n * `buildToolConfig`) this caches every stable segment of the prefix —\n * Bedrock processes them in `tools` → `system` → `messages` order, at\n * most three of the four checkpoints it allows — so later calls reusing\n * the prefix bill it at the cache-read rate (`Usage.cachedTokens`).\n */\n private applyCacheBreakpoints(\n messages: ConverseRequest[\"messages\"],\n cachePoint: BedrockCachePoint | undefined,\n ): ConverseRequest[\"messages\"] {\n if (!cachePoint || !messages || messages.length === 0) {\n return messages;\n }\n\n const last = messages.length - 1;\n const lastMessage = messages[last];\n\n if (!lastMessage) {\n return messages;\n }\n\n return [\n ...messages.slice(0, last),\n {\n ...lastMessage,\n content: [...(lastMessage.content ?? []), { cachePoint }],\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 resolveThinkingBudget(reasoning: ModelCallOptions[\"reasoning\"]): number | undefined {\n if (!this.capabilities.reasoning || !reasoning || reasoning.effort === \"none\") {\n return undefined;\n }\n\n const budgetTokens = reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[reasoning.effort ?? \"\"];\n\n if (budgetTokens !== undefined && budgetTokens < MIN_THINKING_BUDGET) {\n throw new Error(`thinking budget (${budgetTokens}) must be at least ${MIN_THINKING_BUDGET}`);\n }\n\n return budgetTokens;\n }\n\n /** Resolve Bedrock's output ceiling while reserving room for extended thinking. */\n private resolveMaxTokens(\n maxTokens: number | undefined,\n thinkingBudget: number | undefined,\n ): number | undefined {\n if (thinkingBudget === undefined) {\n return maxTokens;\n }\n\n if (maxTokens === undefined) {\n return thinkingBudget + DEFAULT_MAX_TOKENS;\n }\n\n if (maxTokens <= thinkingBudget) {\n throw new Error(\n `maxTokens (${maxTokens}) must be greater than thinking budget (${thinkingBudget})`,\n );\n }\n\n return maxTokens;\n }\n\n private buildReasoningConfig(\n budgetTokens: number | undefined,\n ): Pick<ConverseRequest, \"additionalModelRequestFields\"> {\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). With a\n * cache point, a trailing `{ cachePoint }` caches every tool definition\n * — Claude only, since Nova accepts no cache point in `tools`.\n */\n private buildToolConfig(\n options: ModelCallOptions | undefined,\n cachePoint: BedrockCachePoint | undefined,\n ): Pick<ConverseRequest, \"toolConfig\"> {\n const { tools, definitions } = selectProviderTools(options, {\n accepts: [BEDROCK_WIRE_FORMAT, this.provider],\n module: LOG_MODULE,\n model: this.name,\n logger: this.logger,\n });\n const toolConfig = toBedrockToolConfig(tools);\n // Provider-defined entries are whole Converse `Tool` members, e.g.\n // `{ systemTool: { name: \"nova_grounding\" } }` (Nova web grounding).\n const providerDefined = definitions as unknown as Tool[];\n\n const allTools = [...(toolConfig?.tools ?? []), ...providerDefined];\n\n if (allTools.length === 0) {\n return toolConfig ? { toolConfig } : {};\n }\n\n // The cache point goes last, so every tool definition is cached.\n const withCachePoint =\n cachePoint && supportsToolCachePoint(this.name) ? [...allTools, { cachePoint }] : allTools;\n\n return { toolConfig: { ...toolConfig, tools: withCachePoint } };\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 const reasoningBlocks = blocks\n .map(toReasoningMetadata)\n .filter((block): block is BedrockReasoningBlock => block !== undefined);\n\n for (const block of blocks) {\n // `server_tool_use` blocks are run by Bedrock (system tools such as\n // Nova grounding); only client tool uses are dispatched.\n if (\"toolUse\" in block && block.toolUse && block.toolUse.type !== SERVER_TOOL_USE) {\n toolCalls.push({\n id: block.toolUse.toolUseId ?? \"\",\n name: block.toolUse.name ?? \"\",\n input: (block.toolUse.input ?? {}) as Record<string, unknown>,\n ...(reasoningBlocks.length > 0\n ? { providerMetadata: { bedrock: { reasoningBlocks } } }\n : {}),\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /** Encode accumulated stream deltas as persistence-safe reasoning metadata. */\n private toReasoningMetadata(block: {\n text?: string;\n signature?: string;\n redactedContent?: Uint8Array;\n }): BedrockReasoningBlock | undefined {\n if (block.redactedContent !== undefined) {\n return toReasoningMetadata({ reasoningContent: { redactedContent: block.redactedContent } });\n }\n\n return toReasoningMetadata({\n reasoningContent: {\n reasoningText: {\n text: block.text ?? \"\",\n ...(block.signature ? { signature: block.signature } : {}),\n },\n },\n });\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, and the 1-hour share of the\n * writes (`cacheDetails` entries with `ttl: \"1h\"`) as\n * `cacheWrite1hTokens`. With caching, `inputTokens` \"represents only\n * the non-cached input tokens\" (AWS prompt-caching guide), so the usage\n * is marked `inputIncludesCache: false`. Bedrock's Converse `TokenUsage`\n * carries no reasoning-token channel, so `Usage.reasoningTokens` is\n * 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 const cacheWrite1h = (raw.cacheDetails ?? [])\n .filter((detail) => detail.ttl === \"1h\")\n .reduce((sum, detail) => sum + (detail.inputTokens ?? 0), 0);\n\n return {\n input,\n output,\n total: raw.totalTokens ?? input + output,\n inputIncludesCache: false,\n ...(cached && cached > 0 ? { cachedTokens: cached } : {}),\n ...(cacheWrite && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n ...(cacheWrite && cacheWrite > 0 && cacheWrite1h > 0\n ? { cacheWrite1hTokens: Math.min(cacheWrite1h, cacheWrite) }\n : {}),\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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"}
@@ -0,0 +1,8 @@
1
+ //#region ../../packages/ai-bedrock/src/provider-options.d.ts
2
+ /** Adapter-only fields merged after the neutral request parameters. */
3
+ type BedrockCallOptions = {
4
+ body?: Record<string, unknown>;
5
+ };
6
+ //#endregion
7
+ export { BedrockCallOptions };
8
+ //# sourceMappingURL=provider-options.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-options.d.mts","names":[],"sources":["../../../../../../../packages/ai-bedrock/src/provider-options.ts"],"mappings":";;KAGY,kBAAA;EAAuB,IAAA,GAAO,MAAM;AAAA"}
@@ -0,0 +1,36 @@
1
+ import { InvalidRequestError } from "@warlock.js/ai";
2
+
3
+ //#region ../../packages/ai-bedrock/src/provider-options.ts
4
+ const RESERVED_FIELDS = new Set([
5
+ "modelId",
6
+ "messages",
7
+ "system",
8
+ "toolConfig"
9
+ ]);
10
+ function mergeProviderBody(built, options) {
11
+ const body = (options?.providerOptions?.bedrock)?.body ?? {};
12
+ const reserved = Object.keys(body).filter((key) => RESERVED_FIELDS.has(key));
13
+ if (reserved.length > 0) throw new InvalidRequestError(`providerOptions.bedrock.body cannot set ${reserved.join(", ")}: use the call's messages, tools and model options.`, { context: { fields: reserved } });
14
+ const defaults = built;
15
+ const overrides = Object.fromEntries(Object.entries(body).map(([key, value]) => {
16
+ const previous = defaults[key];
17
+ return [key, isPlainObject(previous) && isPlainObject(value) ? {
18
+ ...previous,
19
+ ...value
20
+ } : value];
21
+ }));
22
+ return {
23
+ ...built,
24
+ ...overrides
25
+ };
26
+ }
27
+ /** Merge only plain objects; arrays, null and provider scalar values replace the field. */
28
+ function isPlainObject(value) {
29
+ if (value === null || typeof value !== "object") return false;
30
+ const prototype = Object.getPrototypeOf(value);
31
+ return prototype === Object.prototype || prototype === null;
32
+ }
33
+
34
+ //#endregion
35
+ export { mergeProviderBody };
36
+ //# sourceMappingURL=provider-options.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-options.mjs","names":[],"sources":["../../../../../../../packages/ai-bedrock/src/provider-options.ts"],"sourcesContent":["import { InvalidRequestError, type ModelCallOptions } from \"@warlock.js/ai\";\n\n/** Adapter-only fields merged after the neutral request parameters. */\nexport type BedrockCallOptions = { body?: Record<string, unknown> };\n\nconst RESERVED_FIELDS = new Set([\"modelId\", \"messages\", \"system\", \"toolConfig\"]);\n\nexport function mergeProviderBody<T extends object>(\n built: T,\n options: ModelCallOptions | undefined,\n): T {\n const provider = options?.providerOptions?.bedrock as BedrockCallOptions | undefined;\n const body = provider?.body ?? {};\n const reserved = Object.keys(body).filter((key) => RESERVED_FIELDS.has(key));\n if (reserved.length > 0) {\n throw new InvalidRequestError(\n `providerOptions.bedrock.body cannot set ${reserved.join(\", \")}: use the call's messages, tools and model options.`,\n { context: { fields: reserved } },\n );\n }\n const defaults = built as Record<string, unknown>;\n const overrides = Object.fromEntries(\n Object.entries(body).map(([key, value]) => {\n const previous = defaults[key];\n return [\n key,\n isPlainObject(previous) && isPlainObject(value) ? { ...previous, ...value } : value,\n ];\n }),\n );\n return { ...built, ...overrides };\n}\n\n/** Merge only plain objects; arrays, null and provider scalar values replace the field. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n"],"mappings":";;;AAKA,MAAM,kBAAkB,IAAI,IAAI;CAAC;CAAW;CAAY;CAAU;AAAY,CAAC;AAE/E,SAAgB,kBACd,OACA,SACG;CAEH,MAAM,QADW,SAAS,iBAAiB,QACtB,EAAE,QAAQ,CAAC;CAChC,MAAM,WAAW,OAAO,KAAK,IAAI,CAAC,CAAC,QAAQ,QAAQ,gBAAgB,IAAI,GAAG,CAAC;CAC3E,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,oBACR,2CAA2C,SAAS,KAAK,IAAI,EAAE,sDAC/D,EAAE,SAAS,EAAE,QAAQ,SAAS,EAAE,CAClC;CAEF,MAAM,WAAW;CACjB,MAAM,YAAY,OAAO,YACvB,OAAO,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW;EACzC,MAAM,WAAW,SAAS;EAC1B,OAAO,CACL,KACA,cAAc,QAAQ,KAAK,cAAc,KAAK,IAAI;GAAE,GAAG;GAAU,GAAG;EAAM,IAAI,KAChF;CACF,CAAC,CACH;CACA,OAAO;EAAE,GAAG;EAAO,GAAG;CAAU;AAClC;;AAGA,SAAS,cAAc,OAAkD;CACvE,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;CACxD,MAAM,YAAY,OAAO,eAAe,KAAK;CAC7C,OAAO,cAAc,OAAO,aAAa,cAAc;AACzD"}
package/esm/sdk.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { BedrockEmbedderConfig, BedrockModelConfig, BedrockSDKConfig } from "./config.type.mjs";
2
2
  import { EmbedderContract, ModelContract, SDKAdapterContract } from "@warlock.js/ai";
3
3
 
4
- //#region ../ai-bedrock/src/sdk.d.ts
4
+ //#region ../../packages/ai-bedrock/src/sdk.d.ts
5
5
  /**
6
6
  * AWS Bedrock-backed implementation of `SDKAdapterContract`.
7
7
  *
@@ -27,6 +27,10 @@ import { EmbedderContract, ModelContract, SDKAdapterContract } from "@warlock.js
27
27
  * const bedrock = new BedrockSDK({ region: "us-east-1" });
28
28
  * const model = bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" });
29
29
  * const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
30
+ *
31
+ * @example
32
+ * // Amazon Bedrock API key (bearer auth) instead of the AWS credential chain
33
+ * const bedrock = new BedrockSDK({ apiKey: process.env.BEDROCK_API_KEY!, region: "us-east-1" });
30
34
  */
31
35
  declare class BedrockSDK implements SDKAdapterContract {
32
36
  private readonly client;
package/esm/sdk.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../ai-bedrock/src/sdk.ts"],"mappings":";;;;;;AA0CA;;;;;;;;;;;;;;;;;;;;;;;;cAAa,UAAA,YAAsB,kBAAA;EAAA,iBAChB,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,OAAA;cAEE,MAAA,EAAQ,gBAAA;EA4CX;;;AAAgD;;;;;;;EA1BzD,KAAA,CAAM,MAAA,EAAQ,kBAAA,GAAqB,aAAA;;;;;;;EAc7B,KAAA,CAAM,IAAA,UAAc,MAAA,YAAkB,OAAA;;;;;;;;;EAY5C,QAAA,CAAS,MAAA,EAAQ,qBAAA,GAAwB,gBAAA;AAAA"}
1
+ {"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../../packages/ai-bedrock/src/sdk.ts"],"mappings":";;;;;;AA0CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,UAAA,YAAsB,kBAAA;EAAA,iBAChB,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,OAAA;cAEE,MAAA,EAAQ,gBAAA;;;;;;;;;;;EAoBpB,KAAA,CAAM,MAAA,EAAQ,kBAAA,GAAqB,aAAA;;;;;;;EAc7B,KAAA,CAAM,IAAA,UAAc,MAAA,YAAkB,OAAA;;;;;;;;;EAY5C,QAAA,CAAS,MAAA,EAAQ,qBAAA,GAAwB,gBAAA;AAAA"}
package/esm/sdk.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { BedrockEmbedder } from "./embedder.mjs";
2
2
  import { BedrockModel } from "./model.mjs";
3
3
  import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime";
4
- import { approximateTokenCount } from "@warlock.js/ai";
4
+ import { InvalidRequestError, approximateTokenCount } from "@warlock.js/ai";
5
5
 
6
- //#region ../ai-bedrock/src/sdk.ts
6
+ //#region ../../packages/ai-bedrock/src/sdk.ts
7
7
  /**
8
8
  * AWS Bedrock-backed implementation of `SDKAdapterContract`.
9
9
  *
@@ -29,11 +29,15 @@ import { approximateTokenCount } from "@warlock.js/ai";
29
29
  * const bedrock = new BedrockSDK({ region: "us-east-1" });
30
30
  * const model = bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" });
31
31
  * const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
32
+ *
33
+ * @example
34
+ * // Amazon Bedrock API key (bearer auth) instead of the AWS credential chain
35
+ * const bedrock = new BedrockSDK({ apiKey: process.env.BEDROCK_API_KEY!, region: "us-east-1" });
32
36
  */
33
37
  var BedrockSDK = class {
34
38
  constructor(config) {
35
- const { provider, pricing, ...clientConfig } = config;
36
- this.client = new BedrockRuntimeClient(clientConfig);
39
+ const { provider, pricing, apiKey, ...clientConfig } = config;
40
+ this.client = new BedrockRuntimeClient(apiKey === void 0 ? clientConfig : withApiKey(clientConfig, apiKey));
37
41
  this.provider = provider ?? "bedrock";
38
42
  this.pricing = pricing;
39
43
  }
@@ -76,6 +80,33 @@ var BedrockSDK = class {
76
80
  return new BedrockEmbedder(this.client, config, this.provider);
77
81
  }
78
82
  };
83
+ /**
84
+ * Configure the runtime client for an Amazon Bedrock API key.
85
+ *
86
+ * Bedrock API keys are bearer tokens: the request carries
87
+ * `Authorization: Bearer <key>` instead of a SigV4 signature (AWS docs,
88
+ * "Use an Amazon Bedrock API key",
89
+ * https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys-use.html,
90
+ * checked 2026-10-17). The installed `@aws-sdk/client-bedrock-runtime`
91
+ * supports this natively: its auth scheme provider offers
92
+ * `smithy.api#httpBearerAuth` beside SigV4, fed by the client's `token`
93
+ * option, and `authSchemePreference: ["httpBearerAuth"]` selects it ahead
94
+ * of SigV4, so the AWS credential chain is never consulted.
95
+ *
96
+ * Fails closed on an empty key, and on a key combined with `credentials`
97
+ * or `token` — two credentials for one client leave which one signs the
98
+ * request ambiguous.
99
+ */
100
+ function withApiKey(clientConfig, apiKey) {
101
+ if (typeof apiKey !== "string" || apiKey.trim() === "") throw new InvalidRequestError("BedrockSDK: `apiKey` must be a non-empty string.");
102
+ const conflicting = ["credentials", "token"].filter((field) => clientConfig[field] !== void 0);
103
+ if (conflicting.length > 0) throw new InvalidRequestError(`BedrockSDK: pass either \`apiKey\` or ${conflicting.map((field) => `\`${field}\``).join(" / ")}, not both.`, { context: { fields: conflicting } });
104
+ return {
105
+ ...clientConfig,
106
+ token: { token: apiKey },
107
+ authSchemePreference: ["httpBearerAuth"]
108
+ };
109
+ }
79
110
 
80
111
  //#endregion
81
112
  export { BedrockSDK };
package/esm/sdk.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../ai-bedrock/src/sdk.ts"],"sourcesContent":["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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,aAAb,MAAsD;CAKpD,AAAO,YAAY,QAA0B;EAC3C,MAAM,EAAE,UAAU,SAAS,GAAG,iBAAiB;EAE/C,KAAK,SAAS,IAAI,qBAAqB,YAAY;EACnD,KAAK,WAAW,YAAY;EAC5B,KAAK,UAAU;CACjB;;;;;;;;;;;CAYA,AAAO,MAAM,QAA2C;EACtD,MAAM,kBAAkB,OAAO,WAAW,KAAK,UAAU,OAAO;EAChE,MAAM,iBACJ,oBAAoB,OAAO,UAAU,SAAS;GAAE,GAAG;GAAQ,SAAS;EAAgB;EAEtF,OAAO,IAAI,aAAa,KAAK,QAAQ,gBAAgB,KAAK,QAAQ;CACpE;;;;;;;CAQA,MAAa,MAAM,MAAc,QAAkC;EACjE,OAAO,sBAAsB,IAAI;CACnC;;;;;;;;;CAUA,AAAO,SAAS,QAAiD;EAC/D,OAAO,IAAI,gBAAgB,KAAK,QAAQ,QAAQ,KAAK,QAAQ;CAC/D;AACF"}
1
+ {"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../../packages/ai-bedrock/src/sdk.ts"],"sourcesContent":["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, InvalidRequestError } from \"@warlock.js/ai\";\nimport type { BedrockEmbedderConfig, BedrockModelConfig, BedrockSDKConfig } 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 *\n * @example\n * // Amazon Bedrock API key (bearer auth) instead of the AWS credential chain\n * const bedrock = new BedrockSDK({ apiKey: process.env.BEDROCK_API_KEY!, region: \"us-east-1\" });\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, apiKey, ...clientConfig } = config;\n\n this.client = new BedrockRuntimeClient(\n apiKey === undefined ? clientConfig : withApiKey(clientConfig, apiKey),\n );\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\n/**\n * Configure the runtime client for an Amazon Bedrock API key.\n *\n * Bedrock API keys are bearer tokens: the request carries\n * `Authorization: Bearer <key>` instead of a SigV4 signature (AWS docs,\n * \"Use an Amazon Bedrock API key\",\n * https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys-use.html,\n * checked 2026-10-17). The installed `@aws-sdk/client-bedrock-runtime`\n * supports this natively: its auth scheme provider offers\n * `smithy.api#httpBearerAuth` beside SigV4, fed by the client's `token`\n * option, and `authSchemePreference: [\"httpBearerAuth\"]` selects it ahead\n * of SigV4, so the AWS credential chain is never consulted.\n *\n * Fails closed on an empty key, and on a key combined with `credentials`\n * or `token` — two credentials for one client leave which one signs the\n * request ambiguous.\n */\nfunction withApiKey(\n clientConfig: Omit<BedrockSDKConfig, \"provider\" | \"pricing\" | \"apiKey\">,\n apiKey: string,\n): Omit<BedrockSDKConfig, \"provider\" | \"pricing\" | \"apiKey\"> {\n if (typeof apiKey !== \"string\" || apiKey.trim() === \"\") {\n throw new InvalidRequestError(\"BedrockSDK: `apiKey` must be a non-empty string.\");\n }\n\n const conflicting = ([\"credentials\", \"token\"] as const).filter(\n (field) => clientConfig[field] !== undefined,\n );\n\n if (conflicting.length > 0) {\n throw new InvalidRequestError(\n `BedrockSDK: pass either \\`apiKey\\` or ${conflicting.map((field) => `\\`${field}\\``).join(\" / \")}, not both.`,\n { context: { fields: conflicting } },\n );\n }\n\n return {\n ...clientConfig,\n token: { token: apiKey },\n authSchemePreference: [\"httpBearerAuth\"],\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,aAAb,MAAsD;CAKpD,AAAO,YAAY,QAA0B;EAC3C,MAAM,EAAE,UAAU,SAAS,QAAQ,GAAG,iBAAiB;EAEvD,KAAK,SAAS,IAAI,qBAChB,WAAW,SAAY,eAAe,WAAW,cAAc,MAAM,CACvE;EACA,KAAK,WAAW,YAAY;EAC5B,KAAK,UAAU;CACjB;;;;;;;;;;;CAYA,AAAO,MAAM,QAA2C;EACtD,MAAM,kBAAkB,OAAO,WAAW,KAAK,UAAU,OAAO;EAChE,MAAM,iBACJ,oBAAoB,OAAO,UAAU,SAAS;GAAE,GAAG;GAAQ,SAAS;EAAgB;EAEtF,OAAO,IAAI,aAAa,KAAK,QAAQ,gBAAgB,KAAK,QAAQ;CACpE;;;;;;;CAQA,MAAa,MAAM,MAAc,QAAkC;EACjE,OAAO,sBAAsB,IAAI;CACnC;;;;;;;;;CAUA,AAAO,SAAS,QAAiD;EAC/D,OAAO,IAAI,gBAAgB,KAAK,QAAQ,QAAQ,KAAK,QAAQ;CAC/D;AACF;;;;;;;;;;;;;;;;;;AAmBA,SAAS,WACP,cACA,QAC2D;CAC3D,IAAI,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM,IAClD,MAAM,IAAI,oBAAoB,kDAAkD;CAGlF,MAAM,cAAe,CAAC,eAAe,OAAO,CAAC,CAAW,QACrD,UAAU,aAAa,WAAW,MACrC;CAEA,IAAI,YAAY,SAAS,GACvB,MAAM,IAAI,oBACR,yCAAyC,YAAY,KAAK,UAAU,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,cAChG,EAAE,SAAS,EAAE,QAAQ,YAAY,EAAE,CACrC;CAGF,OAAO;EACL,GAAG;EACH,OAAO,EAAE,OAAO,OAAO;EACvB,sBAAsB,CAAC,gBAAgB;CACzC;AACF"}
@@ -1,4 +1,4 @@
1
- //#region ../ai-bedrock/src/utils/map-stop-reason.ts
1
+ //#region ../../packages/ai-bedrock/src/utils/map-stop-reason.ts
2
2
  const stopReasonMap = {
3
3
  end_turn: "stop",
4
4
  stop_sequence: "stop",
@@ -1 +1 @@
1
- {"version":3,"file":"map-stop-reason.mjs","names":[],"sources":["../../../../../../../ai-bedrock/src/utils/map-stop-reason.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"],"mappings":";AAEA,MAAM,gBAA8C;CAClD,UAAU;CACV,eAAe;CACf,YAAY;CACZ,UAAU;AACZ;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,cAAc,KAA8C;CAC1E,OAAO,cAAc,OAAO,OAAO;AACrC"}
1
+ {"version":3,"file":"map-stop-reason.mjs","names":[],"sources":["../../../../../../../../packages/ai-bedrock/src/utils/map-stop-reason.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"],"mappings":";AAEA,MAAM,gBAA8C;CAClD,UAAU;CACV,eAAe;CACf,YAAY;CACZ,UAAU;AACZ;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,cAAc,KAA8C;CAC1E,OAAO,cAAc,OAAO,OAAO;AACrC"}
@@ -1,4 +1,4 @@
1
- //#region ../ai-bedrock/src/utils/reasoning-blocks.ts
1
+ //#region ../../packages/ai-bedrock/src/utils/reasoning-blocks.ts
2
2
  /** Convert a Converse reasoning content block to persistence-safe metadata. */
3
3
  function toReasoningMetadata(block) {
4
4
  const reasoning = block.reasoningContent;
@@ -1 +1 @@
1
- {"version":3,"file":"reasoning-blocks.mjs","names":[],"sources":["../../../../../../../ai-bedrock/src/utils/reasoning-blocks.ts"],"sourcesContent":["import type { ContentBlock } from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * JSON-safe representation of a Bedrock Converse reasoning block retained in\n * tool-call provider metadata. Binary redacted reasoning is base64 encoded so\n * it survives message-history persistence unchanged.\n */\nexport type BedrockReasoningBlock =\n | { type: \"reasoning\"; text: string; signature?: string }\n | { type: \"redacted\"; data: string };\n\n/** Convert a Converse reasoning content block to persistence-safe metadata. */\nexport function toReasoningMetadata(block: ContentBlock): BedrockReasoningBlock | undefined {\n const reasoning = block.reasoningContent;\n\n if (!reasoning) {\n return undefined;\n }\n\n if (reasoning.reasoningText) {\n const { text, signature } = reasoning.reasoningText;\n\n if (typeof text !== \"string\") {\n return undefined;\n }\n\n return { type: \"reasoning\", text, ...(typeof signature === \"string\" ? { signature } : {}) };\n }\n\n if (reasoning.redactedContent instanceof Uint8Array) {\n return { type: \"redacted\", data: Buffer.from(reasoning.redactedContent).toString(\"base64\") };\n }\n\n return undefined;\n}\n\n/** Restore one persistence-safe metadata entry to a Converse reasoning block. */\nexport function fromReasoningMetadata(value: unknown): ContentBlock | undefined {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return undefined;\n }\n\n if (value.type === \"reasoning\" && typeof value.text === \"string\") {\n return {\n reasoningContent: {\n reasoningText: {\n text: value.text,\n ...(typeof value.signature === \"string\" ? { signature: value.signature } : {}),\n },\n },\n };\n }\n\n if (value.type === \"redacted\" && typeof value.data === \"string\" && isBase64(value.data)) {\n return { reasoningContent: { redactedContent: new Uint8Array(Buffer.from(value.data, \"base64\")) } };\n }\n\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/** Require canonical base64, avoiding Buffer's permissive decoding of garbage. */\nfunction isBase64(value: string): boolean {\n if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {\n return false;\n }\n\n return Buffer.from(value, \"base64\").toString(\"base64\") === value;\n}\n"],"mappings":";;AAYA,SAAgB,oBAAoB,OAAwD;CAC1F,MAAM,YAAY,MAAM;CAExB,IAAI,CAAC,WACH;CAGF,IAAI,UAAU,eAAe;EAC3B,MAAM,EAAE,MAAM,cAAc,UAAU;EAEtC,IAAI,OAAO,SAAS,UAClB;EAGF,OAAO;GAAE,MAAM;GAAa;GAAM,GAAI,OAAO,cAAc,WAAW,EAAE,UAAU,IAAI,CAAC;EAAG;CAC5F;CAEA,IAAI,UAAU,2BAA2B,YACvC,OAAO;EAAE,MAAM;EAAY,MAAM,OAAO,KAAK,UAAU,eAAe,CAAC,CAAC,SAAS,QAAQ;CAAE;AAI/F;;AAGA,SAAgB,sBAAsB,OAA0C;CAC9E,IAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAC5C;CAGF,IAAI,MAAM,SAAS,eAAe,OAAO,MAAM,SAAS,UACtD,OAAO,EACL,kBAAkB,EAChB,eAAe;EACb,MAAM,MAAM;EACZ,GAAI,OAAO,MAAM,cAAc,WAAW,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;CAC9E,EACF,EACF;CAGF,IAAI,MAAM,SAAS,cAAc,OAAO,MAAM,SAAS,YAAY,SAAS,MAAM,IAAI,GACpF,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,IAAI,WAAW,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC,EAAE,EAAE;AAItG;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;AAGA,SAAS,SAAS,OAAwB;CACxC,IAAI,CAAC,mEAAmE,KAAK,KAAK,GAChF,OAAO;CAGT,OAAO,OAAO,KAAK,OAAO,QAAQ,CAAC,CAAC,SAAS,QAAQ,MAAM;AAC7D"}
1
+ {"version":3,"file":"reasoning-blocks.mjs","names":[],"sources":["../../../../../../../../packages/ai-bedrock/src/utils/reasoning-blocks.ts"],"sourcesContent":["import type { ContentBlock } from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * JSON-safe representation of a Bedrock Converse reasoning block retained in\n * tool-call provider metadata. Binary redacted reasoning is base64 encoded so\n * it survives message-history persistence unchanged.\n */\nexport type BedrockReasoningBlock =\n | { type: \"reasoning\"; text: string; signature?: string }\n | { type: \"redacted\"; data: string };\n\n/** Convert a Converse reasoning content block to persistence-safe metadata. */\nexport function toReasoningMetadata(block: ContentBlock): BedrockReasoningBlock | undefined {\n const reasoning = block.reasoningContent;\n\n if (!reasoning) {\n return undefined;\n }\n\n if (reasoning.reasoningText) {\n const { text, signature } = reasoning.reasoningText;\n\n if (typeof text !== \"string\") {\n return undefined;\n }\n\n return { type: \"reasoning\", text, ...(typeof signature === \"string\" ? { signature } : {}) };\n }\n\n if (reasoning.redactedContent instanceof Uint8Array) {\n return { type: \"redacted\", data: Buffer.from(reasoning.redactedContent).toString(\"base64\") };\n }\n\n return undefined;\n}\n\n/** Restore one persistence-safe metadata entry to a Converse reasoning block. */\nexport function fromReasoningMetadata(value: unknown): ContentBlock | undefined {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return undefined;\n }\n\n if (value.type === \"reasoning\" && typeof value.text === \"string\") {\n return {\n reasoningContent: {\n reasoningText: {\n text: value.text,\n ...(typeof value.signature === \"string\" ? { signature: value.signature } : {}),\n },\n },\n };\n }\n\n if (value.type === \"redacted\" && typeof value.data === \"string\" && isBase64(value.data)) {\n return {\n reasoningContent: { redactedContent: new Uint8Array(Buffer.from(value.data, \"base64\")) },\n };\n }\n\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/** Require canonical base64, avoiding Buffer's permissive decoding of garbage. */\nfunction isBase64(value: string): boolean {\n if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {\n return false;\n }\n\n return Buffer.from(value, \"base64\").toString(\"base64\") === value;\n}\n"],"mappings":";;AAYA,SAAgB,oBAAoB,OAAwD;CAC1F,MAAM,YAAY,MAAM;CAExB,IAAI,CAAC,WACH;CAGF,IAAI,UAAU,eAAe;EAC3B,MAAM,EAAE,MAAM,cAAc,UAAU;EAEtC,IAAI,OAAO,SAAS,UAClB;EAGF,OAAO;GAAE,MAAM;GAAa;GAAM,GAAI,OAAO,cAAc,WAAW,EAAE,UAAU,IAAI,CAAC;EAAG;CAC5F;CAEA,IAAI,UAAU,2BAA2B,YACvC,OAAO;EAAE,MAAM;EAAY,MAAM,OAAO,KAAK,UAAU,eAAe,CAAC,CAAC,SAAS,QAAQ;CAAE;AAI/F;;AAGA,SAAgB,sBAAsB,OAA0C;CAC9E,IAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAC5C;CAGF,IAAI,MAAM,SAAS,eAAe,OAAO,MAAM,SAAS,UACtD,OAAO,EACL,kBAAkB,EAChB,eAAe;EACb,MAAM,MAAM;EACZ,GAAI,OAAO,MAAM,cAAc,WAAW,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;CAC9E,EACF,EACF;CAGF,IAAI,MAAM,SAAS,cAAc,OAAO,MAAM,SAAS,YAAY,SAAS,MAAM,IAAI,GACpF,OAAO,EACL,kBAAkB,EAAE,iBAAiB,IAAI,WAAW,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC,EAAE,EACzF;AAIJ;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;AAGA,SAAS,SAAS,OAAwB;CACxC,IAAI,CAAC,mEAAmE,KAAK,KAAK,GAChF,OAAO;CAGT,OAAO,OAAO,KAAK,OAAO,QAAQ,CAAC,CAAC,SAAS,QAAQ,MAAM;AAC7D"}
@@ -1,7 +1,7 @@
1
1
  import { fromReasoningMetadata } from "./reasoning-blocks.mjs";
2
2
  import { InvalidRequestError } from "@warlock.js/ai";
3
3
 
4
- //#region ../ai-bedrock/src/utils/to-bedrock-messages.ts
4
+ //#region ../../packages/ai-bedrock/src/utils/to-bedrock-messages.ts
5
5
  const MEDIA_TYPE_TO_FORMAT = {
6
6
  "image/jpeg": "jpeg",
7
7
  "image/png": "png",
@@ -78,9 +78,22 @@ function toBedrockMessages(messages) {
78
78
  }
79
79
  return {
80
80
  system: system.length > 0 ? system : void 0,
81
- messages: mapped
81
+ messages: mergeAdjacentTurns(mapped)
82
82
  };
83
83
  }
84
+ /** Converse requires alternating turns; preserve every content block in order. */
85
+ function mergeAdjacentTurns(messages) {
86
+ const merged = [];
87
+ for (const message of messages) {
88
+ const previous = merged[merged.length - 1];
89
+ if (previous && previous.role === message.role) previous.content.push(...message.content ?? []);
90
+ else merged.push({
91
+ ...message,
92
+ content: [...message.content ?? []]
93
+ });
94
+ }
95
+ return merged;
96
+ }
84
97
  /**
85
98
  * Recover opaque Converse reasoning blocks retained on a prior tool call.
86
99
  * Bedrock requires them to be replayed before the assistant's text and
@@ -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\";\nimport { fromReasoningMetadata } from \"./reasoning-blocks\";\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 const reasoningBlocks = getReasoningBlocks(message.toolCalls);\n\n blocks.push(...reasoningBlocks);\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 * Recover opaque Converse reasoning blocks retained on a prior tool call.\n * Bedrock requires them to be replayed before the assistant's text and\n * tool-use blocks on the follow-up request.\n */\nfunction getReasoningBlocks(toolCalls: NonNullable<Message[\"toolCalls\"]>): ContentBlock[] {\n for (const toolCall of toolCalls) {\n const bedrock = toolCall.providerMetadata?.bedrock;\n\n if (!isRecord(bedrock) || !Array.isArray(bedrock.reasoningBlocks)) {\n continue;\n }\n\n return bedrock.reasoningBlocks.map(fromReasoningMetadata).filter(\n (block): block is ContentBlock => block !== undefined,\n );\n }\n\n return [];\n}\n\n/** Narrow an opaque metadata value to an object without altering its contents. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\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":"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"}
1
+ {"version":3,"file":"to-bedrock-messages.mjs","names":[],"sources":["../../../../../../../../packages/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\";\nimport { fromReasoningMetadata } from \"./reasoning-blocks\";\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 const reasoningBlocks = getReasoningBlocks(message.toolCalls);\n\n blocks.push(...reasoningBlocks);\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: mergeAdjacentTurns(mapped),\n };\n}\n\n/** Converse requires alternating turns; preserve every content block in order. */\nfunction mergeAdjacentTurns(messages: BedrockMessage[]): BedrockMessage[] {\n const merged: BedrockMessage[] = [];\n for (const message of messages) {\n const previous = merged[merged.length - 1];\n if (previous && previous.role === message.role) {\n previous.content!.push(...(message.content ?? []));\n } else {\n merged.push({ ...message, content: [...(message.content ?? [])] });\n }\n }\n return merged;\n}\n\n/**\n * Recover opaque Converse reasoning blocks retained on a prior tool call.\n * Bedrock requires them to be replayed before the assistant's text and\n * tool-use blocks on the follow-up request.\n */\nfunction getReasoningBlocks(toolCalls: NonNullable<Message[\"toolCalls\"]>): ContentBlock[] {\n for (const toolCall of toolCalls) {\n const bedrock = toolCall.providerMetadata?.bedrock;\n\n if (!isRecord(bedrock) || !Array.isArray(bedrock.reasoningBlocks)) {\n continue;\n }\n\n return bedrock.reasoningBlocks\n .map(fromReasoningMetadata)\n .filter((block): block is ContentBlock => block !== undefined);\n }\n\n return [];\n}\n\n/** Narrow an opaque metadata value to an object without altering its contents. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\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(\"Bedrock Converse does not support audio attachments.\");\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":";;;;AAoBA,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;GAC7C,MAAM,kBAAkB,mBAAmB,QAAQ,SAAS;GAE5D,OAAO,KAAK,GAAG,eAAe;GAE9B,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,mBAAmB,MAAM;CACrC;AACF;;AAGA,SAAS,mBAAmB,UAA8C;CACxE,MAAM,SAA2B,CAAC;CAClC,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,WAAW,OAAO,OAAO,SAAS;EACxC,IAAI,YAAY,SAAS,SAAS,QAAQ,MACxC,SAAS,QAAS,KAAK,GAAI,QAAQ,WAAW,CAAC,CAAE;OAEjD,OAAO,KAAK;GAAE,GAAG;GAAS,SAAS,CAAC,GAAI,QAAQ,WAAW,CAAC,CAAE;EAAE,CAAC;CAErE;CACA,OAAO;AACT;;;;;;AAOA,SAAS,mBAAmB,WAA8D;CACxF,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,UAAU,SAAS,kBAAkB;EAE3C,IAAI,CAAC,SAAS,OAAO,KAAK,CAAC,MAAM,QAAQ,QAAQ,eAAe,GAC9D;EAGF,OAAO,QAAQ,gBACZ,IAAI,qBAAqB,CAAC,CAC1B,QAAQ,UAAiC,UAAU,MAAS;CACjE;CAEA,OAAO,CAAC;AACV;;AAGA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;;;;;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,oBAAoB,sDAAsD;CAGtF,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"}
@@ -1,6 +1,6 @@
1
1
  import { extractJsonSchema } from "@warlock.js/ai";
2
2
 
3
- //#region ../ai-bedrock/src/utils/to-bedrock-tools.ts
3
+ //#region ../../packages/ai-bedrock/src/utils/to-bedrock-tools.ts
4
4
  /**
5
5
  * Convert vendor-neutral `ToolConfig[]` into Bedrock Converse's
6
6
  * `ToolConfiguration`. Each tool becomes a `toolSpec` with a JSON
@@ -1 +1 @@
1
- {"version":3,"file":"to-bedrock-tools.mjs","names":[],"sources":["../../../../../../../ai-bedrock/src/utils/to-bedrock-tools.ts"],"sourcesContent":["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"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,oBACd,OAC+B;CAC/B,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B;CAGF,OAAO,EACL,OAAO,MAAM,KACV,UAAgB,EACf,UAAU;EACR,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,aAAa,EAAE,MAAM,aAAa,KAAK,KAAK,EAAE;CAChD,EACF,EACF,EACF;AACF;;;;;;;AAQA,SAAS,aAAa,OAAuE;CAC3F,MAAM,SAAS,kBAAkB,KAAK;CAEtC,IAAI,UAAU,OAAO,SAAS,UAC5B,OAAO;CAGT,OAAO,EAAE,MAAM,SAAS;AAC1B"}
1
+ {"version":3,"file":"to-bedrock-tools.mjs","names":[],"sources":["../../../../../../../../packages/ai-bedrock/src/utils/to-bedrock-tools.ts"],"sourcesContent":["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((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 * 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"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,oBACd,OAC+B;CAC/B,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B;CAGF,OAAO,EACL,OAAO,MAAM,KAAK,UAAgB,EAChC,UAAU;EACR,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,aAAa,EAAE,MAAM,aAAa,KAAK,KAAK,EAAE;CAChD,EACF,EAAE,EACJ;AACF;;;;;;;AAQA,SAAS,aAAa,OAAuE;CAC3F,MAAM,SAAS,kBAAkB,KAAK;CAEtC,IAAI,UAAU,OAAO,SAAS,UAC5B,OAAO;CAGT,OAAO,EAAE,MAAM,SAAS;AAC1B"}
@@ -1,6 +1,6 @@
1
- import { AIError, ContextLengthExceededError, InvalidRequestError, ProviderAuthError, ProviderError, ProviderRateLimitError, ProviderTimeoutError, QuotaExceededError } from "@warlock.js/ai";
1
+ import { AIError, ContextLengthExceededError, InvalidRequestError, ProviderAuthError, ProviderError, ProviderOverloadedError, ProviderRateLimitError, ProviderTimeoutError, QuotaExceededError } from "@warlock.js/ai";
2
2
 
3
- //#region ../ai-bedrock/src/utils/wrap-bedrock-error.ts
3
+ //#region ../../packages/ai-bedrock/src/utils/wrap-bedrock-error.ts
4
4
  const TIMEOUT_NAMES = new Set([
5
5
  "ModelTimeoutException",
6
6
  "TimeoutError",
@@ -54,6 +54,10 @@ function wrapBedrockError(thrown) {
54
54
  cause: thrown,
55
55
  context
56
56
  });
57
+ if (shape.name === "ServiceUnavailableException" || shape.httpStatusCode === 503) return new ProviderOverloadedError(message, {
58
+ cause: thrown,
59
+ context
60
+ });
57
61
  if (shape.name === "ValidationException") {
58
62
  if (/too long|context window|maximum context|exceeds the maximum/i.test(message)) return new ContextLengthExceededError(message, {
59
63
  cause: thrown,
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-bedrock-error.mjs","names":[],"sources":["../../../../../../../ai-bedrock/src/utils/wrap-bedrock-error.ts"],"sourcesContent":["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"],"mappings":";;;AA0BA,MAAM,gBAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,iBAAiB,QAA0B;CACzD,IAAI,kBAAkB,SACpB,OAAO;CAGT,MAAM,QAAQ,QAAQ,MAAM;CAC5B,MAAM,UAAU,aAAa,KAAK;CAClC,MAAM,UAAU,MAAM,YAAY,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;CAE1F,IAAI,UAAU,KAAK,GACjB,OAAO,IAAI,qBAAqB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGrE,IAAI,MAAM,SAAS,2BAA2B,MAAM,mBAAmB,KACrE,OAAO,IAAI,kBAAkB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGlE,IAAI,MAAM,mBAAmB,KAC3B,OAAO,IAAI,kBAAkB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGlE,IAAI,MAAM,SAAS,iCACjB,OAAO,IAAI,mBAAmB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGnE,IAAI,MAAM,SAAS,yBAAyB,MAAM,mBAAmB,KACnE,OAAO,IAAI,uBAAuB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGvE,IAAI,MAAM,SAAS,uBAAuB;EACxC,IAAI,+DAA+D,KAAK,OAAO,GAC7E,OAAO,IAAI,2BAA2B,SAAS;GAAE,OAAO;GAAQ;EAAQ,CAAC;EAG3E,OAAO,IAAI,oBAAoB,SAAS;GAAE,OAAO;GAAQ;EAAQ,CAAC;CACpE;CAEA,IACE,MAAM,SAAS,+BACf,MAAM,SAAS,uBACf,eAAe,MAAM,cAAc,GAEnC,OAAO,IAAI,oBAAoB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGpE,OAAO,IAAI,cAAc,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;AAC9D;;;;;;AAOA,SAAS,QAAQ,QAAoC;CACnD,IAAI,OAAO,WAAW,YAAY,WAAW,MAC3C,OAAO,CAAC;CAGV,MAAM,MAAM;CACZ,MAAM,WAAW,IAAI;CAErB,OAAO;EACL,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;EAChD,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU;EACzD,gBACE,YAAY,OAAO,SAAS,mBAAmB,WAC3C,SAAS,iBACT,OAAO,IAAI,WAAW,WACnB,IAAI,SACL;EACR,WAAW,YAAY,OAAO,SAAS,cAAc,WAAW,SAAS,YAAY;EACrF,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;CAClD;AACF;;;;;;AAOA,SAAS,UAAU,OAAmC;CACpD,IAAI,MAAM,QAAQ,cAAc,IAAI,MAAM,IAAI,GAC5C,OAAO;CAGT,OAAO,MAAM,SAAS,eAAe,MAAM,SAAS;AACtD;;AAGA,SAAS,eAAe,QAAqC;CAC3D,OAAO,OAAO,WAAW,YAAY,UAAU,OAAO,SAAS;AACjE;;;;;;AAOA,SAAS,aAAa,OAAmD;CACvE,MAAM,UAAmC,CAAC;CAE1C,IAAI,MAAM,mBAAmB,QAC3B,QAAQ,SAAS,MAAM;CAGzB,IAAI,MAAM,MACR,QAAQ,OAAO,MAAM;CAGvB,IAAI,MAAM,WACR,QAAQ,YAAY,MAAM;CAG5B,OAAO;AACT"}
1
+ {"version":3,"file":"wrap-bedrock-error.mjs","names":[],"sources":["../../../../../../../../packages/ai-bedrock/src/utils/wrap-bedrock-error.ts"],"sourcesContent":["import {\n AIError,\n ContextLengthExceededError,\n InvalidRequestError,\n ProviderAuthError,\n ProviderError,\n ProviderOverloadedError,\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 // Converse `ServiceUnavailableException` (503): the service is\n // temporarily unable to serve the request — retry later.\n // https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html\n if (shape.name === \"ServiceUnavailableException\" || shape.httpStatusCode === 503) {\n return new ProviderOverloadedError(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"],"mappings":";;;AA2BA,MAAM,gBAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,iBAAiB,QAA0B;CACzD,IAAI,kBAAkB,SACpB,OAAO;CAGT,MAAM,QAAQ,QAAQ,MAAM;CAC5B,MAAM,UAAU,aAAa,KAAK;CAClC,MAAM,UAAU,MAAM,YAAY,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;CAE1F,IAAI,UAAU,KAAK,GACjB,OAAO,IAAI,qBAAqB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGrE,IAAI,MAAM,SAAS,2BAA2B,MAAM,mBAAmB,KACrE,OAAO,IAAI,kBAAkB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGlE,IAAI,MAAM,mBAAmB,KAC3B,OAAO,IAAI,kBAAkB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGlE,IAAI,MAAM,SAAS,iCACjB,OAAO,IAAI,mBAAmB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGnE,IAAI,MAAM,SAAS,yBAAyB,MAAM,mBAAmB,KACnE,OAAO,IAAI,uBAAuB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAMvE,IAAI,MAAM,SAAS,iCAAiC,MAAM,mBAAmB,KAC3E,OAAO,IAAI,wBAAwB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGxE,IAAI,MAAM,SAAS,uBAAuB;EACxC,IAAI,+DAA+D,KAAK,OAAO,GAC7E,OAAO,IAAI,2BAA2B,SAAS;GAAE,OAAO;GAAQ;EAAQ,CAAC;EAG3E,OAAO,IAAI,oBAAoB,SAAS;GAAE,OAAO;GAAQ;EAAQ,CAAC;CACpE;CAEA,IACE,MAAM,SAAS,+BACf,MAAM,SAAS,uBACf,eAAe,MAAM,cAAc,GAEnC,OAAO,IAAI,oBAAoB,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;CAGpE,OAAO,IAAI,cAAc,SAAS;EAAE,OAAO;EAAQ;CAAQ,CAAC;AAC9D;;;;;;AAOA,SAAS,QAAQ,QAAoC;CACnD,IAAI,OAAO,WAAW,YAAY,WAAW,MAC3C,OAAO,CAAC;CAGV,MAAM,MAAM;CACZ,MAAM,WAAW,IAAI;CAErB,OAAO;EACL,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;EAChD,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU;EACzD,gBACE,YAAY,OAAO,SAAS,mBAAmB,WAC3C,SAAS,iBACT,OAAO,IAAI,WAAW,WACnB,IAAI,SACL;EACR,WAAW,YAAY,OAAO,SAAS,cAAc,WAAW,SAAS,YAAY;EACrF,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;CAClD;AACF;;;;;;AAOA,SAAS,UAAU,OAAmC;CACpD,IAAI,MAAM,QAAQ,cAAc,IAAI,MAAM,IAAI,GAC5C,OAAO;CAGT,OAAO,MAAM,SAAS,eAAe,MAAM,SAAS;AACtD;;AAGA,SAAS,eAAe,QAAqC;CAC3D,OAAO,OAAO,WAAW,YAAY,UAAU,OAAO,SAAS;AACjE;;;;;;AAOA,SAAS,aAAa,OAAmD;CACvE,MAAM,UAAmC,CAAC;CAE1C,IAAI,MAAM,mBAAmB,QAC3B,QAAQ,SAAS,MAAM;CAGzB,IAAI,MAAM,MACR,QAAQ,OAAO,MAAM;CAGvB,IAAI,MAAM,WACR,QAAQ,YAAY,MAAM;CAG5B,OAAO;AACT"}