@humain/terminal 0.0.3-beta.2 → 0.0.3-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +0 -1
- package/dist/bun/cli.js.map +1 -1
- package/dist/humain/bedrock-provider/vendor/index.bundle.d.mts +3 -0
- package/dist/humain/bedrock-provider/vendor/index.bundle.mjs +1509 -0
- package/dist/humain/index.d.ts.map +1 -1
- package/dist/humain/index.js +3 -0
- package/dist/humain/index.js.map +1 -1
- package/npm-shrinkwrap.json +7 -2
- package/package.json +7 -2
- package/dist/bun/register-bedrock.d.ts +0 -2
- package/dist/bun/register-bedrock.d.ts.map +0 -1
- package/dist/bun/register-bedrock.js +0 -4
- package/dist/bun/register-bedrock.js.map +0 -1
|
@@ -0,0 +1,1509 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// packages/ai/src/api/bedrock-converse-stream.ts
|
|
9
|
+
import {
|
|
10
|
+
BedrockRuntimeClient,
|
|
11
|
+
BedrockRuntimeServiceException,
|
|
12
|
+
StopReason as BedrockStopReason,
|
|
13
|
+
CachePointType,
|
|
14
|
+
CacheTTL,
|
|
15
|
+
ConversationRole,
|
|
16
|
+
ConverseStreamCommand,
|
|
17
|
+
ImageFormat,
|
|
18
|
+
ToolResultStatus
|
|
19
|
+
} from "@aws-sdk/client-bedrock-runtime";
|
|
20
|
+
import { NodeHttpHandler } from "@smithy/node-http-handler";
|
|
21
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
22
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
23
|
+
|
|
24
|
+
// packages/ai/src/utils/event-stream.ts
|
|
25
|
+
var EventStream = class {
|
|
26
|
+
constructor(isComplete, extractResult) {
|
|
27
|
+
this.queue = [];
|
|
28
|
+
this.waiting = [];
|
|
29
|
+
this.done = false;
|
|
30
|
+
this.isComplete = isComplete;
|
|
31
|
+
this.extractResult = extractResult;
|
|
32
|
+
this.finalResultPromise = new Promise((resolve) => {
|
|
33
|
+
this.resolveFinalResult = resolve;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
push(event) {
|
|
37
|
+
if (this.done) return;
|
|
38
|
+
if (this.isComplete(event)) {
|
|
39
|
+
this.done = true;
|
|
40
|
+
this.resolveFinalResult(this.extractResult(event));
|
|
41
|
+
}
|
|
42
|
+
const waiter = this.waiting.shift();
|
|
43
|
+
if (waiter) {
|
|
44
|
+
waiter({ value: event, done: false });
|
|
45
|
+
} else {
|
|
46
|
+
this.queue.push(event);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
end(result) {
|
|
50
|
+
this.done = true;
|
|
51
|
+
if (result !== void 0) {
|
|
52
|
+
this.resolveFinalResult(result);
|
|
53
|
+
}
|
|
54
|
+
while (this.waiting.length > 0) {
|
|
55
|
+
const waiter = this.waiting.shift();
|
|
56
|
+
waiter({ value: void 0, done: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async *[Symbol.asyncIterator]() {
|
|
60
|
+
while (true) {
|
|
61
|
+
if (this.queue.length > 0) {
|
|
62
|
+
yield this.queue.shift();
|
|
63
|
+
} else if (this.done) {
|
|
64
|
+
return;
|
|
65
|
+
} else {
|
|
66
|
+
const result = await new Promise((resolve) => this.waiting.push(resolve));
|
|
67
|
+
if (result.done) return;
|
|
68
|
+
yield result.value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
result() {
|
|
73
|
+
return this.finalResultPromise;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var AssistantMessageEventStream = class extends EventStream {
|
|
77
|
+
constructor() {
|
|
78
|
+
super(
|
|
79
|
+
(event) => event.type === "done" || event.type === "error",
|
|
80
|
+
(event) => {
|
|
81
|
+
if (event.type === "done") {
|
|
82
|
+
return event.message;
|
|
83
|
+
} else if (event.type === "error") {
|
|
84
|
+
return event.error;
|
|
85
|
+
}
|
|
86
|
+
throw new Error("Unexpected event type for final result");
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// packages/ai/src/utils/diagnostics.ts
|
|
93
|
+
function appendAssistantMessageDiagnostic(message, diagnostic) {
|
|
94
|
+
message.diagnostics = [...message.diagnostics ?? [], diagnostic];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// packages/ai/src/models.ts
|
|
98
|
+
function calculateCost(model, usage) {
|
|
99
|
+
const inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
100
|
+
let rates = model.cost;
|
|
101
|
+
let matchedThreshold = -1;
|
|
102
|
+
for (const tier of model.cost.tiers ?? []) {
|
|
103
|
+
if (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {
|
|
104
|
+
rates = tier;
|
|
105
|
+
matchedThreshold = tier.inputTokensAbove;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const longWrite = usage.cacheWrite1h ?? 0;
|
|
109
|
+
const shortWrite = usage.cacheWrite - longWrite;
|
|
110
|
+
usage.cost.input = rates.input / 1e6 * usage.input;
|
|
111
|
+
usage.cost.output = rates.output / 1e6 * usage.output;
|
|
112
|
+
usage.cost.cacheRead = rates.cacheRead / 1e6 * usage.cacheRead;
|
|
113
|
+
usage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1e6;
|
|
114
|
+
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
115
|
+
return usage.cost;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// packages/ai/src/utils/error-body.ts
|
|
119
|
+
var MAX_PROVIDER_ERROR_BODY_CHARS = 4e3;
|
|
120
|
+
function normalizeProviderError(error) {
|
|
121
|
+
if (!(error instanceof Error)) {
|
|
122
|
+
return { message: safeJsonStringify(error), messageCarriesBody: false };
|
|
123
|
+
}
|
|
124
|
+
const sdkError = error;
|
|
125
|
+
const status = extractStatus(sdkError);
|
|
126
|
+
const body = extractBody(sdkError);
|
|
127
|
+
const messageCarriesBody = body === void 0 || error.message.includes(body);
|
|
128
|
+
return {
|
|
129
|
+
status,
|
|
130
|
+
body,
|
|
131
|
+
message: error.message,
|
|
132
|
+
messageCarriesBody
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function extractStatus(error) {
|
|
136
|
+
if (typeof error.statusCode === "number") return error.statusCode;
|
|
137
|
+
if (typeof error.status === "number") return error.status;
|
|
138
|
+
if (typeof error.$metadata?.httpStatusCode === "number") return error.$metadata.httpStatusCode;
|
|
139
|
+
if (typeof error.$response?.statusCode === "number") return error.$response.statusCode;
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
function extractBody(error) {
|
|
143
|
+
const bodyText = pickBodyText(error);
|
|
144
|
+
if (bodyText === void 0) return void 0;
|
|
145
|
+
const trimmed = bodyText.trim();
|
|
146
|
+
if (trimmed.length === 0) return void 0;
|
|
147
|
+
return truncateErrorText(trimmed, MAX_PROVIDER_ERROR_BODY_CHARS);
|
|
148
|
+
}
|
|
149
|
+
function pickBodyText(error) {
|
|
150
|
+
if (typeof error.body === "string") return error.body;
|
|
151
|
+
if (isPlainNonEmptyObject(error.error)) return safeJsonStringify(error.error);
|
|
152
|
+
const responseBody = error.$response?.body;
|
|
153
|
+
if (typeof responseBody === "string") return responseBody;
|
|
154
|
+
if (isReadableStreamLike(responseBody)) return void 0;
|
|
155
|
+
if (isPlainNonEmptyObject(responseBody)) return safeJsonStringify(responseBody);
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
function isReadableStreamLike(value) {
|
|
159
|
+
return typeof value === "object" && value !== null && "pipe" in value && typeof value.pipe === "function";
|
|
160
|
+
}
|
|
161
|
+
function isPlainNonEmptyObject(value) {
|
|
162
|
+
if (typeof value !== "object" || value === null) return false;
|
|
163
|
+
const proto = Object.getPrototypeOf(value);
|
|
164
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
165
|
+
return Object.keys(value).length > 0;
|
|
166
|
+
}
|
|
167
|
+
function truncateErrorText(text, maxChars) {
|
|
168
|
+
if (text.length <= maxChars) return text;
|
|
169
|
+
return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
|
|
170
|
+
}
|
|
171
|
+
function safeJsonStringify(value) {
|
|
172
|
+
try {
|
|
173
|
+
const serialized = JSON.stringify(value);
|
|
174
|
+
return serialized === void 0 ? String(value) : serialized;
|
|
175
|
+
} catch {
|
|
176
|
+
return String(value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// packages/ai/src/utils/headers.ts
|
|
181
|
+
function providerHeadersToRecord(headers) {
|
|
182
|
+
if (!headers) return void 0;
|
|
183
|
+
const result = {};
|
|
184
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
185
|
+
if (value !== null) result[key] = value;
|
|
186
|
+
}
|
|
187
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// packages/ai/src/utils/json-parse.ts
|
|
191
|
+
import { parse as partialParse } from "partial-json";
|
|
192
|
+
var VALID_JSON_ESCAPES = /* @__PURE__ */ new Set(['"', "\\", "/", "b", "f", "n", "r", "t", "u"]);
|
|
193
|
+
function isControlCharacter(char) {
|
|
194
|
+
const codePoint = char.codePointAt(0);
|
|
195
|
+
return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31;
|
|
196
|
+
}
|
|
197
|
+
function escapeControlCharacter(char) {
|
|
198
|
+
switch (char) {
|
|
199
|
+
case "\b":
|
|
200
|
+
return "\\b";
|
|
201
|
+
case "\f":
|
|
202
|
+
return "\\f";
|
|
203
|
+
case "\n":
|
|
204
|
+
return "\\n";
|
|
205
|
+
case "\r":
|
|
206
|
+
return "\\r";
|
|
207
|
+
case " ":
|
|
208
|
+
return "\\t";
|
|
209
|
+
default:
|
|
210
|
+
return `\\u${char.codePointAt(0)?.toString(16).padStart(4, "0") ?? "0000"}`;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function repairJson(json) {
|
|
214
|
+
let repaired = "";
|
|
215
|
+
let inString = false;
|
|
216
|
+
for (let index = 0; index < json.length; index++) {
|
|
217
|
+
const char = json[index];
|
|
218
|
+
if (!inString) {
|
|
219
|
+
repaired += char;
|
|
220
|
+
if (char === '"') {
|
|
221
|
+
inString = true;
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (char === '"') {
|
|
226
|
+
repaired += char;
|
|
227
|
+
inString = false;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (char === "\\") {
|
|
231
|
+
const nextChar = json[index + 1];
|
|
232
|
+
if (nextChar === void 0) {
|
|
233
|
+
repaired += "\\\\";
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (nextChar === "u") {
|
|
237
|
+
const unicodeDigits = json.slice(index + 2, index + 6);
|
|
238
|
+
if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) {
|
|
239
|
+
repaired += `\\u${unicodeDigits}`;
|
|
240
|
+
index += 5;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (VALID_JSON_ESCAPES.has(nextChar)) {
|
|
245
|
+
repaired += `\\${nextChar}`;
|
|
246
|
+
index += 1;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
repaired += "\\\\";
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
repaired += isControlCharacter(char) ? escapeControlCharacter(char) : char;
|
|
253
|
+
}
|
|
254
|
+
return repaired;
|
|
255
|
+
}
|
|
256
|
+
function parseJsonWithRepair(json) {
|
|
257
|
+
try {
|
|
258
|
+
return JSON.parse(json);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
const repairedJson = repairJson(json);
|
|
261
|
+
if (repairedJson !== json) {
|
|
262
|
+
return JSON.parse(repairedJson);
|
|
263
|
+
}
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function parseStreamingJson(partialJson) {
|
|
268
|
+
if (!partialJson || partialJson.trim() === "") {
|
|
269
|
+
return {};
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
return parseJsonWithRepair(partialJson);
|
|
273
|
+
} catch {
|
|
274
|
+
try {
|
|
275
|
+
const result = partialParse(partialJson);
|
|
276
|
+
return result ?? {};
|
|
277
|
+
} catch {
|
|
278
|
+
try {
|
|
279
|
+
const result = partialParse(repairJson(partialJson));
|
|
280
|
+
return result ?? {};
|
|
281
|
+
} catch {
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// packages/ai/src/utils/provider-env.ts
|
|
289
|
+
var procEnvCache = null;
|
|
290
|
+
function getBunSandboxEnvValue(name) {
|
|
291
|
+
if (typeof process === "undefined" || !process.versions?.bun || Object.keys(process.env).length > 0) {
|
|
292
|
+
return void 0;
|
|
293
|
+
}
|
|
294
|
+
if (procEnvCache === null) {
|
|
295
|
+
procEnvCache = /* @__PURE__ */ new Map();
|
|
296
|
+
try {
|
|
297
|
+
const { readFileSync } = __require("node:fs");
|
|
298
|
+
const data = readFileSync("/proc/self/environ", "utf-8");
|
|
299
|
+
for (const entry of data.split("\0")) {
|
|
300
|
+
const idx = entry.indexOf("=");
|
|
301
|
+
if (idx > 0) {
|
|
302
|
+
procEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return procEnvCache.get(name);
|
|
309
|
+
}
|
|
310
|
+
function getProviderEnvValue(name, env) {
|
|
311
|
+
return env?.[name] || (typeof process !== "undefined" ? process.env[name] : void 0) || getBunSandboxEnvValue(name) || void 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// packages/ai/src/utils/node-http-proxy.ts
|
|
315
|
+
var DEFAULT_PROXY_PORTS = {
|
|
316
|
+
ftp: 21,
|
|
317
|
+
gopher: 70,
|
|
318
|
+
http: 80,
|
|
319
|
+
https: 443,
|
|
320
|
+
ws: 80,
|
|
321
|
+
wss: 443
|
|
322
|
+
};
|
|
323
|
+
function getProxyEnv(key, env) {
|
|
324
|
+
const lowercaseKey = key.toLowerCase();
|
|
325
|
+
const uppercaseKey = key.toUpperCase();
|
|
326
|
+
return env?.[lowercaseKey] || env?.[uppercaseKey] || getProviderEnvValue(lowercaseKey) || getProviderEnvValue(uppercaseKey) || "";
|
|
327
|
+
}
|
|
328
|
+
function parseProxyTargetUrl(targetUrl) {
|
|
329
|
+
if (targetUrl instanceof URL) {
|
|
330
|
+
return targetUrl;
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
return new URL(targetUrl);
|
|
334
|
+
} catch {
|
|
335
|
+
return void 0;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function shouldProxyHostname(hostname, port, env) {
|
|
339
|
+
const noProxy = getProxyEnv("no_proxy", env).toLowerCase();
|
|
340
|
+
if (!noProxy) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
if (noProxy === "*") {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
return noProxy.split(/[,\s]/).every((proxy) => {
|
|
347
|
+
if (!proxy) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
const parsedProxy = proxy.match(/^(.+):(\d+)$/);
|
|
351
|
+
let proxyHostname = parsedProxy ? parsedProxy[1] : proxy;
|
|
352
|
+
const proxyPort = parsedProxy ? Number.parseInt(parsedProxy[2], 10) : 0;
|
|
353
|
+
if (proxyPort && proxyPort !== port) {
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
if (!/^[.*]/.test(proxyHostname)) {
|
|
357
|
+
return hostname !== proxyHostname;
|
|
358
|
+
}
|
|
359
|
+
if (proxyHostname.startsWith("*")) {
|
|
360
|
+
proxyHostname = proxyHostname.slice(1);
|
|
361
|
+
}
|
|
362
|
+
return !hostname.endsWith(proxyHostname);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function getProxyForUrl(targetUrl, env) {
|
|
366
|
+
const parsedUrl = parseProxyTargetUrl(targetUrl);
|
|
367
|
+
if (!parsedUrl?.protocol || !parsedUrl.host) {
|
|
368
|
+
return "";
|
|
369
|
+
}
|
|
370
|
+
const protocol = parsedUrl.protocol.split(":", 1)[0];
|
|
371
|
+
const hostname = parsedUrl.host.replace(/:\d*$/, "");
|
|
372
|
+
const port = Number.parseInt(parsedUrl.port, 10) || DEFAULT_PROXY_PORTS[protocol] || 0;
|
|
373
|
+
if (!shouldProxyHostname(hostname, port, env)) {
|
|
374
|
+
return "";
|
|
375
|
+
}
|
|
376
|
+
let proxy = getProxyEnv(`${protocol}_proxy`, env) || getProxyEnv("all_proxy", env);
|
|
377
|
+
if (proxy && !proxy.includes("://")) {
|
|
378
|
+
proxy = `${protocol}://${proxy}`;
|
|
379
|
+
}
|
|
380
|
+
return proxy;
|
|
381
|
+
}
|
|
382
|
+
var UNSUPPORTED_PROXY_PROTOCOL_MESSAGE = "Unsupported proxy protocol. SOCKS and PAC proxy URLs are not supported; use an HTTP or HTTPS proxy URL.";
|
|
383
|
+
function resolveHttpProxyUrlForTarget(targetUrl, env) {
|
|
384
|
+
const proxy = getProxyForUrl(targetUrl, env);
|
|
385
|
+
if (!proxy) {
|
|
386
|
+
return void 0;
|
|
387
|
+
}
|
|
388
|
+
let proxyUrl;
|
|
389
|
+
try {
|
|
390
|
+
proxyUrl = new URL(proxy);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
throw new Error(
|
|
393
|
+
`Invalid proxy URL ${JSON.stringify(proxy)}: ${error instanceof Error ? error.message : String(error)}`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
if (proxyUrl.protocol !== "http:" && proxyUrl.protocol !== "https:") {
|
|
397
|
+
throw new Error(`${UNSUPPORTED_PROXY_PROTOCOL_MESSAGE} Got ${proxyUrl.protocol}`);
|
|
398
|
+
}
|
|
399
|
+
return proxyUrl;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// packages/ai/src/utils/sanitize-unicode.ts
|
|
403
|
+
function sanitizeSurrogates(text) {
|
|
404
|
+
return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// packages/ai/src/api/constrained-sampling.ts
|
|
408
|
+
function resolveJsonSchemaStrictSampling(tool, supportsStrictMode) {
|
|
409
|
+
const config = tool.constrainedSampling;
|
|
410
|
+
if (!config || config.type !== "json_schema") {
|
|
411
|
+
return void 0;
|
|
412
|
+
}
|
|
413
|
+
if (supportsStrictMode) {
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
if (config.strict === "require") {
|
|
417
|
+
throw new Error(
|
|
418
|
+
`Tool "${tool.name}" requires JSON-schema constrained sampling, but strict tools are unsupported.`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
return void 0;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// packages/ai/src/utils/estimate.ts
|
|
425
|
+
var CHARS_PER_TOKEN = 4;
|
|
426
|
+
var ESTIMATED_IMAGE_CHARS = 4800;
|
|
427
|
+
function calculateContextTokens(usage) {
|
|
428
|
+
return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
429
|
+
}
|
|
430
|
+
function safeJsonStringify2(value) {
|
|
431
|
+
try {
|
|
432
|
+
return JSON.stringify(value) ?? "undefined";
|
|
433
|
+
} catch {
|
|
434
|
+
return "[unserializable]";
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function estimateTextAndImageContentChars(content) {
|
|
438
|
+
if (typeof content === "string") return content.length;
|
|
439
|
+
let chars = 0;
|
|
440
|
+
for (const block of content) chars += block.type === "text" ? block.text.length : ESTIMATED_IMAGE_CHARS;
|
|
441
|
+
return chars;
|
|
442
|
+
}
|
|
443
|
+
function estimateTextTokens(text) {
|
|
444
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
445
|
+
}
|
|
446
|
+
function estimateTextAndImageContentTokens(content) {
|
|
447
|
+
return Math.ceil(estimateTextAndImageContentChars(content) / CHARS_PER_TOKEN);
|
|
448
|
+
}
|
|
449
|
+
function estimateMessageTokens(message) {
|
|
450
|
+
let chars = 0;
|
|
451
|
+
if (message.role === "user") return estimateTextAndImageContentTokens(message.content);
|
|
452
|
+
if (message.role === "toolResult") return estimateTextAndImageContentTokens(message.content);
|
|
453
|
+
for (const block of message.content) {
|
|
454
|
+
if (block.type === "text") {
|
|
455
|
+
chars += block.text.length;
|
|
456
|
+
} else if (block.type === "thinking") {
|
|
457
|
+
chars += block.thinking.length;
|
|
458
|
+
} else {
|
|
459
|
+
chars += block.name.length + safeJsonStringify2(block.arguments).length;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return Math.ceil(chars / CHARS_PER_TOKEN);
|
|
463
|
+
}
|
|
464
|
+
function getLastAssistantUsageInfo(messages) {
|
|
465
|
+
let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;
|
|
466
|
+
let usageInfo;
|
|
467
|
+
for (let i = 0; i < messages.length; i++) {
|
|
468
|
+
const message = messages[i];
|
|
469
|
+
if (message.role === "assistant") {
|
|
470
|
+
const assistant = message;
|
|
471
|
+
const usageAppliesToPrefix = assistant.timestamp >= latestPrefixTimestamp;
|
|
472
|
+
if (usageAppliesToPrefix && assistant.stopReason !== "aborted" && assistant.stopReason !== "error" && calculateContextTokens(assistant.usage) > 0) {
|
|
473
|
+
usageInfo = { usage: assistant.usage, index: i };
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);
|
|
477
|
+
}
|
|
478
|
+
return usageInfo;
|
|
479
|
+
}
|
|
480
|
+
function estimateMessages(messages) {
|
|
481
|
+
const usageInfo = getLastAssistantUsageInfo(messages);
|
|
482
|
+
if (usageInfo) {
|
|
483
|
+
const usageTokens = calculateContextTokens(usageInfo.usage);
|
|
484
|
+
let trailingTokens = 0;
|
|
485
|
+
for (let i = usageInfo.index + 1; i < messages.length; i++) {
|
|
486
|
+
trailingTokens += estimateMessageTokens(messages[i]);
|
|
487
|
+
}
|
|
488
|
+
return { tokens: usageTokens + trailingTokens, usageTokens, trailingTokens, lastUsageIndex: usageInfo.index };
|
|
489
|
+
}
|
|
490
|
+
let tokens = 0;
|
|
491
|
+
for (const message of messages) tokens += estimateMessageTokens(message);
|
|
492
|
+
return { tokens, usageTokens: 0, trailingTokens: tokens, lastUsageIndex: null };
|
|
493
|
+
}
|
|
494
|
+
function estimateToolsTokens(tools) {
|
|
495
|
+
if (!tools || tools.length === 0) return 0;
|
|
496
|
+
return estimateTextTokens(safeJsonStringify2(tools));
|
|
497
|
+
}
|
|
498
|
+
function isMessageArray(value) {
|
|
499
|
+
return Array.isArray(value);
|
|
500
|
+
}
|
|
501
|
+
function estimateContextTokens(context) {
|
|
502
|
+
if (isMessageArray(context)) return estimateMessages(context);
|
|
503
|
+
const estimate = estimateMessages(context.messages);
|
|
504
|
+
if (estimate.lastUsageIndex !== null) {
|
|
505
|
+
const addedNames = new Set(
|
|
506
|
+
context.messages.slice(estimate.lastUsageIndex + 1).filter((message) => message.role === "toolResult").flatMap((message) => message.addedToolNames ?? [])
|
|
507
|
+
);
|
|
508
|
+
const addedToolTokens = estimateToolsTokens(context.tools?.filter((tool) => addedNames.has(tool.name)));
|
|
509
|
+
return {
|
|
510
|
+
tokens: estimate.tokens + addedToolTokens,
|
|
511
|
+
usageTokens: estimate.usageTokens,
|
|
512
|
+
trailingTokens: estimate.trailingTokens + addedToolTokens,
|
|
513
|
+
lastUsageIndex: estimate.lastUsageIndex
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
const prefixTokens = (context.systemPrompt ? estimateTextTokens(context.systemPrompt) : 0) + estimateToolsTokens(context.tools);
|
|
517
|
+
return {
|
|
518
|
+
tokens: estimate.tokens + prefixTokens,
|
|
519
|
+
usageTokens: estimate.usageTokens,
|
|
520
|
+
trailingTokens: estimate.trailingTokens + prefixTokens,
|
|
521
|
+
lastUsageIndex: estimate.lastUsageIndex
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// packages/ai/src/api/simple-options.ts
|
|
526
|
+
var CONTEXT_SAFETY_TOKENS = 4096;
|
|
527
|
+
var MIN_MAX_TOKENS = 1;
|
|
528
|
+
function clampMaxTokensToContext(model, context, maxTokens) {
|
|
529
|
+
if (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);
|
|
530
|
+
const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;
|
|
531
|
+
return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));
|
|
532
|
+
}
|
|
533
|
+
function buildBaseOptions(model, context, options, apiKey) {
|
|
534
|
+
const samplingParams = model.samplingParams || options?.samplingParams ? { ...model.samplingParams, ...options?.samplingParams } : void 0;
|
|
535
|
+
return {
|
|
536
|
+
temperature: options?.temperature,
|
|
537
|
+
samplingParams,
|
|
538
|
+
maxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),
|
|
539
|
+
signal: options?.signal,
|
|
540
|
+
telemetryContext: options?.telemetryContext,
|
|
541
|
+
apiKey: apiKey || options?.apiKey,
|
|
542
|
+
fetch: options?.fetch,
|
|
543
|
+
transport: options?.transport,
|
|
544
|
+
cacheRetention: options?.cacheRetention,
|
|
545
|
+
sessionId: options?.sessionId,
|
|
546
|
+
headers: options?.headers,
|
|
547
|
+
onPayload: options?.onPayload,
|
|
548
|
+
onResponse: options?.onResponse,
|
|
549
|
+
timeoutMs: options?.timeoutMs,
|
|
550
|
+
websocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,
|
|
551
|
+
maxRetries: options?.maxRetries,
|
|
552
|
+
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
553
|
+
metadata: options?.metadata,
|
|
554
|
+
env: options?.env
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
var MIN_ANSWER_TOKENS = 1024;
|
|
558
|
+
function clampReasoning(effort) {
|
|
559
|
+
return effort === "xhigh" || effort === "max" ? "high" : effort;
|
|
560
|
+
}
|
|
561
|
+
function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
|
|
562
|
+
const defaultBudgets = {
|
|
563
|
+
minimal: 1024,
|
|
564
|
+
low: 2048,
|
|
565
|
+
medium: 8192,
|
|
566
|
+
high: 16384
|
|
567
|
+
};
|
|
568
|
+
const budgets = { ...defaultBudgets, ...customBudgets };
|
|
569
|
+
const level = clampReasoning(reasoningLevel);
|
|
570
|
+
let thinkingBudget = budgets[level];
|
|
571
|
+
const maxTokens = baseMaxTokens === void 0 ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
|
|
572
|
+
if (maxTokens <= thinkingBudget) {
|
|
573
|
+
thinkingBudget = Math.max(0, maxTokens - MIN_ANSWER_TOKENS);
|
|
574
|
+
}
|
|
575
|
+
return { maxTokens, thinkingBudget };
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// packages/ai/src/api/transform-messages.ts
|
|
579
|
+
var NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
580
|
+
var NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
|
|
581
|
+
function replaceImagesWithPlaceholder(content, placeholder) {
|
|
582
|
+
const result = [];
|
|
583
|
+
let previousWasPlaceholder = false;
|
|
584
|
+
for (const block of content) {
|
|
585
|
+
if (block.type === "image") {
|
|
586
|
+
if (!previousWasPlaceholder) {
|
|
587
|
+
result.push({ type: "text", text: placeholder });
|
|
588
|
+
}
|
|
589
|
+
previousWasPlaceholder = true;
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
result.push(block);
|
|
593
|
+
previousWasPlaceholder = block.text === placeholder;
|
|
594
|
+
}
|
|
595
|
+
return result;
|
|
596
|
+
}
|
|
597
|
+
function downgradeUnsupportedImages(messages, model) {
|
|
598
|
+
if (model.input.includes("image")) {
|
|
599
|
+
return messages;
|
|
600
|
+
}
|
|
601
|
+
return messages.map((msg) => {
|
|
602
|
+
if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
603
|
+
return {
|
|
604
|
+
...msg,
|
|
605
|
+
content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (msg.role === "toolResult") {
|
|
609
|
+
return {
|
|
610
|
+
...msg,
|
|
611
|
+
content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
return msg;
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
function transformMessages(messages, model, normalizeToolCallId2) {
|
|
618
|
+
const toolCallIdMap = /* @__PURE__ */ new Map();
|
|
619
|
+
const normalizedMessages = messages.map((msg) => msg.content == null ? { ...msg, content: [] } : msg);
|
|
620
|
+
const imageAwareMessages = downgradeUnsupportedImages(normalizedMessages, model);
|
|
621
|
+
const transformed = imageAwareMessages.map((msg) => {
|
|
622
|
+
if (msg.role === "user") {
|
|
623
|
+
return msg;
|
|
624
|
+
}
|
|
625
|
+
if (msg.role === "toolResult") {
|
|
626
|
+
const normalizedId = toolCallIdMap.get(msg.toolCallId);
|
|
627
|
+
if (normalizedId && normalizedId !== msg.toolCallId) {
|
|
628
|
+
return { ...msg, toolCallId: normalizedId };
|
|
629
|
+
}
|
|
630
|
+
return msg;
|
|
631
|
+
}
|
|
632
|
+
if (msg.role === "assistant") {
|
|
633
|
+
const assistantMsg = msg;
|
|
634
|
+
const isSameModel = assistantMsg.provider === model.provider && assistantMsg.api === model.api && assistantMsg.model === model.id;
|
|
635
|
+
const transformedContent = assistantMsg.content.flatMap((block) => {
|
|
636
|
+
if (block.type === "thinking") {
|
|
637
|
+
if (block.redacted) {
|
|
638
|
+
return isSameModel ? block : [];
|
|
639
|
+
}
|
|
640
|
+
if (isSameModel && block.thinkingSignature) return block;
|
|
641
|
+
if (!block.thinking || block.thinking.trim() === "") return [];
|
|
642
|
+
if (isSameModel) return block;
|
|
643
|
+
return {
|
|
644
|
+
type: "text",
|
|
645
|
+
text: block.thinking
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
if (block.type === "text") {
|
|
649
|
+
if (isSameModel) return block;
|
|
650
|
+
return {
|
|
651
|
+
type: "text",
|
|
652
|
+
text: block.text
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if (block.type === "toolCall") {
|
|
656
|
+
const toolCall = block;
|
|
657
|
+
let normalizedToolCall = toolCall;
|
|
658
|
+
if (!isSameModel && toolCall.thoughtSignature) {
|
|
659
|
+
normalizedToolCall = { ...toolCall };
|
|
660
|
+
delete normalizedToolCall.thoughtSignature;
|
|
661
|
+
}
|
|
662
|
+
if (!isSameModel && normalizeToolCallId2) {
|
|
663
|
+
const normalizedId = normalizeToolCallId2(toolCall.id, model, assistantMsg);
|
|
664
|
+
if (normalizedId !== toolCall.id) {
|
|
665
|
+
toolCallIdMap.set(toolCall.id, normalizedId);
|
|
666
|
+
normalizedToolCall = { ...normalizedToolCall, id: normalizedId };
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return normalizedToolCall;
|
|
670
|
+
}
|
|
671
|
+
return block;
|
|
672
|
+
});
|
|
673
|
+
return {
|
|
674
|
+
...assistantMsg,
|
|
675
|
+
content: transformedContent
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
return msg;
|
|
679
|
+
});
|
|
680
|
+
const result = [];
|
|
681
|
+
let pendingToolCalls = [];
|
|
682
|
+
let existingToolResultIds = /* @__PURE__ */ new Set();
|
|
683
|
+
const insertSyntheticToolResults = () => {
|
|
684
|
+
if (pendingToolCalls.length > 0) {
|
|
685
|
+
for (const tc of pendingToolCalls) {
|
|
686
|
+
if (!existingToolResultIds.has(tc.id)) {
|
|
687
|
+
result.push({
|
|
688
|
+
role: "toolResult",
|
|
689
|
+
toolCallId: tc.id,
|
|
690
|
+
toolName: tc.name,
|
|
691
|
+
content: [{ type: "text", text: "No result provided" }],
|
|
692
|
+
isError: true,
|
|
693
|
+
timestamp: Date.now()
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
pendingToolCalls = [];
|
|
698
|
+
existingToolResultIds = /* @__PURE__ */ new Set();
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
for (let i = 0; i < transformed.length; i++) {
|
|
702
|
+
const msg = transformed[i];
|
|
703
|
+
if (msg.role === "assistant") {
|
|
704
|
+
insertSyntheticToolResults();
|
|
705
|
+
const assistantMsg = msg;
|
|
706
|
+
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
const toolCalls = assistantMsg.content.filter((b) => b.type === "toolCall");
|
|
710
|
+
if (toolCalls.length > 0) {
|
|
711
|
+
pendingToolCalls = toolCalls;
|
|
712
|
+
existingToolResultIds = /* @__PURE__ */ new Set();
|
|
713
|
+
}
|
|
714
|
+
result.push(msg);
|
|
715
|
+
} else if (msg.role === "toolResult") {
|
|
716
|
+
existingToolResultIds.add(msg.toolCallId);
|
|
717
|
+
result.push(msg);
|
|
718
|
+
} else if (msg.role === "user") {
|
|
719
|
+
insertSyntheticToolResults();
|
|
720
|
+
result.push(msg);
|
|
721
|
+
} else {
|
|
722
|
+
result.push(msg);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
insertSyntheticToolResults();
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// packages/ai/src/api/bedrock-converse-stream.ts
|
|
730
|
+
var EMPTY_TEXT_PLACEHOLDER = "<empty>";
|
|
731
|
+
var stream = (model, context, options = {}) => {
|
|
732
|
+
const stream2 = new AssistantMessageEventStream();
|
|
733
|
+
(async () => {
|
|
734
|
+
const output = {
|
|
735
|
+
role: "assistant",
|
|
736
|
+
content: [],
|
|
737
|
+
api: "bedrock-converse-stream",
|
|
738
|
+
provider: model.provider,
|
|
739
|
+
model: model.id,
|
|
740
|
+
usage: {
|
|
741
|
+
input: 0,
|
|
742
|
+
output: 0,
|
|
743
|
+
cacheRead: 0,
|
|
744
|
+
cacheWrite: 0,
|
|
745
|
+
totalTokens: 0,
|
|
746
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
747
|
+
},
|
|
748
|
+
stopReason: "pending",
|
|
749
|
+
timestamp: Date.now()
|
|
750
|
+
};
|
|
751
|
+
const blocks = output.content;
|
|
752
|
+
const optionsProfile = options.profile || options.env?.AWS_PROFILE;
|
|
753
|
+
const config = {
|
|
754
|
+
profile: optionsProfile || getProviderEnvValue("AWS_PROFILE", options.env)
|
|
755
|
+
};
|
|
756
|
+
const configuredRegion = getConfiguredBedrockRegion(options);
|
|
757
|
+
const hasAmbientConfiguredProfile = Boolean(getProviderEnvValue("AWS_PROFILE"));
|
|
758
|
+
const endpointRegion = getStandardBedrockEndpointRegion(model.baseUrl);
|
|
759
|
+
const useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(
|
|
760
|
+
model.baseUrl,
|
|
761
|
+
configuredRegion,
|
|
762
|
+
hasAmbientConfiguredProfile
|
|
763
|
+
);
|
|
764
|
+
if (useExplicitEndpoint) {
|
|
765
|
+
config.endpoint = model.baseUrl;
|
|
766
|
+
}
|
|
767
|
+
const skipAuth = getProviderEnvValue("AWS_BEDROCK_SKIP_AUTH", options.env) === "1";
|
|
768
|
+
const bearerToken = options.bearerToken || options.apiKey || getProviderEnvValue("AWS_BEARER_TOKEN_BEDROCK", options.env) || void 0;
|
|
769
|
+
const useBearerToken = bearerToken !== void 0 && !skipAuth;
|
|
770
|
+
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
771
|
+
const arnRegionMatch = model.id.match(/^arn:aws(?:-[a-z0-9-]+)?:bedrock:([a-z0-9-]+):/);
|
|
772
|
+
if (arnRegionMatch) {
|
|
773
|
+
config.region = arnRegionMatch[1];
|
|
774
|
+
} else if (configuredRegion) {
|
|
775
|
+
config.region = configuredRegion;
|
|
776
|
+
} else if (endpointRegion && useExplicitEndpoint) {
|
|
777
|
+
config.region = endpointRegion;
|
|
778
|
+
} else if (!hasAmbientConfiguredProfile) {
|
|
779
|
+
config.region = "us-east-1";
|
|
780
|
+
}
|
|
781
|
+
if (skipAuth) {
|
|
782
|
+
config.credentials = {
|
|
783
|
+
accessKeyId: "dummy-access-key",
|
|
784
|
+
secretAccessKey: "dummy-secret-key"
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
const credentials = getConfiguredBedrockCredentials(options.env);
|
|
788
|
+
if (!skipAuth && credentials && !optionsProfile) {
|
|
789
|
+
config.credentials = credentials;
|
|
790
|
+
}
|
|
791
|
+
const proxyUrl = shouldBypassBedrockProxy(model.baseUrl) ? void 0 : resolveHttpProxyUrlForTarget(model.baseUrl, options.env);
|
|
792
|
+
if (proxyUrl) {
|
|
793
|
+
config.requestHandler = new NodeHttpHandler({
|
|
794
|
+
httpAgent: new HttpProxyAgent(proxyUrl),
|
|
795
|
+
httpsAgent: new HttpsProxyAgent(proxyUrl)
|
|
796
|
+
});
|
|
797
|
+
} else if (shouldUseBedrockHttp1Handler(model.baseUrl, options.env)) {
|
|
798
|
+
config.requestHandler = new NodeHttpHandler();
|
|
799
|
+
}
|
|
800
|
+
} else {
|
|
801
|
+
config.region = configuredRegion || (endpointRegion && useExplicitEndpoint ? endpointRegion : void 0) || "us-east-1";
|
|
802
|
+
}
|
|
803
|
+
if (useBearerToken) {
|
|
804
|
+
config.token = { token: bearerToken };
|
|
805
|
+
config.authSchemePreference = ["httpBearerAuth"];
|
|
806
|
+
}
|
|
807
|
+
let responseRequestId;
|
|
808
|
+
let client;
|
|
809
|
+
try {
|
|
810
|
+
client = new BedrockRuntimeClient(config);
|
|
811
|
+
const customHeaders = providerHeadersToRecord(options.headers);
|
|
812
|
+
if (customHeaders) {
|
|
813
|
+
addCustomHeadersMiddleware(client, customHeaders);
|
|
814
|
+
}
|
|
815
|
+
const cacheRetention = resolveCacheRetention(options.cacheRetention, options.env);
|
|
816
|
+
const inferenceMaxTokens = options.maxTokens ?? (isAnthropicClaudeModel(model) ? model.maxTokens : void 0);
|
|
817
|
+
let commandInput = {
|
|
818
|
+
modelId: model.id,
|
|
819
|
+
messages: convertMessages(context, model, cacheRetention, options.env),
|
|
820
|
+
system: buildSystemPrompt(context.systemPrompt, model, cacheRetention, options.env),
|
|
821
|
+
inferenceConfig: {
|
|
822
|
+
...inferenceMaxTokens !== void 0 && { maxTokens: inferenceMaxTokens },
|
|
823
|
+
...options.temperature !== void 0 && { temperature: options.temperature }
|
|
824
|
+
},
|
|
825
|
+
toolConfig: convertToolConfig(context.tools, options.toolChoice, model.compat?.supportsStrictMode ?? false),
|
|
826
|
+
additionalModelRequestFields: buildAdditionalModelRequestFields(model, options),
|
|
827
|
+
...options.requestMetadata !== void 0 && { requestMetadata: options.requestMetadata }
|
|
828
|
+
};
|
|
829
|
+
const nextCommandInput = await options?.onPayload?.(commandInput, model);
|
|
830
|
+
if (nextCommandInput !== void 0) {
|
|
831
|
+
commandInput = nextCommandInput;
|
|
832
|
+
}
|
|
833
|
+
const command = new ConverseStreamCommand(commandInput);
|
|
834
|
+
const response = await client.send(command, { abortSignal: options.signal });
|
|
835
|
+
responseRequestId = normalizeDiagnosticValue(response.$metadata.requestId);
|
|
836
|
+
if (response.$metadata.httpStatusCode !== void 0) {
|
|
837
|
+
const responseHeaders = {};
|
|
838
|
+
if (response.$metadata.requestId) {
|
|
839
|
+
responseHeaders["x-amzn-requestid"] = response.$metadata.requestId;
|
|
840
|
+
}
|
|
841
|
+
await options?.onResponse?.({ status: response.$metadata.httpStatusCode, headers: responseHeaders }, model);
|
|
842
|
+
}
|
|
843
|
+
for await (const item of response.stream) {
|
|
844
|
+
if (item.messageStart) {
|
|
845
|
+
if (item.messageStart.role !== ConversationRole.ASSISTANT) {
|
|
846
|
+
throw new Error("Unexpected assistant message start but got user message start instead");
|
|
847
|
+
}
|
|
848
|
+
stream2.push({ type: "start", partial: output });
|
|
849
|
+
} else if (item.contentBlockStart) {
|
|
850
|
+
handleContentBlockStart(item.contentBlockStart, blocks, output, stream2);
|
|
851
|
+
} else if (item.contentBlockDelta) {
|
|
852
|
+
handleContentBlockDelta(item.contentBlockDelta, blocks, output, stream2);
|
|
853
|
+
} else if (item.contentBlockStop) {
|
|
854
|
+
handleContentBlockStop(item.contentBlockStop, blocks, output, stream2);
|
|
855
|
+
} else if (item.messageStop) {
|
|
856
|
+
output.rawStopReason = item.messageStop.stopReason;
|
|
857
|
+
const { stopReason, errorMessage } = mapStopReason(item.messageStop.stopReason);
|
|
858
|
+
output.stopReason = stopReason;
|
|
859
|
+
if (errorMessage) {
|
|
860
|
+
output.errorMessage = errorMessage;
|
|
861
|
+
}
|
|
862
|
+
} else if (item.metadata) {
|
|
863
|
+
handleMetadata(item.metadata, model, output);
|
|
864
|
+
} else if (item.internalServerException) {
|
|
865
|
+
throw item.internalServerException;
|
|
866
|
+
} else if (item.modelStreamErrorException) {
|
|
867
|
+
throw item.modelStreamErrorException;
|
|
868
|
+
} else if (item.validationException) {
|
|
869
|
+
throw item.validationException;
|
|
870
|
+
} else if (item.throttlingException) {
|
|
871
|
+
throw item.throttlingException;
|
|
872
|
+
} else if (item.serviceUnavailableException) {
|
|
873
|
+
throw item.serviceUnavailableException;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if (options.signal?.aborted) {
|
|
877
|
+
throw new Error("Request was aborted");
|
|
878
|
+
}
|
|
879
|
+
if (output.stopReason === "pending") {
|
|
880
|
+
throw new Error("Bedrock stream ended without a stop reason");
|
|
881
|
+
}
|
|
882
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
883
|
+
throw new Error(output.errorMessage || "An unknown error occurred");
|
|
884
|
+
}
|
|
885
|
+
stream2.push({ type: "done", reason: output.stopReason, message: output });
|
|
886
|
+
stream2.end();
|
|
887
|
+
} catch (error) {
|
|
888
|
+
for (const block of output.content) {
|
|
889
|
+
delete block.index;
|
|
890
|
+
delete block.partialJson;
|
|
891
|
+
}
|
|
892
|
+
output.stopReason = options.signal?.aborted ? "aborted" : "error";
|
|
893
|
+
output.errorMessage = formatBedrockError(error);
|
|
894
|
+
if (output.stopReason === "error") {
|
|
895
|
+
appendBedrockFailureDiagnostic(output, error, responseRequestId);
|
|
896
|
+
}
|
|
897
|
+
stream2.push({ type: "error", reason: output.stopReason, error: output });
|
|
898
|
+
stream2.end();
|
|
899
|
+
} finally {
|
|
900
|
+
client?.destroy?.();
|
|
901
|
+
}
|
|
902
|
+
})();
|
|
903
|
+
return stream2;
|
|
904
|
+
};
|
|
905
|
+
var BEDROCK_ERROR_PREFIXES = {
|
|
906
|
+
InternalServerException: "Internal server error",
|
|
907
|
+
ModelStreamErrorException: "Model stream error",
|
|
908
|
+
ValidationException: "Validation error",
|
|
909
|
+
ThrottlingException: "Throttling error",
|
|
910
|
+
ServiceUnavailableException: "Service unavailable"
|
|
911
|
+
};
|
|
912
|
+
var BEDROCK_DATA_RETENTION_DOCS_URL = "https://docs.aws.amazon.com/bedrock/latest/userguide/data-retention.html";
|
|
913
|
+
function formatBedrockError(error) {
|
|
914
|
+
const norm = normalizeProviderError(error);
|
|
915
|
+
const core = !norm.messageCarriesBody && norm.status !== void 0 && norm.body !== void 0 ? `${norm.status}: ${norm.body}` : norm.message;
|
|
916
|
+
const dataRetentionHint = /data retention mode/i.test(core) ? ` See ${BEDROCK_DATA_RETENTION_DOCS_URL} for supported data retention modes.` : "";
|
|
917
|
+
if (error instanceof BedrockRuntimeServiceException) {
|
|
918
|
+
const prefix = BEDROCK_ERROR_PREFIXES[error.name] ?? error.name;
|
|
919
|
+
return `${prefix}: ${core}${dataRetentionHint}`;
|
|
920
|
+
}
|
|
921
|
+
return `${core}${dataRetentionHint}`;
|
|
922
|
+
}
|
|
923
|
+
var MAX_BEDROCK_DIAGNOSTIC_VALUE_CHARS = 200;
|
|
924
|
+
function normalizeDiagnosticValue(value) {
|
|
925
|
+
if (typeof value !== "string") return void 0;
|
|
926
|
+
const trimmed = value.trim();
|
|
927
|
+
if (trimmed.length === 0 || trimmed.length > MAX_BEDROCK_DIAGNOSTIC_VALUE_CHARS) return void 0;
|
|
928
|
+
return trimmed;
|
|
929
|
+
}
|
|
930
|
+
function extractBedrockErrorCode(error) {
|
|
931
|
+
if (!(error instanceof Error) || !error.name.endsWith("Exception")) return void 0;
|
|
932
|
+
return normalizeDiagnosticValue(error.name);
|
|
933
|
+
}
|
|
934
|
+
function appendBedrockFailureDiagnostic(output, error, fallbackRequestId) {
|
|
935
|
+
const metadata = error?.$metadata;
|
|
936
|
+
const details = {};
|
|
937
|
+
if (typeof metadata?.httpStatusCode === "number") details.status = metadata.httpStatusCode;
|
|
938
|
+
const errorCode = extractBedrockErrorCode(error);
|
|
939
|
+
if (errorCode !== void 0) details.errorCode = errorCode;
|
|
940
|
+
const requestId = normalizeDiagnosticValue(metadata?.requestId) ?? fallbackRequestId;
|
|
941
|
+
if (requestId !== void 0) details.requestId = requestId;
|
|
942
|
+
if (Object.keys(details).length === 0) return;
|
|
943
|
+
appendAssistantMessageDiagnostic(output, { type: "bedrock_response_failure", timestamp: Date.now(), details });
|
|
944
|
+
}
|
|
945
|
+
var RESERVED_HEADER_EXACT = /* @__PURE__ */ new Set(["authorization", "host"]);
|
|
946
|
+
function isReservedHeader(key) {
|
|
947
|
+
const lower = key.toLowerCase();
|
|
948
|
+
return lower.startsWith("x-amz-") || RESERVED_HEADER_EXACT.has(lower);
|
|
949
|
+
}
|
|
950
|
+
function addCustomHeadersMiddleware(client, headers) {
|
|
951
|
+
const middleware = (next) => async (args) => {
|
|
952
|
+
const request = args.request;
|
|
953
|
+
if (request && typeof request === "object" && "headers" in request) {
|
|
954
|
+
const requestHeaders = request.headers;
|
|
955
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
956
|
+
if (!isReservedHeader(key)) {
|
|
957
|
+
requestHeaders[key] = value;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return next(args);
|
|
962
|
+
};
|
|
963
|
+
client.middlewareStack.add(middleware, { step: "build", name: "pi-ai-custom-headers", priority: "low" });
|
|
964
|
+
}
|
|
965
|
+
var streamSimple = (model, context, options) => {
|
|
966
|
+
const base = buildBaseOptions(model, context, options, void 0);
|
|
967
|
+
if (!options?.reasoning) {
|
|
968
|
+
return stream(model, context, { ...base, reasoning: void 0 });
|
|
969
|
+
}
|
|
970
|
+
if (isAnthropicClaudeModel(model)) {
|
|
971
|
+
if (supportsAdaptiveThinking(model.id, model.name)) {
|
|
972
|
+
return stream(model, context, {
|
|
973
|
+
...base,
|
|
974
|
+
reasoning: options.reasoning,
|
|
975
|
+
thinkingBudgets: options.thinkingBudgets
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
const adjusted = adjustMaxTokensForThinking(
|
|
979
|
+
base.maxTokens,
|
|
980
|
+
model.maxTokens,
|
|
981
|
+
options.reasoning,
|
|
982
|
+
options.thinkingBudgets
|
|
983
|
+
);
|
|
984
|
+
const maxTokens = clampMaxTokensToContext(model, context, adjusted.maxTokens);
|
|
985
|
+
return stream(model, context, {
|
|
986
|
+
...base,
|
|
987
|
+
maxTokens,
|
|
988
|
+
reasoning: options.reasoning,
|
|
989
|
+
thinkingBudgets: {
|
|
990
|
+
...options.thinkingBudgets || {},
|
|
991
|
+
[clampReasoning(options.reasoning)]: Math.min(adjusted.thinkingBudget, Math.max(0, maxTokens - 1024))
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
return stream(model, context, {
|
|
996
|
+
...base,
|
|
997
|
+
reasoning: options.reasoning,
|
|
998
|
+
thinkingBudgets: options.thinkingBudgets
|
|
999
|
+
});
|
|
1000
|
+
};
|
|
1001
|
+
function handleContentBlockStart(event, blocks, output, stream2) {
|
|
1002
|
+
const index = event.contentBlockIndex;
|
|
1003
|
+
const start = event.start;
|
|
1004
|
+
if (start?.toolUse) {
|
|
1005
|
+
const block = {
|
|
1006
|
+
type: "toolCall",
|
|
1007
|
+
id: start.toolUse.toolUseId || "",
|
|
1008
|
+
name: start.toolUse.name || "",
|
|
1009
|
+
arguments: {},
|
|
1010
|
+
partialJson: "",
|
|
1011
|
+
index
|
|
1012
|
+
};
|
|
1013
|
+
output.content.push(block);
|
|
1014
|
+
stream2.push({ type: "toolcall_start", contentIndex: blocks.length - 1, partial: output });
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
function handleContentBlockDelta(event, blocks, output, stream2) {
|
|
1018
|
+
const contentBlockIndex = event.contentBlockIndex;
|
|
1019
|
+
const delta = event.delta;
|
|
1020
|
+
let index = blocks.findIndex((b) => b.index === contentBlockIndex);
|
|
1021
|
+
let block = blocks[index];
|
|
1022
|
+
if (delta?.text !== void 0) {
|
|
1023
|
+
if (!block) {
|
|
1024
|
+
const newBlock = { type: "text", text: "", index: contentBlockIndex };
|
|
1025
|
+
output.content.push(newBlock);
|
|
1026
|
+
index = blocks.length - 1;
|
|
1027
|
+
block = blocks[index];
|
|
1028
|
+
stream2.push({ type: "text_start", contentIndex: index, partial: output });
|
|
1029
|
+
}
|
|
1030
|
+
if (block.type === "text") {
|
|
1031
|
+
block.text += delta.text;
|
|
1032
|
+
stream2.push({ type: "text_delta", contentIndex: index, delta: delta.text, partial: output });
|
|
1033
|
+
}
|
|
1034
|
+
} else if (delta?.toolUse && block?.type === "toolCall") {
|
|
1035
|
+
block.partialJson = (block.partialJson || "") + (delta.toolUse.input || "");
|
|
1036
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
1037
|
+
stream2.push({ type: "toolcall_delta", contentIndex: index, delta: delta.toolUse.input || "", partial: output });
|
|
1038
|
+
} else if (delta?.reasoningContent) {
|
|
1039
|
+
let thinkingBlock = block;
|
|
1040
|
+
let thinkingIndex = index;
|
|
1041
|
+
if (!thinkingBlock) {
|
|
1042
|
+
const newBlock = { type: "thinking", thinking: "", thinkingSignature: "", index: contentBlockIndex };
|
|
1043
|
+
output.content.push(newBlock);
|
|
1044
|
+
thinkingIndex = blocks.length - 1;
|
|
1045
|
+
thinkingBlock = blocks[thinkingIndex];
|
|
1046
|
+
stream2.push({ type: "thinking_start", contentIndex: thinkingIndex, partial: output });
|
|
1047
|
+
}
|
|
1048
|
+
if (thinkingBlock?.type === "thinking") {
|
|
1049
|
+
if (delta.reasoningContent.text) {
|
|
1050
|
+
thinkingBlock.thinking += delta.reasoningContent.text;
|
|
1051
|
+
stream2.push({
|
|
1052
|
+
type: "thinking_delta",
|
|
1053
|
+
contentIndex: thinkingIndex,
|
|
1054
|
+
delta: delta.reasoningContent.text,
|
|
1055
|
+
partial: output
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
if (delta.reasoningContent.signature) {
|
|
1059
|
+
thinkingBlock.thinkingSignature = (thinkingBlock.thinkingSignature || "") + delta.reasoningContent.signature;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
function handleMetadata(event, model, output) {
|
|
1065
|
+
if (event.usage) {
|
|
1066
|
+
output.usage.input = event.usage.inputTokens || 0;
|
|
1067
|
+
output.usage.output = event.usage.outputTokens || 0;
|
|
1068
|
+
output.usage.cacheRead = event.usage.cacheReadInputTokens || 0;
|
|
1069
|
+
output.usage.cacheWrite = event.usage.cacheWriteInputTokens || 0;
|
|
1070
|
+
output.usage.totalTokens = event.usage.totalTokens || output.usage.input + output.usage.output;
|
|
1071
|
+
calculateCost(model, output.usage);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
function handleContentBlockStop(event, blocks, output, stream2) {
|
|
1075
|
+
const index = blocks.findIndex((b) => b.index === event.contentBlockIndex);
|
|
1076
|
+
const block = blocks[index];
|
|
1077
|
+
if (!block) return;
|
|
1078
|
+
delete block.index;
|
|
1079
|
+
switch (block.type) {
|
|
1080
|
+
case "text":
|
|
1081
|
+
stream2.push({ type: "text_end", contentIndex: index, content: block.text, partial: output });
|
|
1082
|
+
break;
|
|
1083
|
+
case "thinking":
|
|
1084
|
+
stream2.push({ type: "thinking_end", contentIndex: index, content: block.thinking, partial: output });
|
|
1085
|
+
break;
|
|
1086
|
+
case "toolCall":
|
|
1087
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
1088
|
+
delete block.partialJson;
|
|
1089
|
+
stream2.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: output });
|
|
1090
|
+
break;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
function getModelMatchCandidates(modelId, modelName) {
|
|
1094
|
+
const values = modelName ? [modelId, modelName] : [modelId];
|
|
1095
|
+
return values.flatMap((value) => {
|
|
1096
|
+
const lower = value.toLowerCase();
|
|
1097
|
+
return [lower, lower.replace(/[\s_.:]+/g, "-")];
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
function supportsAdaptiveThinking(modelId, modelName) {
|
|
1101
|
+
const candidates = getModelMatchCandidates(modelId, modelName);
|
|
1102
|
+
return candidates.some(
|
|
1103
|
+
(s) => s.includes("opus-4-6") || s.includes("opus-4-7") || s.includes("opus-4-8") || s.includes("opus-5") || s.includes("sonnet-4-6") || s.includes("sonnet-5") || s.includes("fable-5")
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
function supportsNativeXhighEffort(model) {
|
|
1107
|
+
const candidates = getModelMatchCandidates(model.id, model.name);
|
|
1108
|
+
return candidates.some(
|
|
1109
|
+
(s) => s.includes("opus-4-7") || s.includes("opus-4-8") || s.includes("opus-5") || s.includes("sonnet-5") || s.includes("fable-5")
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
function mapThinkingLevelToEffort(model, level) {
|
|
1113
|
+
if (level === "xhigh" && supportsNativeXhighEffort(model)) return "xhigh";
|
|
1114
|
+
const mapped = level ? model.thinkingLevelMap?.[level] : void 0;
|
|
1115
|
+
if (typeof mapped === "string") return mapped;
|
|
1116
|
+
switch (level) {
|
|
1117
|
+
case "minimal":
|
|
1118
|
+
case "low":
|
|
1119
|
+
return "low";
|
|
1120
|
+
case "medium":
|
|
1121
|
+
return "medium";
|
|
1122
|
+
case "high":
|
|
1123
|
+
return "high";
|
|
1124
|
+
default:
|
|
1125
|
+
return "high";
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
function resolveCacheRetention(cacheRetention, env) {
|
|
1129
|
+
if (cacheRetention) {
|
|
1130
|
+
return cacheRetention;
|
|
1131
|
+
}
|
|
1132
|
+
if (getProviderEnvValue("HUMAIN_TERMINAL_CACHE_RETENTION", env) === "long" || getProviderEnvValue("PI_CACHE_RETENTION", env) === "long") {
|
|
1133
|
+
return "long";
|
|
1134
|
+
}
|
|
1135
|
+
return "short";
|
|
1136
|
+
}
|
|
1137
|
+
function isAnthropicClaudeModel(model) {
|
|
1138
|
+
const id = model.id.toLowerCase();
|
|
1139
|
+
const name = model.name?.toLowerCase() ?? "";
|
|
1140
|
+
return id.includes("anthropic.claude") || id.includes("anthropic/claude") || name.includes("anthropic.claude") || name.includes("anthropic/claude") || name.includes("claude");
|
|
1141
|
+
}
|
|
1142
|
+
function supportsPromptCaching(model, env) {
|
|
1143
|
+
const candidates = getModelMatchCandidates(model.id, model.name);
|
|
1144
|
+
const hasClaudeRef = candidates.some((s) => s.includes("claude"));
|
|
1145
|
+
if (!hasClaudeRef) {
|
|
1146
|
+
if (getProviderEnvValue("AWS_BEDROCK_FORCE_CACHE", env) === "1") return true;
|
|
1147
|
+
return false;
|
|
1148
|
+
}
|
|
1149
|
+
if (candidates.some((s) => s.includes("fable-5") || s.includes("opus-5") || s.includes("sonnet-5"))) return true;
|
|
1150
|
+
if (candidates.some((s) => s.includes("-4-"))) return true;
|
|
1151
|
+
if (candidates.some((s) => s.includes("claude-3-7-sonnet"))) return true;
|
|
1152
|
+
if (candidates.some((s) => s.includes("claude-3-5-haiku"))) return true;
|
|
1153
|
+
return false;
|
|
1154
|
+
}
|
|
1155
|
+
function supportsThinkingSignature(model) {
|
|
1156
|
+
return isAnthropicClaudeModel(model);
|
|
1157
|
+
}
|
|
1158
|
+
function buildSystemPrompt(systemPrompt, model, cacheRetention, env) {
|
|
1159
|
+
if (!systemPrompt) return void 0;
|
|
1160
|
+
const blocks = [{ text: sanitizeSurrogates(systemPrompt) }];
|
|
1161
|
+
if (cacheRetention !== "none" && supportsPromptCaching(model, env)) {
|
|
1162
|
+
blocks.push({
|
|
1163
|
+
cachePoint: { type: CachePointType.DEFAULT, ...cacheRetention === "long" ? { ttl: CacheTTL.ONE_HOUR } : {} }
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
return blocks;
|
|
1167
|
+
}
|
|
1168
|
+
function normalizeToolCallId(id) {
|
|
1169
|
+
const sanitized = id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1170
|
+
return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;
|
|
1171
|
+
}
|
|
1172
|
+
function createNonBlankTextBlock(text) {
|
|
1173
|
+
const sanitized = sanitizeSurrogates(text);
|
|
1174
|
+
return sanitized.trim().length === 0 ? void 0 : { text: sanitized };
|
|
1175
|
+
}
|
|
1176
|
+
function createRequiredTextBlock(text) {
|
|
1177
|
+
return createNonBlankTextBlock(text) ?? { text: EMPTY_TEXT_PLACEHOLDER };
|
|
1178
|
+
}
|
|
1179
|
+
function convertToolResultContent(content) {
|
|
1180
|
+
const result = [];
|
|
1181
|
+
for (const c of content) {
|
|
1182
|
+
if (c.type === "image") {
|
|
1183
|
+
result.push({ image: createImageBlock(c.mimeType, c.data) });
|
|
1184
|
+
} else {
|
|
1185
|
+
const textBlock = createNonBlankTextBlock(c.text);
|
|
1186
|
+
if (textBlock) result.push(textBlock);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
if (result.length === 0) result.push({ text: EMPTY_TEXT_PLACEHOLDER });
|
|
1190
|
+
return result;
|
|
1191
|
+
}
|
|
1192
|
+
function convertMessages(context, model, cacheRetention, env) {
|
|
1193
|
+
const result = [];
|
|
1194
|
+
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
1195
|
+
for (let i = 0; i < transformedMessages.length; i++) {
|
|
1196
|
+
const m = transformedMessages[i];
|
|
1197
|
+
switch (m.role) {
|
|
1198
|
+
case "user": {
|
|
1199
|
+
const content = [];
|
|
1200
|
+
if (typeof m.content === "string") {
|
|
1201
|
+
content.push(createRequiredTextBlock(m.content));
|
|
1202
|
+
} else {
|
|
1203
|
+
for (const c of m.content) {
|
|
1204
|
+
switch (c.type) {
|
|
1205
|
+
case "text": {
|
|
1206
|
+
const textBlock = createNonBlankTextBlock(c.text);
|
|
1207
|
+
if (textBlock) content.push(textBlock);
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
case "image":
|
|
1211
|
+
content.push({ image: createImageBlock(c.mimeType, c.data) });
|
|
1212
|
+
break;
|
|
1213
|
+
default:
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
if (content.length === 0) content.push({ text: EMPTY_TEXT_PLACEHOLDER });
|
|
1218
|
+
}
|
|
1219
|
+
result.push({
|
|
1220
|
+
role: ConversationRole.USER,
|
|
1221
|
+
content
|
|
1222
|
+
});
|
|
1223
|
+
break;
|
|
1224
|
+
}
|
|
1225
|
+
case "assistant": {
|
|
1226
|
+
if (m.content.length === 0) {
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
const contentBlocks = [];
|
|
1230
|
+
for (const c of m.content) {
|
|
1231
|
+
switch (c.type) {
|
|
1232
|
+
case "text": {
|
|
1233
|
+
const textBlock = createNonBlankTextBlock(c.text);
|
|
1234
|
+
if (!textBlock) continue;
|
|
1235
|
+
contentBlocks.push(textBlock);
|
|
1236
|
+
break;
|
|
1237
|
+
}
|
|
1238
|
+
case "toolCall":
|
|
1239
|
+
contentBlocks.push({
|
|
1240
|
+
toolUse: { toolUseId: c.id, name: c.name, input: c.arguments }
|
|
1241
|
+
});
|
|
1242
|
+
break;
|
|
1243
|
+
case "thinking": {
|
|
1244
|
+
const thinking = sanitizeSurrogates(c.thinking);
|
|
1245
|
+
if (thinking.trim().length === 0) continue;
|
|
1246
|
+
if (supportsThinkingSignature(model)) {
|
|
1247
|
+
if (!c.thinkingSignature || c.thinkingSignature.trim().length === 0) {
|
|
1248
|
+
contentBlocks.push({ text: thinking });
|
|
1249
|
+
} else {
|
|
1250
|
+
contentBlocks.push({
|
|
1251
|
+
reasoningContent: {
|
|
1252
|
+
reasoningText: {
|
|
1253
|
+
text: thinking,
|
|
1254
|
+
signature: c.thinkingSignature
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
} else {
|
|
1260
|
+
contentBlocks.push({
|
|
1261
|
+
reasoningContent: {
|
|
1262
|
+
reasoningText: { text: thinking }
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
break;
|
|
1267
|
+
}
|
|
1268
|
+
default:
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
if (contentBlocks.length === 0) {
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
result.push({
|
|
1276
|
+
role: ConversationRole.ASSISTANT,
|
|
1277
|
+
content: contentBlocks
|
|
1278
|
+
});
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
case "toolResult": {
|
|
1282
|
+
const toolResults = [];
|
|
1283
|
+
toolResults.push({
|
|
1284
|
+
toolResult: {
|
|
1285
|
+
toolUseId: m.toolCallId,
|
|
1286
|
+
content: convertToolResultContent(m.content),
|
|
1287
|
+
status: m.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1290
|
+
let j = i + 1;
|
|
1291
|
+
while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
|
|
1292
|
+
const nextMsg = transformedMessages[j];
|
|
1293
|
+
toolResults.push({
|
|
1294
|
+
toolResult: {
|
|
1295
|
+
toolUseId: nextMsg.toolCallId,
|
|
1296
|
+
content: convertToolResultContent(nextMsg.content),
|
|
1297
|
+
status: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
j++;
|
|
1301
|
+
}
|
|
1302
|
+
i = j - 1;
|
|
1303
|
+
result.push({
|
|
1304
|
+
role: ConversationRole.USER,
|
|
1305
|
+
content: toolResults
|
|
1306
|
+
});
|
|
1307
|
+
break;
|
|
1308
|
+
}
|
|
1309
|
+
default:
|
|
1310
|
+
continue;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (cacheRetention !== "none" && supportsPromptCaching(model, env) && result.length > 0) {
|
|
1314
|
+
const lastMessage = result[result.length - 1];
|
|
1315
|
+
if (lastMessage.role === ConversationRole.USER && lastMessage.content) {
|
|
1316
|
+
lastMessage.content.push({
|
|
1317
|
+
cachePoint: {
|
|
1318
|
+
type: CachePointType.DEFAULT,
|
|
1319
|
+
...cacheRetention === "long" ? { ttl: CacheTTL.ONE_HOUR } : {}
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
return result;
|
|
1325
|
+
}
|
|
1326
|
+
function convertToolConfig(tools, toolChoice, supportsStrictMode) {
|
|
1327
|
+
if (!tools?.length) return void 0;
|
|
1328
|
+
if (toolChoice === "none") return void 0;
|
|
1329
|
+
const bedrockTools = tools.map((tool) => {
|
|
1330
|
+
const strict = resolveJsonSchemaStrictSampling(tool, supportsStrictMode);
|
|
1331
|
+
return {
|
|
1332
|
+
toolSpec: {
|
|
1333
|
+
name: tool.name,
|
|
1334
|
+
description: tool.description,
|
|
1335
|
+
inputSchema: { json: tool.parameters },
|
|
1336
|
+
...strict === true ? { strict: true } : {}
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
});
|
|
1340
|
+
let bedrockToolChoice;
|
|
1341
|
+
switch (toolChoice) {
|
|
1342
|
+
case "auto":
|
|
1343
|
+
bedrockToolChoice = { auto: {} };
|
|
1344
|
+
break;
|
|
1345
|
+
case "any":
|
|
1346
|
+
bedrockToolChoice = { any: {} };
|
|
1347
|
+
break;
|
|
1348
|
+
default:
|
|
1349
|
+
if (toolChoice?.type === "tool") {
|
|
1350
|
+
bedrockToolChoice = { tool: { name: toolChoice.name } };
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return { tools: bedrockTools, toolChoice: bedrockToolChoice };
|
|
1354
|
+
}
|
|
1355
|
+
function mapStopReason(reason) {
|
|
1356
|
+
switch (reason) {
|
|
1357
|
+
case BedrockStopReason.END_TURN:
|
|
1358
|
+
case BedrockStopReason.STOP_SEQUENCE:
|
|
1359
|
+
return { stopReason: "stop" };
|
|
1360
|
+
case BedrockStopReason.MAX_TOKENS:
|
|
1361
|
+
case BedrockStopReason.MODEL_CONTEXT_WINDOW_EXCEEDED:
|
|
1362
|
+
return { stopReason: "length" };
|
|
1363
|
+
case BedrockStopReason.TOOL_USE:
|
|
1364
|
+
return { stopReason: "toolUse" };
|
|
1365
|
+
default:
|
|
1366
|
+
return reason ? { stopReason: "error", errorMessage: `Provider stopped with: ${reason}` } : { stopReason: "error" };
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
function getConfiguredBedrockRegion(options) {
|
|
1370
|
+
return options.region || getProviderEnvValue("AWS_REGION", options.env) || getProviderEnvValue("AWS_DEFAULT_REGION", options.env) || void 0;
|
|
1371
|
+
}
|
|
1372
|
+
function getConfiguredBedrockCredentials(env) {
|
|
1373
|
+
const accessKeyId = getProviderEnvValue("AWS_ACCESS_KEY_ID", env);
|
|
1374
|
+
const secretAccessKey = getProviderEnvValue("AWS_SECRET_ACCESS_KEY", env);
|
|
1375
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
1376
|
+
return void 0;
|
|
1377
|
+
}
|
|
1378
|
+
const sessionToken = getProviderEnvValue("AWS_SESSION_TOKEN", env);
|
|
1379
|
+
return {
|
|
1380
|
+
accessKeyId,
|
|
1381
|
+
secretAccessKey,
|
|
1382
|
+
...sessionToken ? { sessionToken } : {}
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
function getStandardBedrockEndpointRegion(baseUrl) {
|
|
1386
|
+
if (!baseUrl) {
|
|
1387
|
+
return void 0;
|
|
1388
|
+
}
|
|
1389
|
+
try {
|
|
1390
|
+
const { hostname } = new URL(baseUrl);
|
|
1391
|
+
const match = hostname.toLowerCase().match(/^bedrock-runtime(?:-fips)?\.([a-z0-9-]+)\.amazonaws\.com(?:\.cn)?$/);
|
|
1392
|
+
return match?.[1];
|
|
1393
|
+
} catch {
|
|
1394
|
+
return void 0;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
function shouldUseExplicitBedrockEndpoint(baseUrl, configuredRegion, hasAmbientConfiguredProfile) {
|
|
1398
|
+
const endpointRegion = getStandardBedrockEndpointRegion(baseUrl);
|
|
1399
|
+
if (!endpointRegion) {
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
return !configuredRegion && !hasAmbientConfiguredProfile;
|
|
1403
|
+
}
|
|
1404
|
+
function shouldUseBedrockHttp1Handler(baseUrl, env) {
|
|
1405
|
+
if (getProviderEnvValue("AWS_BEDROCK_FORCE_HTTP1", env) === "1") {
|
|
1406
|
+
return true;
|
|
1407
|
+
}
|
|
1408
|
+
if (!baseUrl) {
|
|
1409
|
+
return false;
|
|
1410
|
+
}
|
|
1411
|
+
try {
|
|
1412
|
+
return new URL(baseUrl).protocol === "http:";
|
|
1413
|
+
} catch {
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
function shouldBypassBedrockProxy(baseUrl) {
|
|
1418
|
+
if (!baseUrl) {
|
|
1419
|
+
return false;
|
|
1420
|
+
}
|
|
1421
|
+
try {
|
|
1422
|
+
const url = new URL(baseUrl);
|
|
1423
|
+
return url.protocol === "http:" && isLoopbackHostname(url.hostname);
|
|
1424
|
+
} catch {
|
|
1425
|
+
return false;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
function isLoopbackHostname(hostname) {
|
|
1429
|
+
return hostname === "localhost" || hostname === "0.0.0.0" || hostname === "[::1]" || hostname.startsWith("127.");
|
|
1430
|
+
}
|
|
1431
|
+
function isGovCloudBedrockTarget(model, options) {
|
|
1432
|
+
const region = getConfiguredBedrockRegion(options);
|
|
1433
|
+
if (region?.toLowerCase().startsWith("us-gov-")) {
|
|
1434
|
+
return true;
|
|
1435
|
+
}
|
|
1436
|
+
const modelId = model.id.toLowerCase();
|
|
1437
|
+
return modelId.startsWith("us-gov.") || modelId.startsWith("arn:aws-us-gov:");
|
|
1438
|
+
}
|
|
1439
|
+
function buildAdditionalModelRequestFields(model, options) {
|
|
1440
|
+
if (!options.reasoning || !model.reasoning) {
|
|
1441
|
+
return void 0;
|
|
1442
|
+
}
|
|
1443
|
+
if (isAnthropicClaudeModel(model)) {
|
|
1444
|
+
const display = isGovCloudBedrockTarget(model, options) ? void 0 : options.thinkingDisplay ?? "summarized";
|
|
1445
|
+
const result = supportsAdaptiveThinking(model.id, model.name) ? {
|
|
1446
|
+
thinking: { type: "adaptive", ...display !== void 0 ? { display } : {} },
|
|
1447
|
+
output_config: { effort: mapThinkingLevelToEffort(model, options.reasoning) }
|
|
1448
|
+
} : (() => {
|
|
1449
|
+
const defaultBudgets = {
|
|
1450
|
+
minimal: 1024,
|
|
1451
|
+
low: 2048,
|
|
1452
|
+
medium: 8192,
|
|
1453
|
+
high: 16384,
|
|
1454
|
+
xhigh: 16384,
|
|
1455
|
+
// Budget-based Claude clamps extended levels to high
|
|
1456
|
+
max: 16384
|
|
1457
|
+
};
|
|
1458
|
+
const level = options.reasoning === "xhigh" || options.reasoning === "max" ? "high" : options.reasoning;
|
|
1459
|
+
const budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning];
|
|
1460
|
+
return {
|
|
1461
|
+
thinking: {
|
|
1462
|
+
type: "enabled",
|
|
1463
|
+
budget_tokens: budget,
|
|
1464
|
+
...display !== void 0 ? { display } : {}
|
|
1465
|
+
}
|
|
1466
|
+
};
|
|
1467
|
+
})();
|
|
1468
|
+
if (!supportsAdaptiveThinking(model.id, model.name) && (options.interleavedThinking ?? true)) {
|
|
1469
|
+
result.anthropic_beta = ["interleaved-thinking-2025-05-14"];
|
|
1470
|
+
}
|
|
1471
|
+
return result;
|
|
1472
|
+
}
|
|
1473
|
+
return void 0;
|
|
1474
|
+
}
|
|
1475
|
+
function createImageBlock(mimeType, data) {
|
|
1476
|
+
let format;
|
|
1477
|
+
switch (mimeType) {
|
|
1478
|
+
case "image/jpeg":
|
|
1479
|
+
case "image/jpg":
|
|
1480
|
+
format = ImageFormat.JPEG;
|
|
1481
|
+
break;
|
|
1482
|
+
case "image/png":
|
|
1483
|
+
format = ImageFormat.PNG;
|
|
1484
|
+
break;
|
|
1485
|
+
case "image/gif":
|
|
1486
|
+
format = ImageFormat.GIF;
|
|
1487
|
+
break;
|
|
1488
|
+
case "image/webp":
|
|
1489
|
+
format = ImageFormat.WEBP;
|
|
1490
|
+
break;
|
|
1491
|
+
default:
|
|
1492
|
+
throw new Error(`Unknown image type: ${mimeType}`);
|
|
1493
|
+
}
|
|
1494
|
+
const binaryString = atob(data);
|
|
1495
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
1496
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
1497
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
1498
|
+
}
|
|
1499
|
+
return { source: { bytes }, format };
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// packages/ai/src/bedrock-provider.ts
|
|
1503
|
+
var bedrockProviderModule = {
|
|
1504
|
+
stream,
|
|
1505
|
+
streamSimple
|
|
1506
|
+
};
|
|
1507
|
+
export {
|
|
1508
|
+
bedrockProviderModule
|
|
1509
|
+
};
|