@fleetagent/pi-ai 0.1.9 → 0.2.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -24
- package/dist/cli.js.map +1 -1
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +1 -1
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.generated.d.ts +180 -0
- package/dist/image-models.generated.d.ts.map +1 -1
- package/dist/image-models.generated.js +184 -4
- package/dist/image-models.generated.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +3 -3
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts +5389 -2066
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +5402 -2301
- package/dist/models.generated.js.map +1 -1
- package/dist/models.js +60 -45
- package/dist/models.js.map +1 -1
- package/dist/oauth.d.ts +6 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +4 -1
- package/dist/oauth.js.map +1 -1
- package/dist/providers/amazon-bedrock.d.ts +5 -4
- package/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.js +303 -330
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/anthropic.d.ts +5 -4
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +492 -499
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/azure-openai-responses.d.ts +4 -2
- package/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.js +52 -35
- package/dist/providers/azure-openai-responses.js.map +1 -1
- package/dist/providers/faux.d.ts +19 -22
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js +106 -70
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/github-copilot-headers.d.ts +7 -4
- package/dist/providers/github-copilot-headers.d.ts.map +1 -1
- package/dist/providers/github-copilot-headers.js.map +1 -1
- package/dist/providers/google-shared.d.ts +24 -5
- package/dist/providers/google-shared.d.ts.map +1 -1
- package/dist/providers/google-shared.js +139 -140
- package/dist/providers/google-shared.js.map +1 -1
- package/dist/providers/google-vertex.d.ts +3 -7
- package/dist/providers/google-vertex.d.ts.map +1 -1
- package/dist/providers/google-vertex.js +216 -219
- package/dist/providers/google-vertex.js.map +1 -1
- package/dist/providers/google.d.ts +4 -7
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +214 -218
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/images/openrouter.d.ts.map +1 -1
- package/dist/providers/images/openrouter.js +37 -27
- package/dist/providers/images/openrouter.js.map +1 -1
- package/dist/providers/mistral.d.ts +7 -6
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/mistral.js +287 -265
- package/dist/providers/mistral.js.map +1 -1
- package/dist/providers/openai-codex-responses.d.ts +8 -5
- package/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/dist/providers/openai-codex-responses.js +493 -391
- package/dist/providers/openai-codex-responses.js.map +1 -1
- package/dist/providers/openai-completions.d.ts +7 -10
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +670 -664
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/providers/openai-responses-shared.d.ts +5 -4
- package/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/dist/providers/openai-responses-shared.js +390 -360
- package/dist/providers/openai-responses-shared.js.map +1 -1
- package/dist/providers/openai-responses.d.ts +5 -5
- package/dist/providers/openai-responses.d.ts.map +1 -1
- package/dist/providers/openai-responses.js +134 -109
- package/dist/providers/openai-responses.js.map +1 -1
- package/dist/providers/simple-options.d.ts +4 -2
- package/dist/providers/simple-options.d.ts.map +1 -1
- package/dist/providers/simple-options.js.map +1 -1
- package/dist/providers/transform-messages.d.ts.map +1 -1
- package/dist/providers/transform-messages.js +112 -137
- package/dist/providers/transform-messages.js.map +1 -1
- package/dist/stream.d.ts +0 -1
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +0 -1
- package/dist/stream.js.map +1 -1
- package/dist/types.d.ts +91 -63
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/error-body.d.ts.map +1 -1
- package/dist/utils/error-body.js +15 -4
- package/dist/utils/error-body.js.map +1 -1
- package/dist/utils/estimate.d.ts +4 -0
- package/dist/utils/estimate.d.ts.map +1 -1
- package/dist/utils/estimate.js +3 -1
- package/dist/utils/estimate.js.map +1 -1
- package/dist/utils/headers.d.ts +3 -0
- package/dist/utils/headers.d.ts.map +1 -1
- package/dist/utils/headers.js +21 -0
- package/dist/utils/headers.js.map +1 -1
- package/dist/utils/json-parse.d.ts.map +1 -1
- package/dist/utils/json-parse.js +17 -19
- package/dist/utils/json-parse.js.map +1 -1
- package/dist/utils/oauth/anthropic.d.ts +4 -11
- package/dist/utils/oauth/anthropic.d.ts.map +1 -1
- package/dist/utils/oauth/anthropic.js +100 -117
- package/dist/utils/oauth/anthropic.js.map +1 -1
- package/dist/utils/oauth/device-code.d.ts.map +1 -1
- package/dist/utils/oauth/device-code.js +51 -38
- package/dist/utils/oauth/device-code.js.map +1 -1
- package/dist/utils/oauth/github-copilot.d.ts +6 -9
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/dist/utils/oauth/github-copilot.js +47 -42
- package/dist/utils/oauth/github-copilot.js.map +1 -1
- package/dist/utils/oauth/index.d.ts +8 -17
- package/dist/utils/oauth/index.d.ts.map +1 -1
- package/dist/utils/oauth/index.js +27 -23
- package/dist/utils/oauth/index.js.map +1 -1
- package/dist/utils/oauth/oauth-page.d.ts.map +1 -1
- package/dist/utils/oauth/oauth-page.js.map +1 -1
- package/dist/utils/oauth/openai-codex.d.ts +7 -12
- package/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/dist/utils/oauth/openai-codex.js +72 -89
- package/dist/utils/oauth/openai-codex.js.map +1 -1
- package/dist/utils/oauth/pkce.d.ts +5 -4
- package/dist/utils/oauth/pkce.d.ts.map +1 -1
- package/dist/utils/oauth/pkce.js.map +1 -1
- package/dist/utils/oauth/types.d.ts +7 -2
- package/dist/utils/oauth/types.d.ts.map +1 -1
- package/dist/utils/oauth/types.js.map +1 -1
- package/dist/utils/provider-retry.d.ts +16 -0
- package/dist/utils/provider-retry.d.ts.map +1 -0
- package/dist/utils/provider-retry.js +94 -0
- package/dist/utils/provider-retry.js.map +1 -0
- package/dist/utils/retry.d.ts +14 -0
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +84 -0
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/typebox-helpers.d.ts +5 -4
- package/dist/utils/typebox-helpers.d.ts.map +1 -1
- package/dist/utils/typebox-helpers.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +102 -99
- package/dist/utils/validation.js.map +1 -1
- package/package.json +2 -2
package/dist/models.js
CHANGED
|
@@ -17,6 +17,18 @@ function isRecord(value) {
|
|
|
17
17
|
function isFinitePositiveNumber(value) {
|
|
18
18
|
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
19
19
|
}
|
|
20
|
+
function isModelInput(value) {
|
|
21
|
+
return Array.isArray(value) && value.every((entry) => entry === "text" || entry === "image");
|
|
22
|
+
}
|
|
23
|
+
function isModelCost(value) {
|
|
24
|
+
if (!isRecord(value))
|
|
25
|
+
return false;
|
|
26
|
+
for (const field of ["input", "output", "cacheRead", "cacheWrite"]) {
|
|
27
|
+
if (typeof value[field] !== "number" || !Number.isFinite(value[field]))
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
20
32
|
function isModel(value, provider, id) {
|
|
21
33
|
if (!isRecord(value))
|
|
22
34
|
return false;
|
|
@@ -30,14 +42,10 @@ function isModel(value, provider, id) {
|
|
|
30
42
|
return false;
|
|
31
43
|
if (typeof value.reasoning !== "boolean")
|
|
32
44
|
return false;
|
|
33
|
-
if (!
|
|
45
|
+
if (!isModelInput(value.input))
|
|
34
46
|
return false;
|
|
35
|
-
if (!
|
|
47
|
+
if (!isModelCost(value.cost))
|
|
36
48
|
return false;
|
|
37
|
-
for (const field of ["input", "output", "cacheRead", "cacheWrite"]) {
|
|
38
|
-
if (typeof value.cost[field] !== "number" || !Number.isFinite(value.cost[field]))
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
49
|
return isFinitePositiveNumber(value.contextWindow) && isFinitePositiveNumber(value.maxTokens);
|
|
42
50
|
}
|
|
43
51
|
function validateCatalogModels(value) {
|
|
@@ -132,6 +140,36 @@ function createResult(models, result) {
|
|
|
132
140
|
const counts = models ? countCatalogModels(models) : { providerCount: 0, modelCount: 0 };
|
|
133
141
|
return { ...result, ...counts };
|
|
134
142
|
}
|
|
143
|
+
function getFreshCatalogCache(options, cached, now, ttlMs) {
|
|
144
|
+
if (options.force || !cached || now - cached.fetchedAt >= ttlMs)
|
|
145
|
+
return undefined;
|
|
146
|
+
return cached;
|
|
147
|
+
}
|
|
148
|
+
function createConditionalCatalogHeaders(options, cached) {
|
|
149
|
+
const headers = {};
|
|
150
|
+
if (!options.force && cached?.etag)
|
|
151
|
+
headers["If-None-Match"] = cached.etag;
|
|
152
|
+
if (!options.force && cached?.lastModified)
|
|
153
|
+
headers["If-Modified-Since"] = cached.lastModified;
|
|
154
|
+
return headers;
|
|
155
|
+
}
|
|
156
|
+
function reuseCachedCatalog(cachePath, cached, fetchedAt) {
|
|
157
|
+
const refreshedCache = { ...cached, fetchedAt };
|
|
158
|
+
writeCachedCatalog(cachePath, refreshedCache);
|
|
159
|
+
applyCatalogModels(refreshedCache.models);
|
|
160
|
+
return createResult(refreshedCache.models, {
|
|
161
|
+
loaded: true,
|
|
162
|
+
updated: false,
|
|
163
|
+
fromCache: true,
|
|
164
|
+
revision: refreshedCache.revision,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function validateCatalogIndex(value) {
|
|
168
|
+
if (!isRecord(value) || value.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) {
|
|
169
|
+
throw new Error("Unsupported model catalog index schema");
|
|
170
|
+
}
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
135
173
|
function initializeStaticRegistry() {
|
|
136
174
|
modelRegistry.clear();
|
|
137
175
|
for (const [provider, models] of Object.entries(MODELS)) {
|
|
@@ -165,7 +203,7 @@ export function resetModelCatalog() {
|
|
|
165
203
|
}
|
|
166
204
|
/**
|
|
167
205
|
* Fetch an upstream model catalog index, cache the selected revision, and overlay it on generated models.
|
|
168
|
-
* The upstream format matches the catalog
|
|
206
|
+
* The upstream format matches the catalog produced by the publish-model-catalog workflow.
|
|
169
207
|
*/
|
|
170
208
|
export async function refreshModelCatalog(options = {}) {
|
|
171
209
|
const indexUrl = getIndexUrl(options);
|
|
@@ -175,53 +213,29 @@ export async function refreshModelCatalog(options = {}) {
|
|
|
175
213
|
const cached = readCachedCatalog(cachePath, indexUrl);
|
|
176
214
|
const now = options.now?.() ?? Date.now();
|
|
177
215
|
const ttlMs = options.ttlMs ?? 6 * 60 * 60 * 1000;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
216
|
+
const freshCache = getFreshCatalogCache(options, cached, now, ttlMs);
|
|
217
|
+
if (freshCache) {
|
|
218
|
+
applyCatalogModels(freshCache.models);
|
|
219
|
+
return createResult(freshCache.models, {
|
|
181
220
|
loaded: true,
|
|
182
221
|
updated: false,
|
|
183
222
|
fromCache: true,
|
|
184
|
-
revision:
|
|
223
|
+
revision: freshCache.revision,
|
|
185
224
|
});
|
|
186
225
|
}
|
|
187
226
|
const fetchImpl = options.fetch ?? fetch;
|
|
188
|
-
const headers =
|
|
189
|
-
if (!options.force && cached?.etag)
|
|
190
|
-
headers["If-None-Match"] = cached.etag;
|
|
191
|
-
if (!options.force && cached?.lastModified)
|
|
192
|
-
headers["If-Modified-Since"] = cached.lastModified;
|
|
227
|
+
const headers = createConditionalCatalogHeaders(options, cached);
|
|
193
228
|
const indexResponse = await fetchImpl(indexUrl, { headers, signal: options.signal });
|
|
194
|
-
if (indexResponse.status === 304 && cached)
|
|
195
|
-
|
|
196
|
-
writeCachedCatalog(cachePath, nextCached);
|
|
197
|
-
applyCatalogModels(nextCached.models);
|
|
198
|
-
return createResult(nextCached.models, {
|
|
199
|
-
loaded: true,
|
|
200
|
-
updated: false,
|
|
201
|
-
fromCache: true,
|
|
202
|
-
revision: nextCached.revision,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
229
|
+
if (indexResponse.status === 304 && cached)
|
|
230
|
+
return reuseCachedCatalog(cachePath, cached, now);
|
|
205
231
|
if (!indexResponse.ok)
|
|
206
232
|
throw new Error(`Model catalog index request failed: ${indexResponse.status}`);
|
|
207
|
-
const index = (await indexResponse.json());
|
|
208
|
-
if (!isRecord(index) || index.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) {
|
|
209
|
-
throw new Error("Unsupported model catalog index schema");
|
|
210
|
-
}
|
|
233
|
+
const index = validateCatalogIndex(await indexResponse.json());
|
|
211
234
|
const revision = selectRevision(index);
|
|
212
235
|
if (!revision)
|
|
213
236
|
throw new Error("Model catalog index does not contain a revision");
|
|
214
|
-
if (!options.force && cached?.revision === revision)
|
|
215
|
-
|
|
216
|
-
writeCachedCatalog(cachePath, nextCached);
|
|
217
|
-
applyCatalogModels(nextCached.models);
|
|
218
|
-
return createResult(nextCached.models, {
|
|
219
|
-
loaded: true,
|
|
220
|
-
updated: false,
|
|
221
|
-
fromCache: true,
|
|
222
|
-
revision,
|
|
223
|
-
});
|
|
224
|
-
}
|
|
237
|
+
if (!options.force && cached?.revision === revision)
|
|
238
|
+
return reuseCachedCatalog(cachePath, cached, now);
|
|
225
239
|
const catalogResponse = await fetchImpl(resolveCatalogUrl(indexUrl, revision), { signal: options.signal });
|
|
226
240
|
if (!catalogResponse.ok)
|
|
227
241
|
throw new Error(`Model catalog request failed: ${catalogResponse.status}`);
|
|
@@ -277,19 +291,20 @@ export function getSupportedThinkingLevels(model) {
|
|
|
277
291
|
}
|
|
278
292
|
export function clampThinkingLevel(model, level) {
|
|
279
293
|
const availableLevels = getSupportedThinkingLevels(model);
|
|
280
|
-
|
|
294
|
+
const availableLevelSet = new Set(availableLevels);
|
|
295
|
+
if (availableLevelSet.has(level))
|
|
281
296
|
return level;
|
|
282
297
|
const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
|
|
283
298
|
if (requestedIndex === -1)
|
|
284
299
|
return availableLevels[0] ?? "off";
|
|
285
300
|
for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {
|
|
286
301
|
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
287
|
-
if (
|
|
302
|
+
if (availableLevelSet.has(candidate))
|
|
288
303
|
return candidate;
|
|
289
304
|
}
|
|
290
305
|
for (let i = requestedIndex - 1; i >= 0; i--) {
|
|
291
306
|
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
292
|
-
if (
|
|
307
|
+
if (availableLevelSet.has(candidate))
|
|
293
308
|
return candidate;
|
|
294
309
|
}
|
|
295
310
|
return availableLevels[0] ?? "off";
|
package/dist/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { MODELS } from \"./models.generated.ts\";\nimport type { Api, KnownProvider, Model, ModelThinkingLevel, Usage } from \"./types.ts\";\n\nconst MODEL_CATALOG_SCHEMA_VERSION = 1;\n\ninterface ModelCatalogIndexEntry {\n\tminimumPiVersion: string;\n\trevision: string;\n}\n\ninterface ModelCatalogIndex {\n\tschemaVersion: number;\n\tdefaultRevision?: string;\n\tcatalogs?: ModelCatalogIndexEntry[];\n}\n\ninterface CachedModelCatalog {\n\tschemaVersion: number;\n\tindexUrl: string;\n\trevision: string;\n\tfetchedAt: number;\n\tetag?: string;\n\tlastModified?: string;\n\tmodels: Record<string, Record<string, Model<Api>>>;\n}\n\nexport interface ModelCatalogRefreshOptions {\n\t/** URL of the upstream models/v1/index.json catalog index. Defaults to PI_MODEL_CATALOG_URL. */\n\tindexUrl?: string;\n\t/** Persistent cache file. Defaults to PI_MODEL_CATALOG_CACHE_PATH or ~/.cache/pi/model-catalog.json. */\n\tcachePath?: string;\n\t/** Reuse cache without a network request while it is this fresh. Default: 6 hours. */\n\tttlMs?: number;\n\t/** Ignore TTL and conditional validators. */\n\tforce?: boolean;\n\tsignal?: AbortSignal;\n\t/** Test hook. Defaults to global fetch. */\n\tfetch?: typeof fetch;\n\t/** Test hook. Defaults to Date.now(). */\n\tnow?: () => number;\n}\n\nexport interface ModelCatalogRefreshResult {\n\tloaded: boolean;\n\tupdated: boolean;\n\tfromCache: boolean;\n\trevision?: string;\n\tproviderCount: number;\n\tmodelCount: number;\n}\ntype NodeFs = {\n\texistsSync(path: string): boolean;\n\tmkdirSync(path: string, options: { recursive: boolean }): void;\n\treadFileSync(path: string, encoding: BufferEncoding): string;\n\twriteFileSync(path: string, content: string): void;\n};\n\ntype NodeOs = { homedir(): string };\n\ntype NodePath = {\n\tdirname(path: string): string;\n\tjoin(...parts: string[]): string;\n};\n\nfunction getNodeBuiltin<T>(name: string): T | undefined {\n\treturn typeof process === \"undefined\" ? undefined : (process.getBuiltinModule?.(name) as T | undefined);\n}\n\nfunction getNodeModelCatalogCachePath(): string | undefined {\n\tconst os = getNodeBuiltin<NodeOs>(\"os\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!os || !path) return undefined;\n\treturn path.join(os.homedir(), \".cache\", \"pi\", \"model-catalog.json\");\n}\n\nconst modelRegistry: Map<string, Map<string, Model<Api>>> = new Map();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isFinitePositiveNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction isModel(value: unknown, provider: string, id: string): value is Model<Api> {\n\tif (!isRecord(value)) return false;\n\tif (value.id !== id || value.provider !== provider) return false;\n\tif (typeof value.name !== \"string\" || value.name.length === 0) return false;\n\tif (typeof value.api !== \"string\" || value.api.length === 0) return false;\n\tif (typeof value.baseUrl !== \"string\" || value.baseUrl.length === 0) return false;\n\tif (typeof value.reasoning !== \"boolean\") return false;\n\tif (!Array.isArray(value.input) || value.input.some((entry) => entry !== \"text\" && entry !== \"image\")) return false;\n\tif (!isRecord(value.cost)) return false;\n\tfor (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const) {\n\t\tif (typeof value.cost[field] !== \"number\" || !Number.isFinite(value.cost[field])) return false;\n\t}\n\treturn isFinitePositiveNumber(value.contextWindow) && isFinitePositiveNumber(value.maxTokens);\n}\n\nfunction validateCatalogModels(value: unknown): Record<string, Record<string, Model<Api>>> {\n\tif (!isRecord(value)) throw new Error(\"Model catalog must contain an object\");\n\tconst providers: Record<string, Record<string, Model<Api>>> = {};\n\tfor (const [provider, providerModels] of Object.entries(value)) {\n\t\tif (!isRecord(providerModels)) throw new Error(`Model catalog provider must contain an object: ${provider}`);\n\t\tconst models: Record<string, Model<Api>> = {};\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tif (!isModel(model, provider, id)) throw new Error(`Invalid model catalog entry: ${provider}/${id}`);\n\t\t\tmodels[id] = model;\n\t\t}\n\t\tproviders[provider] = models;\n\t}\n\treturn providers;\n}\n\nfunction countCatalogModels(models: Record<string, Record<string, Model<Api>>>): {\n\tproviderCount: number;\n\tmodelCount: number;\n} {\n\tlet modelCount = 0;\n\tfor (const providerModels of Object.values(models)) modelCount += Object.keys(providerModels).length;\n\treturn { providerCount: Object.keys(models).length, modelCount };\n}\n\nfunction applyCatalogModels(models: Record<string, Record<string, Model<Api>>>): void {\n\tfor (const [provider, providerModels] of Object.entries(models)) {\n\t\tconst registryProviderModels = modelRegistry.get(provider) ?? new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tregistryProviderModels.set(id, model);\n\t\t}\n\t\tmodelRegistry.set(provider, registryProviderModels);\n\t}\n}\n\nfunction readCachedCatalog(cachePath: string | undefined, indexUrl?: string): CachedModelCatalog | undefined {\n\ttry {\n\t\tif (!cachePath) return undefined;\n\t\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\t\tif (!fs?.existsSync(cachePath)) return undefined;\n\t\tconst parsed = JSON.parse(fs.readFileSync(cachePath, \"utf8\")) as unknown;\n\t\tif (!isRecord(parsed)) return undefined;\n\t\tif (parsed.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) return undefined;\n\t\tif (typeof parsed.indexUrl !== \"string\" || typeof parsed.revision !== \"string\") return undefined;\n\t\tif (indexUrl !== undefined && parsed.indexUrl !== indexUrl) return undefined;\n\t\tif (typeof parsed.fetchedAt !== \"number\" || !Number.isFinite(parsed.fetchedAt)) return undefined;\n\t\tconst cached: CachedModelCatalog = {\n\t\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\t\tindexUrl: parsed.indexUrl,\n\t\t\trevision: parsed.revision,\n\t\t\tfetchedAt: parsed.fetchedAt,\n\t\t\tmodels: validateCatalogModels(parsed.models),\n\t\t};\n\t\tif (typeof parsed.etag === \"string\") cached.etag = parsed.etag;\n\t\tif (typeof parsed.lastModified === \"string\") cached.lastModified = parsed.lastModified;\n\t\treturn cached;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction writeCachedCatalog(cachePath: string | undefined, catalog: CachedModelCatalog): void {\n\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!cachePath || !fs || !path) return;\n\tfs.mkdirSync(path.dirname(cachePath), { recursive: true });\n\tfs.writeFileSync(cachePath, `${JSON.stringify(catalog, null, 2)}\\n`);\n}\n\nfunction getCachePath(options?: Pick<ModelCatalogRefreshOptions, \"cachePath\">): string | undefined {\n\tconst envPath = typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_CACHE_PATH;\n\treturn options?.cachePath ?? envPath ?? getNodeModelCatalogCachePath();\n}\n\nfunction getIndexUrl(options?: Pick<ModelCatalogRefreshOptions, \"indexUrl\">): string | undefined {\n\treturn options?.indexUrl ?? (typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_URL);\n}\n\nfunction resolveCatalogUrl(indexUrl: string, revision: string): string {\n\treturn new URL(`revisions/${encodeURIComponent(revision)}/models.json`, indexUrl).toString();\n}\n\nfunction selectRevision(index: ModelCatalogIndex): string | undefined {\n\treturn index.defaultRevision ?? index.catalogs?.at(-1)?.revision;\n}\n\nfunction createResult(\n\tmodels: Record<string, Record<string, Model<Api>>> | undefined,\n\tresult: Pick<ModelCatalogRefreshResult, \"loaded\" | \"updated\" | \"fromCache\" | \"revision\">,\n): ModelCatalogRefreshResult {\n\tconst counts = models ? countCatalogModels(models) : { providerCount: 0, modelCount: 0 };\n\treturn { ...result, ...counts };\n}\n\nfunction initializeStaticRegistry(): void {\n\tmodelRegistry.clear();\n\tfor (const [provider, models] of Object.entries(MODELS)) {\n\t\tconst providerModels = new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(models)) {\n\t\t\tproviderModels.set(id, model as Model<Api>);\n\t\t}\n\t\tmodelRegistry.set(provider, providerModels);\n\t}\n}\n\ninitializeStaticRegistry();\n\n/**\n * Load a previously refreshed model catalog from disk and overlay it on the generated catalog.\n * This is synchronous so callers can update built-in model lists before constructing registries.\n */\nexport function loadCachedModelCatalog(\n\toptions: Pick<ModelCatalogRefreshOptions, \"cachePath\" | \"indexUrl\"> = {},\n): ModelCatalogRefreshResult {\n\tconst cached = readCachedCatalog(getCachePath(options), getIndexUrl(options));\n\tif (!cached) return createResult(undefined, { loaded: false, updated: false, fromCache: true });\n\tapplyCatalogModels(cached.models);\n\treturn createResult(cached.models, {\n\t\tloaded: true,\n\t\tupdated: false,\n\t\tfromCache: true,\n\t\trevision: cached.revision,\n\t});\n}\n\n/** Reset runtime overlays. Intended for tests. */\nexport function resetModelCatalog(): void {\n\tinitializeStaticRegistry();\n}\n\n/**\n * Fetch an upstream model catalog index, cache the selected revision, and overlay it on generated models.\n * The upstream format matches the catalog published by earendil-works/pi's publish-model-catalog workflow.\n */\nexport async function refreshModelCatalog(\n\toptions: ModelCatalogRefreshOptions = {},\n): Promise<ModelCatalogRefreshResult> {\n\tconst indexUrl = getIndexUrl(options);\n\tif (!indexUrl) return createResult(undefined, { loaded: false, updated: false, fromCache: false });\n\tconst cachePath = getCachePath(options);\n\tconst cached = readCachedCatalog(cachePath, indexUrl);\n\tconst now = options.now?.() ?? Date.now();\n\tconst ttlMs = options.ttlMs ?? 6 * 60 * 60 * 1000;\n\tif (!options.force && cached && now - cached.fetchedAt < ttlMs) {\n\t\tapplyCatalogModels(cached.models);\n\t\treturn createResult(cached.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision: cached.revision,\n\t\t});\n\t}\n\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst headers: Record<string, string> = {};\n\tif (!options.force && cached?.etag) headers[\"If-None-Match\"] = cached.etag;\n\tif (!options.force && cached?.lastModified) headers[\"If-Modified-Since\"] = cached.lastModified;\n\tconst indexResponse = await fetchImpl(indexUrl, { headers, signal: options.signal });\n\tif (indexResponse.status === 304 && cached) {\n\t\tconst nextCached = { ...cached, fetchedAt: now };\n\t\twriteCachedCatalog(cachePath, nextCached);\n\t\tapplyCatalogModels(nextCached.models);\n\t\treturn createResult(nextCached.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision: nextCached.revision,\n\t\t});\n\t}\n\tif (!indexResponse.ok) throw new Error(`Model catalog index request failed: ${indexResponse.status}`);\n\tconst index = (await indexResponse.json()) as ModelCatalogIndex;\n\tif (!isRecord(index) || index.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) {\n\t\tthrow new Error(\"Unsupported model catalog index schema\");\n\t}\n\tconst revision = selectRevision(index);\n\tif (!revision) throw new Error(\"Model catalog index does not contain a revision\");\n\tif (!options.force && cached?.revision === revision) {\n\t\tconst nextCached = { ...cached, fetchedAt: now };\n\t\twriteCachedCatalog(cachePath, nextCached);\n\t\tapplyCatalogModels(nextCached.models);\n\t\treturn createResult(nextCached.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision,\n\t\t});\n\t}\n\n\tconst catalogResponse = await fetchImpl(resolveCatalogUrl(indexUrl, revision), { signal: options.signal });\n\tif (!catalogResponse.ok) throw new Error(`Model catalog request failed: ${catalogResponse.status}`);\n\tconst models = validateCatalogModels(await catalogResponse.json());\n\tconst nextCached: CachedModelCatalog = {\n\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\tindexUrl,\n\t\trevision,\n\t\tfetchedAt: now,\n\t\tmodels,\n\t};\n\tconst etag = indexResponse.headers.get(\"etag\");\n\tif (etag) nextCached.etag = etag;\n\tconst lastModified = indexResponse.headers.get(\"last-modified\");\n\tif (lastModified) nextCached.lastModified = lastModified;\n\twriteCachedCatalog(cachePath, nextCached);\n\tapplyCatalogModels(models);\n\treturn createResult(models, { loaded: true, updated: true, fromCache: false, revision });\n}\n\ntype ModelApi<\n\tTProvider extends KnownProvider,\n\tTModelId extends keyof (typeof MODELS)[TProvider],\n> = (typeof MODELS)[TProvider][TModelId] extends { api: infer TApi } ? (TApi extends Api ? TApi : never) : never;\n\nexport function getModel<TProvider extends KnownProvider, TModelId extends keyof (typeof MODELS)[TProvider]>(\n\tprovider: TProvider,\n\tmodelId: TModelId,\n): Model<ModelApi<TProvider, TModelId>> {\n\tconst providerModels = modelRegistry.get(provider);\n\treturn providerModels?.get(modelId as string) as Model<ModelApi<TProvider, TModelId>>;\n}\n\nexport function getProviders(): KnownProvider[] {\n\treturn Array.from(modelRegistry.keys()) as KnownProvider[];\n}\n\nexport function getModels<TProvider extends KnownProvider>(\n\tprovider: TProvider,\n): Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[] {\n\tconst models = modelRegistry.get(provider);\n\treturn models ? (Array.from(models.values()) as Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[]) : [];\n}\n\nexport function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage[\"cost\"] {\n\tusage.cost.input = (model.cost.input / 1000000) * usage.input;\n\tusage.cost.output = (model.cost.output / 1000000) * usage.output;\n\tusage.cost.cacheRead = (model.cost.cacheRead / 1000000) * usage.cacheRead;\n\tusage.cost.cacheWrite = (model.cost.cacheWrite / 1000000) * usage.cacheWrite;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage.cost;\n}\n\nconst EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"];\n\nexport function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn EXTENDED_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tlevel: ModelThinkingLevel,\n): ModelThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tif (availableLevels.includes(level)) return level;\n\n\tconst requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\tfor (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n\n/**\n * Check if two models are equal by comparing both their id and provider.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual<TApi extends Api>(\n\ta: Model<TApi> | null | undefined,\n\tb: Model<TApi> | null | undefined,\n): boolean {\n\tif (!a || !b) return false;\n\treturn a.id === b.id && a.provider === b.provider;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { MODELS } from \"./models.generated.ts\";\nimport type { Api, KnownProvider, Model, ModelThinkingLevel, Usage, UsageCost } from \"./types.ts\";\n\nconst MODEL_CATALOG_SCHEMA_VERSION = 1;\n\ninterface ModelCatalogIndexEntry {\n\tminimumPiVersion: string;\n\trevision: string;\n}\n\ninterface ModelCatalogIndex {\n\tschemaVersion: number;\n\tdefaultRevision?: string;\n\tcatalogs?: ModelCatalogIndexEntry[];\n}\n\ninterface CachedModelCatalog {\n\tschemaVersion: number;\n\tindexUrl: string;\n\trevision: string;\n\tfetchedAt: number;\n\tetag?: string;\n\tlastModified?: string;\n\tmodels: Record<string, Record<string, Model<Api>>>;\n}\n\nexport interface ModelCatalogRefreshOptions {\n\t/** URL of the upstream models/v1/index.json catalog index. Defaults to PI_MODEL_CATALOG_URL. */\n\tindexUrl?: string;\n\t/** Persistent cache file. Defaults to PI_MODEL_CATALOG_CACHE_PATH or ~/.cache/pi/model-catalog.json. */\n\tcachePath?: string;\n\t/** Reuse cache without a network request while it is this fresh. Default: 6 hours. */\n\tttlMs?: number;\n\t/** Ignore TTL and conditional validators. */\n\tforce?: boolean;\n\tsignal?: AbortSignal;\n\t/** Test hook. Defaults to global fetch. */\n\tfetch?: typeof fetch;\n\t/** Test hook. Defaults to Date.now(). */\n\tnow?: () => number;\n}\n\nexport interface ModelCatalogRefreshResult {\n\tloaded: boolean;\n\tupdated: boolean;\n\tfromCache: boolean;\n\trevision?: string;\n\tproviderCount: number;\n\tmodelCount: number;\n}\ninterface NodeDirectoryCreationOptions {\n\trecursive: boolean;\n}\n\ninterface ModelCatalogCounts {\n\tproviderCount: number;\n\tmodelCount: number;\n}\n\ntype NodeFs = {\n\texistsSync(path: string): boolean;\n\tmkdirSync(path: string, options: NodeDirectoryCreationOptions): void;\n\treadFileSync(path: string, encoding: BufferEncoding): string;\n\twriteFileSync(path: string, content: string): void;\n};\n\ntype NodeOs = { homedir(): string };\n\ntype NodePath = {\n\tdirname(path: string): string;\n\tjoin(...parts: string[]): string;\n};\n\nfunction getNodeBuiltin<T>(name: string): T | undefined {\n\treturn typeof process === \"undefined\" ? undefined : (process.getBuiltinModule?.(name) as T | undefined);\n}\n\nfunction getNodeModelCatalogCachePath(): string | undefined {\n\tconst os = getNodeBuiltin<NodeOs>(\"os\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!os || !path) return undefined;\n\treturn path.join(os.homedir(), \".cache\", \"pi\", \"model-catalog.json\");\n}\n\nconst modelRegistry: Map<string, Map<string, Model<Api>>> = new Map();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isFinitePositiveNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction isModelInput(value: unknown): boolean {\n\treturn Array.isArray(value) && value.every((entry) => entry === \"text\" || entry === \"image\");\n}\n\nfunction isModelCost(value: unknown): boolean {\n\tif (!isRecord(value)) return false;\n\tfor (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const) {\n\t\tif (typeof value[field] !== \"number\" || !Number.isFinite(value[field])) return false;\n\t}\n\treturn true;\n}\n\nfunction isModel(value: unknown, provider: string, id: string): value is Model<Api> {\n\tif (!isRecord(value)) return false;\n\tif (value.id !== id || value.provider !== provider) return false;\n\tif (typeof value.name !== \"string\" || value.name.length === 0) return false;\n\tif (typeof value.api !== \"string\" || value.api.length === 0) return false;\n\tif (typeof value.baseUrl !== \"string\" || value.baseUrl.length === 0) return false;\n\tif (typeof value.reasoning !== \"boolean\") return false;\n\tif (!isModelInput(value.input)) return false;\n\tif (!isModelCost(value.cost)) return false;\n\treturn isFinitePositiveNumber(value.contextWindow) && isFinitePositiveNumber(value.maxTokens);\n}\n\nfunction validateCatalogModels(value: unknown): Record<string, Record<string, Model<Api>>> {\n\tif (!isRecord(value)) throw new Error(\"Model catalog must contain an object\");\n\tconst providers: Record<string, Record<string, Model<Api>>> = {};\n\tfor (const [provider, providerModels] of Object.entries(value)) {\n\t\tif (!isRecord(providerModels)) throw new Error(`Model catalog provider must contain an object: ${provider}`);\n\t\tconst models: Record<string, Model<Api>> = {};\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tif (!isModel(model, provider, id)) throw new Error(`Invalid model catalog entry: ${provider}/${id}`);\n\t\t\tmodels[id] = model;\n\t\t}\n\t\tproviders[provider] = models;\n\t}\n\treturn providers;\n}\n\nfunction countCatalogModels(models: Record<string, Record<string, Model<Api>>>): ModelCatalogCounts {\n\tlet modelCount = 0;\n\tfor (const providerModels of Object.values(models)) modelCount += Object.keys(providerModels).length;\n\treturn { providerCount: Object.keys(models).length, modelCount };\n}\n\nfunction applyCatalogModels(models: Record<string, Record<string, Model<Api>>>): void {\n\tfor (const [provider, providerModels] of Object.entries(models)) {\n\t\tconst registryProviderModels = modelRegistry.get(provider) ?? new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tregistryProviderModels.set(id, model);\n\t\t}\n\t\tmodelRegistry.set(provider, registryProviderModels);\n\t}\n}\n\nfunction readCachedCatalog(cachePath: string | undefined, indexUrl?: string): CachedModelCatalog | undefined {\n\ttry {\n\t\tif (!cachePath) return undefined;\n\t\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\t\tif (!fs?.existsSync(cachePath)) return undefined;\n\t\tconst parsed = JSON.parse(fs.readFileSync(cachePath, \"utf8\")) as unknown;\n\t\tif (!isRecord(parsed)) return undefined;\n\t\tif (parsed.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) return undefined;\n\t\tif (typeof parsed.indexUrl !== \"string\" || typeof parsed.revision !== \"string\") return undefined;\n\t\tif (indexUrl !== undefined && parsed.indexUrl !== indexUrl) return undefined;\n\t\tif (typeof parsed.fetchedAt !== \"number\" || !Number.isFinite(parsed.fetchedAt)) return undefined;\n\t\tconst cached: CachedModelCatalog = {\n\t\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\t\tindexUrl: parsed.indexUrl,\n\t\t\trevision: parsed.revision,\n\t\t\tfetchedAt: parsed.fetchedAt,\n\t\t\tmodels: validateCatalogModels(parsed.models),\n\t\t};\n\t\tif (typeof parsed.etag === \"string\") cached.etag = parsed.etag;\n\t\tif (typeof parsed.lastModified === \"string\") cached.lastModified = parsed.lastModified;\n\t\treturn cached;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction writeCachedCatalog(cachePath: string | undefined, catalog: CachedModelCatalog): void {\n\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!cachePath || !fs || !path) return;\n\tfs.mkdirSync(path.dirname(cachePath), { recursive: true });\n\tfs.writeFileSync(cachePath, `${JSON.stringify(catalog, null, 2)}\\n`);\n}\n\nfunction getCachePath(options?: Pick<ModelCatalogRefreshOptions, \"cachePath\">): string | undefined {\n\tconst envPath = typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_CACHE_PATH;\n\treturn options?.cachePath ?? envPath ?? getNodeModelCatalogCachePath();\n}\n\nfunction getIndexUrl(options?: Pick<ModelCatalogRefreshOptions, \"indexUrl\">): string | undefined {\n\treturn options?.indexUrl ?? (typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_URL);\n}\n\nfunction resolveCatalogUrl(indexUrl: string, revision: string): string {\n\treturn new URL(`revisions/${encodeURIComponent(revision)}/models.json`, indexUrl).toString();\n}\n\nfunction selectRevision(index: ModelCatalogIndex): string | undefined {\n\treturn index.defaultRevision ?? index.catalogs?.at(-1)?.revision;\n}\n\nfunction createResult(\n\tmodels: Record<string, Record<string, Model<Api>>> | undefined,\n\tresult: Pick<ModelCatalogRefreshResult, \"loaded\" | \"updated\" | \"fromCache\" | \"revision\">,\n): ModelCatalogRefreshResult {\n\tconst counts = models ? countCatalogModels(models) : { providerCount: 0, modelCount: 0 };\n\treturn { ...result, ...counts };\n}\n\nfunction getFreshCatalogCache(\n\toptions: ModelCatalogRefreshOptions,\n\tcached: CachedModelCatalog | undefined,\n\tnow: number,\n\tttlMs: number,\n): CachedModelCatalog | undefined {\n\tif (options.force || !cached || now - cached.fetchedAt >= ttlMs) return undefined;\n\treturn cached;\n}\n\nfunction createConditionalCatalogHeaders(\n\toptions: ModelCatalogRefreshOptions,\n\tcached: CachedModelCatalog | undefined,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {};\n\tif (!options.force && cached?.etag) headers[\"If-None-Match\"] = cached.etag;\n\tif (!options.force && cached?.lastModified) headers[\"If-Modified-Since\"] = cached.lastModified;\n\treturn headers;\n}\n\nfunction reuseCachedCatalog(\n\tcachePath: string | undefined,\n\tcached: CachedModelCatalog,\n\tfetchedAt: number,\n): ModelCatalogRefreshResult {\n\tconst refreshedCache = { ...cached, fetchedAt };\n\twriteCachedCatalog(cachePath, refreshedCache);\n\tapplyCatalogModels(refreshedCache.models);\n\treturn createResult(refreshedCache.models, {\n\t\tloaded: true,\n\t\tupdated: false,\n\t\tfromCache: true,\n\t\trevision: refreshedCache.revision,\n\t});\n}\n\nfunction validateCatalogIndex(value: unknown): ModelCatalogIndex {\n\tif (!isRecord(value) || value.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) {\n\t\tthrow new Error(\"Unsupported model catalog index schema\");\n\t}\n\treturn value as unknown as ModelCatalogIndex;\n}\n\nfunction initializeStaticRegistry(): void {\n\tmodelRegistry.clear();\n\tfor (const [provider, models] of Object.entries(MODELS)) {\n\t\tconst providerModels = new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(models)) {\n\t\t\tproviderModels.set(id, model as Model<Api>);\n\t\t}\n\t\tmodelRegistry.set(provider, providerModels);\n\t}\n}\n\ninitializeStaticRegistry();\n\n/**\n * Load a previously refreshed model catalog from disk and overlay it on the generated catalog.\n * This is synchronous so callers can update built-in model lists before constructing registries.\n */\nexport function loadCachedModelCatalog(\n\toptions: Pick<ModelCatalogRefreshOptions, \"cachePath\" | \"indexUrl\"> = {},\n): ModelCatalogRefreshResult {\n\tconst cached = readCachedCatalog(getCachePath(options), getIndexUrl(options));\n\tif (!cached) return createResult(undefined, { loaded: false, updated: false, fromCache: true });\n\tapplyCatalogModels(cached.models);\n\treturn createResult(cached.models, {\n\t\tloaded: true,\n\t\tupdated: false,\n\t\tfromCache: true,\n\t\trevision: cached.revision,\n\t});\n}\n\n/** Reset runtime overlays. Intended for tests. */\nexport function resetModelCatalog(): void {\n\tinitializeStaticRegistry();\n}\n\n/**\n * Fetch an upstream model catalog index, cache the selected revision, and overlay it on generated models.\n * The upstream format matches the catalog produced by the publish-model-catalog workflow.\n */\nexport async function refreshModelCatalog(\n\toptions: ModelCatalogRefreshOptions = {},\n): Promise<ModelCatalogRefreshResult> {\n\tconst indexUrl = getIndexUrl(options);\n\tif (!indexUrl) return createResult(undefined, { loaded: false, updated: false, fromCache: false });\n\tconst cachePath = getCachePath(options);\n\tconst cached = readCachedCatalog(cachePath, indexUrl);\n\tconst now = options.now?.() ?? Date.now();\n\tconst ttlMs = options.ttlMs ?? 6 * 60 * 60 * 1000;\n\tconst freshCache = getFreshCatalogCache(options, cached, now, ttlMs);\n\tif (freshCache) {\n\t\tapplyCatalogModels(freshCache.models);\n\t\treturn createResult(freshCache.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision: freshCache.revision,\n\t\t});\n\t}\n\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst headers = createConditionalCatalogHeaders(options, cached);\n\tconst indexResponse = await fetchImpl(indexUrl, { headers, signal: options.signal });\n\tif (indexResponse.status === 304 && cached) return reuseCachedCatalog(cachePath, cached, now);\n\tif (!indexResponse.ok) throw new Error(`Model catalog index request failed: ${indexResponse.status}`);\n\tconst index = validateCatalogIndex(await indexResponse.json());\n\tconst revision = selectRevision(index);\n\tif (!revision) throw new Error(\"Model catalog index does not contain a revision\");\n\tif (!options.force && cached?.revision === revision) return reuseCachedCatalog(cachePath, cached, now);\n\n\tconst catalogResponse = await fetchImpl(resolveCatalogUrl(indexUrl, revision), { signal: options.signal });\n\tif (!catalogResponse.ok) throw new Error(`Model catalog request failed: ${catalogResponse.status}`);\n\tconst models = validateCatalogModels(await catalogResponse.json());\n\tconst nextCached: CachedModelCatalog = {\n\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\tindexUrl,\n\t\trevision,\n\t\tfetchedAt: now,\n\t\tmodels,\n\t};\n\tconst etag = indexResponse.headers.get(\"etag\");\n\tif (etag) nextCached.etag = etag;\n\tconst lastModified = indexResponse.headers.get(\"last-modified\");\n\tif (lastModified) nextCached.lastModified = lastModified;\n\twriteCachedCatalog(cachePath, nextCached);\n\tapplyCatalogModels(models);\n\treturn createResult(models, { loaded: true, updated: true, fromCache: false, revision });\n}\n\ntype ModelApi<\n\tTProvider extends KnownProvider,\n\tTModelId extends keyof (typeof MODELS)[TProvider],\n> = (typeof MODELS)[TProvider][TModelId] extends { api: infer TApi } ? (TApi extends Api ? TApi : never) : never;\n\nexport function getModel<TProvider extends KnownProvider, TModelId extends keyof (typeof MODELS)[TProvider]>(\n\tprovider: TProvider,\n\tmodelId: TModelId,\n): Model<ModelApi<TProvider, TModelId>> {\n\tconst providerModels = modelRegistry.get(provider);\n\treturn providerModels?.get(modelId as string) as Model<ModelApi<TProvider, TModelId>>;\n}\n\nexport function getProviders(): KnownProvider[] {\n\treturn Array.from(modelRegistry.keys()) as KnownProvider[];\n}\n\nexport function getModels<TProvider extends KnownProvider>(\n\tprovider: TProvider,\n): Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[] {\n\tconst models = modelRegistry.get(provider);\n\treturn models ? (Array.from(models.values()) as Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[]) : [];\n}\n\nexport function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): UsageCost {\n\tusage.cost.input = (model.cost.input / 1000000) * usage.input;\n\tusage.cost.output = (model.cost.output / 1000000) * usage.output;\n\tusage.cost.cacheRead = (model.cost.cacheRead / 1000000) * usage.cacheRead;\n\tusage.cost.cacheWrite = (model.cost.cacheWrite / 1000000) * usage.cacheWrite;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage.cost;\n}\n\nconst EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"];\n\nexport function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn EXTENDED_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tlevel: ModelThinkingLevel,\n): ModelThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tconst availableLevelSet = new Set(availableLevels);\n\tif (availableLevelSet.has(level)) return level;\n\n\tconst requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\tfor (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevelSet.has(candidate)) return candidate;\n\t}\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevelSet.has(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n\n/**\n * Check if two models are equal by comparing both their id and provider.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual<TApi extends Api>(\n\ta: Model<TApi> | null | undefined,\n\tb: Model<TApi> | null | undefined,\n): boolean {\n\tif (!a || !b) return false;\n\treturn a.id === b.id && a.provider === b.provider;\n}\n"]}
|
package/dist/oauth.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { type AnthropicLoginOptions, anthropicOAuthProvider, loginAnthropic, refreshAnthropicToken, } from "./utils/oauth/anthropic.ts";
|
|
2
|
+
export { type OAuthDeviceCodePollOptions, type OAuthDeviceCodePollResult, pollOAuthDeviceCodeFlow, } from "./utils/oauth/device-code.ts";
|
|
3
|
+
export { getOAuthApiKey, getOAuthProvider, getOAuthProviderInfoList, getOAuthProviders, type OAuthApiKeyResolution, refreshOAuthToken, registerOAuthProvider, resetOAuthProviders, unregisterOAuthProvider, } from "./utils/oauth/index.ts";
|
|
4
|
+
export { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken, } from "./utils/oauth/openai-codex.ts";
|
|
5
|
+
export type { PKCEPair } from "./utils/oauth/pkce.ts";
|
|
6
|
+
export type { OAuthAuthInfo, OAuthCredentials, OAuthDeviceCodeInfo, OAuthLoginCallbacks, OAuthPrompt, OAuthProvider, OAuthProviderId, OAuthProviderInfo, OAuthProviderInterface, OAuthSelectOption, OAuthSelectPrompt, } from "./utils/oauth/types.ts";
|
|
2
7
|
//# sourceMappingURL=oauth.d.ts.map
|
package/dist/oauth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC","sourcesContent":["export
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,qBAAqB,EAC1B,sBAAsB,EACtB,cAAc,EACd,qBAAqB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACN,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,uBAAuB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,GACvB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EACX,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GACjB,MAAM,wBAAwB,CAAC","sourcesContent":["export {\n\ttype AnthropicLoginOptions,\n\tanthropicOAuthProvider,\n\tloginAnthropic,\n\trefreshAnthropicToken,\n} from \"./utils/oauth/anthropic.ts\";\nexport {\n\ttype OAuthDeviceCodePollOptions,\n\ttype OAuthDeviceCodePollResult,\n\tpollOAuthDeviceCodeFlow,\n} from \"./utils/oauth/device-code.ts\";\nexport {\n\tgetOAuthApiKey,\n\tgetOAuthProvider,\n\tgetOAuthProviderInfoList,\n\tgetOAuthProviders,\n\ttype OAuthApiKeyResolution,\n\trefreshOAuthToken,\n\tregisterOAuthProvider,\n\tresetOAuthProviders,\n\tunregisterOAuthProvider,\n} from \"./utils/oauth/index.ts\";\nexport {\n\tloginOpenAICodex,\n\topenaiCodexOAuthProvider,\n\trefreshOpenAICodexToken,\n} from \"./utils/oauth/openai-codex.ts\";\nexport type { PKCEPair } from \"./utils/oauth/pkce.ts\";\nexport type {\n\tOAuthAuthInfo,\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProvider,\n\tOAuthProviderId,\n\tOAuthProviderInfo,\n\tOAuthProviderInterface,\n\tOAuthSelectOption,\n\tOAuthSelectPrompt,\n} from \"./utils/oauth/types.ts\";\n"]}
|
package/dist/oauth.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { anthropicOAuthProvider, loginAnthropic, refreshAnthropicToken, } from "./utils/oauth/anthropic.js";
|
|
2
|
+
export { pollOAuthDeviceCodeFlow, } from "./utils/oauth/device-code.js";
|
|
3
|
+
export { getOAuthApiKey, getOAuthProvider, getOAuthProviderInfoList, getOAuthProviders, refreshOAuthToken, registerOAuthProvider, resetOAuthProviders, unregisterOAuthProvider, } from "./utils/oauth/index.js";
|
|
4
|
+
export { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken, } from "./utils/oauth/openai-codex.js";
|
|
2
5
|
//# sourceMappingURL=oauth.js.map
|
package/dist/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC","sourcesContent":["export
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,sBAAsB,EACtB,cAAc,EACd,qBAAqB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGN,uBAAuB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EAEjB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,GACvB,MAAM,+BAA+B,CAAC","sourcesContent":["export {\n\ttype AnthropicLoginOptions,\n\tanthropicOAuthProvider,\n\tloginAnthropic,\n\trefreshAnthropicToken,\n} from \"./utils/oauth/anthropic.ts\";\nexport {\n\ttype OAuthDeviceCodePollOptions,\n\ttype OAuthDeviceCodePollResult,\n\tpollOAuthDeviceCodeFlow,\n} from \"./utils/oauth/device-code.ts\";\nexport {\n\tgetOAuthApiKey,\n\tgetOAuthProvider,\n\tgetOAuthProviderInfoList,\n\tgetOAuthProviders,\n\ttype OAuthApiKeyResolution,\n\trefreshOAuthToken,\n\tregisterOAuthProvider,\n\tresetOAuthProviders,\n\tunregisterOAuthProvider,\n} from \"./utils/oauth/index.ts\";\nexport {\n\tloginOpenAICodex,\n\topenaiCodexOAuthProvider,\n\trefreshOpenAICodexToken,\n} from \"./utils/oauth/openai-codex.ts\";\nexport type { PKCEPair } from \"./utils/oauth/pkce.ts\";\nexport type {\n\tOAuthAuthInfo,\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProvider,\n\tOAuthProviderId,\n\tOAuthProviderInfo,\n\tOAuthProviderInterface,\n\tOAuthSelectOption,\n\tOAuthSelectPrompt,\n} from \"./utils/oauth/types.ts\";\n"]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { SimpleStreamOptions, StreamFunction, StreamOptions, ThinkingBudgets, ThinkingLevel } from "../types.ts";
|
|
2
2
|
export type BedrockThinkingDisplay = "summarized" | "omitted";
|
|
3
|
+
export type BedrockToolSelection = "auto" | "any" | "none" | {
|
|
4
|
+
type: "tool";
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
3
7
|
export interface BedrockOptions extends StreamOptions {
|
|
4
8
|
region?: string;
|
|
5
9
|
profile?: string;
|
|
6
|
-
toolChoice?:
|
|
7
|
-
type: "tool";
|
|
8
|
-
name: string;
|
|
9
|
-
};
|
|
10
|
+
toolChoice?: BedrockToolSelection;
|
|
10
11
|
reasoning?: ThinkingLevel;
|
|
11
12
|
thinkingBudgets?: ThinkingBudgets;
|
|
12
13
|
interleavedThinking?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amazon-bedrock.d.ts","sourceRoot":"","sources":["../../src/providers/amazon-bedrock.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAMX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAEb,eAAe,EAEf,aAAa,EAIb,MAAM,aAAa,CAAC;AAQrB,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,cAAe,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAEtE,SAAS,CAAC,EAAE,aAAa,CAAC;IAE1B,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC;;;sGAGkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;yGAIqG;IACrG,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,yBAAyB,EAAE,cAAc,CAqLnF,CAAC;AAoEF,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,yBAAyB,EAAE,mBAAmB,CA4C9F,CAAC","sourcesContent":["import {\n\tBedrockRuntimeClient,\n\ttype BedrockRuntimeClientConfig,\n\tBedrockRuntimeServiceException,\n\tStopReason as BedrockStopReason,\n\ttype Tool as BedrockTool,\n\tCachePointType,\n\tCacheTTL,\n\ttype ContentBlock,\n\ttype ContentBlockDeltaEvent,\n\ttype ContentBlockStartEvent,\n\ttype ContentBlockStopEvent,\n\tConversationRole,\n\tConverseStreamCommand,\n\ttype ConverseStreamMetadataEvent,\n\tImageFormat,\n\ttype Message,\n\ttype SystemContentBlock,\n\ttype ToolChoice,\n\ttype ToolConfiguration,\n\tToolResultStatus,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport { NodeHttpHandler } from \"@smithy/node-http-handler\";\nimport type { BuildMiddleware, DocumentType, MetadataBearer } from \"@smithy/types\";\nimport { calculateCost } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingBudgets,\n\tThinkingContent,\n\tThinkingLevel,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n} from \"../types.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { createHttpProxyAgentsForTarget } from \"../utils/node-http-proxy.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\nimport { adjustMaxTokensForThinking, buildBaseOptions, clampReasoning } from \"./simple-options.ts\";\nimport { transformMessages } from \"./transform-messages.ts\";\n\nexport type BedrockThinkingDisplay = \"summarized\" | \"omitted\";\n\nexport interface BedrockOptions extends StreamOptions {\n\tregion?: string;\n\tprofile?: string;\n\ttoolChoice?: \"auto\" | \"any\" | \"none\" | { type: \"tool\"; name: string };\n\t/* See https://docs.aws.amazon.com/bedrock/latest/userguide/inference-reasoning.html for supported models. */\n\treasoning?: ThinkingLevel;\n\t/* Custom token budgets per thinking level. Overrides default budgets. */\n\tthinkingBudgets?: ThinkingBudgets;\n\t/* Only supported by Claude 4.x models, see https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-extended-thinking.html#claude-messages-extended-thinking-tool-use-interleaved */\n\tinterleavedThinking?: boolean;\n\t/**\n\t * Controls how Claude's thinking content is returned in responses.\n\t * - \"summarized\": Thinking blocks contain summarized thinking text (default here).\n\t * - \"omitted\": Thinking content is redacted but the signature still travels back\n\t * for multi-turn continuity, reducing time-to-first-text-token.\n\t *\n\t * Note: Anthropic's API default for Claude Opus 4.7 and Mythos Preview is\n\t * \"omitted\". We default to \"summarized\" here to keep behavior consistent with\n\t * older Claude 4 models. Only applies to Claude models on Bedrock.\n\t */\n\tthinkingDisplay?: BedrockThinkingDisplay;\n\t/** Key-value pairs attached to the inference request for cost allocation tagging.\n\t * Keys: max 64 chars, no `aws:` prefix. Values: max 256 chars. Max 50 pairs.\n\t * Tags appear in AWS Cost Explorer split cost allocation data.\n\t * @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html */\n\trequestMetadata?: Record<string, string>;\n\t/** Bearer token for Bedrock API key authentication.\n\t * When set, bypasses SigV4 signing and sends Authorization: Bearer <token> instead.\n\t * Requires `bedrock:CallWithBearerToken` IAM permission on the token's identity.\n\t * Set via AWS_BEARER_TOKEN_BEDROCK env var or pass directly.\n\t * @see https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonbedrock.html */\n\tbearerToken?: string;\n}\n\ntype Block = (TextContent | ThinkingContent | ToolCall) & { index?: number; partialJson?: string };\n\nexport const streamBedrock: StreamFunction<\"bedrock-converse-stream\", BedrockOptions> = (\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions: BedrockOptions = {},\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"bedrock-converse-stream\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst blocks = output.content as Block[];\n\n\t\tconst config: BedrockRuntimeClientConfig = {\n\t\t\tprofile: options.profile,\n\t\t};\n\t\tconst configuredRegion = getConfiguredBedrockRegion(options);\n\t\tconst hasConfiguredProfile = hasConfiguredBedrockProfile();\n\t\tconst endpointRegion = getStandardBedrockEndpointRegion(model.baseUrl);\n\t\tconst useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(\n\t\t\tmodel.baseUrl,\n\t\t\tconfiguredRegion,\n\t\t\thasConfiguredProfile,\n\t\t);\n\n\t\t// Only pin standard AWS Bedrock runtime endpoints when no region/profile is configured.\n\t\t// This preserves custom endpoints (VPC/proxy) from #3402 without forcing built-in\n\t\t// catalog defaults such as us-east-1 to override AWS_REGION/AWS_PROFILE.\n\t\tif (useExplicitEndpoint) {\n\t\t\tconfig.endpoint = model.baseUrl;\n\t\t}\n\n\t\t// Resolve bearer token for Bedrock API key auth.\n\t\tconst bearerToken = options.bearerToken || process.env.AWS_BEARER_TOKEN_BEDROCK || undefined;\n\t\tconst useBearerToken = bearerToken !== undefined && process.env.AWS_BEDROCK_SKIP_AUTH !== \"1\";\n\n\t\t// in Node.js/Bun environment only\n\t\tif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\t\t\t// Region resolution: explicit option > env vars > SDK default chain.\n\t\t\t// When AWS_PROFILE is set, we leave region undefined so the SDK can\n\t\t\t// resovle it from aws profile configs. Otherwise fall back to us-east-1.\n\t\t\tif (configuredRegion) {\n\t\t\t\tconfig.region = configuredRegion;\n\t\t\t} else if (endpointRegion && useExplicitEndpoint) {\n\t\t\t\tconfig.region = endpointRegion;\n\t\t\t} else if (!hasConfiguredProfile) {\n\t\t\t\tconfig.region = \"us-east-1\";\n\t\t\t}\n\n\t\t\t// Support proxies that don't need authentication\n\t\t\tif (process.env.AWS_BEDROCK_SKIP_AUTH === \"1\") {\n\t\t\t\tconfig.credentials = {\n\t\t\t\t\taccessKeyId: \"dummy-access-key\",\n\t\t\t\t\tsecretAccessKey: \"dummy-secret-key\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst proxyAgents = createHttpProxyAgentsForTarget(model.baseUrl);\n\t\t\tif (proxyAgents) {\n\t\t\t\t// Bedrock runtime uses NodeHttp2Handler by default since v3.798.0, which is based\n\t\t\t\t// on `http2` module and has no support for http agent.\n\t\t\t\t// Use NodeHttpHandler to support HTTP(S) proxy agents.\n\t\t\t\tconfig.requestHandler = new NodeHttpHandler(proxyAgents);\n\t\t\t} else if (process.env.AWS_BEDROCK_FORCE_HTTP1 === \"1\") {\n\t\t\t\t// Some custom endpoints require HTTP/1.1 instead of HTTP/2\n\t\t\t\tconfig.requestHandler = new NodeHttpHandler();\n\t\t\t}\n\t\t} else {\n\t\t\t// Non-Node environment (browser): fall back to us-east-1 since\n\t\t\t// there's no config file resolution available.\n\t\t\tconfig.region =\n\t\t\t\tconfiguredRegion || (endpointRegion && useExplicitEndpoint ? endpointRegion : undefined) || \"us-east-1\";\n\t\t}\n\n\t\tif (useBearerToken) {\n\t\t\tconfig.token = { token: bearerToken };\n\t\t\tconfig.authSchemePreference = [\"httpBearerAuth\"];\n\t\t}\n\n\t\ttry {\n\t\t\tconst client = new BedrockRuntimeClient(config);\n\t\t\tif (options.headers && Object.keys(options.headers).length > 0) {\n\t\t\t\taddCustomHeadersMiddleware(client, options.headers);\n\t\t\t}\n\t\t\tconst cacheRetention = resolveCacheRetention(options.cacheRetention);\n\t\t\tconst inferenceMaxTokens = options.maxTokens ?? (isAnthropicClaudeModel(model) ? model.maxTokens : undefined);\n\t\t\tlet commandInput = {\n\t\t\t\tmodelId: model.id,\n\t\t\t\tmessages: convertMessages(context, model, cacheRetention),\n\t\t\t\tsystem: buildSystemPrompt(context.systemPrompt, model, cacheRetention),\n\t\t\t\tinferenceConfig: {\n\t\t\t\t\t...(inferenceMaxTokens !== undefined && { maxTokens: inferenceMaxTokens }),\n\t\t\t\t\t...(options.temperature !== undefined && { temperature: options.temperature }),\n\t\t\t\t},\n\t\t\t\ttoolConfig: convertToolConfig(context.tools, options.toolChoice),\n\t\t\t\tadditionalModelRequestFields: buildAdditionalModelRequestFields(model, options),\n\t\t\t\t...(options.requestMetadata !== undefined && { requestMetadata: options.requestMetadata }),\n\t\t\t};\n\t\t\tconst nextCommandInput = await options?.onPayload?.(commandInput, model);\n\t\t\tif (nextCommandInput !== undefined) {\n\t\t\t\tcommandInput = nextCommandInput as typeof commandInput;\n\t\t\t}\n\t\t\tconst command = new ConverseStreamCommand(commandInput);\n\n\t\t\tconst response = await client.send(command, { abortSignal: options.signal });\n\t\t\tif (response.$metadata.httpStatusCode !== undefined) {\n\t\t\t\tconst responseHeaders: Record<string, string> = {};\n\t\t\t\tif (response.$metadata.requestId) {\n\t\t\t\t\tresponseHeaders[\"x-amzn-requestid\"] = response.$metadata.requestId;\n\t\t\t\t}\n\t\t\t\tawait options?.onResponse?.({ status: response.$metadata.httpStatusCode, headers: responseHeaders }, model);\n\t\t\t}\n\n\t\t\tfor await (const item of response.stream!) {\n\t\t\t\tif (item.messageStart) {\n\t\t\t\t\tif (item.messageStart.role !== ConversationRole.ASSISTANT) {\n\t\t\t\t\t\tthrow new Error(\"Unexpected assistant message start but got user message start instead\");\n\t\t\t\t\t}\n\t\t\t\t\tstream.push({ type: \"start\", partial: output });\n\t\t\t\t} else if (item.contentBlockStart) {\n\t\t\t\t\thandleContentBlockStart(item.contentBlockStart, blocks, output, stream);\n\t\t\t\t} else if (item.contentBlockDelta) {\n\t\t\t\t\thandleContentBlockDelta(item.contentBlockDelta, blocks, output, stream);\n\t\t\t\t} else if (item.contentBlockStop) {\n\t\t\t\t\thandleContentBlockStop(item.contentBlockStop, blocks, output, stream);\n\t\t\t\t} else if (item.messageStop) {\n\t\t\t\t\toutput.stopReason = mapStopReason(item.messageStop.stopReason);\n\t\t\t\t} else if (item.metadata) {\n\t\t\t\t\thandleMetadata(item.metadata, model, output);\n\t\t\t\t} else if (item.internalServerException) {\n\t\t\t\t\tthrow item.internalServerException;\n\t\t\t\t} else if (item.modelStreamErrorException) {\n\t\t\t\t\tthrow item.modelStreamErrorException;\n\t\t\t\t} else if (item.validationException) {\n\t\t\t\t\tthrow item.validationException;\n\t\t\t\t} else if (item.throttlingException) {\n\t\t\t\t\tthrow item.throttlingException;\n\t\t\t\t} else if (item.serviceUnavailableException) {\n\t\t\t\t\tthrow item.serviceUnavailableException;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"error\" || output.stopReason === \"aborted\") {\n\t\t\t\tthrow new Error(\"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as Block).index;\n\t\t\t\t// partialJson is only a streaming scratch buffer; never persist it.\n\t\t\t\tdelete (block as Block).partialJson;\n\t\t\t}\n\t\t\toutput.stopReason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatBedrockError(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\n/**\n * Human-readable prefixes for Bedrock SDK exception names.\n * The downstream retry logic in agent-session matches patterns like\n * `server.?error` and `service.?unavailable`, so we preserve the legacy\n * prefix format rather than using the raw SDK exception name.\n */\nconst BEDROCK_ERROR_PREFIXES: Record<string, string> = {\n\tInternalServerException: \"Internal server error\",\n\tModelStreamErrorException: \"Model stream error\",\n\tValidationException: \"Validation error\",\n\tThrottlingException: \"Throttling error\",\n\tServiceUnavailableException: \"Service unavailable\",\n};\n\n/**\n * Format a Bedrock error with a human-readable prefix.\n * AWS SDK exceptions (both from `client.send()` and from stream event items)\n * extend BedrockRuntimeServiceException. We map the `.name` to a stable\n * human-readable prefix so downstream consumers (retry logic, context-overflow\n * detection) can distinguish error categories via simple string matching.\n */\nfunction formatBedrockError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : JSON.stringify(error);\n\tif (error instanceof BedrockRuntimeServiceException) {\n\t\tconst prefix = BEDROCK_ERROR_PREFIXES[error.name] ?? error.name;\n\t\treturn `${prefix}: ${message}`;\n\t}\n\treturn message;\n}\n\n/**\n * Header keys that must never be overwritten by caller-supplied headers.\n * `host` and `x-amz-*` participate in the SigV4 canonical request; `authorization`\n * is owned by SigV4 or the bearer-token path (config.token + authSchemePreference).\n * Compared case-insensitively (caller key is lower-cased before lookup).\n */\nconst RESERVED_HEADER_EXACT = new Set([\"authorization\", \"host\"]);\n\nfunction isReservedHeader(key: string): boolean {\n\tconst lower = key.toLowerCase();\n\treturn lower.startsWith(\"x-amz-\") || RESERVED_HEADER_EXACT.has(lower);\n}\n\n/**\n * Attach caller-supplied headers to the outgoing Bedrock request via a Smithy\n * `build`-step middleware. The `build` step runs after request serialisation but\n * before SigV4 signing, so injected headers are covered by the signature. Reserved\n * SigV4 / auth headers (`x-amz-*`, `authorization`, `host`) are silently skipped;\n * all other caller headers override any existing same-named header on the request.\n */\nfunction addCustomHeadersMiddleware(client: BedrockRuntimeClient, headers: Record<string, string>): void {\n\tconst middleware: BuildMiddleware<object, MetadataBearer> = (next) => async (args) => {\n\t\tconst request = args.request;\n\t\tif (request && typeof request === \"object\" && \"headers\" in request) {\n\t\t\tconst requestHeaders = (request as { headers: Record<string, string> }).headers;\n\t\t\tfor (const [key, value] of Object.entries(headers)) {\n\t\t\t\tif (!isReservedHeader(key)) {\n\t\t\t\t\trequestHeaders[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn next(args);\n\t};\n\tclient.middlewareStack.add(middleware, { step: \"build\", name: \"pi-ai-custom-headers\", priority: \"low\" });\n}\n\nexport const streamSimpleBedrock: StreamFunction<\"bedrock-converse-stream\", SimpleStreamOptions> = (\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst base = buildBaseOptions(model, context, options, undefined);\n\tif (!options?.reasoning) {\n\t\treturn streamBedrock(model, context, { ...base, reasoning: undefined } satisfies BedrockOptions);\n\t}\n\n\tif (isAnthropicClaudeModel(model)) {\n\t\tif (supportsAdaptiveThinking(model.id, model.name)) {\n\t\t\treturn streamBedrock(model, context, {\n\t\t\t\t...base,\n\t\t\t\treasoning: options.reasoning,\n\t\t\t\tthinkingBudgets: options.thinkingBudgets,\n\t\t\t} satisfies BedrockOptions);\n\t\t}\n\n\t\t// Undefined means the caller did not request an output cap; let the helper use the model cap.\n\t\t// Do not coerce to 0 here, or the thinking budget would become the entire maxTokens value.\n\t\tconst adjusted = adjustMaxTokensForThinking(\n\t\t\tbase.maxTokens,\n\t\t\tmodel.maxTokens,\n\t\t\toptions.reasoning,\n\t\t\toptions.thinkingBudgets,\n\t\t);\n\n\t\treturn streamBedrock(model, context, {\n\t\t\t...base,\n\t\t\tmaxTokens: adjusted.maxTokens,\n\t\t\treasoning: options.reasoning,\n\t\t\tthinkingBudgets: {\n\t\t\t\t...(options.thinkingBudgets || {}),\n\t\t\t\t[clampReasoning(options.reasoning)!]: adjusted.thinkingBudget,\n\t\t\t},\n\t\t} satisfies BedrockOptions);\n\t}\n\n\treturn streamBedrock(model, context, {\n\t\t...base,\n\t\treasoning: options.reasoning,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t} satisfies BedrockOptions);\n};\n\nfunction handleContentBlockStart(\n\tevent: ContentBlockStartEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst index = event.contentBlockIndex!;\n\tconst start = event.start;\n\n\tif (start?.toolUse) {\n\t\tconst block: Block = {\n\t\t\ttype: \"toolCall\",\n\t\t\tid: start.toolUse.toolUseId || \"\",\n\t\t\tname: start.toolUse.name || \"\",\n\t\t\targuments: {},\n\t\t\tpartialJson: \"\",\n\t\t\tindex,\n\t\t};\n\t\toutput.content.push(block);\n\t\tstream.push({ type: \"toolcall_start\", contentIndex: blocks.length - 1, partial: output });\n\t}\n}\n\nfunction handleContentBlockDelta(\n\tevent: ContentBlockDeltaEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst contentBlockIndex = event.contentBlockIndex!;\n\tconst delta = event.delta;\n\tlet index = blocks.findIndex((b) => b.index === contentBlockIndex);\n\tlet block = blocks[index];\n\n\tif (delta?.text !== undefined) {\n\t\t// If no text block exists yet, create one, as `handleContentBlockStart` is not sent for text blocks\n\t\tif (!block) {\n\t\t\tconst newBlock: Block = { type: \"text\", text: \"\", index: contentBlockIndex };\n\t\t\toutput.content.push(newBlock);\n\t\t\tindex = blocks.length - 1;\n\t\t\tblock = blocks[index];\n\t\t\tstream.push({ type: \"text_start\", contentIndex: index, partial: output });\n\t\t}\n\t\tif (block.type === \"text\") {\n\t\t\tblock.text += delta.text;\n\t\t\tstream.push({ type: \"text_delta\", contentIndex: index, delta: delta.text, partial: output });\n\t\t}\n\t} else if (delta?.toolUse && block?.type === \"toolCall\") {\n\t\tblock.partialJson = (block.partialJson || \"\") + (delta.toolUse.input || \"\");\n\t\tblock.arguments = parseStreamingJson(block.partialJson);\n\t\tstream.push({ type: \"toolcall_delta\", contentIndex: index, delta: delta.toolUse.input || \"\", partial: output });\n\t} else if (delta?.reasoningContent) {\n\t\tlet thinkingBlock = block;\n\t\tlet thinkingIndex = index;\n\n\t\tif (!thinkingBlock) {\n\t\t\tconst newBlock: Block = { type: \"thinking\", thinking: \"\", thinkingSignature: \"\", index: contentBlockIndex };\n\t\t\toutput.content.push(newBlock);\n\t\t\tthinkingIndex = blocks.length - 1;\n\t\t\tthinkingBlock = blocks[thinkingIndex];\n\t\t\tstream.push({ type: \"thinking_start\", contentIndex: thinkingIndex, partial: output });\n\t\t}\n\n\t\tif (thinkingBlock?.type === \"thinking\") {\n\t\t\tif (delta.reasoningContent.text) {\n\t\t\t\tthinkingBlock.thinking += delta.reasoningContent.text;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: thinkingIndex,\n\t\t\t\t\tdelta: delta.reasoningContent.text,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (delta.reasoningContent.signature) {\n\t\t\t\tthinkingBlock.thinkingSignature =\n\t\t\t\t\t(thinkingBlock.thinkingSignature || \"\") + delta.reasoningContent.signature;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction handleMetadata(\n\tevent: ConverseStreamMetadataEvent,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toutput: AssistantMessage,\n): void {\n\tif (event.usage) {\n\t\toutput.usage.input = event.usage.inputTokens || 0;\n\t\toutput.usage.output = event.usage.outputTokens || 0;\n\t\toutput.usage.cacheRead = event.usage.cacheReadInputTokens || 0;\n\t\toutput.usage.cacheWrite = event.usage.cacheWriteInputTokens || 0;\n\t\toutput.usage.totalTokens = event.usage.totalTokens || output.usage.input + output.usage.output;\n\t\tcalculateCost(model, output.usage);\n\t}\n}\n\nfunction handleContentBlockStop(\n\tevent: ContentBlockStopEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst index = blocks.findIndex((b) => b.index === event.contentBlockIndex);\n\tconst block = blocks[index];\n\tif (!block) return;\n\tdelete (block as Block).index;\n\n\tswitch (block.type) {\n\t\tcase \"text\":\n\t\t\tstream.push({ type: \"text_end\", contentIndex: index, content: block.text, partial: output });\n\t\t\tbreak;\n\t\tcase \"thinking\":\n\t\t\tstream.push({ type: \"thinking_end\", contentIndex: index, content: block.thinking, partial: output });\n\t\t\tbreak;\n\t\tcase \"toolCall\":\n\t\t\tblock.arguments = parseStreamingJson(block.partialJson);\n\t\t\t// Finalize in-place and strip the scratch buffer so replay only\n\t\t\t// carries parsed arguments.\n\t\t\tdelete (block as Block).partialJson;\n\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: index, toolCall: block, partial: output });\n\t\t\tbreak;\n\t}\n}\n\n/**\n * Check if the model supports adaptive thinking (Opus 4.6+, Sonnet 4.6).\n * Checks both model ID and model name to support application inference profiles\n * whose ARNs don't contain the model name.\n */\nfunction getModelMatchCandidates(modelId: string, modelName?: string): string[] {\n\tconst values = modelName ? [modelId, modelName] : [modelId];\n\treturn values.flatMap((value) => {\n\t\tconst lower = value.toLowerCase();\n\t\treturn [lower, lower.replace(/[\\s_.:]+/g, \"-\")];\n\t});\n}\n\nfunction supportsAdaptiveThinking(modelId: string, modelName?: string): boolean {\n\tconst candidates = getModelMatchCandidates(modelId, modelName);\n\treturn candidates.some((s) => s.includes(\"opus-4-6\") || s.includes(\"opus-4-7\") || s.includes(\"sonnet-4-6\"));\n}\n\nfunction supportsNativeXhighEffort(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst candidates = getModelMatchCandidates(model.id, model.name);\n\treturn candidates.some((s) => s.includes(\"opus-4-7\"));\n}\n\nfunction mapThinkingLevelToEffort(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tlevel: SimpleStreamOptions[\"reasoning\"],\n): \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" {\n\tif (level === \"xhigh\" && supportsNativeXhighEffort(model)) return \"xhigh\";\n\n\tconst mapped = level ? model.thinkingLevelMap?.[level] : undefined;\n\tif (typeof mapped === \"string\") return mapped as \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\n\tswitch (level) {\n\t\tcase \"minimal\":\n\t\tcase \"low\":\n\t\t\treturn \"low\";\n\t\tcase \"medium\":\n\t\t\treturn \"medium\";\n\t\tcase \"high\":\n\t\t\treturn \"high\";\n\t\tdefault:\n\t\t\treturn \"high\";\n\t}\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (typeof process !== \"undefined\" && process.env.PI_CACHE_RETENTION === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\n/**\n * Check if the model is an Anthropic Claude model on Bedrock.\n * Checks both model ID and model name to support application inference profiles\n * whose ARNs don't contain the model name.\n */\nfunction isAnthropicClaudeModel(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst id = model.id.toLowerCase();\n\tconst name = model.name?.toLowerCase() ?? \"\";\n\treturn (\n\t\tid.includes(\"anthropic.claude\") ||\n\t\tid.includes(\"anthropic/claude\") ||\n\t\tname.includes(\"anthropic.claude\") ||\n\t\tname.includes(\"anthropic/claude\") ||\n\t\tname.includes(\"claude\")\n\t);\n}\n\n/**\n * Check if the model supports prompt caching.\n * Supported: Claude 3.5 Haiku, Claude 3.7 Sonnet, Claude 4.x models, Claude 5 models\n *\n * For base models and system-defined inference profiles the model ID / ARN\n * contains the model name, so we can decide locally.\n *\n * For application inference profiles (whose ARNs don't contain the model name),\n * also checks model.name which is user-controlled via models.json or registerProvider.\n * As a last resort, set AWS_BEDROCK_FORCE_CACHE=1 to enable cache points.\n * Amazon Nova models have automatic caching and don't need explicit cache points.\n */\nfunction supportsPromptCaching(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst candidates = getModelMatchCandidates(model.id, model.name);\n\n\tconst hasClaudeRef = candidates.some((s) => s.includes(\"claude\"));\n\tif (!hasClaudeRef) {\n\t\t// Application inference profiles don't contain the model name in the ARN.\n\t\t// Allow users to force cache points via environment variable.\n\t\tif (typeof process !== \"undefined\" && process.env.AWS_BEDROCK_FORCE_CACHE === \"1\") return true;\n\t\treturn false;\n\t}\n\t// Claude 5 models (fable-5, sonnet-5)\n\tif (candidates.some((s) => s.includes(\"fable-5\") || s.includes(\"sonnet-5\"))) return true;\n\t// Claude 4.x models (opus-4, sonnet-4, haiku-4)\n\tif (candidates.some((s) => s.includes(\"-4-\"))) return true;\n\t// Claude 3.7 Sonnet\n\tif (candidates.some((s) => s.includes(\"claude-3-7-sonnet\"))) return true;\n\t// Claude 3.5 Haiku\n\tif (candidates.some((s) => s.includes(\"claude-3-5-haiku\"))) return true;\n\treturn false;\n}\n\n/**\n * Check if the model supports thinking signatures in reasoningContent.\n * Only Anthropic Claude models support the signature field.\n * Other models (OpenAI, Qwen, Minimax, Moonshot, etc.) reject it with:\n * \"This model doesn't support the reasoningContent.reasoningText.signature field\"\n *\n * Checks both model ID and model name to support application inference profiles.\n */\nfunction supportsThinkingSignature(model: Model<\"bedrock-converse-stream\">): boolean {\n\treturn isAnthropicClaudeModel(model);\n}\n\nfunction buildSystemPrompt(\n\tsystemPrompt: string | undefined,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): SystemContentBlock[] | undefined {\n\tif (!systemPrompt) return undefined;\n\n\tconst blocks: SystemContentBlock[] = [{ text: sanitizeSurrogates(systemPrompt) }];\n\n\t// Add cache point for supported Claude models when caching is enabled\n\tif (cacheRetention !== \"none\" && supportsPromptCaching(model)) {\n\t\tblocks.push({\n\t\t\tcachePoint: { type: CachePointType.DEFAULT, ...(cacheRetention === \"long\" ? { ttl: CacheTTL.ONE_HOUR } : {}) },\n\t\t});\n\t}\n\n\treturn blocks;\n}\n\nfunction normalizeToolCallId(id: string): string {\n\tconst sanitized = id.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\treturn sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n}\n\nfunction convertMessages(\n\tcontext: Context,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): Message[] {\n\tconst result: Message[] = [];\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tfor (let i = 0; i < transformedMessages.length; i++) {\n\t\tconst m = transformedMessages[i];\n\n\t\tswitch (m.role) {\n\t\t\tcase \"user\": {\n\t\t\t\tconst content: ContentBlock[] = [];\n\t\t\t\tif (typeof m.content === \"string\") {\n\t\t\t\t\tcontent.push({ text: sanitizeSurrogates(m.content) });\n\t\t\t\t} else {\n\t\t\t\t\tfor (const c of m.content) {\n\t\t\t\t\t\tswitch (c.type) {\n\t\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t\tcontent.push({ text: sanitizeSurrogates(c.text) });\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"image\":\n\t\t\t\t\t\t\t\tcontent.push({ image: createImageBlock(c.mimeType, c.data) });\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tresult.push({\n\t\t\t\t\trole: ConversationRole.USER,\n\t\t\t\t\tcontent,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"assistant\": {\n\t\t\t\t// Skip assistant messages with empty content (e.g., from aborted requests)\n\t\t\t\t// Bedrock rejects messages with empty content arrays\n\t\t\t\tif (m.content.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst contentBlocks: ContentBlock[] = [];\n\t\t\t\tfor (const c of m.content) {\n\t\t\t\t\tswitch (c.type) {\n\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t// Skip empty text blocks\n\t\t\t\t\t\t\tif (c.text.trim().length === 0) continue;\n\t\t\t\t\t\t\tcontentBlocks.push({ text: sanitizeSurrogates(c.text) });\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"toolCall\":\n\t\t\t\t\t\t\tcontentBlocks.push({\n\t\t\t\t\t\t\t\ttoolUse: { toolUseId: c.id, name: c.name, input: c.arguments },\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"thinking\":\n\t\t\t\t\t\t\t// Skip empty thinking blocks\n\t\t\t\t\t\t\tif (c.thinking.trim().length === 0) continue;\n\t\t\t\t\t\t\t// Only Anthropic models support the signature field in reasoningText.\n\t\t\t\t\t\t\t// For other models, we omit the signature to avoid errors like:\n\t\t\t\t\t\t\t// \"This model doesn't support the reasoningContent.reasoningText.signature field\"\n\t\t\t\t\t\t\tif (supportsThinkingSignature(model)) {\n\t\t\t\t\t\t\t\t// Signatures arrive after thinking deltas. If a partial or externally\n\t\t\t\t\t\t\t\t// persisted message lacks a signature, Bedrock rejects the replayed\n\t\t\t\t\t\t\t\t// reasoning block. Fall back to plain text, matching Anthropic.\n\t\t\t\t\t\t\t\tif (!c.thinkingSignature || c.thinkingSignature.trim().length === 0) {\n\t\t\t\t\t\t\t\t\tcontentBlocks.push({ text: sanitizeSurrogates(c.thinking) });\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcontentBlocks.push({\n\t\t\t\t\t\t\t\t\t\treasoningContent: {\n\t\t\t\t\t\t\t\t\t\t\treasoningText: {\n\t\t\t\t\t\t\t\t\t\t\t\ttext: sanitizeSurrogates(c.thinking),\n\t\t\t\t\t\t\t\t\t\t\t\tsignature: c.thinkingSignature,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcontentBlocks.push({\n\t\t\t\t\t\t\t\t\treasoningContent: {\n\t\t\t\t\t\t\t\t\t\treasoningText: { text: sanitizeSurrogates(c.thinking) },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Skip if all content blocks were filtered out\n\t\t\t\tif (contentBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tresult.push({\n\t\t\t\t\trole: ConversationRole.ASSISTANT,\n\t\t\t\t\tcontent: contentBlocks,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolResult\": {\n\t\t\t\t// Collect all consecutive toolResult messages into a single user message\n\t\t\t\t// Bedrock requires all tool results to be in one message\n\t\t\t\tconst toolResults: ContentBlock.ToolResultMember[] = [];\n\n\t\t\t\t// Add current tool result with all content blocks combined\n\t\t\t\ttoolResults.push({\n\t\t\t\t\ttoolResult: {\n\t\t\t\t\t\ttoolUseId: m.toolCallId,\n\t\t\t\t\t\tcontent: m.content.map((c) =>\n\t\t\t\t\t\t\tc.type === \"image\"\n\t\t\t\t\t\t\t\t? { image: createImageBlock(c.mimeType, c.data) }\n\t\t\t\t\t\t\t\t: { text: sanitizeSurrogates(c.text) },\n\t\t\t\t\t\t),\n\t\t\t\t\t\tstatus: m.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\t// Look ahead for consecutive toolResult messages\n\t\t\t\tlet j = i + 1;\n\t\t\t\twhile (j < transformedMessages.length && transformedMessages[j].role === \"toolResult\") {\n\t\t\t\t\tconst nextMsg = transformedMessages[j] as ToolResultMessage;\n\t\t\t\t\ttoolResults.push({\n\t\t\t\t\t\ttoolResult: {\n\t\t\t\t\t\t\ttoolUseId: nextMsg.toolCallId,\n\t\t\t\t\t\t\tcontent: nextMsg.content.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\"\n\t\t\t\t\t\t\t\t\t? { image: createImageBlock(c.mimeType, c.data) }\n\t\t\t\t\t\t\t\t\t: { text: sanitizeSurrogates(c.text) },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tstatus: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tj++;\n\t\t\t\t}\n\n\t\t\t\t// Skip the messages we've already processed\n\t\t\t\ti = j - 1;\n\n\t\t\t\tresult.push({\n\t\t\t\t\trole: ConversationRole.USER,\n\t\t\t\t\tcontent: toolResults,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tcontinue;\n\t\t}\n\t}\n\n\t// Add cache point to the last user message for supported Claude models when caching is enabled\n\tif (cacheRetention !== \"none\" && supportsPromptCaching(model) && result.length > 0) {\n\t\tconst lastMessage = result[result.length - 1];\n\t\tif (lastMessage.role === ConversationRole.USER && lastMessage.content) {\n\t\t\t(lastMessage.content as ContentBlock[]).push({\n\t\t\t\tcachePoint: {\n\t\t\t\t\ttype: CachePointType.DEFAULT,\n\t\t\t\t\t...(cacheRetention === \"long\" ? { ttl: CacheTTL.ONE_HOUR } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction convertToolConfig(\n\ttools: Tool[] | undefined,\n\ttoolChoice: BedrockOptions[\"toolChoice\"],\n): ToolConfiguration | undefined {\n\tif (!tools?.length || toolChoice === \"none\") return undefined;\n\n\tconst bedrockTools: BedrockTool[] = tools.map((tool) => ({\n\t\ttoolSpec: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tinputSchema: { json: tool.parameters as unknown as DocumentType },\n\t\t},\n\t}));\n\n\tlet bedrockToolChoice: ToolChoice | undefined;\n\tswitch (toolChoice) {\n\t\tcase \"auto\":\n\t\t\tbedrockToolChoice = { auto: {} };\n\t\t\tbreak;\n\t\tcase \"any\":\n\t\t\tbedrockToolChoice = { any: {} };\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (toolChoice?.type === \"tool\") {\n\t\t\t\tbedrockToolChoice = { tool: { name: toolChoice.name } };\n\t\t\t}\n\t}\n\n\treturn { tools: bedrockTools, toolChoice: bedrockToolChoice };\n}\n\nfunction mapStopReason(reason: string | undefined): StopReason {\n\tswitch (reason) {\n\t\tcase BedrockStopReason.END_TURN:\n\t\tcase BedrockStopReason.STOP_SEQUENCE:\n\t\t\treturn \"stop\";\n\t\tcase BedrockStopReason.MAX_TOKENS:\n\t\tcase BedrockStopReason.MODEL_CONTEXT_WINDOW_EXCEEDED:\n\t\t\treturn \"length\";\n\t\tcase BedrockStopReason.TOOL_USE:\n\t\t\treturn \"toolUse\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\n\nfunction getConfiguredBedrockRegion(options: BedrockOptions): string | undefined {\n\tif (typeof process === \"undefined\") {\n\t\treturn options.region;\n\t}\n\n\treturn options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || undefined;\n}\n\nfunction hasConfiguredBedrockProfile(): boolean {\n\tif (typeof process === \"undefined\") {\n\t\treturn false;\n\t}\n\n\treturn Boolean(process.env.AWS_PROFILE);\n}\n\nfunction getStandardBedrockEndpointRegion(baseUrl: string | undefined): string | undefined {\n\tif (!baseUrl) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst { hostname } = new URL(baseUrl);\n\t\tconst match = hostname.toLowerCase().match(/^bedrock-runtime(?:-fips)?\\.([a-z0-9-]+)\\.amazonaws\\.com(?:\\.cn)?$/);\n\t\treturn match?.[1];\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction shouldUseExplicitBedrockEndpoint(\n\tbaseUrl: string,\n\tconfiguredRegion: string | undefined,\n\thasConfiguredProfile: boolean,\n): boolean {\n\tconst endpointRegion = getStandardBedrockEndpointRegion(baseUrl);\n\tif (!endpointRegion) {\n\t\treturn true;\n\t}\n\n\treturn !configuredRegion && !hasConfiguredProfile;\n}\n\nfunction isGovCloudBedrockTarget(model: Model<\"bedrock-converse-stream\">, options: BedrockOptions): boolean {\n\tconst region = getConfiguredBedrockRegion(options);\n\tif (region?.toLowerCase().startsWith(\"us-gov-\")) {\n\t\treturn true;\n\t}\n\n\tconst modelId = model.id.toLowerCase();\n\treturn modelId.startsWith(\"us-gov.\") || modelId.startsWith(\"arn:aws-us-gov:\");\n}\n\nfunction buildAdditionalModelRequestFields(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toptions: BedrockOptions,\n): Record<string, any> | undefined {\n\tif (!options.reasoning || !model.reasoning) {\n\t\treturn undefined;\n\t}\n\n\tif (isAnthropicClaudeModel(model)) {\n\t\t// GovCloud Bedrock currently rejects the Claude thinking.display field.\n\t\t// Omit it there until the GovCloud Converse schema catches up.\n\t\tconst display = isGovCloudBedrockTarget(model, options) ? undefined : (options.thinkingDisplay ?? \"summarized\");\n\t\tconst result: Record<string, any> = supportsAdaptiveThinking(model.id, model.name)\n\t\t\t? {\n\t\t\t\t\tthinking: { type: \"adaptive\", ...(display !== undefined ? { display } : {}) },\n\t\t\t\t\toutput_config: { effort: mapThinkingLevelToEffort(model, options.reasoning) },\n\t\t\t\t}\n\t\t\t: (() => {\n\t\t\t\t\tconst defaultBudgets: Record<ThinkingLevel, number> = {\n\t\t\t\t\t\tminimal: 1024,\n\t\t\t\t\t\tlow: 2048,\n\t\t\t\t\t\tmedium: 8192,\n\t\t\t\t\t\thigh: 16384,\n\t\t\t\t\t\txhigh: 16384, // Claude doesn't support xhigh, clamp to high\n\t\t\t\t\t};\n\n\t\t\t\t\t// Custom budgets override defaults (xhigh not in ThinkingBudgets, use high)\n\t\t\t\t\tconst level = options.reasoning === \"xhigh\" ? \"high\" : options.reasoning;\n\t\t\t\t\tconst budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning];\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tthinking: {\n\t\t\t\t\t\t\ttype: \"enabled\",\n\t\t\t\t\t\t\tbudget_tokens: budget,\n\t\t\t\t\t\t\t...(display !== undefined ? { display } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t})();\n\n\t\tif (!supportsAdaptiveThinking(model.id, model.name) && (options.interleavedThinking ?? true)) {\n\t\t\tresult.anthropic_beta = [\"interleaved-thinking-2025-05-14\"];\n\t\t}\n\n\t\treturn result;\n\t}\n\n\treturn undefined;\n}\n\nfunction createImageBlock(mimeType: string, data: string) {\n\tlet format: ImageFormat;\n\tswitch (mimeType) {\n\t\tcase \"image/jpeg\":\n\t\tcase \"image/jpg\":\n\t\t\tformat = ImageFormat.JPEG;\n\t\t\tbreak;\n\t\tcase \"image/png\":\n\t\t\tformat = ImageFormat.PNG;\n\t\t\tbreak;\n\t\tcase \"image/gif\":\n\t\t\tformat = ImageFormat.GIF;\n\t\t\tbreak;\n\t\tcase \"image/webp\":\n\t\t\tformat = ImageFormat.WEBP;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown image type: ${mimeType}`);\n\t}\n\n\tconst binaryString = atob(data);\n\tconst bytes = new Uint8Array(binaryString.length);\n\tfor (let i = 0; i < binaryString.length; i++) {\n\t\tbytes[i] = binaryString.charCodeAt(i);\n\t}\n\n\treturn { source: { bytes }, format };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"amazon-bedrock.d.ts","sourceRoot":"","sources":["../../src/providers/amazon-bedrock.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAQX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAEb,eAAe,EAEf,aAAa,EAKb,MAAM,aAAa,CAAC;AASrB,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,SAAS,CAAC;AAC9D,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAI5F,MAAM,WAAW,cAAe,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAElC,SAAS,CAAC,EAAE,aAAa,CAAC;IAE1B,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC;;;sGAGkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;yGAIqG;IACrG,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAkKD,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,yBAAyB,EAAE,cAAc,CAwCnF,CAAC;AAoEF,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,yBAAyB,EAAE,mBAAmB,CA4C9F,CAAC","sourcesContent":["import {\n\tBedrockRuntimeClient,\n\ttype BedrockRuntimeClientConfig,\n\tBedrockRuntimeServiceException,\n\tStopReason as BedrockStopReason,\n\ttype Tool as BedrockTool,\n\tCachePointType,\n\tCacheTTL,\n\ttype ContentBlock,\n\ttype ContentBlockDeltaEvent,\n\ttype ContentBlockStartEvent,\n\ttype ContentBlockStopEvent,\n\tConversationRole,\n\tConverseStreamCommand,\n\ttype ConverseStreamCommandInput,\n\ttype ConverseStreamMetadataEvent,\n\ttype ConverseStreamOutput,\n\tImageFormat,\n\ttype Message,\n\ttype ReasoningContentBlockDelta,\n\ttype SystemContentBlock,\n\ttype ToolChoice,\n\ttype ToolConfiguration,\n\tToolResultStatus,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport { NodeHttpHandler } from \"@smithy/node-http-handler\";\nimport type { BuildMiddleware, DocumentType, MetadataBearer } from \"@smithy/types\";\nimport { calculateCost } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantContent,\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tModel,\n\tMessage as PiMessage,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingBudgets,\n\tThinkingContent,\n\tThinkingLevel,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n\tUserMessage,\n} from \"../types.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { providerHeadersToRecord } from \"../utils/headers.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { createHttpProxyAgentsForTarget } from \"../utils/node-http-proxy.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\nimport { adjustMaxTokensForThinking, buildBaseOptions, clampReasoning } from \"./simple-options.ts\";\nimport { transformMessages } from \"./transform-messages.ts\";\n\nexport type BedrockThinkingDisplay = \"summarized\" | \"omitted\";\nexport type BedrockToolSelection = \"auto\" | \"any\" | \"none\" | { type: \"tool\"; name: string };\n\ntype BedrockReasoningEffort = \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\nexport interface BedrockOptions extends StreamOptions {\n\tregion?: string;\n\tprofile?: string;\n\ttoolChoice?: BedrockToolSelection;\n\t/* See https://docs.aws.amazon.com/bedrock/latest/userguide/inference-reasoning.html for supported models. */\n\treasoning?: ThinkingLevel;\n\t/* Custom token budgets per thinking level. Overrides default budgets. */\n\tthinkingBudgets?: ThinkingBudgets;\n\t/* Only supported by Claude 4.x models, see https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-extended-thinking.html#claude-messages-extended-thinking-tool-use-interleaved */\n\tinterleavedThinking?: boolean;\n\t/**\n\t * Controls how Claude's thinking content is returned in responses.\n\t * - \"summarized\": Thinking blocks contain summarized thinking text (default here).\n\t * - \"omitted\": Thinking content is redacted but the signature still travels back\n\t * for multi-turn continuity, reducing time-to-first-text-token.\n\t *\n\t * Note: Anthropic's API default for Claude Opus 4.7 and Mythos Preview is\n\t * \"omitted\". We default to \"summarized\" here to keep behavior consistent with\n\t * older Claude 4 models. Only applies to Claude models on Bedrock.\n\t */\n\tthinkingDisplay?: BedrockThinkingDisplay;\n\t/** Key-value pairs attached to the inference request for cost allocation tagging.\n\t * Keys: max 64 chars, no `aws:` prefix. Values: max 256 chars. Max 50 pairs.\n\t * Tags appear in AWS Cost Explorer split cost allocation data.\n\t * @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html */\n\trequestMetadata?: Record<string, string>;\n\t/** Bearer token for Bedrock API key authentication.\n\t * When set, bypasses SigV4 signing and sends Authorization: Bearer <token> instead.\n\t * Requires `bedrock:CallWithBearerToken` IAM permission on the token's identity.\n\t * Set via AWS_BEARER_TOKEN_BEDROCK env var or pass directly.\n\t * @see https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonbedrock.html */\n\tbearerToken?: string;\n}\n\ntype Block = (TextContent | ThinkingContent | ToolCall) & { index?: number; partialJson?: string };\ntype CompletedBedrockAssistantMessage = AssistantMessage & { stopReason: \"stop\" | \"length\" | \"toolUse\" };\ninterface BedrockStreamState {\n\tblocks: Block[];\n\toutput: AssistantMessage;\n\tstream: AssistantMessageEventStream;\n\tmodel: Model<\"bedrock-converse-stream\">;\n}\n\nfunction configureNodeBedrockRuntime(\n\tconfig: BedrockRuntimeClientConfig,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tconfiguredRegion: string | undefined,\n\tendpointRegion: string | undefined,\n\tuseExplicitEndpoint: boolean,\n\thasConfiguredProfile: boolean,\n): void {\n\tif (configuredRegion) config.region = configuredRegion;\n\telse if (endpointRegion && useExplicitEndpoint) config.region = endpointRegion;\n\telse if (!hasConfiguredProfile) config.region = \"us-east-1\";\n\tif (process.env.AWS_BEDROCK_SKIP_AUTH === \"1\") {\n\t\tconfig.credentials = { accessKeyId: \"dummy-access-key\", secretAccessKey: \"dummy-secret-key\" };\n\t}\n\tconst proxyAgents = createHttpProxyAgentsForTarget(model.baseUrl);\n\tif (proxyAgents) config.requestHandler = new NodeHttpHandler(proxyAgents);\n\telse if (process.env.AWS_BEDROCK_FORCE_HTTP1 === \"1\") config.requestHandler = new NodeHttpHandler();\n}\n\nfunction createBedrockRuntimeConfig(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toptions: BedrockOptions,\n): BedrockRuntimeClientConfig {\n\tconst config: BedrockRuntimeClientConfig = { profile: options.profile };\n\tconst configuredRegion = getConfiguredBedrockRegion(options);\n\tconst hasConfiguredProfile = hasConfiguredBedrockProfile();\n\tconst endpointRegion = getStandardBedrockEndpointRegion(model.baseUrl);\n\tconst useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(model.baseUrl, configuredRegion, hasConfiguredProfile);\n\tif (useExplicitEndpoint) config.endpoint = model.baseUrl;\n\tif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\t\tconfigureNodeBedrockRuntime(\n\t\t\tconfig,\n\t\t\tmodel,\n\t\t\tconfiguredRegion,\n\t\t\tendpointRegion,\n\t\t\tuseExplicitEndpoint,\n\t\t\thasConfiguredProfile,\n\t\t);\n\t} else {\n\t\tconfig.region =\n\t\t\tconfiguredRegion || (endpointRegion && useExplicitEndpoint ? endpointRegion : undefined) || \"us-east-1\";\n\t}\n\tconst bearerToken = options.bearerToken || process.env.AWS_BEARER_TOKEN_BEDROCK || undefined;\n\tif (bearerToken !== undefined && process.env.AWS_BEDROCK_SKIP_AUTH !== \"1\") {\n\t\tconfig.token = { token: bearerToken };\n\t\tconfig.authSchemePreference = [\"httpBearerAuth\"];\n\t}\n\treturn config;\n}\n\nfunction createBedrockCommandInput(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions: BedrockOptions,\n): ConverseStreamCommandInput {\n\tconst cacheRetention = resolveCacheRetention(options.cacheRetention);\n\tconst inferenceMaxTokens = options.maxTokens ?? (isAnthropicClaudeModel(model) ? model.maxTokens : undefined);\n\treturn {\n\t\tmodelId: model.id,\n\t\tmessages: convertMessages(context, model, cacheRetention),\n\t\tsystem: buildSystemPrompt(context.systemPrompt, model, cacheRetention),\n\t\tinferenceConfig: {\n\t\t\t...(inferenceMaxTokens !== undefined && { maxTokens: inferenceMaxTokens }),\n\t\t\t...(options.temperature !== undefined && { temperature: options.temperature }),\n\t\t},\n\t\ttoolConfig: convertToolConfig(context.tools, options.toolChoice),\n\t\tadditionalModelRequestFields: buildAdditionalModelRequestFields(model, options),\n\t\t...(options.requestMetadata !== undefined && { requestMetadata: options.requestMetadata }),\n\t};\n}\n\nfunction handleBedrockStreamEvent(item: ConverseStreamOutput, state: BedrockStreamState): void {\n\tif (item.messageStart) {\n\t\tif (item.messageStart.role !== ConversationRole.ASSISTANT) {\n\t\t\tthrow new Error(\"Unexpected assistant message start but got user message start instead\");\n\t\t}\n\t\tstate.stream.push({ type: \"start\", partial: state.output });\n\t\treturn;\n\t}\n\tif (item.contentBlockStart) {\n\t\thandleContentBlockStart(item.contentBlockStart, state.blocks, state.output, state.stream);\n\t\treturn;\n\t}\n\tif (item.contentBlockDelta) {\n\t\thandleContentBlockDelta(item.contentBlockDelta, state);\n\t\treturn;\n\t}\n\tif (item.contentBlockStop) {\n\t\thandleContentBlockStop(item.contentBlockStop, state.blocks, state.output, state.stream);\n\t\treturn;\n\t}\n\tif (item.messageStop) {\n\t\tstate.output.stopReason = mapStopReason(item.messageStop.stopReason);\n\t\treturn;\n\t}\n\tif (item.metadata) {\n\t\thandleMetadata(item.metadata, state.model, state.output);\n\t\treturn;\n\t}\n\tconst exception =\n\t\titem.internalServerException ??\n\t\titem.modelStreamErrorException ??\n\t\titem.validationException ??\n\t\titem.throttlingException ??\n\t\titem.serviceUnavailableException;\n\tif (exception) throw exception;\n}\n\nfunction validateBedrockStreamCompletion(\n\toutput: AssistantMessage,\n\tsignal?: AbortSignal,\n): asserts output is CompletedBedrockAssistantMessage {\n\tif (signal?.aborted) throw new Error(\"Request was aborted\");\n\tif (output.stopReason === \"pending\") throw new Error(\"Bedrock stream ended without a stop reason\");\n\tif (output.stopReason === \"error\" || output.stopReason === \"aborted\") throw new Error(\"An unknown error occurred\");\n}\n\nasync function executeBedrockStream(\n\tcontext: Context,\n\toptions: BedrockOptions,\n\tstate: BedrockStreamState,\n): Promise<void> {\n\tconst client = new BedrockRuntimeClient(createBedrockRuntimeConfig(state.model, options));\n\tconst customHeaders = providerHeadersToRecord(options.headers);\n\tif (customHeaders) addCustomHeadersMiddleware(client, customHeaders);\n\tlet commandInput = createBedrockCommandInput(state.model, context, options);\n\tconst nextCommandInput = await options.onPayload?.(commandInput, state.model);\n\tif (nextCommandInput !== undefined) commandInput = nextCommandInput as ConverseStreamCommandInput;\n\tconst response = await client.send(new ConverseStreamCommand(commandInput), { abortSignal: options.signal });\n\tif (response.$metadata.httpStatusCode !== undefined) {\n\t\tconst responseHeaders: Record<string, string> = {};\n\t\tif (response.$metadata.requestId) responseHeaders[\"x-amzn-requestid\"] = response.$metadata.requestId;\n\t\tawait options.onResponse?.({ status: response.$metadata.httpStatusCode, headers: responseHeaders }, state.model);\n\t}\n\tfor await (const item of response.stream!) handleBedrockStreamEvent(item, state);\n\tvalidateBedrockStreamCompletion(state.output, options.signal);\n\tstate.stream.push({ type: \"done\", reason: state.output.stopReason, message: state.output });\n\tstate.stream.end();\n}\n\nfunction handleBedrockStreamFailure(error: unknown, options: BedrockOptions, state: BedrockStreamState): void {\n\tfor (const block of state.output.content) {\n\t\tdelete (block as Block).index;\n\t\tdelete (block as Block).partialJson;\n\t}\n\tstate.output.stopReason = options.signal?.aborted ? \"aborted\" : \"error\";\n\tstate.output.errorMessage = formatBedrockError(error);\n\tstate.stream.push({ type: \"error\", reason: state.output.stopReason, error: state.output });\n\tstate.stream.end();\n}\n\nexport const streamBedrock: StreamFunction<\"bedrock-converse-stream\", BedrockOptions> = (\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions: BedrockOptions = {},\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"bedrock-converse-stream\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst state: BedrockStreamState = {\n\t\t\tblocks: output.content as Block[],\n\t\t\toutput,\n\t\t\tstream,\n\t\t\tmodel,\n\t\t};\n\t\ttry {\n\t\t\tawait executeBedrockStream(context, options, state);\n\t\t} catch (error) {\n\t\t\thandleBedrockStreamFailure(error, options, state);\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\n/**\n * Human-readable prefixes for Bedrock SDK exception names.\n * The downstream retry logic in agent-session matches patterns like\n * `server.?error` and `service.?unavailable`, so we preserve the legacy\n * prefix format rather than using the raw SDK exception name.\n */\nconst BEDROCK_ERROR_PREFIXES: Record<string, string> = {\n\tInternalServerException: \"Internal server error\",\n\tModelStreamErrorException: \"Model stream error\",\n\tValidationException: \"Validation error\",\n\tThrottlingException: \"Throttling error\",\n\tServiceUnavailableException: \"Service unavailable\",\n};\n\n/**\n * Format a Bedrock error with a human-readable prefix.\n * AWS SDK exceptions (both from `client.send()` and from stream event items)\n * extend BedrockRuntimeServiceException. We map the `.name` to a stable\n * human-readable prefix so downstream consumers (retry logic, context-overflow\n * detection) can distinguish error categories via simple string matching.\n */\nfunction formatBedrockError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : JSON.stringify(error);\n\tif (error instanceof BedrockRuntimeServiceException) {\n\t\tconst prefix = BEDROCK_ERROR_PREFIXES[error.name] ?? error.name;\n\t\treturn `${prefix}: ${message}`;\n\t}\n\treturn message;\n}\n\n/**\n * Header keys that must never be overwritten by caller-supplied headers.\n * `host` and `x-amz-*` participate in the SigV4 canonical request; `authorization`\n * is owned by SigV4 or the bearer-token path (config.token + authSchemePreference).\n * Compared case-insensitively (caller key is lower-cased before lookup).\n */\nconst RESERVED_HEADER_EXACT = new Set([\"authorization\", \"host\"]);\n\nfunction isReservedHeader(key: string): boolean {\n\tconst lower = key.toLowerCase();\n\treturn lower.startsWith(\"x-amz-\") || RESERVED_HEADER_EXACT.has(lower);\n}\n\n/**\n * Attach caller-supplied headers to the outgoing Bedrock request via a Smithy\n * `build`-step middleware. The `build` step runs after request serialisation but\n * before SigV4 signing, so injected headers are covered by the signature. Reserved\n * SigV4 / auth headers (`x-amz-*`, `authorization`, `host`) are silently skipped;\n * all other caller headers override any existing same-named header on the request.\n */\nfunction addCustomHeadersMiddleware(client: BedrockRuntimeClient, headers: Record<string, string>): void {\n\tconst middleware: BuildMiddleware<object, MetadataBearer> = (next) => async (args) => {\n\t\tconst request = args.request;\n\t\tif (request && typeof request === \"object\" && \"headers\" in request) {\n\t\t\tconst requestHeaders = (request as { headers: Record<string, string> }).headers;\n\t\t\tfor (const [key, value] of Object.entries(headers)) {\n\t\t\t\tif (!isReservedHeader(key)) {\n\t\t\t\t\trequestHeaders[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn next(args);\n\t};\n\tclient.middlewareStack.add(middleware, { step: \"build\", name: \"pi-ai-custom-headers\", priority: \"low\" });\n}\n\nexport const streamSimpleBedrock: StreamFunction<\"bedrock-converse-stream\", SimpleStreamOptions> = (\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst base = buildBaseOptions(model, context, options, undefined);\n\tif (!options?.reasoning) {\n\t\treturn streamBedrock(model, context, { ...base, reasoning: undefined } satisfies BedrockOptions);\n\t}\n\n\tif (isAnthropicClaudeModel(model)) {\n\t\tif (supportsAdaptiveThinking(model.id, model.name)) {\n\t\t\treturn streamBedrock(model, context, {\n\t\t\t\t...base,\n\t\t\t\treasoning: options.reasoning,\n\t\t\t\tthinkingBudgets: options.thinkingBudgets,\n\t\t\t} satisfies BedrockOptions);\n\t\t}\n\n\t\t// Undefined means the caller did not request an output cap; let the helper use the model cap.\n\t\t// Do not coerce to 0 here, or the thinking budget would become the entire maxTokens value.\n\t\tconst adjusted = adjustMaxTokensForThinking(\n\t\t\tbase.maxTokens,\n\t\t\tmodel.maxTokens,\n\t\t\toptions.reasoning,\n\t\t\toptions.thinkingBudgets,\n\t\t);\n\n\t\treturn streamBedrock(model, context, {\n\t\t\t...base,\n\t\t\tmaxTokens: adjusted.maxTokens,\n\t\t\treasoning: options.reasoning,\n\t\t\tthinkingBudgets: {\n\t\t\t\t...(options.thinkingBudgets || {}),\n\t\t\t\t[clampReasoning(options.reasoning)!]: adjusted.thinkingBudget,\n\t\t\t},\n\t\t} satisfies BedrockOptions);\n\t}\n\n\treturn streamBedrock(model, context, {\n\t\t...base,\n\t\treasoning: options.reasoning,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t} satisfies BedrockOptions);\n};\n\nfunction handleContentBlockStart(\n\tevent: ContentBlockStartEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst index = event.contentBlockIndex!;\n\tconst start = event.start;\n\n\tif (start?.toolUse) {\n\t\tconst block: Block = {\n\t\t\ttype: \"toolCall\",\n\t\t\tid: start.toolUse.toolUseId || \"\",\n\t\t\tname: start.toolUse.name || \"\",\n\t\t\targuments: {},\n\t\t\tpartialJson: \"\",\n\t\t\tindex,\n\t\t};\n\t\toutput.content.push(block);\n\t\tstream.push({ type: \"toolcall_start\", contentIndex: blocks.length - 1, partial: output });\n\t}\n}\n\nfunction handleTextContentDelta(\n\ttext: string,\n\tcontentBlockIndex: number,\n\tblock: Block | undefined,\n\tindex: number,\n\tstate: BedrockStreamState,\n): void {\n\tlet textBlock = block;\n\tlet textIndex = index;\n\tif (!textBlock) {\n\t\tconst newBlock: Block = { type: \"text\", text: \"\", index: contentBlockIndex };\n\t\tstate.output.content.push(newBlock);\n\t\ttextIndex = state.blocks.length - 1;\n\t\ttextBlock = state.blocks[textIndex];\n\t\tstate.stream.push({ type: \"text_start\", contentIndex: textIndex, partial: state.output });\n\t}\n\tif (textBlock.type !== \"text\") return;\n\ttextBlock.text += text;\n\tstate.stream.push({ type: \"text_delta\", contentIndex: textIndex, delta: text, partial: state.output });\n}\n\nfunction handleToolUseContentDelta(input: string, block: Block, index: number, state: BedrockStreamState): void {\n\tif (block.type !== \"toolCall\") return;\n\tblock.partialJson = (block.partialJson || \"\") + input;\n\tblock.arguments = parseStreamingJson(block.partialJson);\n\tstate.stream.push({ type: \"toolcall_delta\", contentIndex: index, delta: input, partial: state.output });\n}\n\nfunction handleReasoningContentDelta(\n\treasoningContent: ReasoningContentBlockDelta,\n\tcontentBlockIndex: number,\n\tblock: Block | undefined,\n\tindex: number,\n\tstate: BedrockStreamState,\n): void {\n\tlet thinkingBlock = block;\n\tlet thinkingIndex = index;\n\tif (!thinkingBlock) {\n\t\tconst newBlock: Block = { type: \"thinking\", thinking: \"\", thinkingSignature: \"\", index: contentBlockIndex };\n\t\tstate.output.content.push(newBlock);\n\t\tthinkingIndex = state.blocks.length - 1;\n\t\tthinkingBlock = state.blocks[thinkingIndex];\n\t\tstate.stream.push({ type: \"thinking_start\", contentIndex: thinkingIndex, partial: state.output });\n\t}\n\tif (thinkingBlock?.type !== \"thinking\") return;\n\tif (reasoningContent.text) {\n\t\tthinkingBlock.thinking += reasoningContent.text;\n\t\tstate.stream.push({\n\t\t\ttype: \"thinking_delta\",\n\t\t\tcontentIndex: thinkingIndex,\n\t\t\tdelta: reasoningContent.text,\n\t\t\tpartial: state.output,\n\t\t});\n\t}\n\tif (reasoningContent.signature) {\n\t\tthinkingBlock.thinkingSignature = (thinkingBlock.thinkingSignature || \"\") + reasoningContent.signature;\n\t}\n}\n\nfunction handleContentBlockDelta(event: ContentBlockDeltaEvent, state: BedrockStreamState): void {\n\tconst contentBlockIndex = event.contentBlockIndex!;\n\tconst delta = event.delta;\n\tif (!delta) return;\n\tconst index = state.blocks.findIndex((block) => block.index === contentBlockIndex);\n\tconst block = state.blocks[index];\n\n\tif (delta.text !== undefined) {\n\t\thandleTextContentDelta(delta.text, contentBlockIndex, block, index, state);\n\t\treturn;\n\t}\n\tif (delta.toolUse && block?.type === \"toolCall\") {\n\t\thandleToolUseContentDelta(delta.toolUse.input || \"\", block, index, state);\n\t\treturn;\n\t}\n\tif (delta.reasoningContent) {\n\t\thandleReasoningContentDelta(delta.reasoningContent, contentBlockIndex, block, index, state);\n\t}\n}\n\nfunction handleMetadata(\n\tevent: ConverseStreamMetadataEvent,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toutput: AssistantMessage,\n): void {\n\tif (event.usage) {\n\t\toutput.usage.input = event.usage.inputTokens || 0;\n\t\toutput.usage.output = event.usage.outputTokens || 0;\n\t\toutput.usage.cacheRead = event.usage.cacheReadInputTokens || 0;\n\t\toutput.usage.cacheWrite = event.usage.cacheWriteInputTokens || 0;\n\t\toutput.usage.totalTokens = event.usage.totalTokens || output.usage.input + output.usage.output;\n\t\tcalculateCost(model, output.usage);\n\t}\n}\n\nfunction handleContentBlockStop(\n\tevent: ContentBlockStopEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst index = blocks.findIndex((b) => b.index === event.contentBlockIndex);\n\tconst block = blocks[index];\n\tif (!block) return;\n\tdelete (block as Block).index;\n\n\tswitch (block.type) {\n\t\tcase \"text\":\n\t\t\tstream.push({ type: \"text_end\", contentIndex: index, content: block.text, partial: output });\n\t\t\tbreak;\n\t\tcase \"thinking\":\n\t\t\tstream.push({ type: \"thinking_end\", contentIndex: index, content: block.thinking, partial: output });\n\t\t\tbreak;\n\t\tcase \"toolCall\":\n\t\t\tblock.arguments = parseStreamingJson(block.partialJson);\n\t\t\t// Finalize in-place and strip the scratch buffer so replay only\n\t\t\t// carries parsed arguments.\n\t\t\tdelete (block as Block).partialJson;\n\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: index, toolCall: block, partial: output });\n\t\t\tbreak;\n\t}\n}\n\n/**\n * Check if the model supports adaptive thinking (Opus 4.6+, Sonnet 4.6).\n * Checks both model ID and model name to support application inference profiles\n * whose ARNs don't contain the model name.\n */\nfunction getModelMatchCandidates(modelId: string, modelName?: string): string[] {\n\tconst values = modelName ? [modelId, modelName] : [modelId];\n\treturn values.flatMap((value) => {\n\t\tconst lower = value.toLowerCase();\n\t\treturn [lower, lower.replace(/[\\s_.:]+/g, \"-\")];\n\t});\n}\n\nfunction supportsAdaptiveThinking(modelId: string, modelName?: string): boolean {\n\tconst candidates = getModelMatchCandidates(modelId, modelName);\n\treturn candidates.some((s) => s.includes(\"opus-4-6\") || s.includes(\"opus-4-7\") || s.includes(\"sonnet-4-6\"));\n}\n\nfunction supportsNativeXhighEffort(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst candidates = getModelMatchCandidates(model.id, model.name);\n\treturn candidates.some((s) => s.includes(\"opus-4-7\"));\n}\n\nfunction mapThinkingLevelToEffort(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tlevel: ThinkingLevel | undefined,\n): BedrockReasoningEffort {\n\tif (level === \"xhigh\" && supportsNativeXhighEffort(model)) return \"xhigh\";\n\n\tconst mapped = level ? model.thinkingLevelMap?.[level] : undefined;\n\tif (typeof mapped === \"string\") return mapped as BedrockReasoningEffort;\n\n\tswitch (level) {\n\t\tcase \"minimal\":\n\t\tcase \"low\":\n\t\t\treturn \"low\";\n\t\tcase \"medium\":\n\t\t\treturn \"medium\";\n\t\tcase \"high\":\n\t\t\treturn \"high\";\n\t\tdefault:\n\t\t\treturn \"high\";\n\t}\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (typeof process !== \"undefined\" && process.env.PI_CACHE_RETENTION === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\n/**\n * Check if the model is an Anthropic Claude model on Bedrock.\n * Checks both model ID and model name to support application inference profiles\n * whose ARNs don't contain the model name.\n */\nfunction isAnthropicClaudeModel(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst id = model.id.toLowerCase();\n\tconst name = model.name?.toLowerCase() ?? \"\";\n\treturn (\n\t\tid.includes(\"anthropic.claude\") ||\n\t\tid.includes(\"anthropic/claude\") ||\n\t\tname.includes(\"anthropic.claude\") ||\n\t\tname.includes(\"anthropic/claude\") ||\n\t\tname.includes(\"claude\")\n\t);\n}\n\n/**\n * Check if the model supports prompt caching.\n * Supported: Claude 3.5 Haiku, Claude 3.7 Sonnet, Claude 4.x models, Claude 5 models\n *\n * For base models and system-defined inference profiles the model ID / ARN\n * contains the model name, so we can decide locally.\n *\n * For application inference profiles (whose ARNs don't contain the model name),\n * also checks model.name which is user-controlled via models.json or registerProvider.\n * As a last resort, set AWS_BEDROCK_FORCE_CACHE=1 to enable cache points.\n * Amazon Nova models have automatic caching and don't need explicit cache points.\n */\nfunction supportsPromptCaching(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst candidates = getModelMatchCandidates(model.id, model.name);\n\n\tconst hasClaudeRef = candidates.some((s) => s.includes(\"claude\"));\n\tif (!hasClaudeRef) {\n\t\t// Application inference profiles don't contain the model name in the ARN.\n\t\t// Allow users to force cache points via environment variable.\n\t\tif (typeof process !== \"undefined\" && process.env.AWS_BEDROCK_FORCE_CACHE === \"1\") return true;\n\t\treturn false;\n\t}\n\t// Claude 5 models (fable-5, sonnet-5)\n\tif (candidates.some((s) => s.includes(\"fable-5\") || s.includes(\"sonnet-5\"))) return true;\n\t// Claude 4.x models (opus-4, sonnet-4, haiku-4)\n\tif (candidates.some((s) => s.includes(\"-4-\"))) return true;\n\t// Claude 3.7 Sonnet\n\tif (candidates.some((s) => s.includes(\"claude-3-7-sonnet\"))) return true;\n\t// Claude 3.5 Haiku\n\tif (candidates.some((s) => s.includes(\"claude-3-5-haiku\"))) return true;\n\treturn false;\n}\n\n/**\n * Check if the model supports thinking signatures in reasoningContent.\n * Only Anthropic Claude models support the signature field.\n * Other models (OpenAI, Qwen, Minimax, Moonshot, etc.) reject it with:\n * \"This model doesn't support the reasoningContent.reasoningText.signature field\"\n *\n * Checks both model ID and model name to support application inference profiles.\n */\nfunction supportsThinkingSignature(model: Model<\"bedrock-converse-stream\">): boolean {\n\treturn isAnthropicClaudeModel(model);\n}\n\nfunction buildSystemPrompt(\n\tsystemPrompt: string | undefined,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): SystemContentBlock[] | undefined {\n\tif (!systemPrompt) return undefined;\n\n\tconst blocks: SystemContentBlock[] = [{ text: sanitizeSurrogates(systemPrompt) }];\n\n\t// Add cache point for supported Claude models when caching is enabled\n\tif (cacheRetention !== \"none\" && supportsPromptCaching(model)) {\n\t\tblocks.push({\n\t\t\tcachePoint: { type: CachePointType.DEFAULT, ...(cacheRetention === \"long\" ? { ttl: CacheTTL.ONE_HOUR } : {}) },\n\t\t});\n\t}\n\n\treturn blocks;\n}\n\nfunction normalizeToolCallId(id: string): string {\n\tconst sanitized = id.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\treturn sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n}\n\nfunction convertUserMessage(message: UserMessage): Message | undefined {\n\tconst content: ContentBlock[] = [];\n\tif (typeof message.content === \"string\") {\n\t\tcontent.push({ text: sanitizeSurrogates(message.content) });\n\t} else {\n\t\tfor (const block of message.content) {\n\t\t\tswitch (block.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\tcontent.push({ text: sanitizeSurrogates(block.text) });\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"image\":\n\t\t\t\t\tcontent.push({ image: createImageBlock(block.mimeType, block.data) });\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn content.length > 0 ? { role: ConversationRole.USER, content } : undefined;\n}\n\nfunction convertAssistantContentBlock(\n\tblock: AssistantContent,\n\tmodel: Model<\"bedrock-converse-stream\">,\n): ContentBlock | undefined {\n\tswitch (block.type) {\n\t\tcase \"text\":\n\t\t\treturn block.text.trim().length > 0 ? { text: sanitizeSurrogates(block.text) } : undefined;\n\t\tcase \"toolCall\":\n\t\t\treturn { toolUse: { toolUseId: block.id, name: block.name, input: block.arguments } };\n\t\tcase \"thinking\":\n\t\t\tif (block.thinking.trim().length === 0) return undefined;\n\t\t\tif (!supportsThinkingSignature(model)) {\n\t\t\t\treturn { reasoningContent: { reasoningText: { text: sanitizeSurrogates(block.thinking) } } };\n\t\t\t}\n\t\t\tif (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) {\n\t\t\t\treturn { text: sanitizeSurrogates(block.thinking) };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\treasoningContent: {\n\t\t\t\t\treasoningText: {\n\t\t\t\t\t\ttext: sanitizeSurrogates(block.thinking),\n\t\t\t\t\t\tsignature: block.thinkingSignature,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t}\n}\n\nfunction convertAssistantMessage(\n\tmessage: AssistantMessage,\n\tmodel: Model<\"bedrock-converse-stream\">,\n): Message | undefined {\n\tif (message.content.length === 0) return undefined;\n\tconst content: ContentBlock[] = [];\n\tfor (const block of message.content) {\n\t\tconst converted = convertAssistantContentBlock(block, model);\n\t\tif (converted) content.push(converted);\n\t}\n\treturn content.length > 0 ? { role: ConversationRole.ASSISTANT, content } : undefined;\n}\n\nfunction convertToolResult(message: ToolResultMessage): ContentBlock.ToolResultMember {\n\treturn {\n\t\ttoolResult: {\n\t\t\ttoolUseId: message.toolCallId,\n\t\t\tcontent: message.content.map((block) =>\n\t\t\t\tblock.type === \"image\"\n\t\t\t\t\t? { image: createImageBlock(block.mimeType, block.data) }\n\t\t\t\t\t: { text: sanitizeSurrogates(block.text) },\n\t\t\t),\n\t\t\tstatus: message.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,\n\t\t},\n\t};\n}\n\ninterface BedrockToolResultBatch {\n\tcontent: ContentBlock.ToolResultMember[];\n\tlastIndex: number;\n}\n\nfunction collectToolResultBatch(messages: PiMessage[], startIndex: number): BedrockToolResultBatch {\n\tconst content: ContentBlock.ToolResultMember[] = [];\n\tlet lastIndex = startIndex;\n\tfor (let index = startIndex; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (message.role !== \"toolResult\") break;\n\t\tcontent.push(convertToolResult(message));\n\t\tlastIndex = index;\n\t}\n\treturn { content, lastIndex };\n}\n\nfunction appendPromptCachePoint(\n\tmessages: Message[],\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): void {\n\tif (cacheRetention === \"none\" || !supportsPromptCaching(model) || messages.length === 0) return;\n\tconst lastMessage = messages[messages.length - 1];\n\tif (lastMessage.role !== ConversationRole.USER || !lastMessage.content) return;\n\t(lastMessage.content as ContentBlock[]).push({\n\t\tcachePoint: {\n\t\t\ttype: CachePointType.DEFAULT,\n\t\t\t...(cacheRetention === \"long\" ? { ttl: CacheTTL.ONE_HOUR } : {}),\n\t\t},\n\t});\n}\n\nfunction convertMessages(\n\tcontext: Context,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): Message[] {\n\tconst result: Message[] = [];\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\tfor (let index = 0; index < transformedMessages.length; index++) {\n\t\tconst message = transformedMessages[index];\n\t\tswitch (message.role) {\n\t\t\tcase \"user\": {\n\t\t\t\tconst converted = convertUserMessage(message);\n\t\t\t\tif (converted) result.push(converted);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"assistant\": {\n\t\t\t\tconst converted = convertAssistantMessage(message, model);\n\t\t\t\tif (converted) result.push(converted);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolResult\": {\n\t\t\t\tconst batch = collectToolResultBatch(transformedMessages, index);\n\t\t\t\tresult.push({ role: ConversationRole.USER, content: batch.content });\n\t\t\t\tindex = batch.lastIndex;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tappendPromptCachePoint(result, model, cacheRetention);\n\treturn result;\n}\n\nfunction convertToolConfig(\n\ttools: Tool[] | undefined,\n\ttoolChoice: BedrockToolSelection | undefined,\n): ToolConfiguration | undefined {\n\tif (!tools?.length || toolChoice === \"none\") return undefined;\n\n\tconst bedrockTools: BedrockTool[] = tools.map((tool) => ({\n\t\ttoolSpec: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tinputSchema: { json: tool.parameters as unknown as DocumentType },\n\t\t},\n\t}));\n\n\tlet bedrockToolChoice: ToolChoice | undefined;\n\tswitch (toolChoice) {\n\t\tcase \"auto\":\n\t\t\tbedrockToolChoice = { auto: {} };\n\t\t\tbreak;\n\t\tcase \"any\":\n\t\t\tbedrockToolChoice = { any: {} };\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (toolChoice?.type === \"tool\") {\n\t\t\t\tbedrockToolChoice = { tool: { name: toolChoice.name } };\n\t\t\t}\n\t}\n\n\treturn { tools: bedrockTools, toolChoice: bedrockToolChoice };\n}\n\nfunction mapStopReason(reason: string | undefined): StopReason {\n\tswitch (reason) {\n\t\tcase BedrockStopReason.END_TURN:\n\t\tcase BedrockStopReason.STOP_SEQUENCE:\n\t\t\treturn \"stop\";\n\t\tcase BedrockStopReason.MAX_TOKENS:\n\t\tcase BedrockStopReason.MODEL_CONTEXT_WINDOW_EXCEEDED:\n\t\t\treturn \"length\";\n\t\tcase BedrockStopReason.TOOL_USE:\n\t\t\treturn \"toolUse\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\n\nfunction getConfiguredBedrockRegion(options: BedrockOptions): string | undefined {\n\tif (typeof process === \"undefined\") {\n\t\treturn options.region;\n\t}\n\n\treturn options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || undefined;\n}\n\nfunction hasConfiguredBedrockProfile(): boolean {\n\tif (typeof process === \"undefined\") {\n\t\treturn false;\n\t}\n\n\treturn Boolean(process.env.AWS_PROFILE);\n}\n\nfunction getStandardBedrockEndpointRegion(baseUrl: string | undefined): string | undefined {\n\tif (!baseUrl) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst { hostname } = new URL(baseUrl);\n\t\tconst match = hostname.toLowerCase().match(/^bedrock-runtime(?:-fips)?\\.([a-z0-9-]+)\\.amazonaws\\.com(?:\\.cn)?$/);\n\t\treturn match?.[1];\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction shouldUseExplicitBedrockEndpoint(\n\tbaseUrl: string,\n\tconfiguredRegion: string | undefined,\n\thasConfiguredProfile: boolean,\n): boolean {\n\tconst endpointRegion = getStandardBedrockEndpointRegion(baseUrl);\n\tif (!endpointRegion) {\n\t\treturn true;\n\t}\n\n\treturn !configuredRegion && !hasConfiguredProfile;\n}\n\nfunction isGovCloudBedrockTarget(model: Model<\"bedrock-converse-stream\">, options: BedrockOptions): boolean {\n\tconst region = getConfiguredBedrockRegion(options);\n\tif (region?.toLowerCase().startsWith(\"us-gov-\")) {\n\t\treturn true;\n\t}\n\n\tconst modelId = model.id.toLowerCase();\n\treturn modelId.startsWith(\"us-gov.\") || modelId.startsWith(\"arn:aws-us-gov:\");\n}\n\nfunction buildAdditionalModelRequestFields(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toptions: BedrockOptions,\n): Record<string, any> | undefined {\n\tif (!options.reasoning || !model.reasoning) {\n\t\treturn undefined;\n\t}\n\n\tif (isAnthropicClaudeModel(model)) {\n\t\t// GovCloud Bedrock currently rejects the Claude thinking.display field.\n\t\t// Omit it there until the GovCloud Converse schema catches up.\n\t\tconst display = isGovCloudBedrockTarget(model, options) ? undefined : (options.thinkingDisplay ?? \"summarized\");\n\t\tconst result: Record<string, any> = supportsAdaptiveThinking(model.id, model.name)\n\t\t\t? {\n\t\t\t\t\tthinking: { type: \"adaptive\", ...(display !== undefined ? { display } : {}) },\n\t\t\t\t\toutput_config: { effort: mapThinkingLevelToEffort(model, options.reasoning) },\n\t\t\t\t}\n\t\t\t: (() => {\n\t\t\t\t\tconst defaultBudgets: Record<ThinkingLevel, number> = {\n\t\t\t\t\t\tminimal: 1024,\n\t\t\t\t\t\tlow: 2048,\n\t\t\t\t\t\tmedium: 8192,\n\t\t\t\t\t\thigh: 16384,\n\t\t\t\t\t\txhigh: 16384, // Claude doesn't support xhigh, clamp to high\n\t\t\t\t\t};\n\n\t\t\t\t\t// Custom budgets override defaults (xhigh not in ThinkingBudgets, use high)\n\t\t\t\t\tconst level = options.reasoning === \"xhigh\" ? \"high\" : options.reasoning;\n\t\t\t\t\tconst budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning];\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tthinking: {\n\t\t\t\t\t\t\ttype: \"enabled\",\n\t\t\t\t\t\t\tbudget_tokens: budget,\n\t\t\t\t\t\t\t...(display !== undefined ? { display } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t})();\n\n\t\tif (!supportsAdaptiveThinking(model.id, model.name) && (options.interleavedThinking ?? true)) {\n\t\t\tresult.anthropic_beta = [\"interleaved-thinking-2025-05-14\"];\n\t\t}\n\n\t\treturn result;\n\t}\n\n\treturn undefined;\n}\n\nfunction createImageBlock(mimeType: string, data: string) {\n\tlet format: ImageFormat;\n\tswitch (mimeType) {\n\t\tcase \"image/jpeg\":\n\t\tcase \"image/jpg\":\n\t\t\tformat = ImageFormat.JPEG;\n\t\t\tbreak;\n\t\tcase \"image/png\":\n\t\t\tformat = ImageFormat.PNG;\n\t\t\tbreak;\n\t\tcase \"image/gif\":\n\t\t\tformat = ImageFormat.GIF;\n\t\t\tbreak;\n\t\tcase \"image/webp\":\n\t\t\tformat = ImageFormat.WEBP;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown image type: ${mimeType}`);\n\t}\n\n\tconst binaryString = atob(data);\n\tconst bytes = new Uint8Array(binaryString.length);\n\tfor (let i = 0; i < binaryString.length; i++) {\n\t\tbytes[i] = binaryString.charCodeAt(i);\n\t}\n\n\treturn { source: { bytes }, format };\n}\n"]}
|