@namzu/bedrock 1.0.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +282 -0
  2. package/dist/__tests__/bedrock.test.js +44 -0
  3. package/dist/__tests__/bedrock.test.js.map +1 -1
  4. package/dist/__tests__/prompt-cache.test.d.ts +2 -0
  5. package/dist/__tests__/prompt-cache.test.d.ts.map +1 -0
  6. package/dist/__tests__/prompt-cache.test.js +68 -0
  7. package/dist/__tests__/prompt-cache.test.js.map +1 -0
  8. package/dist/__tests__/thinking-refused.test.d.ts +2 -0
  9. package/dist/__tests__/thinking-refused.test.d.ts.map +1 -0
  10. package/dist/__tests__/thinking-refused.test.js +35 -0
  11. package/dist/__tests__/thinking-refused.test.js.map +1 -0
  12. package/dist/__tests__/tool-choice-none.test.d.ts +2 -0
  13. package/dist/__tests__/tool-choice-none.test.d.ts.map +1 -0
  14. package/dist/__tests__/tool-choice-none.test.js +76 -0
  15. package/dist/__tests__/tool-choice-none.test.js.map +1 -0
  16. package/dist/__tests__/tool-content-blocks.test.d.ts +2 -0
  17. package/dist/__tests__/tool-content-blocks.test.d.ts.map +1 -0
  18. package/dist/__tests__/tool-content-blocks.test.js +92 -0
  19. package/dist/__tests__/tool-content-blocks.test.js.map +1 -0
  20. package/dist/__tests__/vision.test.d.ts +2 -0
  21. package/dist/__tests__/vision.test.d.ts.map +1 -0
  22. package/dist/__tests__/vision.test.js +77 -0
  23. package/dist/__tests__/vision.test.js.map +1 -0
  24. package/dist/client.d.ts +13 -1
  25. package/dist/client.d.ts.map +1 -1
  26. package/dist/client.js +20 -7
  27. package/dist/client.js.map +1 -1
  28. package/package.json +4 -4
  29. package/src/__tests__/bedrock.test.ts +47 -0
  30. package/src/__tests__/prompt-cache.test.ts +81 -0
  31. package/src/__tests__/thinking-refused.test.ts +44 -0
  32. package/src/__tests__/tool-choice-none.test.ts +87 -0
  33. package/src/__tests__/tool-content-blocks.test.ts +119 -0
  34. package/src/__tests__/vision.test.ts +98 -0
  35. package/src/client.ts +22 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,287 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 1500973: Every driver that cannot think now says so instead of dropping the request.
8
+
9
+ `thinking` sits on `ChatCompletionParams`, so every driver accepts it. Five of
10
+ them — Bedrock, OpenRouter, HTTP, Ollama, LM Studio — implemented none of it
11
+ and dropped the field: the caller got an ordinary completion with an empty
12
+ `reasoning` array, which is indistinguishable from a model that simply chose
13
+ not to reason. The request looked honoured and the answer looked like an
14
+ answer.
15
+
16
+ The OpenAI driver already refused instead, with the reasoning written out
17
+ beside it. So the rule had been decided once and applied once, while five
18
+ siblings went on being silent. It moves to `@namzu/sdk` as
19
+ `assertThinkingUnsupported(driverName, params)`, and a new driver now inherits
20
+ it rather than re-deciding it.
21
+
22
+ The error names the driver, which in a multi-provider setup is the difference
23
+ between a bug report about the model and a one-line configuration fix.
24
+
25
+ **Turning thinking off stays a no-op** on all of them, because that is the
26
+ state a driver without thinking is already in — a config shared across
27
+ providers saying `{ type: 'disabled' }` should not fail on the ones that were
28
+ never going to think.
29
+
30
+ `assertThinkingSupported` in `@namzu/openai` is unchanged as an export and now
31
+ delegates to the shared helper. Its message changed: it no longer says
32
+ "extended thinking", because `adaptive` is refused too and calling that
33
+ extended would be wrong.
34
+
35
+ **Migration.** If you passed `thinking` to any of the five and relied on it
36
+ being ignored, remove it — you were receiving a non-thinking answer either way,
37
+ and now you find out at the call instead of by inspecting an empty array.
38
+
39
+ Not in this change: implementing thinking natively on Bedrock, which serves the
40
+ same Claude models through a different wire and deserves the per-model
41
+ resolution the Anthropic driver just gained. That needs the Converse request
42
+ and response shapes verified against the reference first, and is not something
43
+ to guess at.
44
+
45
+ ## 2.0.0
46
+
47
+ ### Major Changes
48
+
49
+ - 935b8f3: Three controls a caller could set that the runtime then quietly declined to apply.
50
+
51
+ - **`toolChoice: 'none'` permitted tool calls on two drivers.** It means the model must not call a tool. One driver mapped it to the wire's "auto" and the other to `{ type: 'auto' }` — both of which say the model _may_. A caller that had forbidden tool use got a request that allowed it, with nothing in the response to say so. The runtime depends on the guarantee: an advisory consultation passes `'none'` so the advisor answers in prose, into a turn where no executor is waiting for a tool call. Both drivers now answer `'none'` by sending no tools at all, which no wire format can misread.
52
+
53
+ - **`memoryLimitMb` and `maxProcesses` were dropped by the stronger isolation tiers.** They were applied inside the unconfined tier's branch only, so asking for namespace or profile isolation silently removed the blast-radius caps — a control failing in the one direction nobody checks. They are the same shell builtin on every tier; the stronger tiers now apply them one level in, inside the wrapper they already spawn through, and keep doing their own job. The sibling backend in the sandbox package already refuses per-sandbox controls it cannot enforce rather than ignoring them; this is the same rule, satisfied by enforcing.
54
+
55
+ - **`AgentManager.dispose()` cancelled nothing.** It called `cancelAll('' as RunId)`, and `cancelAll` filters by parent run — no task has an empty parent, so it matched nothing, and the next lines cleared the instance map. Every live child was released without its abort controller firing: the work kept running, the budget kept draining, and nothing was left holding a reference to stop it. It now cancels every live child before dropping them. `cancelAll` stays scoped to one parent, which is its actual job.
56
+
57
+ `toBedrockToolConfig` and `buildLimitedSpawn` are exported so the mapping and the spawn shape can be asserted directly rather than through a live process.
58
+
59
+ ### Minor Changes
60
+
61
+ - 935b8f3: Prompt caching is now requested, not just measured.
62
+
63
+ The driver read the cache-hit and cache-write counters off every response
64
+ and never asked for caching, so both were permanently zero: the entire
65
+ static prefix — tool schemas, system instructions, the whole conversation
66
+ so far — was re-sent and re-billed at full rate on every single turn of
67
+ every run. Nothing failed, which is why it went unnoticed; it was purely
68
+ money and latency.
69
+
70
+ A breakpoint on this wire is a content BLOCK rather than an annotation on a
71
+ neighbouring one: everything ahead of it in render order is cached. Render
72
+ order is tools → system → messages, so the driver places one at the tail of
73
+ each section, and each later breakpoint covers everything before it:
74
+
75
+ - after the tool schemas, which render first and are the largest static
76
+ segment — this keeps them cached even when the conversation below changes
77
+ every turn;
78
+ - after the last system block the runtime tagged as static, NOT at the end
79
+ of the system section. The per-run dynamic tail comes after that tag; a
80
+ breakpoint over text that changes every run invalidates the entry each
81
+ turn and bills a cache write for nothing;
82
+ - after the last message, so the next iteration — which only appends —
83
+ reads all the prior history at cache rates.
84
+
85
+ Three breakpoints, one under the wire's limit of four. None are placed
86
+ unless the caller sets `cacheControl`, and none are placed over system
87
+ text with nothing static in it or on a message with no content.
88
+
89
+ - 935b8f3: Every driver can now see.
90
+
91
+ These three dropped `attachments` outright, so a user who attached a
92
+ screenshot got a turn about nothing. `supportsVision: false` said so, which
93
+ made the declaration honest and the driver useless — and it was the last
94
+ place in the estate where a namzu capability existed on one driver and
95
+ silently did not on another.
96
+
97
+ Each wire carries an image differently, so this is one intent and three
98
+ mappings:
99
+
100
+ - **Converse**: raw bytes in an image content block beside the text. The
101
+ tool-result path already did this; the user path never looked at
102
+ `attachments`.
103
+ - **The two-dialect HTTP driver**: a `data:` URI content part on one
104
+ dialect, a base64 source block on the other.
105
+ - **The gateway driver**: a `data:` URI content part.
106
+
107
+ Across all three: a media type the endpoint cannot decode is named in the
108
+ text rather than sent, because a payload it rejects fails the whole request
109
+ and losing the turn is worse than losing sight of one image. A message with
110
+ no attachments keeps its plain-string content, so nothing about an ordinary
111
+ request changes shape. Several attachments on one message are carried in
112
+ order.
113
+
114
+ An image inside a **tool result** still degrades to a text placeholder on
115
+ the HTTP and gateway drivers: a tool message is text-only in those dialects,
116
+ so there is nowhere to put it. Converse carries it, and always did.
117
+
118
+ ### Patch Changes
119
+
120
+ - 935b8f3: The conversation cache anchor advances, so the next request can read it.
121
+
122
+ A single breakpoint at the conversation tail writes a new cache entry every
123
+ turn and reads none of them: by the next request the tail has moved, so the
124
+ marker sits somewhere the previous entry does not cover. The tools and
125
+ system tiers keep hitting through their own breakpoints — which is exactly
126
+ what made this invisible. Only the messages tier silently re-billed as a
127
+ write.
128
+
129
+ Both drivers now place a second anchor one turn back, which is where the
130
+ previous request put its tail marker and therefore the prefix that is
131
+ already cached.
132
+
133
+ It matters most where the history grows fastest. Pending tool results
134
+ collapse into a single message, so a fan-out of ten parallel calls appends
135
+ twenty content blocks in one turn — far enough to push the prior boundary
136
+ out of reach of a backward scan that stops at the first non-empty message.
137
+
138
+ This spends the fourth of the four allowed breakpoints, previously
139
+ documented as deliberately unspent. It is spent on the one tier that was
140
+ never hitting. A conversation with a single message still gets one anchor,
141
+ because there is nowhere behind it to put a second.
142
+
143
+ - 935b8f3: Retry now works on the bedrock driver, and the shared classifier reads a
144
+ status wherever a vendor hides it.
145
+
146
+ An unclassified error is treated as non-retryable, which is the right
147
+ default — but it meant the retry policy was effectively dead on this
148
+ driver, and the one failure most worth backing off from was the one that
149
+ killed the run. The service reports failures as named exception classes,
150
+ and the classifier looked at neither the name nor the status, because the
151
+ status lives in a metadata bag rather than on the error.
152
+
153
+ - `classifyProviderError` now also reads `$metadata.httpStatusCode`. A
154
+ status is a status wherever it hides, and this helps any driver — first
155
+ or third party — whose SDK reports it that way.
156
+ - The bedrock driver maps its own exception vocabulary to provider error
157
+ codes: throttling and quota to `rate_limit`, unavailable and not-ready to
158
+ `overloaded`, internal and stream faults to `server_error`, and the
159
+ non-retryable ones (`ValidationException`, `AccessDeniedException`,
160
+ `ResourceNotFoundException`) to their exact codes so they fail fast
161
+ instead of burning the retry budget.
162
+
163
+ The vocabulary lives in the driver rather than the shared classifier: a
164
+ driver knows its own vendor's error names, and the classifier should stay
165
+ generic. An unrecognised exception passes through untouched — an honest
166
+ unknown beats a confident wrong classification.
167
+
168
+ - 935b8f3: Lift the dependency floor to versions without published advisories
169
+
170
+ Eighty-two open advisories collapsed to a handful of real decisions, because most of them were the same package reached through one path.
171
+
172
+ The telemetry exporters carried a serialization library with twenty-four advisories against it, two of them critical. The exporters move from the 0.57 line to 0.221, and the stable packages beside them from 1.x to 2.x — a major bump for this package, since a consumer pinning the older peers must move with it.
173
+
174
+ The two vendor driver SDKs move to their current releases, closing the advisories that came with them.
175
+
176
+ The test runner accounted for fourteen critical advisories on its own. It is a development dependency and never reaches a published artifact, but it runs in CI against the repository's own contents, so it moves to the first patched release rather than being waved through as out-of-scope.
177
+
178
+ - 935b8f3: Stop dropping tool-failure status on Bedrock, and stop accepting a sandbox
179
+ egress policy this backend cannot enforce.
180
+
181
+ - **Bedrock** flattened every failed tool result into an ordinary success.
182
+ The executor computed `isError`, the SSE and A2A bridges carried it, and
183
+ the driver dropped it — even though Converse has a first-class
184
+ `toolResult.status`. The model's trained tool-failure recovery path keys
185
+ off that field, so namzu was relying on prose formatting to convey "that
186
+ call failed".
187
+
188
+ Scope note: the five OpenAI-shaped drivers are NOT affected, because
189
+ Chat Completions has no error field on a tool message at all. The error
190
+ reaches those models inside the result text, which is the only channel
191
+ the protocol has.
192
+
193
+ - **Docker sandbox** accepted `EgressPolicy` and silently ignored it. A
194
+ host that set `deny-all` believed the container had no network and it had
195
+ whatever `network` was configured. A security control that is accepted
196
+ and ignored is worse than one that does not exist. Now: `deny-all` maps
197
+ to `--network none` (which Docker enforces natively), `allow-all` keeps
198
+ the configured network, and `static` / `resolver` **throw** — this
199
+ backend has no proxy to filter hosts through, and downgrading a
200
+ restrictive policy to "allow everything" is exactly the failure worth
201
+ refusing.
202
+
203
+ - **Docker sandbox** containers now run with `--cap-drop=ALL` and
204
+ `--security-opt=no-new-privileges`, plus an opt-in `runAsUser`.
205
+ `CAP_DAC_OVERRIDE` alone walks past the read-only bind mounts the layout
206
+ sets up, and without `no-new-privileges` a setuid binary in the image
207
+ re-escalates.
208
+
209
+ - 935b8f3: Stop dumping a tool result's base64 payload into the prompt.
210
+
211
+ Four drivers mishandled a tool result carrying content blocks, each in its
212
+ own way: bedrock and the http driver's anthropic dialect `JSON.stringify`d
213
+ the whole array, putting a screenshot's base64 into the prompt as JSON
214
+ text; openrouter and the http driver's openai dialect passed the array
215
+ through raw to an endpoint expecting a string; lmstudio folded it into a
216
+ template literal, producing `[object Object]` per block. The model cannot
217
+ decode any of it, and it costs a fortune in tokens.
218
+
219
+ - The three text-only wires now flatten with the SDK's existing helper,
220
+ which names a non-text block and its size instead of inlining it. The
221
+ openai and ollama drivers already did this — the helper was there and
222
+ four callers were missing.
223
+ - **bedrock sends the image as an image.** That wire carries images
224
+ natively, so a placeholder would be a downgrade the other drivers accept
225
+ only because their format has no room for one. Text and image survive as
226
+ separate blocks in order, and a media type the format does not accept
227
+ still degrades to a named placeholder rather than being smuggled through
228
+ as text.
229
+
230
+ - 935b8f3: Four drivers dumped tool-result payloads into the prompt, and one ignored the strict-schema hint.
231
+
232
+ **A tool result carrying an image was `JSON.stringify`d** on four drivers, so a screenshot reached the model as a wall of quoted base64. The model paid for every character, could read none of them, and — worse — saw a serialized object where a picture should be, with nothing saying anything had been withheld. The SDK's `toolResultToText` exists for exactly this and produces a named placeholder reporting the media type and the size. All four now use it: `@namzu/bedrock`, both dialects of `@namzu/http`, and `@namzu/lmstudio`.
233
+
234
+ **`enforceToolInputSchema` was ignored by `@namzu/openai`.** It names the tools whose model-facing schema should be enforced by constrained generation rather than merely suggested; both sibling drivers consumed it. A caller who had asked for a guaranteed-valid tool input silently got a best-effort one and learned about it from a repair attempt. This is the wire the flag maps onto most directly — it takes the flag on the function itself. The existing test asserting the tools went through untouched read as "the hint is kept out of the request" and actually pinned "the hint does nothing"; it now asserts the hint is consumed and still never appears verbatim.
235
+
236
+ **An extended-thinking request is refused by `@namzu/openai` rather than dropped.** The parameter was accepted and ignored, so a caller who asked for reasoning got an ordinary completion with an empty reasoning list — which reads as "the model did not reason" rather than "nobody asked it to". Turning thinking off stays a no-op, since that is the state the driver is already in.
237
+
238
+ Eleven previously empty test files now cover these drivers, including the capability claims themselves: every driver that declares no vision, documents or tools is pinned against drift in both directions, because the runtime warns or fails on those flags before a request is built, and a flag flipped ahead of its mapping is as wrong as a mapping written without the flag.
239
+
240
+ - 935b8f3: Overflow reaches the rescue that exists for it.
241
+
242
+ Overflow is the one 4xx the runtime can act on: it sheds history and
243
+ retries. Everything else in the 400 family is surfaced. So the rescue is
244
+ gated on the code being **exactly** `context_length_exceeded`, and anything
245
+ that misses that gate dies holding the remedy.
246
+
247
+ Three things missed it. Measured before and after, five of six realistic
248
+ overflow shapes never reached relief; now all six do.
249
+
250
+ - **The structural code was extracted and then discarded.** The cause-chain
251
+ walk returned the first `code` it found and fed it only to the two
252
+ transport-errno sets, so a provider that said `context_length_exceeded` in
253
+ the one field designed to say it was answered with a substring search that
254
+ did not match. A structural code is now consulted **before** the status,
255
+ because it is strictly more specific: a 400 is a category, the code is the
256
+ diagnosis. The gateway `type` discriminator and a nested error envelope
257
+ are read the same way.
258
+ - **The phrase list missed the common wordings.** "too long for", "maximum
259
+ length", "exceeds the maximum", "input is too large" all fell through to a
260
+ plain non-retryable invalid request.
261
+ - **The Converse driver pre-filed `ValidationException` as
262
+ `invalid_request`.** That name covers both a malformed request and a
263
+ prompt past the model's window, and only one of those is recoverable — so
264
+ guessing from the name made the recoverable case unrecoverable by
265
+ construction, because the shared classifier short-circuits on an error
266
+ that already carries a code and never read the body. It now hands that one
267
+ name to the classifier. The result is still a `ProviderError`, so the
268
+ driver's contract is unchanged; it just stops answering a question it
269
+ cannot answer from the name alone.
270
+
271
+ The rate-limit half of the same class is fixed alongside: a provider that
272
+ reports `rate_limit_exceeded` structurally under a 400 is now retryable
273
+ instead of being filed as a bad request.
274
+
275
+ - 935b8f3: A user message can carry a document
276
+
277
+ Documents existed in the type system only in the tool-result direction, and both first-party drivers mapped images only on the input side. So "here is the contract, answer questions about it" — a mainstream workload — was reachable only by having a tool read the file and stringify it. That loses the provider's native document handling (page structure, built-in OCR, citations) and pays the text cost instead.
278
+
279
+ `UserMessage.attachments` is now `MessageAttachment[]`: an image or a document. The discriminant is optional and stays optional — an attachment without one is an image, which is what every attachment was before, so no existing caller changes.
280
+
281
+ `supportsDocuments` sits beside `supportsVision` in the driver capability declaration, and the runtime checks it the same way: a document sent to a driver that declares `false` warns before the request, or throws under `strictCapabilities`, instead of letting the model answer about a file it never saw. The two are counted separately because they are separate wire shapes and a driver can map one without the other.
282
+
283
+ The two first-party drivers map documents natively. The remaining five map images only and now say so; a document reaching them degrades to a named placeholder that says which kind was dropped, rather than one that calls a document an image.
284
+
3
285
  ## 1.0.3
4
286
 
5
287
  ### Patch Changes
@@ -39,6 +39,7 @@ describe('@namzu/bedrock', () => {
39
39
  supportsStreaming: true,
40
40
  supportsFunctionCalling: true,
41
41
  supportsVision: false,
42
+ supportsDocuments: false,
42
43
  });
43
44
  });
44
45
  it('is exposed on the provider instance for runtime negotiation', () => {
@@ -46,5 +47,48 @@ describe('@namzu/bedrock', () => {
46
47
  expect(provider.capabilities).toEqual(BEDROCK_CAPABILITIES);
47
48
  });
48
49
  });
50
+ it('keeps the Namzu enforcement hint out of the Bedrock command', async () => {
51
+ const provider = new BedrockProvider({ region: 'us-east-1' });
52
+ let commandInput;
53
+ provider.client = {
54
+ send: async (command) => {
55
+ commandInput = command.input;
56
+ return {
57
+ $metadata: { requestId: 'request-test' },
58
+ stream: (async function* () { })(),
59
+ };
60
+ },
61
+ };
62
+ for await (const _chunk of provider.chatStream({
63
+ model: 'anthropic.claude-sonnet-5-v1:0',
64
+ messages: [{ role: 'user', content: 'edit' }],
65
+ tools: [
66
+ {
67
+ type: 'function',
68
+ function: {
69
+ name: 'edit',
70
+ description: 'Edit',
71
+ parameters: { type: 'object' },
72
+ },
73
+ },
74
+ ],
75
+ enforceToolInputSchema: ['edit'],
76
+ })) {
77
+ // Drain the empty test stream.
78
+ }
79
+ expect(commandInput).not.toHaveProperty('enforceToolInputSchema');
80
+ expect(commandInput?.toolConfig).toEqual({
81
+ tools: [
82
+ {
83
+ toolSpec: {
84
+ name: 'edit',
85
+ description: 'Edit',
86
+ inputSchema: { json: { type: 'object' } },
87
+ },
88
+ },
89
+ ],
90
+ toolChoice: { auto: {} },
91
+ });
92
+ });
49
93
  });
50
94
  //# sourceMappingURL=bedrock.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bedrock.test.js","sourceRoot":"","sources":["../../src/__tests__/bedrock.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEpF,6EAA6E;AAC7E,yEAAyE;AACzE,8CAA8C;AAC9C,UAAU,CAAC,GAAG,EAAE;IACf,IAAI,gBAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,gBAAgB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC;AACF,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC/B,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YACjD,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC3D,eAAe,EAAE,CAAA;YACjB,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1D,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YAC1E,eAAe,EAAE,CAAA;YACjB,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAA;QACrE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YAClE,eAAe,EAAE,CAAA;YACjB,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;YAC9D,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACvE,eAAe,EAAE,CAAA;YACjB,MAAM,IAAI,GAAG,gBAAgB,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;YACxD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YACjD,MAAM,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC;gBACpC,aAAa,EAAE,IAAI;gBACnB,iBAAiB,EAAE,IAAI;gBACvB,uBAAuB,EAAE,IAAI;gBAC7B,cAAc,EAAE,KAAK;aACrB,CAAC,CAAA;QACH,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;YACtE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;YAC7D,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"bedrock.test.js","sourceRoot":"","sources":["../../src/__tests__/bedrock.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prompt-cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-cache.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/prompt-cache.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseBedrockUsage } from '../client.js';
3
+ /**
4
+ * Cache reads and cache writes are priced differently from ordinary input,
5
+ * so folding either into the prompt count misreports what a run cost — and
6
+ * misreports it silently, because the total still looks plausible.
7
+ *
8
+ * The counters are also the only evidence that the breakpoints are working
9
+ * at all: a run whose cached count stays at zero is paying full price for
10
+ * a prefix it believes is cached, and nothing else says so.
11
+ */
12
+ describe('cache counters are reported on their own axis', () => {
13
+ it('keeps reads out of the prompt count', () => {
14
+ const usage = parseBedrockUsage({
15
+ inputTokens: 10,
16
+ outputTokens: 2,
17
+ cacheReadInputTokenCount: 900,
18
+ });
19
+ expect(usage.promptTokens).toBe(10);
20
+ expect(usage.cachedTokens).toBe(900);
21
+ });
22
+ it('keeps writes on their own axis too', () => {
23
+ const usage = parseBedrockUsage({
24
+ inputTokens: 10,
25
+ outputTokens: 2,
26
+ cacheWriteInputTokenCount: 40,
27
+ });
28
+ expect(usage.cacheWriteTokens).toBe(40);
29
+ expect(usage.promptTokens).toBe(10);
30
+ });
31
+ it('reports both when both happen in one turn', () => {
32
+ const usage = parseBedrockUsage({
33
+ inputTokens: 10,
34
+ outputTokens: 2,
35
+ cacheReadInputTokenCount: 900,
36
+ cacheWriteInputTokenCount: 40,
37
+ });
38
+ expect(usage).toMatchObject({ cachedTokens: 900, cacheWriteTokens: 40 });
39
+ });
40
+ it('reads an absent counter as zero, not undefined', () => {
41
+ const usage = parseBedrockUsage({ inputTokens: 5, outputTokens: 1 });
42
+ // A consumer summing these must not have to guard every field; an
43
+ // undefined here becomes NaN one addition later.
44
+ expect(usage.cachedTokens).toBe(0);
45
+ expect(usage.cacheWriteTokens).toBe(0);
46
+ });
47
+ it('totals input and output, and nothing else', () => {
48
+ const usage = parseBedrockUsage({
49
+ inputTokens: 10,
50
+ outputTokens: 2,
51
+ cacheReadInputTokenCount: 900,
52
+ });
53
+ // Cached reads are already counted upstream; adding them here would
54
+ // double-count the same tokens in the run's own ledger.
55
+ expect(usage.totalTokens).toBe(12);
56
+ });
57
+ it('reads a missing usage payload as all zeros', () => {
58
+ const usage = parseBedrockUsage(undefined);
59
+ expect(usage).toEqual({
60
+ promptTokens: 0,
61
+ completionTokens: 0,
62
+ totalTokens: 0,
63
+ cachedTokens: 0,
64
+ cacheWriteTokens: 0,
65
+ });
66
+ });
67
+ });
68
+ //# sourceMappingURL=prompt-cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-cache.test.js","sourceRoot":"","sources":["../../src/__tests__/prompt-cache.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;;;;GAQG;AAEH,QAAQ,CAAC,+CAA+C,EAAE,GAAG,EAAE;IAC9D,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAC/B,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,CAAC;YACf,wBAAwB,EAAE,GAAG;SAC7B,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACnC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC7C,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAC/B,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,CAAC;YACf,yBAAyB,EAAE,EAAE;SAC7B,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACvC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACpD,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAC/B,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,CAAC;YACf,wBAAwB,EAAE,GAAG;YAC7B,yBAAyB,EAAE,EAAE;SAC7B,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAA;QAEpE,kEAAkE;QAClE,iDAAiD;QACjD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAClC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACpD,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAC/B,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,CAAC;YACf,wBAAwB,EAAE,GAAG;SAC7B,CAAC,CAAA;QAEF,oEAAoE;QACpE,wDAAwD;QACxD,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,KAAK,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAA;QAE1C,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YACrB,YAAY,EAAE,CAAC;YACf,gBAAgB,EAAE,CAAC;YACnB,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,gBAAgB,EAAE,CAAC;SACnB,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=thinking-refused.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-refused.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/thinking-refused.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { BedrockProvider } from '../client.js';
3
+ /**
4
+ * The shared guard's own tests pass whether or not this driver calls it, so
5
+ * this drives the real `chatStream`. The defect being fixed was exactly a
6
+ * declared parameter that no code path consumed — asserting the helper works
7
+ * would have reproduced that shape one level up.
8
+ *
9
+ * The guard runs before any client work, so no credentials and no network are
10
+ * involved: the request never gets that far.
11
+ */
12
+ const provider = new BedrockProvider({ region: 'us-east-1' });
13
+ async function run(thinking) {
14
+ for await (const _chunk of provider.chatStream({
15
+ model: 'anthropic.claude-sonnet-4-5-20250929-v1:0',
16
+ messages: [{ role: 'user', content: 'hi' }],
17
+ ...(thinking ? { thinking } : {}),
18
+ })) {
19
+ // drain
20
+ }
21
+ }
22
+ describe('BedrockProvider refuses a thinking request rather than dropping it', () => {
23
+ it('throws on a manual thinking request', async () => {
24
+ await expect(run({ type: 'enabled', budgetTokens: 10_000 })).rejects.toThrow(/BedrockProvider does not implement thinking/);
25
+ });
26
+ it('throws on an adaptive one', async () => {
27
+ await expect(run({ type: 'adaptive' })).rejects.toThrow(/does not implement thinking/);
28
+ });
29
+ it('does not throw for an explicit disable', async () => {
30
+ // Reaches the client and fails on credentials or network instead,
31
+ // which is the point: the guard let it past.
32
+ await expect(run({ type: 'disabled' })).rejects.not.toThrow(/does not implement thinking/);
33
+ });
34
+ });
35
+ //# sourceMappingURL=thinking-refused.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-refused.test.js","sourceRoot":"","sources":["../../src/__tests__/thinking-refused.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;;;;GAQG;AAEH,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,WAAW,EAAW,CAAC,CAAA;AAEtE,KAAK,UAAU,GAAG,CAAC,QAA2C;IAC7D,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,QAAQ,CAAC,UAAU,CAAC;QAC9C,KAAK,EAAE,2CAA2C;QAClD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3C,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACT,CAAC,EAAE,CAAC;QAC5B,QAAQ;IACT,CAAC;AACF,CAAC;AAED,QAAQ,CAAC,oEAAoE,EAAE,GAAG,EAAE;IACnF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC3E,6CAA6C,CAC7C,CAAA;IACF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACvD,kEAAkE;QAClE,6CAA6C;QAC7C,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAA;IAC3F,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tool-choice-none.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-choice-none.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-choice-none.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { toBedrockToolConfig } from '../client.js';
3
+ /**
4
+ * `toolChoice: 'none'` means the model must not call a tool. This driver
5
+ * mapped it to the wire's "auto", which means the model MAY — the exact
6
+ * opposite of what the caller asked for, and silent.
7
+ *
8
+ * The runtime relies on it: an advisory consultation passes `'none'` so the
9
+ * advisor answers in prose. Under this driver the advisor could emit a tool
10
+ * call instead, into a turn with no executor waiting for one.
11
+ *
12
+ * The fix is not a better mapping. Every version of every wire format
13
+ * agrees a model cannot call a tool it was never given, so `'none'` sends
14
+ * no tools at all — a guarantee rather than a request.
15
+ */
16
+ const TOOLS = [
17
+ {
18
+ type: 'function',
19
+ function: { name: 'read', description: 'read a file', parameters: { type: 'object' } },
20
+ },
21
+ ];
22
+ describe("a caller that said 'none' gets no tools on the wire", () => {
23
+ it('omits the tool config entirely', () => {
24
+ expect(toBedrockToolConfig({ model: 'm', messages: [], tools: TOOLS, toolChoice: 'none' })).toBe(undefined);
25
+ });
26
+ it('omits it even when the history contains tool blocks', () => {
27
+ const config = toBedrockToolConfig({
28
+ model: 'm',
29
+ messages: [
30
+ {
31
+ role: 'assistant',
32
+ content: null,
33
+ toolCalls: [{ id: 'c1', type: 'function', function: { name: 'read', arguments: '{}' } }],
34
+ },
35
+ { role: 'tool', content: 'ok', toolCallId: 'c1' },
36
+ ],
37
+ toolChoice: 'none',
38
+ });
39
+ expect(config).toBe(undefined);
40
+ });
41
+ });
42
+ describe('the other choices still reach the wire unchanged', () => {
43
+ it('maps auto', () => {
44
+ const config = toBedrockToolConfig({
45
+ model: 'm',
46
+ messages: [],
47
+ tools: TOOLS,
48
+ toolChoice: 'auto',
49
+ });
50
+ expect(config?.toolChoice).toEqual({ auto: {} });
51
+ expect(config?.tools).toHaveLength(1);
52
+ });
53
+ it('maps required', () => {
54
+ const config = toBedrockToolConfig({
55
+ model: 'm',
56
+ messages: [],
57
+ tools: TOOLS,
58
+ toolChoice: 'required',
59
+ });
60
+ expect(config?.toolChoice).toEqual({ any: {} });
61
+ });
62
+ it('maps a named tool', () => {
63
+ const config = toBedrockToolConfig({
64
+ model: 'm',
65
+ messages: [],
66
+ tools: TOOLS,
67
+ toolChoice: { type: 'function', function: { name: 'read' } },
68
+ });
69
+ expect(config?.toolChoice).toEqual({ tool: { name: 'read' } });
70
+ });
71
+ it('defaults to auto when the caller said nothing', () => {
72
+ const config = toBedrockToolConfig({ model: 'm', messages: [], tools: TOOLS });
73
+ expect(config?.toolChoice).toEqual({ auto: {} });
74
+ });
75
+ });
76
+ //# sourceMappingURL=tool-choice-none.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-choice-none.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-choice-none.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tool-content-blocks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-content-blocks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-content-blocks.test.ts"],"names":[],"mappings":""}