@crvouga/mockingbird-service-bedrock 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/README.md +57 -5
- package/dist/{chunk-3H4ZVXWL.js → chunk-CL6K2ZUM.js} +2 -2
- package/dist/{chunk-LG5SXNQW.js → chunk-PFSY7JLL.js} +212 -30
- package/dist/{chunk-LG5SXNQW.js.map → chunk-PFSY7JLL.js.map} +2 -2
- package/dist/cli.js +15 -6
- package/dist/cli.js.map +2 -2
- package/dist/index.d.ts +36 -3
- package/dist/index.js +5 -1
- package/dist/server.d.ts +28 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-3H4ZVXWL.js.map → chunk-CL6K2ZUM.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-bedrock
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.8.0 (2026-10-21)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- raise the serve and fleet body limit to the S3 maximum ([86b9e2b](https://github.com/crvouga/mockingbird/commit/86b9e2b80bcaaaef57f52edbac50b27da0b42f33))
|
|
8
|
+
|
|
9
|
+
### Fixes and improvements
|
|
10
|
+
|
|
11
|
+
- finish junction, notion and bedrock docs and tests ([f1b4ccb](https://github.com/crvouga/mockingbird/commit/f1b4ccb4441144b5151b536aaacc8519b2e86075))
|
|
12
|
+
- reject unknown script match keys and add schema, document and cache validation ([af0c60d](https://github.com/crvouga/mockingbird/commit/af0c60d672ec6810fca1b9a69559f34181303499))
|
|
13
|
+
|
|
14
|
+
## 3.7.0 (2026-10-18)
|
|
4
15
|
|
|
5
16
|
### Features
|
|
6
17
|
|
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ HTTP/1.1 only — fine for the AI SDK, not for the SDK v3 Bedrock client.)
|
|
|
106
106
|
| --- | --- |
|
|
107
107
|
| `POST /model/{modelId}/converse` | Converse JSON: `output.message.content[]` (`text`, `toolUse`, `reasoningContent`), `stopReason`, `usage` (with `cacheRead/WriteInputTokens` when a `cachePoint` is present), `metrics`, `trace.guardrail` (with `guardrailConfig.trace: "enabled"`), `x-amzn-RequestId`. |
|
|
108
108
|
| `POST /model/{modelId}/converse-stream` | The same answer as event frames: `messageStart`, `contentBlockStart` (tool use), `contentBlockDelta` (`text`, `toolUse.input` partial JSON, `reasoningContent`), `contentBlockStop`, `messageStop`, `metadata`; exception frames mid-stream. |
|
|
109
|
-
| `POST /model/{modelId}/invoke` | `amazon.titan-embed-text-*`: `{embedding, inputTextTokenCount}` — a deterministic unit vector from SHA-256(`inputText`) (1024-d by default; `dimensions` 256/512/1024). Claude models: an Anthropic Messages body in, a Messages response out. |
|
|
109
|
+
| `POST /model/{modelId}/invoke` | `amazon.titan-embed-text-*`: `{embedding, inputTextTokenCount}` — a deterministic unit vector from SHA-256(`inputText`) (1024-d by default; `dimensions` 256/512/1024), or a lexical one with `embeddingMode: "lexical"` (see Settings). Claude models: an Anthropic Messages body in, a Messages response out. |
|
|
110
110
|
| `POST /model/{modelId}/invoke-with-bidirectional-stream` | Nova Sonic (`*sonic*`), HTTP/2 duplex: reads `chunk` events as they arrive (SigV4 envelopes unwrapped), answers each user turn with `textOutput` + 24 kHz PCM tone `audioOutput` + `toolUse`, then `usageEvent`; `completionEnd` after `sessionEnd`. |
|
|
111
111
|
| `POST /harnesses/invoke?harnessArn=` | AgentCore harness stream: `messageStart`, `contentBlockDelta` (`text` or `toolResult[]`), `contentBlockStop`, `messageStop`, `metadata`; `validationException` / `internalServerException` / `runtimeClientError` frames. |
|
|
112
112
|
|
|
@@ -114,7 +114,8 @@ HTTP/1.1 only — fine for the AI SDK, not for the SDK v3 Bedrock client.)
|
|
|
114
114
|
accepted without verification. Request checks Bedrock makes and our code branches on are
|
|
115
115
|
enforced: role alternation, first/last message is the user (assistant **prefill** is rejected
|
|
116
116
|
for Claude 4.5+), tool-use/tool-result pairing, `toolConfig` required with tool blocks, a
|
|
117
|
-
document needs a sibling text block, `temperature` + `top_p` together on Claude 4.5
|
|
117
|
+
document needs a sibling text block, `temperature` + `top_p` together on Claude 4.5+, plus the
|
|
118
|
+
best-guess checks listed under "Best guesses, not oracle-verified". Errors are
|
|
118
119
|
`x-amzn-ErrorType: <Name>:http://internal.amazon.com/coral/com.amazon.bedrock/` + `{"message"}`.
|
|
119
120
|
Output longer than `maxTokens` (≈4 chars/token) is cut with `stopReason: "max_tokens"`.
|
|
120
121
|
|
|
@@ -127,8 +128,16 @@ how many calls it answers.
|
|
|
127
128
|
- **Match keys:** `modelId` (glob), `operation` (`Converse`, `ConverseStream`, `InvokeModel`,
|
|
128
129
|
`InvokeModelWithBidirectionalStream`, `InvokeHarness`), `lastUserText` (string = contains, or
|
|
129
130
|
`{contains, regex, flags}`), `systemHash` (SHA-256 hex of the system text blocks joined with
|
|
130
|
-
`\n`), `
|
|
131
|
-
`
|
|
131
|
+
`\n`), `systemText` (the same joined system text, `cachePoint` blocks skipped; string =
|
|
132
|
+
case-insensitive contains, or `{contains, regex, flags}`; a call with no system prompt never
|
|
133
|
+
matches; for `InvokeModel` the Claude `system` string or text blocks, never stored),
|
|
134
|
+
`jsonSchemaName` (`outputConfig.textFormat.structure.jsonSchema.name`; string =
|
|
135
|
+
case-insensitive equality, or `{contains, regex, flags}`; a call without a named `outputConfig`
|
|
136
|
+
schema never matches), `toolsInclude`, `toolChoice` (`auto` / `any` / a tool name), `hasDocument`, `hasImage`,
|
|
137
|
+
`callIndex` (0-based index of the call in the namespace). `match` is a closed set: an unknown
|
|
138
|
+
or misspelled key (`lastUserTxt`) or a malformed criterion makes `PUT`/`POST /__admin/scripts`
|
|
139
|
+
answer 400 (`scripts[0].match.lastUserTxt: unknown match field (one of ...)`) instead of
|
|
140
|
+
silently matching every call; the same goes for an unknown key inside a text match.
|
|
132
141
|
- **Turn selection** reads the conversation, not server state: turn *n* answers the call that
|
|
133
142
|
comes after *n* assistant messages since the member last said something. So turn 0 is the
|
|
134
143
|
first call of a user turn, turn 1 is the call that resumes after a tool result, and every new
|
|
@@ -166,6 +175,7 @@ applies to every model and harness call in the calling namespace):
|
|
|
166
175
|
| `latency` (`latencyMs`) | the response starts after 2 s on the emulator clock |
|
|
167
176
|
| `truncated_frame` | the stream stops half-way through a frame (both decoders throw) |
|
|
168
177
|
| `model_timeout`, `service_unavailable`, `access_denied`, `internal_server` | 408 / 503 / 403 / 500 with the matching `x-amzn-ErrorType` |
|
|
178
|
+
| `resource_not_found` | 404 `ResourceNotFoundException` ("The specified resource ARN was not found. Check the ARN and try again.", per the Converse API reference), before any frame, on Converse, ConverseStream and InvokeModel |
|
|
169
179
|
|
|
170
180
|
Chunk pacing and latency wait on the **emulator clock**: freeze it (`POST /__admin/clock
|
|
171
181
|
{"freeze": true}`) and advance it to release each chunk, so time-to-first-token tests are exact.
|
|
@@ -179,12 +189,53 @@ Chunk pacing and latency wait on the **emulator clock**: freeze it (`POST /__adm
|
|
|
179
189
|
| `GET /__admin/scripts` | Scripts plus `stats` (`calls`, `scripted`, `unscripted`, `byScript`, `byFallback`, `byOperation`). |
|
|
180
190
|
| `DELETE /__admin/scripts[?id=]` | Remove one or all. |
|
|
181
191
|
| `GET /__admin/model-metrics` | Just the stats. |
|
|
182
|
-
| `GET/PUT /__admin/settings` | `defaultText`, `chunkSize` (16), `delayMsPerChunk` (0), `audioTurnChunks` (0: a Nova Sonic spoken turn ends at the audio `contentEnd`; n: after n audio frames). |
|
|
192
|
+
| `GET/PUT /__admin/settings` | `defaultText`, `chunkSize` (16), `delayMsPerChunk` (0), `audioTurnChunks` (0: a Nova Sonic spoken turn ends at the audio `contentEnd`; n: after n audio frames), `embeddingMode` (`sha256` default, or `lexical`), `validatePromptCaching` (`true` default; `false` disables the model check on `cachePoint`). |
|
|
193
|
+
|
|
194
|
+
`embeddingMode: "lexical"` (opt-in; the test-control request in #522, not a Bedrock behaviour)
|
|
195
|
+
keeps Titan vectors deterministic and unit length but makes them similarity-preserving: each
|
|
196
|
+
word (lowercased, accents and punctuation dropped) adds to a SHA-256-chosen signed dimension, so
|
|
197
|
+
texts differing only in case, punctuation or spacing have cosine similarity 1, texts sharing most
|
|
198
|
+
words score high, and texts with no word in common score near 0. It is bag-of-words, not a
|
|
199
|
+
language model: synonyms ("evening" / "night") stay apart. Scripted per-text vectors are not
|
|
200
|
+
implemented. `normalize: false` is ignored in both modes (vectors are always unit length).
|
|
183
201
|
|
|
184
202
|
The request journal (`GET /__admin/requests`) records per call only `modelId`, `script` (or
|
|
185
203
|
`unscripted:<default>`), tool names, flags (`cachePoint`, `guardrail`, `document`, `image`,
|
|
186
204
|
`structured:<form>`), `stopReason` and token counts — never prompt or message text.
|
|
187
205
|
|
|
206
|
+
### Best guesses, not oracle-verified
|
|
207
|
+
|
|
208
|
+
These request checks come from the AWS documentation and what consumers reported about live
|
|
209
|
+
Bedrock, not from observing the service; the exact message text of the ones marked "ours" is an
|
|
210
|
+
emulator choice. All answer `400 ValidationException`.
|
|
211
|
+
|
|
212
|
+
- **Structured-output schemas** (`outputConfig.textFormat.structure.jsonSchema.schema`, Converse
|
|
213
|
+
and ConverseStream, [docs](https://docs.aws.amazon.com/bedrock/latest/userguide/structured-output.html)):
|
|
214
|
+
`schema` that is not a JSON object (ours); `oneOf` (`Schema type 'oneOf' is not supported`);
|
|
215
|
+
`additionalProperties` set to anything other than `false` on any node, `true` or a sub-schema
|
|
216
|
+
(`For 'object' type, 'additionalProperties: <X>' is not supported. Please set
|
|
217
|
+
'additionalProperties' to false`); a string-only `enum` combined with a union `type` such as
|
|
218
|
+
`["string","null"]` (ours); `minimum`, `maximum`, `multipleOf`, `minLength`, `maxLength`,
|
|
219
|
+
`minItems` above 1, an external `$ref`, and a recursive `$ref` cycle (ours). An omitted
|
|
220
|
+
`additionalProperties` and `anyOf` / `allOf` / internal `$ref` / `$defs` pass. Only the
|
|
221
|
+
`outputConfig` form is checked, not `additionalModelRequestFields.output_config` nor
|
|
222
|
+
`InvokeModel` bodies.
|
|
223
|
+
- **Document names** (`document.name`, [API reference](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_DocumentBlock.html)):
|
|
224
|
+
1 to 200 characters of ASCII letters, digits, whitespace, hyphens, parentheses and square
|
|
225
|
+
brackets, with no run of two whitespace characters. The message is the one a consumer recorded
|
|
226
|
+
from live Bedrock.
|
|
227
|
+
- **`cachePoint`** ([docs](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html)):
|
|
228
|
+
a `cachePoint` content block directly after a `document` block (consumer report; message ours);
|
|
229
|
+
and, on Converse / ConverseStream, a `cachePoint` in `system`, `messages` or `toolConfig.tools`
|
|
230
|
+
for a model outside the documented list (Claude 3.5 Haiku, 3.5 Sonnet v2, 3.7 Sonnet, Claude
|
|
231
|
+
4 and later Opus / Sonnet / Haiku, Fable and Mythos; Nova Micro / Lite / Pro / 2 Lite), matched
|
|
232
|
+
on the family inside plain, `us.` / `global.` and ARN forms. The list grows: turn the model
|
|
233
|
+
check off with `PUT /__admin/settings {"validatePromptCaching": false}`. The `ttl` field is
|
|
234
|
+
not checked.
|
|
235
|
+
- **Unknown model ids** still answer normally (`modelId` is any id). A `knownModels` setting that
|
|
236
|
+
makes an unknown id fail was requested in #523 but not built: whether live Bedrock answers
|
|
237
|
+
`ResourceNotFoundException` or `ValidationException` for it has not been observed.
|
|
238
|
+
|
|
188
239
|
### Namespaces
|
|
189
240
|
|
|
190
241
|
`x-mockingbird-namespace`, a `/__admin/ns/<name>` prefix on the endpoint URL, or by credential: the SDKs
|
|
@@ -213,6 +264,7 @@ cannot add headers, so map each worker's access key id:
|
|
|
213
264
|
| `accessKeyCredential` | function | The SigV4 access key id of a request (how credentials map to namespaces). |
|
|
214
265
|
| `clockSleep` | function | A sleep that waits on a (possibly frozen) emulator clock. |
|
|
215
266
|
| `titanEmbedding` | function | The deterministic unit vector Titan answers with. |
|
|
267
|
+
| `lexicalEmbedding`, `EMBEDDING_MODES` | function, array | The opt-in similarity-preserving embedding and the `embeddingMode` values. |
|
|
216
268
|
| `sampleSchema` | function | The minimal instance of a JSON Schema (the unscripted structured output). |
|
|
217
269
|
| `parseScript` | function | Validate one script (what `PUT /__admin/scripts` runs). |
|
|
218
270
|
| `MODEL_OPERATIONS`, `STOP_REASONS`, `TURN_FAULTS` | arrays | The values `operation`, `stopReason` and `fault` accept. |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRuntime,
|
|
3
3
|
parseScript
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PFSY7JLL.js";
|
|
5
5
|
|
|
6
6
|
// src/h2c.ts
|
|
7
7
|
import {
|
|
@@ -338,4 +338,4 @@ export {
|
|
|
338
338
|
createServer,
|
|
339
339
|
serveTarget
|
|
340
340
|
};
|
|
341
|
-
//# sourceMappingURL=chunk-
|
|
341
|
+
//# sourceMappingURL=chunk-CL6K2ZUM.js.map
|
|
@@ -4029,7 +4029,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
4029
4029
|
};
|
|
4030
4030
|
|
|
4031
4031
|
// ../core/dist/version.js
|
|
4032
|
-
var PACKAGE_VERSION = true ? "3.
|
|
4032
|
+
var PACKAGE_VERSION = true ? "3.8.0" : UNRELEASED_VERSION;
|
|
4033
4033
|
|
|
4034
4034
|
// ../core/dist/signing.js
|
|
4035
4035
|
var encoder = new TextEncoder();
|
|
@@ -5327,6 +5327,9 @@ var ValidationProblem = class extends Error {
|
|
|
5327
5327
|
};
|
|
5328
5328
|
var NO_PREFILL = /claude-(?:sonnet|opus)-4-[5-9]|claude-opus-4-1|claude-(?:sonnet|opus|haiku)-[5-9]/i;
|
|
5329
5329
|
var ONE_SAMPLING_PARAM = /claude-(?:sonnet|opus|haiku)-4-[5-9]|claude-opus-4-1|claude-(?:sonnet|opus|haiku)-[5-9]/i;
|
|
5330
|
+
var PROMPT_CACHING = /claude-3-5-haiku|claude-3-5-sonnet-20241022|claude-3-7-sonnet|claude-(?:opus|sonnet|haiku|fable|mythos)-[4-9]|nova-(?:micro|lite|pro|2-lite)/i;
|
|
5331
|
+
var DOCUMENT_NAME = /^[a-zA-Z0-9\s\-()[\]]{1,200}$/;
|
|
5332
|
+
var DOCUMENT_NAME_MESSAGE = "The document file name can only contain alphanumeric characters, whitespace characters, hyphens, parentheses, and square brackets. The name can't contain more than one consecutive whitespace character.";
|
|
5330
5333
|
var parseSchema = (value) => {
|
|
5331
5334
|
if (typeof value !== "string") return value;
|
|
5332
5335
|
try {
|
|
@@ -5335,6 +5338,64 @@ var parseSchema = (value) => {
|
|
|
5335
5338
|
return {};
|
|
5336
5339
|
}
|
|
5337
5340
|
};
|
|
5341
|
+
var UNSUPPORTED_KEYWORDS = ["minimum", "maximum", "multipleOf", "minLength", "maxLength"];
|
|
5342
|
+
var SCHEMA_SLOTS = ["items", "not", "if", "then", "else", "contains"];
|
|
5343
|
+
var SCHEMA_LISTS = ["anyOf", "allOf", "prefixItems"];
|
|
5344
|
+
var SCHEMA_MAPS = ["properties", "$defs", "definitions", "patternProperties"];
|
|
5345
|
+
var unsupportedSchemaReason = (root) => {
|
|
5346
|
+
const resolve = (ref) => {
|
|
5347
|
+
if (ref === "#") return root;
|
|
5348
|
+
let node = root;
|
|
5349
|
+
for (const part of ref.slice(2).split("/")) {
|
|
5350
|
+
node = isRecord5(node) ? node[part.replaceAll("~1", "/").replaceAll("~0", "~")] : void 0;
|
|
5351
|
+
}
|
|
5352
|
+
return node;
|
|
5353
|
+
};
|
|
5354
|
+
const visit = (node, refs) => {
|
|
5355
|
+
if (!isRecord5(node)) return void 0;
|
|
5356
|
+
if (node.oneOf !== void 0) return "Schema type 'oneOf' is not supported";
|
|
5357
|
+
for (const key of UNSUPPORTED_KEYWORDS) {
|
|
5358
|
+
if (node[key] !== void 0) return `Schema keyword '${key}' is not supported`;
|
|
5359
|
+
}
|
|
5360
|
+
if (typeof node.minItems === "number" && node.minItems > 1) {
|
|
5361
|
+
return `Schema keyword 'minItems' only supports the values 0 and 1 (got ${node.minItems})`;
|
|
5362
|
+
}
|
|
5363
|
+
if (node.additionalProperties !== void 0 && node.additionalProperties !== false) {
|
|
5364
|
+
return `For 'object' type, 'additionalProperties: ${JSON.stringify(node.additionalProperties)}' is not supported. Please set 'additionalProperties' to false`;
|
|
5365
|
+
}
|
|
5366
|
+
if (Array.isArray(node.type) && Array.isArray(node.enum) && node.enum.length > 0 && node.enum.every((value) => typeof value === "string")) {
|
|
5367
|
+
return `A string-only 'enum' cannot be combined with the union type ${JSON.stringify(node.type)}`;
|
|
5368
|
+
}
|
|
5369
|
+
if (typeof node.$ref === "string") {
|
|
5370
|
+
if (!node.$ref.startsWith("#")) {
|
|
5371
|
+
return `External $ref '${node.$ref}' is not supported; only internal references are`;
|
|
5372
|
+
}
|
|
5373
|
+
if (refs.includes(node.$ref)) return `Recursive schemas are not supported ('${node.$ref}')`;
|
|
5374
|
+
const problem = visit(resolve(node.$ref), [...refs, node.$ref]);
|
|
5375
|
+
if (problem) return problem;
|
|
5376
|
+
}
|
|
5377
|
+
for (const key of SCHEMA_SLOTS) {
|
|
5378
|
+
const problem = visit(node[key], refs);
|
|
5379
|
+
if (problem) return problem;
|
|
5380
|
+
}
|
|
5381
|
+
for (const key of SCHEMA_LISTS) {
|
|
5382
|
+
for (const each of array(node[key])) {
|
|
5383
|
+
const problem = visit(each, refs);
|
|
5384
|
+
if (problem) return problem;
|
|
5385
|
+
}
|
|
5386
|
+
}
|
|
5387
|
+
for (const key of SCHEMA_MAPS) {
|
|
5388
|
+
const map = node[key];
|
|
5389
|
+
if (!isRecord5(map)) continue;
|
|
5390
|
+
for (const each of Object.values(map)) {
|
|
5391
|
+
const problem = visit(each, refs);
|
|
5392
|
+
if (problem) return problem;
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
return void 0;
|
|
5396
|
+
};
|
|
5397
|
+
return visit(root, []);
|
|
5398
|
+
};
|
|
5338
5399
|
var textOf = (blocks) => blocks.map((block) => isRecord5(block) && typeof block.text === "string" ? block.text : "").filter((text2) => text2.length > 0).join("\n");
|
|
5339
5400
|
var conversationFacts = (messages) => {
|
|
5340
5401
|
let lastSaid = -1;
|
|
@@ -5432,11 +5493,15 @@ var converseMessage = (value, index) => {
|
|
|
5432
5493
|
hasCachePoint: false,
|
|
5433
5494
|
chars: 0
|
|
5434
5495
|
};
|
|
5435
|
-
for (const block of content) {
|
|
5496
|
+
for (const [at, block] of content.entries()) {
|
|
5436
5497
|
if (!isRecord5(block)) continue;
|
|
5437
5498
|
out.chars += JSON.stringify(block).length;
|
|
5438
5499
|
if (typeof block.text === "string") out.hasContent = true;
|
|
5439
5500
|
if (isRecord5(block.document)) {
|
|
5501
|
+
const name2 = block.document.name;
|
|
5502
|
+
if (typeof name2 === "string" && (!DOCUMENT_NAME.test(name2) || /\s{2,}/.test(name2))) {
|
|
5503
|
+
throw new ValidationProblem(DOCUMENT_NAME_MESSAGE);
|
|
5504
|
+
}
|
|
5440
5505
|
out.hasDocument = true;
|
|
5441
5506
|
out.hasContent = true;
|
|
5442
5507
|
}
|
|
@@ -5445,7 +5510,14 @@ var converseMessage = (value, index) => {
|
|
|
5445
5510
|
out.hasContent = true;
|
|
5446
5511
|
}
|
|
5447
5512
|
if (isRecord5(block.video)) out.hasContent = true;
|
|
5448
|
-
if (isRecord5(block.cachePoint))
|
|
5513
|
+
if (isRecord5(block.cachePoint)) {
|
|
5514
|
+
if (isRecord5(content[at - 1]) && isRecord5(content[at - 1].document)) {
|
|
5515
|
+
throw new ValidationProblem(
|
|
5516
|
+
`The model returned the following errors: messages.${index}.content.${at}: a cachePoint cannot directly follow a document block.`
|
|
5517
|
+
);
|
|
5518
|
+
}
|
|
5519
|
+
out.hasCachePoint = true;
|
|
5520
|
+
}
|
|
5449
5521
|
if (isRecord5(block.toolUse)) {
|
|
5450
5522
|
out.toolUses.push({
|
|
5451
5523
|
id: String(block.toolUse.toolUseId ?? ""),
|
|
@@ -5456,7 +5528,7 @@ var converseMessage = (value, index) => {
|
|
|
5456
5528
|
}
|
|
5457
5529
|
return out;
|
|
5458
5530
|
};
|
|
5459
|
-
var analyzeConverse = (operation, modelId, body) => {
|
|
5531
|
+
var analyzeConverse = (operation, modelId, body, options = {}) => {
|
|
5460
5532
|
if (!isRecord5(body))
|
|
5461
5533
|
throw new ValidationProblem(
|
|
5462
5534
|
"Malformed input request, please reformat your input and try again."
|
|
@@ -5505,9 +5577,22 @@ var analyzeConverse = (operation, modelId, body) => {
|
|
|
5505
5577
|
const jsonSchema = textFormat && isRecord5(textFormat.structure) && isRecord5(textFormat.structure.jsonSchema) ? textFormat.structure.jsonSchema : void 0;
|
|
5506
5578
|
const nativeFormat = isRecord5(additional.output_config) && isRecord5(additional.output_config.format) ? additional.output_config.format : void 0;
|
|
5507
5579
|
if (jsonSchema) {
|
|
5580
|
+
let schema = jsonSchema.schema;
|
|
5581
|
+
if (typeof schema === "string") {
|
|
5582
|
+
try {
|
|
5583
|
+
schema = JSON.parse(schema);
|
|
5584
|
+
} catch {
|
|
5585
|
+
schema = void 0;
|
|
5586
|
+
}
|
|
5587
|
+
if (!isRecord5(schema)) {
|
|
5588
|
+
throw new ValidationProblem("The structured output schema is not a valid JSON object.");
|
|
5589
|
+
}
|
|
5590
|
+
}
|
|
5591
|
+
const reason = unsupportedSchemaReason(schema);
|
|
5592
|
+
if (reason) throw new ValidationProblem(reason);
|
|
5508
5593
|
structured = {
|
|
5509
5594
|
form: "outputConfig",
|
|
5510
|
-
schema
|
|
5595
|
+
schema,
|
|
5511
5596
|
...typeof jsonSchema.name === "string" ? { name: jsonSchema.name } : {}
|
|
5512
5597
|
};
|
|
5513
5598
|
} else if (nativeFormat && nativeFormat.type === "json_schema") {
|
|
@@ -5521,6 +5606,12 @@ var analyzeConverse = (operation, modelId, body) => {
|
|
|
5521
5606
|
}
|
|
5522
5607
|
const facts = conversationFacts(messages);
|
|
5523
5608
|
const systemText = textOf(system);
|
|
5609
|
+
const hasCachePoint = messages.some((m) => m.hasCachePoint) || system.some((b) => isRecord5(b) && isRecord5(b.cachePoint)) || array(toolConfig?.tools).some((t) => isRecord5(t) && isRecord5(t.cachePoint));
|
|
5610
|
+
if (hasCachePoint && options.validatePromptCaching !== false && !PROMPT_CACHING.test(modelId)) {
|
|
5611
|
+
throw new ValidationProblem(
|
|
5612
|
+
"The model does not support prompt caching: remove the cachePoint block from the request."
|
|
5613
|
+
);
|
|
5614
|
+
}
|
|
5524
5615
|
return {
|
|
5525
5616
|
operation,
|
|
5526
5617
|
modelId,
|
|
@@ -5531,7 +5622,7 @@ var analyzeConverse = (operation, modelId, body) => {
|
|
|
5531
5622
|
toolChoice,
|
|
5532
5623
|
hasDocument: messages.some((m) => m.hasDocument),
|
|
5533
5624
|
hasImage: messages.some((m) => m.hasImage),
|
|
5534
|
-
hasCachePoint
|
|
5625
|
+
hasCachePoint,
|
|
5535
5626
|
hasGuardrail: isRecord5(body.guardrailConfig),
|
|
5536
5627
|
toolResults: facts.toolResults,
|
|
5537
5628
|
turnIndex: facts.turnIndex,
|
|
@@ -5833,6 +5924,7 @@ var TURN_FAULTS = [
|
|
|
5833
5924
|
"model_timeout",
|
|
5834
5925
|
"service_unavailable",
|
|
5835
5926
|
"internal_server",
|
|
5927
|
+
"resource_not_found",
|
|
5836
5928
|
"mid_stream_exception",
|
|
5837
5929
|
"max_tokens",
|
|
5838
5930
|
"truncated_frame",
|
|
@@ -5866,6 +5958,16 @@ var matches2 = (match, call, context) => {
|
|
|
5866
5958
|
if (match.systemHash !== void 0 && match.systemHash.toLowerCase() !== context.systemHash) {
|
|
5867
5959
|
return false;
|
|
5868
5960
|
}
|
|
5961
|
+
if (match.systemText !== void 0) {
|
|
5962
|
+
if (call.systemText === "" || !textMatches(match.systemText, call.systemText)) return false;
|
|
5963
|
+
}
|
|
5964
|
+
if (match.jsonSchemaName !== void 0) {
|
|
5965
|
+
const name2 = call.structured?.form === "outputConfig" ? call.structured.name : void 0;
|
|
5966
|
+
if (name2 === void 0) return false;
|
|
5967
|
+
const rule = match.jsonSchemaName;
|
|
5968
|
+
if (typeof rule === "string" ? rule.toLowerCase() !== name2.toLowerCase() : !textMatches(rule, name2))
|
|
5969
|
+
return false;
|
|
5970
|
+
}
|
|
5869
5971
|
if (match.toolsInclude?.some((name2) => !call.tools.includes(name2))) return false;
|
|
5870
5972
|
if (match.toolChoice !== void 0) {
|
|
5871
5973
|
const want = ["auto", "any", "none"].includes(match.toolChoice) ? match.toolChoice : `tool:${match.toolChoice}`;
|
|
@@ -5938,6 +6040,75 @@ var checkTurn = (turn, path) => {
|
|
|
5938
6040
|
}
|
|
5939
6041
|
return void 0;
|
|
5940
6042
|
};
|
|
6043
|
+
var MATCH_KEYS = [
|
|
6044
|
+
"modelId",
|
|
6045
|
+
"operation",
|
|
6046
|
+
"lastUserText",
|
|
6047
|
+
"systemHash",
|
|
6048
|
+
"systemText",
|
|
6049
|
+
"jsonSchemaName",
|
|
6050
|
+
"toolsInclude",
|
|
6051
|
+
"toolChoice",
|
|
6052
|
+
"hasDocument",
|
|
6053
|
+
"hasImage",
|
|
6054
|
+
"callIndex"
|
|
6055
|
+
];
|
|
6056
|
+
var checkTextMatch = (rule, path) => {
|
|
6057
|
+
if (typeof rule === "string") return void 0;
|
|
6058
|
+
if (!isRecord6(rule)) return fail2(path, "a string or {contains, regex, flags}");
|
|
6059
|
+
for (const key of Object.keys(rule)) {
|
|
6060
|
+
if (!["contains", "regex", "flags"].includes(key)) {
|
|
6061
|
+
return fail2(`${path}.${key}`, "unknown text match field (one of contains, regex, flags)");
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
6064
|
+
for (const key of ["contains", "regex", "flags"]) {
|
|
6065
|
+
if (rule[key] !== void 0 && typeof rule[key] !== "string")
|
|
6066
|
+
return fail2(`${path}.${key}`, "string");
|
|
6067
|
+
}
|
|
6068
|
+
if (typeof rule.regex === "string") {
|
|
6069
|
+
try {
|
|
6070
|
+
new RegExp(rule.regex, typeof rule.flags === "string" ? rule.flags : "i");
|
|
6071
|
+
} catch {
|
|
6072
|
+
return fail2(`${path}.regex`, "not a valid regular expression (with these flags)");
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
6075
|
+
return void 0;
|
|
6076
|
+
};
|
|
6077
|
+
var checkMatch = (match, path) => {
|
|
6078
|
+
for (const key of Object.keys(match)) {
|
|
6079
|
+
if (!MATCH_KEYS.includes(key)) {
|
|
6080
|
+
return fail2(`${path}.${key}`, `unknown match field (one of ${MATCH_KEYS.join(", ")})`);
|
|
6081
|
+
}
|
|
6082
|
+
}
|
|
6083
|
+
if (match.operation !== void 0) {
|
|
6084
|
+
const ops = Array.isArray(match.operation) ? match.operation : [match.operation];
|
|
6085
|
+
for (const op of ops) {
|
|
6086
|
+
if (!MODEL_OPERATIONS.includes(op)) {
|
|
6087
|
+
return fail2(`${path}.operation`, `one of ${MODEL_OPERATIONS.join(", ")}`);
|
|
6088
|
+
}
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
for (const key of ["modelId", "systemHash", "toolChoice"]) {
|
|
6092
|
+
if (match[key] !== void 0 && typeof match[key] !== "string")
|
|
6093
|
+
return fail2(`${path}.${key}`, "string");
|
|
6094
|
+
}
|
|
6095
|
+
for (const key of ["lastUserText", "systemText", "jsonSchemaName"]) {
|
|
6096
|
+
if (match[key] === void 0) continue;
|
|
6097
|
+
const problem = checkTextMatch(match[key], `${path}.${key}`);
|
|
6098
|
+
if (problem) return problem;
|
|
6099
|
+
}
|
|
6100
|
+
for (const key of ["hasDocument", "hasImage"]) {
|
|
6101
|
+
if (match[key] !== void 0 && typeof match[key] !== "boolean")
|
|
6102
|
+
return fail2(`${path}.${key}`, "boolean");
|
|
6103
|
+
}
|
|
6104
|
+
if (match.callIndex !== void 0 && !(typeof match.callIndex === "number" && Number.isInteger(match.callIndex) && match.callIndex >= 0)) {
|
|
6105
|
+
return fail2(`${path}.callIndex`, "a non-negative integer");
|
|
6106
|
+
}
|
|
6107
|
+
if (match.toolsInclude !== void 0 && !(Array.isArray(match.toolsInclude) && match.toolsInclude.every((n) => typeof n === "string"))) {
|
|
6108
|
+
return fail2(`${path}.toolsInclude`, "string[]");
|
|
6109
|
+
}
|
|
6110
|
+
return void 0;
|
|
6111
|
+
};
|
|
5941
6112
|
var parseScript = (value, index) => {
|
|
5942
6113
|
const path = `scripts[${index}]`;
|
|
5943
6114
|
if (!isRecord6(value)) return fail2(path, "a script is an object");
|
|
@@ -5952,25 +6123,8 @@ var parseScript = (value, index) => {
|
|
|
5952
6123
|
}
|
|
5953
6124
|
if (value.match !== void 0) {
|
|
5954
6125
|
if (!isRecord6(value.match)) return fail2(`${path}.match`, "an object");
|
|
5955
|
-
const
|
|
5956
|
-
if (
|
|
5957
|
-
const ops = Array.isArray(match.operation) ? match.operation : [match.operation];
|
|
5958
|
-
for (const op of ops) {
|
|
5959
|
-
if (!MODEL_OPERATIONS.includes(op)) {
|
|
5960
|
-
return fail2(`${path}.match.operation`, `one of ${MODEL_OPERATIONS.join(", ")}`);
|
|
5961
|
-
}
|
|
5962
|
-
}
|
|
5963
|
-
}
|
|
5964
|
-
if (isRecord6(match.lastUserText) && typeof match.lastUserText.regex === "string") {
|
|
5965
|
-
try {
|
|
5966
|
-
new RegExp(match.lastUserText.regex);
|
|
5967
|
-
} catch {
|
|
5968
|
-
return fail2(`${path}.match.lastUserText.regex`, "not a valid regular expression");
|
|
5969
|
-
}
|
|
5970
|
-
}
|
|
5971
|
-
if (match.toolsInclude !== void 0 && !Array.isArray(match.toolsInclude)) {
|
|
5972
|
-
return fail2(`${path}.match.toolsInclude`, "string[]");
|
|
5973
|
-
}
|
|
6126
|
+
const problem = checkMatch(value.match, `${path}.match`);
|
|
6127
|
+
if (problem) return problem;
|
|
5974
6128
|
}
|
|
5975
6129
|
if (value.times !== void 0 && (typeof value.times !== "number" || value.times < 1)) {
|
|
5976
6130
|
return fail2(`${path}.times`, "a positive count");
|
|
@@ -7018,11 +7172,14 @@ var sonicSession = (request, modelId, host) => {
|
|
|
7018
7172
|
};
|
|
7019
7173
|
|
|
7020
7174
|
// src/state.ts
|
|
7175
|
+
var EMBEDDING_MODES = ["sha256", "lexical"];
|
|
7021
7176
|
var DEFAULT_SETTINGS = {
|
|
7022
7177
|
defaultText: "OK.",
|
|
7023
7178
|
chunkSize: 16,
|
|
7024
7179
|
delayMsPerChunk: 0,
|
|
7025
|
-
audioTurnChunks: 0
|
|
7180
|
+
audioTurnChunks: 0,
|
|
7181
|
+
embeddingMode: "sha256",
|
|
7182
|
+
validatePromptCaching: true
|
|
7026
7183
|
};
|
|
7027
7184
|
var EMPTY_STATS = {
|
|
7028
7185
|
calls: 0,
|
|
@@ -7153,6 +7310,7 @@ var BEDROCK_PRESETS = {
|
|
|
7153
7310
|
type: "service_unavailable"
|
|
7154
7311
|
}),
|
|
7155
7312
|
access_denied: everyCall("403 AccessDeniedException", { type: "access_denied" }),
|
|
7313
|
+
resource_not_found: everyCall("404 ResourceNotFoundException", { type: "resource_not_found" }),
|
|
7156
7314
|
internal_server: everyCall("500 InternalServerException", { type: "internal_server" })
|
|
7157
7315
|
};
|
|
7158
7316
|
var json5 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
@@ -7175,7 +7333,9 @@ var SETTING_CHECKS = {
|
|
|
7175
7333
|
defaultText: (value) => typeof value === "string",
|
|
7176
7334
|
chunkSize: (value) => typeof value === "number" && value >= 1,
|
|
7177
7335
|
delayMsPerChunk: (value) => typeof value === "number" && value >= 0,
|
|
7178
|
-
audioTurnChunks: (value) => typeof value === "number" && value >= 0
|
|
7336
|
+
audioTurnChunks: (value) => typeof value === "number" && value >= 0,
|
|
7337
|
+
embeddingMode: (value) => EMBEDDING_MODES.includes(value),
|
|
7338
|
+
validatePromptCaching: (value) => typeof value === "boolean"
|
|
7179
7339
|
};
|
|
7180
7340
|
var adminRoutes = (runtime) => {
|
|
7181
7341
|
const store = (replace) => ({ body, namespace }) => {
|
|
@@ -7272,6 +7432,11 @@ var FAULT_ERRORS = {
|
|
|
7272
7432
|
"ServiceUnavailableException",
|
|
7273
7433
|
"Bedrock is unable to process your request."
|
|
7274
7434
|
],
|
|
7435
|
+
resource_not_found: [
|
|
7436
|
+
404,
|
|
7437
|
+
"ResourceNotFoundException",
|
|
7438
|
+
"The specified resource ARN was not found. Check the ARN and try again."
|
|
7439
|
+
],
|
|
7275
7440
|
internal_server: [
|
|
7276
7441
|
500,
|
|
7277
7442
|
"InternalServerException",
|
|
@@ -7327,6 +7492,18 @@ var titanEmbedding = async (inputText, dims = 1024) => {
|
|
|
7327
7492
|
const norm = Math.sqrt(values.reduce((sum, v) => sum + v * v, 0)) || 1;
|
|
7328
7493
|
return values.map((v) => v / norm);
|
|
7329
7494
|
};
|
|
7495
|
+
var lexicalEmbedding = async (inputText, dims = 1024) => {
|
|
7496
|
+
const words = inputText.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
|
|
7497
|
+
if (words.length === 0) return titanEmbedding(inputText, dims);
|
|
7498
|
+
const values = new Array(dims).fill(0);
|
|
7499
|
+
for (const word of words) {
|
|
7500
|
+
const digest = new DataView(await crypto.subtle.digest("SHA-256", utf84.encode(word)));
|
|
7501
|
+
const at = digest.getUint32(0, false) % dims;
|
|
7502
|
+
values[at] = values[at] + (digest.getUint8(4) & 1 ? 1 : -1);
|
|
7503
|
+
}
|
|
7504
|
+
const norm = Math.sqrt(values.reduce((sum, v) => sum + v * v, 0));
|
|
7505
|
+
return norm === 0 ? titanEmbedding(inputText, dims) : values.map((v) => v / norm);
|
|
7506
|
+
};
|
|
7330
7507
|
var BedrockAPI = class {
|
|
7331
7508
|
app;
|
|
7332
7509
|
sqlite;
|
|
@@ -7523,7 +7700,9 @@ var BedrockAPI = class {
|
|
|
7523
7700
|
}
|
|
7524
7701
|
let call;
|
|
7525
7702
|
try {
|
|
7526
|
-
call = analyzeConverse(operation, modelId, body
|
|
7703
|
+
call = analyzeConverse(operation, modelId, body, {
|
|
7704
|
+
validatePromptCaching: this.state.current().validatePromptCaching
|
|
7705
|
+
});
|
|
7527
7706
|
} catch (error) {
|
|
7528
7707
|
if (error instanceof ValidationProblem)
|
|
7529
7708
|
return bedrockError(400, "ValidationException", error.message, requestId);
|
|
@@ -7627,7 +7806,8 @@ var BedrockAPI = class {
|
|
|
7627
7806
|
ids: { modelId, script: "unscripted:titan", inputTokens: String(inputTextTokenCount) }
|
|
7628
7807
|
});
|
|
7629
7808
|
if (failed) return notes2(failed);
|
|
7630
|
-
const
|
|
7809
|
+
const embed = this.state.current().embeddingMode === "lexical" ? lexicalEmbedding : titanEmbedding;
|
|
7810
|
+
const embedding = await embed(inputText, dimensions);
|
|
7631
7811
|
return notes2(
|
|
7632
7812
|
jsonRes(
|
|
7633
7813
|
200,
|
|
@@ -7780,6 +7960,7 @@ export {
|
|
|
7780
7960
|
eventFrame,
|
|
7781
7961
|
exceptionFrame,
|
|
7782
7962
|
readFrames,
|
|
7963
|
+
EMBEDDING_MODES,
|
|
7783
7964
|
DEFAULT_SETTINGS,
|
|
7784
7965
|
BEDROCK_PRESETS,
|
|
7785
7966
|
createRuntime2 as createRuntime,
|
|
@@ -7788,6 +7969,7 @@ export {
|
|
|
7788
7969
|
accessKeyCredential,
|
|
7789
7970
|
clockSleep,
|
|
7790
7971
|
titanEmbedding,
|
|
7972
|
+
lexicalEmbedding,
|
|
7791
7973
|
BedrockAPI
|
|
7792
7974
|
};
|
|
7793
|
-
//# sourceMappingURL=chunk-
|
|
7975
|
+
//# sourceMappingURL=chunk-PFSY7JLL.js.map
|