@warlock.js/ai-bedrock 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.cjs +808 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/config.type.d.mts +90 -0
- package/esm/config.type.d.mts.map +1 -0
- package/esm/embedder.mjs +117 -0
- package/esm/embedder.mjs.map +1 -0
- package/esm/index.d.mts +3 -0
- package/esm/index.mjs +3 -0
- package/esm/known-vision-models.mjs +50 -0
- package/esm/known-vision-models.mjs.map +1 -0
- package/esm/model.mjs +290 -0
- package/esm/model.mjs.map +1 -0
- package/esm/sdk.d.mts +66 -0
- package/esm/sdk.d.mts.map +1 -0
- package/esm/sdk.mjs +82 -0
- package/esm/sdk.mjs.map +1 -0
- package/esm/utils/index.mjs +6 -0
- package/esm/utils/map-stop-reason.mjs +31 -0
- package/esm/utils/map-stop-reason.mjs.map +1 -0
- package/esm/utils/to-bedrock-messages.mjs +111 -0
- package/esm/utils/to-bedrock-messages.mjs.map +1 -0
- package/esm/utils/to-bedrock-tools.mjs +41 -0
- package/esm/utils/to-bedrock-tools.mjs.map +1 -0
- package/esm/utils/wrap-bedrock-error.mjs +121 -0
- package/esm/utils/wrap-bedrock-error.mjs.map +1 -0
- package/llms-full.txt +153 -0
- package/llms.txt +9 -0
- package/package.json +39 -0
- package/skills/README.md +9 -0
- package/skills/setup-bedrock/SKILL.md +143 -0
package/esm/model.mjs
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { mapStopReason } from "./utils/map-stop-reason.mjs";
|
|
2
|
+
import { toBedrockMessages } from "./utils/to-bedrock-messages.mjs";
|
|
3
|
+
import { toBedrockToolConfig } from "./utils/to-bedrock-tools.mjs";
|
|
4
|
+
import { wrapBedrockError } from "./utils/wrap-bedrock-error.mjs";
|
|
5
|
+
import "./utils/index.mjs";
|
|
6
|
+
import { inferVisionCapability } from "./known-vision-models.mjs";
|
|
7
|
+
import { ConverseCommand, ConverseStreamCommand } from "@aws-sdk/client-bedrock-runtime";
|
|
8
|
+
import { safeJsonParse } from "@warlock.js/ai";
|
|
9
|
+
import { log } from "@warlock.js/logger";
|
|
10
|
+
|
|
11
|
+
//#region ../../@warlock.js/ai-bedrock/src/model.ts
|
|
12
|
+
const LOG_MODULE = "ai.bedrock";
|
|
13
|
+
/**
|
|
14
|
+
* Bedrock-backed implementation of `ModelContract`.
|
|
15
|
+
*
|
|
16
|
+
* **Role.** The provider-facing bridge between the vendor-neutral
|
|
17
|
+
* `@warlock.js/ai` agent runtime and AWS Bedrock's Converse /
|
|
18
|
+
* ConverseStream API. Converse is the model-agnostic surface — one
|
|
19
|
+
* wire mapping covers every Bedrock-hosted family (Anthropic Claude,
|
|
20
|
+
* Amazon Nova, Meta Llama, Mistral, Cohere) instead of per-family
|
|
21
|
+
* `InvokeModel` body shapes.
|
|
22
|
+
*
|
|
23
|
+
* **Responsibility.**
|
|
24
|
+
* - Owns: a long-lived `BedrockRuntimeClient` + frozen `ModelConfig`
|
|
25
|
+
* (modelId, temperature, maxTokens) used as per-call defaults.
|
|
26
|
+
* - Owns: translating vendor-neutral `Message[]` / `ToolConfig[]` into
|
|
27
|
+
* Converse shapes (system hoisting, `toolUse` / `toolResult` blocks,
|
|
28
|
+
* image bytes) on the way out, and Converse's content-block response
|
|
29
|
+
* (text, tool calls, stop reason, token usage) back into the neutral
|
|
30
|
+
* shapes on the way in.
|
|
31
|
+
* - Does NOT own: dispatching tools, looping, history, retries — those
|
|
32
|
+
* are agent concerns. The model is a per-call protocol adapter.
|
|
33
|
+
*
|
|
34
|
+
* Modeled as a class (see §4.2 of code-style.md — "long-lived state
|
|
35
|
+
* across calls"): the AWS client is heavy to construct and reused for
|
|
36
|
+
* the SDK's lifetime.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime";
|
|
40
|
+
* const client = new BedrockRuntimeClient({ region: "us-east-1" });
|
|
41
|
+
* const model = new BedrockModel(client, {
|
|
42
|
+
* name: "anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const myAgent = agent({ model, tools: [searchTool] });
|
|
46
|
+
* const result = await myAgent.execute("Summarize today's news.");
|
|
47
|
+
*/
|
|
48
|
+
var BedrockModel = class {
|
|
49
|
+
constructor(client, config, provider = "bedrock") {
|
|
50
|
+
this.logger = log;
|
|
51
|
+
this.client = client;
|
|
52
|
+
this.config = config;
|
|
53
|
+
this.name = config.name;
|
|
54
|
+
this.provider = provider;
|
|
55
|
+
this.pricing = config.pricing;
|
|
56
|
+
this.capabilities = {
|
|
57
|
+
structuredOutput: config.structuredOutput ?? true,
|
|
58
|
+
vision: config.vision ?? inferVisionCapability(config.name)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Single-shot completion via the Converse API. Sends the full
|
|
63
|
+
* message list, waits for the terminal response, and reshapes it
|
|
64
|
+
* into a vendor-neutral `ModelResponse`. Per-call `options` override
|
|
65
|
+
* the instance defaults for this call only.
|
|
66
|
+
*/
|
|
67
|
+
async complete(messages, options) {
|
|
68
|
+
this.logger.debug(LOG_MODULE, "request", "Starting Converse call", {
|
|
69
|
+
model: this.name,
|
|
70
|
+
messageCount: messages.length,
|
|
71
|
+
streaming: false,
|
|
72
|
+
toolCount: options?.tools?.length ?? 0
|
|
73
|
+
});
|
|
74
|
+
let response;
|
|
75
|
+
try {
|
|
76
|
+
response = await this.client.send(new ConverseCommand(this.buildRequest(messages, options)), options?.signal ? { abortSignal: options.signal } : void 0);
|
|
77
|
+
} catch (thrown) {
|
|
78
|
+
throw this.logAndWrap(thrown);
|
|
79
|
+
}
|
|
80
|
+
const blocks = response.output?.message?.content ?? [];
|
|
81
|
+
const finishReason = mapStopReason(response.stopReason);
|
|
82
|
+
const usage = this.extractUsage(response.usage);
|
|
83
|
+
const toolCalls = this.extractToolCalls(blocks);
|
|
84
|
+
this.logger.debug(LOG_MODULE, "response", "Converse call succeeded", {
|
|
85
|
+
finishReason,
|
|
86
|
+
usage
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
content: this.extractText(blocks),
|
|
90
|
+
finishReason,
|
|
91
|
+
usage,
|
|
92
|
+
toolCalls
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Incremental streaming completion via ConverseStream. Yields neutral
|
|
97
|
+
* `ModelStreamChunk`s — `delta` for text, `tool-call` once a
|
|
98
|
+
* `toolUse` block's accumulated input JSON is complete, and a
|
|
99
|
+
* terminal `done` with the final finish reason + usage totals.
|
|
100
|
+
*/
|
|
101
|
+
async *stream(messages, options) {
|
|
102
|
+
this.logger.debug(LOG_MODULE, "request", "Starting ConverseStream call", {
|
|
103
|
+
model: this.name,
|
|
104
|
+
messageCount: messages.length,
|
|
105
|
+
streaming: true,
|
|
106
|
+
toolCount: options?.tools?.length ?? 0
|
|
107
|
+
});
|
|
108
|
+
let response;
|
|
109
|
+
try {
|
|
110
|
+
response = await this.client.send(new ConverseStreamCommand(this.buildRequest(messages, options)), options?.signal ? { abortSignal: options.signal } : void 0);
|
|
111
|
+
} catch (thrown) {
|
|
112
|
+
throw this.logAndWrap(thrown);
|
|
113
|
+
}
|
|
114
|
+
let rawStopReason;
|
|
115
|
+
const usage = {
|
|
116
|
+
input: 0,
|
|
117
|
+
output: 0,
|
|
118
|
+
total: 0
|
|
119
|
+
};
|
|
120
|
+
const toolBlocks = /* @__PURE__ */ new Map();
|
|
121
|
+
try {
|
|
122
|
+
for await (const event of response.stream ?? []) {
|
|
123
|
+
if (event.contentBlockStart?.start?.toolUse) {
|
|
124
|
+
const start = event.contentBlockStart.start.toolUse;
|
|
125
|
+
toolBlocks.set(event.contentBlockStart.contentBlockIndex ?? 0, {
|
|
126
|
+
id: start.toolUseId ?? "",
|
|
127
|
+
name: start.name ?? "",
|
|
128
|
+
json: ""
|
|
129
|
+
});
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (event.contentBlockDelta?.delta) {
|
|
133
|
+
const delta = event.contentBlockDelta.delta;
|
|
134
|
+
if (delta.text) yield {
|
|
135
|
+
type: "delta",
|
|
136
|
+
content: delta.text
|
|
137
|
+
};
|
|
138
|
+
else if (delta.toolUse) {
|
|
139
|
+
const accumulator = toolBlocks.get(event.contentBlockDelta.contentBlockIndex ?? 0);
|
|
140
|
+
if (accumulator) accumulator.json += delta.toolUse.input ?? "";
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (event.contentBlockStop) {
|
|
145
|
+
const accumulator = toolBlocks.get(event.contentBlockStop.contentBlockIndex ?? 0);
|
|
146
|
+
if (accumulator) {
|
|
147
|
+
yield {
|
|
148
|
+
type: "tool-call",
|
|
149
|
+
id: accumulator.id,
|
|
150
|
+
name: accumulator.name,
|
|
151
|
+
input: safeJsonParse(accumulator.json, {})
|
|
152
|
+
};
|
|
153
|
+
toolBlocks.delete(event.contentBlockStop.contentBlockIndex ?? 0);
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (event.messageStop) rawStopReason = event.messageStop.stopReason;
|
|
158
|
+
if (event.metadata?.usage) {
|
|
159
|
+
const raw = event.metadata.usage;
|
|
160
|
+
usage.input = raw.inputTokens ?? 0;
|
|
161
|
+
usage.output = raw.outputTokens ?? 0;
|
|
162
|
+
usage.total = raw.totalTokens ?? usage.input + usage.output;
|
|
163
|
+
if (raw.cacheReadInputTokens && raw.cacheReadInputTokens > 0) usage.cachedTokens = raw.cacheReadInputTokens;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (thrown) {
|
|
167
|
+
throw this.logAndWrap(thrown);
|
|
168
|
+
}
|
|
169
|
+
const finishReason = mapStopReason(rawStopReason);
|
|
170
|
+
this.logger.debug(LOG_MODULE, "response", "ConverseStream call succeeded", {
|
|
171
|
+
finishReason,
|
|
172
|
+
usage
|
|
173
|
+
});
|
|
174
|
+
yield {
|
|
175
|
+
type: "done",
|
|
176
|
+
finishReason,
|
|
177
|
+
usage
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Assemble the Converse request shared by `complete()` and
|
|
182
|
+
* `stream()` (both command shapes take the same input). Hoists the
|
|
183
|
+
* system prompt, maps inference params, and conditionally attaches
|
|
184
|
+
* tools and native structured output.
|
|
185
|
+
*/
|
|
186
|
+
buildRequest(messages, options) {
|
|
187
|
+
const { system, messages: bedrockMessages } = toBedrockMessages(messages);
|
|
188
|
+
const maxTokens = options?.maxTokens ?? this.config.maxTokens;
|
|
189
|
+
const temperature = options?.temperature ?? this.config.temperature;
|
|
190
|
+
return {
|
|
191
|
+
modelId: this.name,
|
|
192
|
+
messages: bedrockMessages,
|
|
193
|
+
...system ? { system } : {},
|
|
194
|
+
inferenceConfig: {
|
|
195
|
+
...maxTokens !== void 0 ? { maxTokens } : {},
|
|
196
|
+
...temperature !== void 0 ? { temperature } : {}
|
|
197
|
+
},
|
|
198
|
+
...this.buildToolConfig(options?.tools),
|
|
199
|
+
...this.buildOutputConfig(options?.responseSchema)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Spread-friendly tool fragment. Returns an empty object when no
|
|
204
|
+
* tools were supplied (Bedrock rejects an empty `tools` array).
|
|
205
|
+
*/
|
|
206
|
+
buildToolConfig(tools) {
|
|
207
|
+
const toolConfig = toBedrockToolConfig(tools);
|
|
208
|
+
return toolConfig ? { toolConfig } : {};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Translate the neutral `responseSchema` into Converse's native
|
|
212
|
+
* `outputConfig.textFormat` (JSON-schema structured output). Bedrock
|
|
213
|
+
* requires the schema as a stringified JSON document and only
|
|
214
|
+
* accepts an object root. Emitted only when the model is
|
|
215
|
+
* `structuredOutput`-capable and the schema is an object — otherwise
|
|
216
|
+
* the agent's soft system-prompt hint + client-side `validate()`
|
|
217
|
+
* carry shape (same degradation philosophy as the OpenAI adapter).
|
|
218
|
+
*/
|
|
219
|
+
buildOutputConfig(responseSchema) {
|
|
220
|
+
if (!responseSchema || !this.capabilities.structuredOutput) return {};
|
|
221
|
+
if (responseSchema.type !== "object" || typeof responseSchema.properties !== "object") return {};
|
|
222
|
+
return { outputConfig: { textFormat: {
|
|
223
|
+
type: "json_schema",
|
|
224
|
+
structure: { jsonSchema: {
|
|
225
|
+
name: "response",
|
|
226
|
+
schema: JSON.stringify(responseSchema)
|
|
227
|
+
} }
|
|
228
|
+
} } };
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Concatenate every `text` content block into the single neutral
|
|
232
|
+
* `content` string. `toolUse` and other block types are surfaced
|
|
233
|
+
* separately via `extractToolCalls`.
|
|
234
|
+
*/
|
|
235
|
+
extractText(blocks) {
|
|
236
|
+
return blocks.map((block) => "text" in block && typeof block.text === "string" ? block.text : "").join("");
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Reshape Converse `toolUse` content blocks into the neutral
|
|
240
|
+
* `ModelToolCallRequest[]`. Returns `undefined` when no tools were
|
|
241
|
+
* requested so callers can branch on presence.
|
|
242
|
+
*/
|
|
243
|
+
extractToolCalls(blocks) {
|
|
244
|
+
const toolCalls = [];
|
|
245
|
+
for (const block of blocks) if ("toolUse" in block && block.toolUse) toolCalls.push({
|
|
246
|
+
id: block.toolUse.toolUseId ?? "",
|
|
247
|
+
name: block.toolUse.name ?? "",
|
|
248
|
+
input: block.toolUse.input ?? {}
|
|
249
|
+
});
|
|
250
|
+
return toolCalls.length > 0 ? toolCalls : void 0;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Normalize Converse's `TokenUsage` into the neutral `Usage` shape.
|
|
254
|
+
* Bedrock supplies a pre-summed `totalTokens`; cache-read tokens are
|
|
255
|
+
* surfaced as `cachedTokens` only when non-zero.
|
|
256
|
+
*/
|
|
257
|
+
extractUsage(raw) {
|
|
258
|
+
if (!raw) return {
|
|
259
|
+
input: 0,
|
|
260
|
+
output: 0,
|
|
261
|
+
total: 0
|
|
262
|
+
};
|
|
263
|
+
const input = raw.inputTokens ?? 0;
|
|
264
|
+
const output = raw.outputTokens ?? 0;
|
|
265
|
+
const cached = raw.cacheReadInputTokens;
|
|
266
|
+
return {
|
|
267
|
+
input,
|
|
268
|
+
output,
|
|
269
|
+
total: raw.totalTokens ?? input + output,
|
|
270
|
+
...cached && cached > 0 ? { cachedTokens: cached } : {}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Wrap a thrown provider error into the typed `AIError` hierarchy
|
|
275
|
+
* and emit the standard error log line before it propagates. Shared
|
|
276
|
+
* by every catch site so the log shape stays identical.
|
|
277
|
+
*/
|
|
278
|
+
logAndWrap(thrown) {
|
|
279
|
+
const wrapped = wrapBedrockError(thrown);
|
|
280
|
+
this.logger.error(LOG_MODULE, "error", wrapped.message, {
|
|
281
|
+
code: wrapped.code,
|
|
282
|
+
context: wrapped.context
|
|
283
|
+
});
|
|
284
|
+
return wrapped;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
//#endregion
|
|
289
|
+
export { BedrockModel };
|
|
290
|
+
//# sourceMappingURL=model.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.mjs","names":[],"sources":["../../../../../@warlock.js/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 { inferVisionCapability } from \"./known-vision-models\";\nimport { mapStopReason, toBedrockMessages, toBedrockToolConfig, wrapBedrockError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.bedrock\";\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 };\n }\n\n /**\n * Single-shot completion via the Converse API. Sends the full\n * message list, waits for the terminal response, and reshapes it\n * into a vendor-neutral `ModelResponse`. Per-call `options` override\n * the instance defaults for this call only.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting Converse call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: false,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const blocks = response.output?.message?.content ?? [];\n const finishReason = mapStopReason(response.stopReason);\n const usage = this.extractUsage(response.usage);\n const toolCalls = this.extractToolCalls(blocks);\n\n this.logger.debug(LOG_MODULE, \"response\", \"Converse call succeeded\", { finishReason, usage });\n\n return {\n content: this.extractText(blocks),\n finishReason,\n usage,\n toolCalls,\n };\n }\n\n /**\n * Incremental streaming completion via ConverseStream. Yields neutral\n * `ModelStreamChunk`s — `delta` for text, `tool-call` once a\n * `toolUse` block's accumulated input JSON is complete, and a\n * terminal `done` with the final finish reason + usage totals.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.logger.debug(LOG_MODULE, \"request\", \"Starting ConverseStream call\", {\n model: this.name,\n messageCount: messages.length,\n streaming: true,\n toolCount: options?.tools?.length ?? 0,\n });\n\n let response;\n\n try {\n response = await this.client.send(\n new ConverseStreamCommand(this.buildRequest(messages, options)),\n options?.signal ? { abortSignal: options.signal } : undefined,\n );\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n let rawStopReason: string | undefined;\n const usage: Usage = { input: 0, output: 0, total: 0 };\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n try {\n for await (const event of response.stream ?? []) {\n if (event.contentBlockStart?.start?.toolUse) {\n const start = event.contentBlockStart.start.toolUse;\n\n toolBlocks.set(event.contentBlockStart.contentBlockIndex ?? 0, {\n id: start.toolUseId ?? \"\",\n name: start.name ?? \"\",\n json: \"\",\n });\n\n continue;\n }\n\n if (event.contentBlockDelta?.delta) {\n const delta = event.contentBlockDelta.delta;\n\n if (delta.text) {\n yield { type: \"delta\", content: delta.text };\n } else if (delta.toolUse) {\n const accumulator = toolBlocks.get(event.contentBlockDelta.contentBlockIndex ?? 0);\n\n if (accumulator) {\n accumulator.json += delta.toolUse.input ?? \"\";\n }\n }\n\n continue;\n }\n\n if (event.contentBlockStop) {\n const accumulator = toolBlocks.get(event.contentBlockStop.contentBlockIndex ?? 0);\n\n if (accumulator) {\n yield {\n type: \"tool-call\",\n id: accumulator.id,\n name: accumulator.name,\n input: safeJsonParse<Record<string, unknown>>(accumulator.json, {}),\n };\n\n toolBlocks.delete(event.contentBlockStop.contentBlockIndex ?? 0);\n }\n\n continue;\n }\n\n if (event.messageStop) {\n rawStopReason = event.messageStop.stopReason;\n }\n\n if (event.metadata?.usage) {\n const raw = event.metadata.usage;\n\n usage.input = raw.inputTokens ?? 0;\n usage.output = raw.outputTokens ?? 0;\n usage.total = raw.totalTokens ?? usage.input + usage.output;\n\n if (raw.cacheReadInputTokens && raw.cacheReadInputTokens > 0) {\n usage.cachedTokens = raw.cacheReadInputTokens;\n }\n }\n }\n } catch (thrown) {\n throw this.logAndWrap(thrown);\n }\n\n const finishReason = mapStopReason(rawStopReason);\n\n this.logger.debug(LOG_MODULE, \"response\", \"ConverseStream call succeeded\", {\n finishReason,\n usage,\n });\n\n yield { type: \"done\", finishReason, usage };\n }\n\n /**\n * Assemble the Converse request shared by `complete()` and\n * `stream()` (both command shapes take the same input). Hoists the\n * system prompt, maps inference params, and conditionally attaches\n * tools and native structured output.\n */\n private buildRequest(\n messages: Message[],\n options: ModelCallOptions | undefined,\n ): ConverseRequest {\n const { system, messages: bedrockMessages } = toBedrockMessages(messages);\n const maxTokens = options?.maxTokens ?? this.config.maxTokens;\n const temperature = options?.temperature ?? this.config.temperature;\n\n return {\n modelId: this.name,\n messages: bedrockMessages,\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 };\n }\n\n /**\n * Spread-friendly tool fragment. Returns an empty object when no\n * tools were supplied (Bedrock rejects an empty `tools` array).\n */\n private buildToolConfig(tools: ModelCallOptions[\"tools\"]): Pick<ConverseRequest, \"toolConfig\"> {\n const toolConfig = toBedrockToolConfig(tools);\n\n return toolConfig ? { toolConfig } : {};\n }\n\n /**\n * Translate the neutral `responseSchema` into Converse's native\n * `outputConfig.textFormat` (JSON-schema structured output). Bedrock\n * requires the schema as a stringified JSON document and only\n * accepts an object root. Emitted only when the model is\n * `structuredOutput`-capable and the schema is an object — otherwise\n * the agent's soft system-prompt hint + client-side `validate()`\n * carry shape (same degradation philosophy as the OpenAI adapter).\n */\n private buildOutputConfig(\n responseSchema: Record<string, unknown> | undefined,\n ): Pick<ConverseRequest, \"outputConfig\"> {\n if (!responseSchema || !this.capabilities.structuredOutput) {\n return {};\n }\n\n if (responseSchema.type !== \"object\" || typeof responseSchema.properties !== \"object\") {\n return {};\n }\n\n return {\n outputConfig: {\n textFormat: {\n type: \"json_schema\",\n structure: {\n jsonSchema: { name: \"response\", schema: JSON.stringify(responseSchema) },\n },\n },\n },\n };\n }\n\n /**\n * Concatenate every `text` content block into the single neutral\n * `content` string. `toolUse` and other block types are surfaced\n * separately via `extractToolCalls`.\n */\n private extractText(blocks: ContentBlock[]): string {\n return blocks\n .map((block) => (\"text\" in block && typeof block.text === \"string\" ? block.text : \"\"))\n .join(\"\");\n }\n\n /**\n * Reshape Converse `toolUse` content blocks into the neutral\n * `ModelToolCallRequest[]`. Returns `undefined` when no tools were\n * requested so callers can branch on presence.\n */\n private extractToolCalls(blocks: ContentBlock[]): ModelToolCallRequest[] | undefined {\n const toolCalls: ModelToolCallRequest[] = [];\n\n for (const block of blocks) {\n if (\"toolUse\" in block && block.toolUse) {\n toolCalls.push({\n id: block.toolUse.toolUseId ?? \"\",\n name: block.toolUse.name ?? \"\",\n input: (block.toolUse.input ?? {}) as Record<string, unknown>,\n });\n }\n }\n\n return toolCalls.length > 0 ? toolCalls : undefined;\n }\n\n /**\n * Normalize Converse's `TokenUsage` into the neutral `Usage` shape.\n * Bedrock supplies a pre-summed `totalTokens`; cache-read tokens are\n * surfaced as `cachedTokens` only when non-zero.\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\n return {\n input,\n output,\n total: raw.totalTokens ?? input + output,\n ...(cached && cached > 0 ? { cachedTokens: cached } : {}),\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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"}
|
package/esm/sdk.d.mts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { BedrockEmbedderConfig, BedrockModelConfig, BedrockSDKConfig } from "./config.type.mjs";
|
|
2
|
+
import { EmbedderContract, ModelContract, SDKAdapterContract } from "@warlock.js/ai";
|
|
3
|
+
|
|
4
|
+
//#region ../../@warlock.js/ai-bedrock/src/sdk.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* AWS Bedrock-backed implementation of `SDKAdapterContract`.
|
|
7
|
+
*
|
|
8
|
+
* **Role.** The package entry point for any Bedrock-hosted model via
|
|
9
|
+
* the Converse API. A single `BedrockSDK` holds one live
|
|
10
|
+
* `BedrockRuntimeClient`, shared by every `ModelContract` and
|
|
11
|
+
* `EmbedderContract` it produces. Construct one SDK per AWS
|
|
12
|
+
* account/region and reuse it everywhere.
|
|
13
|
+
*
|
|
14
|
+
* **Responsibility.**
|
|
15
|
+
* - Owns: a long-lived `BedrockRuntimeClient` (region, credential
|
|
16
|
+
* chain) and its lifetime. Factory for `BedrockModel` /
|
|
17
|
+
* `BedrockEmbedder` instances sharing that client.
|
|
18
|
+
* - Does NOT own: anything per-call — those live in `BedrockModel` /
|
|
19
|
+
* `BedrockEmbedder` and the agent runtime.
|
|
20
|
+
*
|
|
21
|
+
* Modeled as a class (see §4.2 of code-style.md — "long-lived state
|
|
22
|
+
* across many calls"): the AWS client is heavy to construct and
|
|
23
|
+
* designed for reuse; keeping it on `this` aligns with the
|
|
24
|
+
* `new BedrockRuntimeClient(...)` upstream convention.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* const bedrock = new BedrockSDK({ region: "us-east-1" });
|
|
28
|
+
* const model = bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" });
|
|
29
|
+
* const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
|
|
30
|
+
*/
|
|
31
|
+
declare class BedrockSDK implements SDKAdapterContract {
|
|
32
|
+
private readonly client;
|
|
33
|
+
private readonly provider;
|
|
34
|
+
private readonly pricing?;
|
|
35
|
+
constructor(config: BedrockSDKConfig);
|
|
36
|
+
/**
|
|
37
|
+
* Build a `BedrockModel` bound to this SDK's client. Each call
|
|
38
|
+
* returns a fresh instance; all instances share the underlying AWS
|
|
39
|
+
* client so connection pools, credential refresh, and retry config
|
|
40
|
+
* stay unified. The SDK's `provider` label is forwarded.
|
|
41
|
+
*
|
|
42
|
+
* Pricing resolution: per-model `config.pricing` wins; otherwise the
|
|
43
|
+
* SDK-level registry entry keyed by `config.name`; otherwise
|
|
44
|
+
* `undefined` (no cost computed).
|
|
45
|
+
*/
|
|
46
|
+
model(config: BedrockModelConfig): ModelContract;
|
|
47
|
+
/**
|
|
48
|
+
* Rough token-count estimate. Uses the character-heuristic
|
|
49
|
+
* (`approximateTokenCount`) from the core package — Bedrock has no
|
|
50
|
+
* offline tokenizer and the per-model tokenizers differ; good enough
|
|
51
|
+
* for budgeting and quota guards, not for billing.
|
|
52
|
+
*/
|
|
53
|
+
count(text: string, _model?: string): Promise<number>;
|
|
54
|
+
/**
|
|
55
|
+
* Build a `BedrockEmbedder` (Amazon Titan Text Embeddings) bound to
|
|
56
|
+
* this SDK's client.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
|
|
60
|
+
* const { vector } = await embedder.embed("Hello world");
|
|
61
|
+
*/
|
|
62
|
+
embedder(config: BedrockEmbedderConfig): EmbedderContract;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { BedrockSDK };
|
|
66
|
+
//# sourceMappingURL=sdk.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../@warlock.js/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"}
|
package/esm/sdk.mjs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { BedrockEmbedder } from "./embedder.mjs";
|
|
2
|
+
import { BedrockModel } from "./model.mjs";
|
|
3
|
+
import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime";
|
|
4
|
+
import { approximateTokenCount } from "@warlock.js/ai";
|
|
5
|
+
|
|
6
|
+
//#region ../../@warlock.js/ai-bedrock/src/sdk.ts
|
|
7
|
+
/**
|
|
8
|
+
* AWS Bedrock-backed implementation of `SDKAdapterContract`.
|
|
9
|
+
*
|
|
10
|
+
* **Role.** The package entry point for any Bedrock-hosted model via
|
|
11
|
+
* the Converse API. A single `BedrockSDK` holds one live
|
|
12
|
+
* `BedrockRuntimeClient`, shared by every `ModelContract` and
|
|
13
|
+
* `EmbedderContract` it produces. Construct one SDK per AWS
|
|
14
|
+
* account/region and reuse it everywhere.
|
|
15
|
+
*
|
|
16
|
+
* **Responsibility.**
|
|
17
|
+
* - Owns: a long-lived `BedrockRuntimeClient` (region, credential
|
|
18
|
+
* chain) and its lifetime. Factory for `BedrockModel` /
|
|
19
|
+
* `BedrockEmbedder` instances sharing that client.
|
|
20
|
+
* - Does NOT own: anything per-call — those live in `BedrockModel` /
|
|
21
|
+
* `BedrockEmbedder` and the agent runtime.
|
|
22
|
+
*
|
|
23
|
+
* Modeled as a class (see §4.2 of code-style.md — "long-lived state
|
|
24
|
+
* across many calls"): the AWS client is heavy to construct and
|
|
25
|
+
* designed for reuse; keeping it on `this` aligns with the
|
|
26
|
+
* `new BedrockRuntimeClient(...)` upstream convention.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const bedrock = new BedrockSDK({ region: "us-east-1" });
|
|
30
|
+
* const model = bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" });
|
|
31
|
+
* const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
|
|
32
|
+
*/
|
|
33
|
+
var BedrockSDK = class {
|
|
34
|
+
constructor(config) {
|
|
35
|
+
const { provider, pricing, ...clientConfig } = config;
|
|
36
|
+
this.client = new BedrockRuntimeClient(clientConfig);
|
|
37
|
+
this.provider = provider ?? "bedrock";
|
|
38
|
+
this.pricing = pricing;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build a `BedrockModel` bound to this SDK's client. Each call
|
|
42
|
+
* returns a fresh instance; all instances share the underlying AWS
|
|
43
|
+
* client so connection pools, credential refresh, and retry config
|
|
44
|
+
* stay unified. The SDK's `provider` label is forwarded.
|
|
45
|
+
*
|
|
46
|
+
* Pricing resolution: per-model `config.pricing` wins; otherwise the
|
|
47
|
+
* SDK-level registry entry keyed by `config.name`; otherwise
|
|
48
|
+
* `undefined` (no cost computed).
|
|
49
|
+
*/
|
|
50
|
+
model(config) {
|
|
51
|
+
const resolvedPricing = config.pricing ?? this.pricing?.[config.name];
|
|
52
|
+
const resolvedConfig = resolvedPricing === config.pricing ? config : {
|
|
53
|
+
...config,
|
|
54
|
+
pricing: resolvedPricing
|
|
55
|
+
};
|
|
56
|
+
return new BedrockModel(this.client, resolvedConfig, this.provider);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Rough token-count estimate. Uses the character-heuristic
|
|
60
|
+
* (`approximateTokenCount`) from the core package — Bedrock has no
|
|
61
|
+
* offline tokenizer and the per-model tokenizers differ; good enough
|
|
62
|
+
* for budgeting and quota guards, not for billing.
|
|
63
|
+
*/
|
|
64
|
+
async count(text, _model) {
|
|
65
|
+
return approximateTokenCount(text);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build a `BedrockEmbedder` (Amazon Titan Text Embeddings) bound to
|
|
69
|
+
* this SDK's client.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
|
|
73
|
+
* const { vector } = await embedder.embed("Hello world");
|
|
74
|
+
*/
|
|
75
|
+
embedder(config) {
|
|
76
|
+
return new BedrockEmbedder(this.client, config, this.provider);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
export { BedrockSDK };
|
|
82
|
+
//# sourceMappingURL=sdk.mjs.map
|
package/esm/sdk.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../@warlock.js/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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region ../../@warlock.js/ai-bedrock/src/utils/map-stop-reason.ts
|
|
2
|
+
const stopReasonMap = {
|
|
3
|
+
end_turn: "stop",
|
|
4
|
+
stop_sequence: "stop",
|
|
5
|
+
max_tokens: "length",
|
|
6
|
+
tool_use: "tool_calls"
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Map Bedrock Converse's `stopReason` to the normalized `FinishReason`
|
|
10
|
+
* union.
|
|
11
|
+
*
|
|
12
|
+
* `end_turn` / `stop_sequence` are natural stops. `max_tokens` maps to
|
|
13
|
+
* `length`. `tool_use` maps to `tool_calls`. Everything else —
|
|
14
|
+
* `content_filtered`, `guardrail_intervened`, `malformed_tool_use`,
|
|
15
|
+
* `malformed_model_output`, `model_context_window_exceeded`, `null`,
|
|
16
|
+
* or any future value — falls through to `"error"`: none produced a
|
|
17
|
+
* clean terminal answer, so the agent must not treat them as success.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* mapStopReason("end_turn"); // "stop"
|
|
21
|
+
* mapStopReason("tool_use"); // "tool_calls"
|
|
22
|
+
* mapStopReason("guardrail_intervened"); // "error"
|
|
23
|
+
* mapStopReason(undefined); // "error"
|
|
24
|
+
*/
|
|
25
|
+
function mapStopReason(raw) {
|
|
26
|
+
return stopReasonMap[raw ?? ""] ?? "error";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { mapStopReason };
|
|
31
|
+
//# sourceMappingURL=map-stop-reason.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map-stop-reason.mjs","names":[],"sources":["../../../../../../@warlock.js/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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { InvalidRequestError } from "@warlock.js/ai";
|
|
2
|
+
|
|
3
|
+
//#region ../../@warlock.js/ai-bedrock/src/utils/to-bedrock-messages.ts
|
|
4
|
+
const MEDIA_TYPE_TO_FORMAT = {
|
|
5
|
+
"image/jpeg": "jpeg",
|
|
6
|
+
"image/png": "png",
|
|
7
|
+
"image/gif": "gif",
|
|
8
|
+
"image/webp": "webp"
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Convert vendor-neutral `Message[]` into Bedrock Converse's request
|
|
12
|
+
* shape.
|
|
13
|
+
*
|
|
14
|
+
* Converse differs from the OpenAI Chat protocol in three ways this
|
|
15
|
+
* function absorbs:
|
|
16
|
+
*
|
|
17
|
+
* 1. **No `system` role.** System messages become a separate
|
|
18
|
+
* `SystemContentBlock[]` (one `{ text }` block each).
|
|
19
|
+
* 2. **Tool results are `user` turns.** A neutral `tool` message
|
|
20
|
+
* becomes a `user` message carrying a single `toolResult` block.
|
|
21
|
+
* 3. **Tool calls are `toolUse` content blocks.** An assistant message
|
|
22
|
+
* with `toolCalls` becomes an `assistant` message: an optional
|
|
23
|
+
* leading `text` block followed by one `toolUse` block per call.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const { system, messages } = toBedrockMessages([
|
|
27
|
+
* { role: "system", content: "Be concise." },
|
|
28
|
+
* { role: "user", content: "Hi" },
|
|
29
|
+
* ]);
|
|
30
|
+
*/
|
|
31
|
+
function toBedrockMessages(messages) {
|
|
32
|
+
const system = [];
|
|
33
|
+
const mapped = [];
|
|
34
|
+
for (const message of messages) {
|
|
35
|
+
if (message.role === "system") {
|
|
36
|
+
system.push({ text: stringifyContent(message.content) });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (message.role === "tool") {
|
|
40
|
+
mapped.push({
|
|
41
|
+
role: "user",
|
|
42
|
+
content: [{ toolResult: {
|
|
43
|
+
toolUseId: message.toolCallId ?? "",
|
|
44
|
+
content: [{ text: stringifyContent(message.content) }]
|
|
45
|
+
} }]
|
|
46
|
+
});
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
|
|
50
|
+
const blocks = [];
|
|
51
|
+
const text = stringifyContent(message.content);
|
|
52
|
+
if (text) blocks.push({ text });
|
|
53
|
+
for (const toolCall of message.toolCalls) blocks.push({ toolUse: {
|
|
54
|
+
toolUseId: toolCall.id,
|
|
55
|
+
name: toolCall.name,
|
|
56
|
+
input: toolCall.input ?? {}
|
|
57
|
+
} });
|
|
58
|
+
mapped.push({
|
|
59
|
+
role: "assistant",
|
|
60
|
+
content: blocks
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
65
|
+
mapped.push({
|
|
66
|
+
role: "user",
|
|
67
|
+
content: message.content.map(toBedrockContentBlock)
|
|
68
|
+
});
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
mapped.push({
|
|
72
|
+
role: message.role === "assistant" ? "assistant" : "user",
|
|
73
|
+
content: [{ text: stringifyContent(message.content) }]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
system: system.length > 0 ? system : void 0,
|
|
78
|
+
messages: mapped
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Multipart content is only meaningful on user messages — for any other
|
|
83
|
+
* role collapse a `ContentPart[]` to its concatenated text. Plain
|
|
84
|
+
* strings pass through unchanged.
|
|
85
|
+
*/
|
|
86
|
+
function stringifyContent(content) {
|
|
87
|
+
if (typeof content === "string") return content;
|
|
88
|
+
return content.filter((part) => part.type === "text").map((part) => part.text).join("");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Map a resolved `ContentPart` to a Bedrock `ContentBlock`. Bedrock's
|
|
92
|
+
* `ImageSource` only accepts raw bytes or an S3 location — there is no
|
|
93
|
+
* remote-URL source. A neutral `{ url }` image therefore cannot be
|
|
94
|
+
* sent and surfaces a typed `InvalidRequestError` upfront rather than
|
|
95
|
+
* a downstream Bedrock validation fault. The agent has already
|
|
96
|
+
* resolved attachments, so this never fetches or reads anything.
|
|
97
|
+
*/
|
|
98
|
+
function toBedrockContentBlock(part) {
|
|
99
|
+
if (part.type === "text") return { text: part.text };
|
|
100
|
+
if ("url" in part.source) throw new InvalidRequestError("Bedrock Converse does not support remote-URL image sources; supply base64 image bytes instead.");
|
|
101
|
+
const format = MEDIA_TYPE_TO_FORMAT[part.source.mediaType];
|
|
102
|
+
if (!format) throw new InvalidRequestError(`Unsupported image media type for Bedrock: "${part.source.mediaType}" (expected image/jpeg, image/png, image/gif, or image/webp).`);
|
|
103
|
+
return { image: {
|
|
104
|
+
format,
|
|
105
|
+
source: { bytes: Buffer.from(part.source.base64, "base64") }
|
|
106
|
+
} };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
//#endregion
|
|
110
|
+
export { toBedrockMessages };
|
|
111
|
+
//# sourceMappingURL=to-bedrock-messages.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-bedrock-messages.mjs","names":[],"sources":["../../../../../../@warlock.js/ai-bedrock/src/utils/to-bedrock-messages.ts"],"sourcesContent":["import { InvalidRequestError, type ContentPart, type Message } from \"@warlock.js/ai\";\nimport type {\n ContentBlock,\n ImageFormat,\n Message as BedrockMessage,\n SystemContentBlock,\n} from \"@aws-sdk/client-bedrock-runtime\";\n\n/**\n * Result of splitting a vendor-neutral `Message[]` for the Bedrock\n * Converse API: system prompts hoist to a separate `SystemContentBlock[]`\n * (Converse has no `\"system\"` role inside `messages`), and the\n * remaining turns map to Bedrock `Message[]`.\n */\nexport type BedrockMessages = {\n system: SystemContentBlock[] | undefined;\n messages: BedrockMessage[];\n};\n\nconst MEDIA_TYPE_TO_FORMAT: Record<string, ImageFormat> = {\n \"image/jpeg\": \"jpeg\",\n \"image/png\": \"png\",\n \"image/gif\": \"gif\",\n \"image/webp\": \"webp\",\n};\n\n/**\n * Convert vendor-neutral `Message[]` into Bedrock Converse's request\n * shape.\n *\n * Converse differs from the OpenAI Chat protocol in three ways this\n * function absorbs:\n *\n * 1. **No `system` role.** System messages become a separate\n * `SystemContentBlock[]` (one `{ text }` block each).\n * 2. **Tool results are `user` turns.** A neutral `tool` message\n * becomes a `user` message carrying a single `toolResult` block.\n * 3. **Tool calls are `toolUse` content blocks.** An assistant message\n * with `toolCalls` becomes an `assistant` message: an optional\n * leading `text` block followed by one `toolUse` block per call.\n *\n * @example\n * const { system, messages } = toBedrockMessages([\n * { role: \"system\", content: \"Be concise.\" },\n * { role: \"user\", content: \"Hi\" },\n * ]);\n */\nexport function toBedrockMessages(messages: Message[]): BedrockMessages {\n const system: SystemContentBlock[] = [];\n const mapped: BedrockMessage[] = [];\n\n for (const message of messages) {\n if (message.role === \"system\") {\n system.push({ text: stringifyContent(message.content) });\n\n continue;\n }\n\n if (message.role === \"tool\") {\n mapped.push({\n role: \"user\",\n content: [\n {\n toolResult: {\n toolUseId: message.toolCallId ?? \"\",\n content: [{ text: stringifyContent(message.content) }],\n },\n },\n ],\n });\n\n continue;\n }\n\n if (message.role === \"assistant\" && message.toolCalls && message.toolCalls.length > 0) {\n const blocks: ContentBlock[] = [];\n const text = stringifyContent(message.content);\n\n if (text) {\n blocks.push({ text });\n }\n\n for (const toolCall of message.toolCalls) {\n blocks.push({\n toolUse: {\n toolUseId: toolCall.id,\n name: toolCall.name,\n input: toolCall.input ?? {},\n },\n } as ContentBlock);\n }\n\n mapped.push({ role: \"assistant\", content: blocks });\n\n continue;\n }\n\n if (message.role === \"user\" && Array.isArray(message.content)) {\n mapped.push({\n role: \"user\",\n content: message.content.map(toBedrockContentBlock),\n });\n\n continue;\n }\n\n mapped.push({\n role: message.role === \"assistant\" ? \"assistant\" : \"user\",\n content: [{ text: stringifyContent(message.content) }],\n });\n }\n\n return {\n system: system.length > 0 ? system : undefined,\n messages: mapped,\n };\n}\n\n/**\n * Multipart content is only meaningful on user messages — for any other\n * role collapse a `ContentPart[]` to its concatenated text. Plain\n * strings pass through unchanged.\n */\nfunction stringifyContent(content: string | ContentPart[]): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n return content\n .filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n}\n\n/**\n * Map a resolved `ContentPart` to a Bedrock `ContentBlock`. Bedrock's\n * `ImageSource` only accepts raw bytes or an S3 location — there is no\n * remote-URL source. A neutral `{ url }` image therefore cannot be\n * sent and surfaces a typed `InvalidRequestError` upfront rather than\n * a downstream Bedrock validation fault. The agent has already\n * resolved attachments, so this never fetches or reads anything.\n */\nfunction toBedrockContentBlock(part: ContentPart): ContentBlock {\n if (part.type === \"text\") {\n return { text: part.text };\n }\n\n if (\"url\" in part.source) {\n throw new InvalidRequestError(\n \"Bedrock Converse does not support remote-URL image sources; supply base64 image bytes instead.\",\n );\n }\n\n const format = MEDIA_TYPE_TO_FORMAT[part.source.mediaType];\n\n if (!format) {\n throw new InvalidRequestError(\n `Unsupported image media type for Bedrock: \"${part.source.mediaType}\" (expected image/jpeg, image/png, image/gif, or image/webp).`,\n );\n }\n\n return {\n image: {\n format,\n source: { bytes: Buffer.from(part.source.base64, \"base64\") },\n },\n };\n}\n"],"mappings":";;;AAmBA,MAAM,uBAAoD;CACxD,cAAc;CACd,aAAa;CACb,aAAa;CACb,cAAc;AAChB;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,UAAsC;CACtE,MAAM,SAA+B,CAAC;CACtC,MAAM,SAA2B,CAAC;CAElC,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,QAAQ,SAAS,UAAU;GAC7B,OAAO,KAAK,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;GAEvD;EACF;EAEA,IAAI,QAAQ,SAAS,QAAQ;GAC3B,OAAO,KAAK;IACV,MAAM;IACN,SAAS,CACP,EACE,YAAY;KACV,WAAW,QAAQ,cAAc;KACjC,SAAS,CAAC,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;IACvD,EACF,CACF;GACF,CAAC;GAED;EACF;EAEA,IAAI,QAAQ,SAAS,eAAe,QAAQ,aAAa,QAAQ,UAAU,SAAS,GAAG;GACrF,MAAM,SAAyB,CAAC;GAChC,MAAM,OAAO,iBAAiB,QAAQ,OAAO;GAE7C,IAAI,MACF,OAAO,KAAK,EAAE,KAAK,CAAC;GAGtB,KAAK,MAAM,YAAY,QAAQ,WAC7B,OAAO,KAAK,EACV,SAAS;IACP,WAAW,SAAS;IACpB,MAAM,SAAS;IACf,OAAO,SAAS,SAAS,CAAC;GAC5B,EACF,CAAiB;GAGnB,OAAO,KAAK;IAAE,MAAM;IAAa,SAAS;GAAO,CAAC;GAElD;EACF;EAEA,IAAI,QAAQ,SAAS,UAAU,MAAM,QAAQ,QAAQ,OAAO,GAAG;GAC7D,OAAO,KAAK;IACV,MAAM;IACN,SAAS,QAAQ,QAAQ,IAAI,qBAAqB;GACpD,CAAC;GAED;EACF;EAEA,OAAO,KAAK;GACV,MAAM,QAAQ,SAAS,cAAc,cAAc;GACnD,SAAS,CAAC,EAAE,MAAM,iBAAiB,QAAQ,OAAO,EAAE,CAAC;EACvD,CAAC;CACH;CAEA,OAAO;EACL,QAAQ,OAAO,SAAS,IAAI,SAAS;EACrC,UAAU;CACZ;AACF;;;;;;AAOA,SAAS,iBAAiB,SAAyC;CACjE,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,OAAO,QACJ,QAAQ,SAAiD,KAAK,SAAS,MAAM,EAC7E,KAAK,SAAS,KAAK,IAAI,EACvB,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,gGACF;CAGF,MAAM,SAAS,qBAAqB,KAAK,OAAO;CAEhD,IAAI,CAAC,QACH,MAAM,IAAI,oBACR,8CAA8C,KAAK,OAAO,UAAU,8DACtE;CAGF,OAAO,EACL,OAAO;EACL;EACA,QAAQ,EAAE,OAAO,OAAO,KAAK,KAAK,OAAO,QAAQ,QAAQ,EAAE;CAC7D,EACF;AACF"}
|