@warlock.js/ai-bedrock 5.29.0 → 5.31.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 +34 -0
- package/cjs/index.cjs +350 -57
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +31 -6
- package/esm/config.type.d.mts.map +1 -1
- package/esm/embedder.mjs +1 -1
- package/esm/embedder.mjs.map +1 -1
- package/esm/index.d.mts +3 -1
- package/esm/index.mjs +2 -1
- package/esm/known-capabilities.mjs +42 -4
- package/esm/known-capabilities.mjs.map +1 -1
- package/esm/known-pricing.d.mts +48 -0
- package/esm/known-pricing.d.mts.map +1 -0
- package/esm/known-pricing.mjs +99 -0
- package/esm/known-pricing.mjs.map +1 -0
- package/esm/known-vision-models.mjs +1 -1
- package/esm/known-vision-models.mjs.map +1 -1
- package/esm/model.mjs +122 -46
- package/esm/model.mjs.map +1 -1
- package/esm/provider-options.d.mts +8 -0
- package/esm/provider-options.d.mts.map +1 -0
- package/esm/provider-options.mjs +36 -0
- package/esm/provider-options.mjs.map +1 -0
- package/esm/sdk.d.mts +5 -1
- package/esm/sdk.d.mts.map +1 -1
- package/esm/sdk.mjs +35 -4
- package/esm/sdk.mjs.map +1 -1
- package/esm/utils/map-stop-reason.mjs +1 -1
- package/esm/utils/map-stop-reason.mjs.map +1 -1
- package/esm/utils/reasoning-blocks.mjs +1 -1
- package/esm/utils/reasoning-blocks.mjs.map +1 -1
- package/esm/utils/to-bedrock-messages.mjs +15 -2
- package/esm/utils/to-bedrock-messages.mjs.map +1 -1
- package/esm/utils/to-bedrock-tools.mjs +1 -1
- package/esm/utils/to-bedrock-tools.mjs.map +1 -1
- package/esm/utils/wrap-bedrock-error.mjs +6 -2
- package/esm/utils/wrap-bedrock-error.mjs.map +1 -1
- package/llms-full.txt +152 -38
- package/llms.txt +1 -1
- package/package.json +5 -4
- package/skills/setup-bedrock/SKILL.md +152 -38
package/llms-full.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
name: setup-bedrock
|
|
11
|
-
description: 'Wire @warlock.js/ai-bedrock — new BedrockSDK({region, credentials?, provider?}) for AWS Bedrock Converse API + Titan embeddings. AWS credential chain (
|
|
11
|
+
description: 'Wire @warlock.js/ai-bedrock — new BedrockSDK({region, apiKey?, credentials?, provider?}) for AWS Bedrock Converse API + Titan embeddings. AWS credential chain or an Amazon Bedrock API key (bearer). .model({name, vision?, reasoning?, promptCaching?, pdf?, audio?}) with cost-truth capabilities inferred per family, extended thinking via options.reasoning → Converse thinking budget_tokens, prompt caching via options.cacheControl → cachePoint on tools (Claude), system and the last message, 1h TTL via promptCacheTtl, usage inputIncludesCache: false + cachedTokens/cacheWriteTokens/cacheWrite1hTokens, built-in Claude prices for global./us. profiles (BEDROCK_GLOBAL_PRICING, BEDROCK_US_PRICING, bedrockPricingFor), ServiceUnavailableException → ProviderOverloadedError. Triggers: `apiKey`, `AWS_BEARER_TOKEN_BEDROCK`, `providerOptions`, `BedrockCallOptions`, `countTokens`, `BedrockSDK`, `bedrock.model`, `bedrock.embedder`, `bedrock.count`, `BedrockRuntimeClient`, `reasoning`, `thinking`, `budget_tokens`, `cachePoint`, `cacheControl`, `ai.providerTool`, `systemTool`, `nova_grounding`, `server_tool_use`, `streamChunks`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`; "how do I use AWS Bedrock", "wire Claude/Nova/Llama on Bedrock", "Titan embeddings", "Bedrock Converse API", "Claude 3.7/4 extended thinking on Bedrock", "Bedrock prompt caching cost"; typical import `import { BedrockSDK } from "@warlock.js/ai-bedrock"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; provider choice — the `pick-ai-provider` topic of the `warlock-js-ai` skill; embeddings concepts — the `embed-text` topic of the `warlock-js-ai` skill; competing libs `@aws-sdk/client-bedrock-runtime`, `@ai-sdk/amazon-bedrock`; sibling adapters `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`.'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# `@warlock.js/ai-bedrock`
|
|
@@ -29,32 +29,38 @@ const bedrock2 = new BedrockSDK({
|
|
|
29
29
|
credentials: { accessKeyId: "AKIA...", secretAccessKey: "..." },
|
|
30
30
|
provider: "bedrock-eu",
|
|
31
31
|
});
|
|
32
|
+
|
|
33
|
+
// Amazon Bedrock API key (bearer auth, no AWS credentials):
|
|
34
|
+
const bedrock3 = new BedrockSDK({
|
|
35
|
+
apiKey: process.env.BEDROCK_API_KEY!,
|
|
36
|
+
region: "us-east-1",
|
|
37
|
+
});
|
|
32
38
|
```
|
|
33
39
|
|
|
34
|
-
Bedrock authenticates via the **AWS credential chain
|
|
40
|
+
Bedrock authenticates via the **AWS credential chain** or an **Amazon Bedrock API key**. `apiKey` sends `Authorization: Bearer <key>` instead of a SigV4 signature (the adapter sets the AWS SDK's `token` + `authSchemePreference: ["httpBearerAuth"]`); combining it with `credentials` or `token`, or passing an empty key, throws `InvalidRequestError`. Without `apiKey`, the AWS SDK still reads a key from `AWS_BEARER_TOKEN_BEDROCK` on its own. `region` is required; `credentials` is optional (omit to use the standard provider chain). The whole config object is forwarded to `BedrockRuntimeClient`, so any AWS client option (`endpoint`, `requestHandler`, retry config) is accepted. `provider` defaults to `"bedrock"`.
|
|
35
41
|
|
|
36
42
|
## Producing a model
|
|
37
43
|
|
|
38
44
|
`name` is the Bedrock **model id or inference-profile id**:
|
|
39
45
|
|
|
40
46
|
```ts
|
|
41
|
-
bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" })
|
|
42
|
-
bedrock.model({ name: "us.amazon.nova-pro-v1:0", temperature: 0.2 })
|
|
43
|
-
bedrock.model({ name: "meta.llama3-1-8b-instruct-v1:0", maxTokens: 1024 })
|
|
47
|
+
bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" });
|
|
48
|
+
bedrock.model({ name: "us.amazon.nova-pro-v1:0", temperature: 0.2 });
|
|
49
|
+
bedrock.model({ name: "meta.llama3-1-8b-instruct-v1:0", maxTokens: 1024 });
|
|
44
50
|
```
|
|
45
51
|
|
|
46
52
|
Uses the model-agnostic **Converse / ConverseStream** API — one wire mapping covers every Bedrock family (Claude, Nova, Llama, Mistral, Cohere) instead of per-family `InvokeModel` body shapes.
|
|
47
53
|
|
|
48
54
|
## Capabilities — what's auto-set
|
|
49
55
|
|
|
50
|
-
| Flag
|
|
51
|
-
|
|
|
52
|
-
| `structuredOutput` | `true` (via Converse `outputConfig.textFormat`)
|
|
53
|
-
| `vision`
|
|
54
|
-
| `reasoning`
|
|
55
|
-
| `promptCaching`
|
|
56
|
-
| `pdf`
|
|
57
|
-
| `audio`
|
|
56
|
+
| Flag | Default |
|
|
57
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
58
|
+
| `structuredOutput` | `true` (via Converse `outputConfig.textFormat`) |
|
|
59
|
+
| `vision` | Inferred from model id substring. `true` for Claude 3/3.5/3.7/4, Nova Lite/Pro/Premier, Llama 3.2-11B/90B, Llama 4. |
|
|
60
|
+
| `reasoning` | Inferred from model id. `true` for Claude 3.7 + Claude 4 (Sonnet/Opus/Haiku) — they expose a configurable thinking budget on Converse. |
|
|
61
|
+
| `promptCaching` | Inferred from model id. `true` for Claude 3.5+/3.7/4/5 and Nova 2 Lite / Micro / Lite / Pro / Premier — the families that honor Converse `cachePoint`. |
|
|
62
|
+
| `pdf` | Inferred from model id. `true` for Claude 3+ and Nova Lite/Pro/Premier (Converse `document` blocks). |
|
|
63
|
+
| `audio` | `false` by default — Converse does not accept audio blocks for the families this adapter targets. Pass `audio: true` for a confirmed audio model. |
|
|
58
64
|
|
|
59
65
|
Explicit config always wins — every flag is overridable per model, e.g. `bedrock.model({ name, reasoning: false, promptCaching: true, pdf: false, audio: true })`.
|
|
60
66
|
|
|
@@ -76,13 +82,38 @@ A thinking budget below `1024` throws before the request. When thinking is enabl
|
|
|
76
82
|
|
|
77
83
|
## Prompt caching
|
|
78
84
|
|
|
79
|
-
For a `promptCaching`-capable model, `ModelCallOptions.cacheControl.breakpoints` (any positive value)
|
|
85
|
+
For a `promptCaching`-capable model, `ModelCallOptions.cacheControl.breakpoints` (any positive value) places a Converse `cachePoint` on every stable segment of the prefix, in the order Bedrock processes them (`tools` → `system` → `messages`, three of the four checkpoints it allows):
|
|
86
|
+
|
|
87
|
+
| Segment | Where the `cachePoint` goes | Models |
|
|
88
|
+
| -------- | --------------------------------------- | ---------------------------------------------------- |
|
|
89
|
+
| tools | after the last `toolConfig.tools` entry | Claude only — Nova accepts no cache point in `tools` |
|
|
90
|
+
| system | after the system blocks | every caching-capable model |
|
|
91
|
+
| messages | appended to the LAST message | every caching-capable model |
|
|
92
|
+
|
|
93
|
+
The lifetime is the per-call `cacheControl.ttl`, else the model's `promptCacheTtl`. `ttl: "1h"` is sent only to models that accept it — Claude Haiku 4.5, Sonnet / Opus 4.5+ and every Claude 5 family; any other model gets the 5-minute default, because AWS warns that the field "can result in a ValidationException" on 5-minute-only models.
|
|
80
94
|
|
|
81
95
|
```ts
|
|
82
|
-
|
|
96
|
+
import { BedrockSDK } from "@warlock.js/ai-bedrock";
|
|
97
|
+
|
|
98
|
+
const bedrock = new BedrockSDK({ region: "us-east-1" });
|
|
99
|
+
const model = bedrock.model({ name: "global.anthropic.claude-sonnet-4-6", promptCacheTtl: "1h" });
|
|
100
|
+
|
|
101
|
+
// tools + system + last message are cached for an hour:
|
|
102
|
+
await model.complete(
|
|
103
|
+
[
|
|
104
|
+
{ role: "system", content: "Long, stable instructions…" },
|
|
105
|
+
{ role: "user", content: "First question" },
|
|
106
|
+
],
|
|
107
|
+
{ cacheControl: { breakpoints: 1 } },
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Per call, the TTL can be overridden:
|
|
111
|
+
await model.complete([{ role: "user", content: "hi" }], {
|
|
112
|
+
cacheControl: { breakpoints: 1, ttl: "5m" },
|
|
113
|
+
});
|
|
83
114
|
```
|
|
84
115
|
|
|
85
|
-
|
|
116
|
+
Source for the placement rules and TTL support: https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html (checked 2026-10-17). No-ops gracefully when the model is not caching-capable or no breakpoint was requested. Read-side accounting works without any breakpoint — see the usage section below.
|
|
86
117
|
|
|
87
118
|
## System prompt
|
|
88
119
|
|
|
@@ -112,6 +143,17 @@ Object-root `responseSchema` + `structuredOutput`-capable → `outputConfig.text
|
|
|
112
143
|
- `contentBlockDelta.delta.text` → `{ type: "delta", content }`
|
|
113
144
|
- `toolUse`: `contentBlockStart` opens an accumulator, `contentBlockDelta.delta.toolUse.input` fragments append, `contentBlockStop` emits one consolidated `{ type: "tool-call", ... }`
|
|
114
145
|
- terminal `{ type: "done", finishReason, usage }` — usage from `metadata.usage` (a `TokenUsage`), including `cachedTokens` / `cacheWriteTokens` when reported (see the usage table below)
|
|
146
|
+
- opt-in (`options.streamChunks`, set by `agent.stream()`): `{ type: "reasoning", delta }` per `reasoningContent.text` delta, `{ type: "tool-args", callId, name, delta }` per client `toolUse.input` delta; no `usage` chunk (usage arrives once at the end)
|
|
147
|
+
|
|
148
|
+
**System tools:** `ai.providerTool({ provider: "bedrock", definition: { systemTool: { name: "nova_grounding" } } })` is appended to `toolConfig.tools` verbatim. `toolUse` blocks with `type: "server_tool_use"` are never dispatched as tool calls.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const grounding = ai.providerTool({
|
|
152
|
+
provider: "bedrock",
|
|
153
|
+
definition: { systemTool: { name: "nova_grounding" } },
|
|
154
|
+
});
|
|
155
|
+
ai.agent({ model: bedrock.model({ name: "us.amazon.nova-premier-v1:0" }), tools: [grounding] });
|
|
156
|
+
```
|
|
115
157
|
|
|
116
158
|
## Finish-reason mapping
|
|
117
159
|
|
|
@@ -122,7 +164,7 @@ Object-root `responseSchema` + `structuredOutput`-capable → `outputConfig.text
|
|
|
122
164
|
```ts
|
|
123
165
|
const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
|
|
124
166
|
const { vector } = await embedder.embed("Hello world");
|
|
125
|
-
const { vectors } = await embedder.embedMany(["a", "b"]);
|
|
167
|
+
const { vectors } = await embedder.embedMany(["a", "b"]); // N sequential calls
|
|
126
168
|
```
|
|
127
169
|
|
|
128
170
|
Targets the **Titan Text Embeddings** family via `InvokeModel`. **Titan has no batch endpoint** — `embedMany` issues one request per input sequentially and aggregates token usage. Cohere-on-Bedrock batch embeddings use an incompatible body shape and are out of scope — use the OpenAI adapter when batch throughput matters.
|
|
@@ -138,50 +180,111 @@ Raw AWS SDK exceptions are wrapped into the typed `@warlock.js/ai` `AIError` hie
|
|
|
138
180
|
- `ServiceQuotaExceededException` → `QuotaExceededError`
|
|
139
181
|
- `ValidationException` with "too long / context window" → `ContextLengthExceededError`, else `InvalidRequestError`
|
|
140
182
|
- `ModelTimeoutException` / `ETIMEDOUT` → `ProviderTimeoutError`
|
|
141
|
-
-
|
|
183
|
+
- `ServiceUnavailableException` / 503 → `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`) — the service is temporarily unable to serve the request
|
|
184
|
+
- other 5xx / `ModelError` → `ProviderError`
|
|
185
|
+
|
|
186
|
+
Every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"` — AWS publishes no rule for failed requests). `fallbackModel` fails over on `PROVIDER_OVERLOADED` by default.
|
|
142
187
|
|
|
143
188
|
## Token counting
|
|
144
189
|
|
|
145
190
|
```ts
|
|
146
|
-
await bedrock.count("some text")
|
|
191
|
+
await bedrock.count("some text"); // approximate heuristic, offline
|
|
147
192
|
```
|
|
148
193
|
|
|
149
194
|
Per-model tokenizers differ across Bedrock families.
|
|
150
195
|
|
|
151
|
-
## Pricing —
|
|
196
|
+
## Pricing — built-in Claude prices and registry
|
|
152
197
|
|
|
153
|
-
|
|
198
|
+
All rates are **USD per 1,000,000 tokens** (`ModelPricing`: `input`, `output`, optional `cachedInput`, `cacheWrite`, `cacheWrite1h`). Resolution at `model()` time: per-model `pricing` (`bedrock.model({ name, pricing })`) > SDK registry (exact id) > built-in profile price > `undefined` (no cost computed).
|
|
154
199
|
|
|
155
200
|
```ts
|
|
201
|
+
import { ai, totalCost } from "@warlock.js/ai";
|
|
202
|
+
import {
|
|
203
|
+
BEDROCK_GLOBAL_PRICING,
|
|
204
|
+
BedrockSDK,
|
|
205
|
+
bedrockPricingFor,
|
|
206
|
+
withClaudeCacheWriteRates,
|
|
207
|
+
} from "@warlock.js/ai-bedrock";
|
|
208
|
+
|
|
156
209
|
const bedrock = new BedrockSDK({
|
|
157
|
-
region: "
|
|
210
|
+
region: "eu-west-1",
|
|
158
211
|
pricing: {
|
|
159
|
-
//
|
|
160
|
-
"anthropic.claude-sonnet-4-
|
|
161
|
-
"
|
|
212
|
+
// In-Region and non-US geographic ids are not built in — price them yourself.
|
|
213
|
+
"eu.anthropic.claude-sonnet-4-6": { input: 3.3, output: 16.5, cachedInput: 0.33 },
|
|
214
|
+
"amazon.nova-pro-v1:0": { input: 0.8, output: 3.2 }, // your own rates for unlisted models
|
|
162
215
|
},
|
|
163
216
|
});
|
|
164
217
|
|
|
165
|
-
|
|
166
|
-
|
|
218
|
+
bedrock.model({ name: "global.anthropic.claude-sonnet-4-6" }).pricing; // built-in global rate
|
|
219
|
+
bedrock.model({ name: "eu.anthropic.claude-sonnet-4-6" }).pricing; // registry + Claude write rates filled (cacheWrite 4.125, cacheWrite1h 6.6)
|
|
220
|
+
bedrockPricingFor("us.anthropic.claude-haiku-4-5-20251001-v1:0"); // US geographic rate
|
|
221
|
+
withClaudeCacheWriteRates("anthropic.claude-opus-4-8", { input: 5, output: 25 }); // + cacheWrite 6.25, cacheWrite1h 10
|
|
222
|
+
Object.keys(BEDROCK_GLOBAL_PRICING); // the priced Claude model ids
|
|
223
|
+
|
|
224
|
+
const { usage } = await ai
|
|
225
|
+
.agent({ model: bedrock.model({ name: "global.anthropic.claude-sonnet-4-6" }) })
|
|
226
|
+
.execute("hi");
|
|
227
|
+
console.log(usage.cost, totalCost(usage.cost)); // per-channel USD breakdown of THIS run, and its sum
|
|
167
228
|
```
|
|
168
229
|
|
|
169
|
-
|
|
230
|
+
- **Source.** https://aws.amazon.com/bedrock/pricing/ — the page's own price feed for "US East (N. Virginia)", fetched 2026-10-17; model ids from the prompt-caching guide. `BEDROCK_GLOBAL_PRICING` holds the `global.` cross-Region profile rates, `BEDROCK_US_PRICING` the `us.` geographic rates (10% above global for these models). Both are keyed by the bare model id; `bedrockPricingFor(id)` strips the profile prefix.
|
|
231
|
+
- **Covered:** Claude Sonnet 5.5 / 5 / 4.6 / 4.5, Opus 5.5 / 5 / 4.8 / 4.7 / 4.6 / 4.5, Fable 5.1 / 5, Haiku 4.5 — with cache read, 5-minute write (1.25x input) and 1-hour write (2x input).
|
|
232
|
+
- **Deliberately unpriced:** in-Region ids with no profile prefix and other geographies (`eu.`, `apac.`, …) — their rates vary by Region; Claude Haiku 5.5 (not verified); and every non-Claude model (Nova, Llama, Titan, …). Pass `pricing` for them.
|
|
233
|
+
- **Claude write rates are filled.** Any Claude entry (your own included) without `cacheWrite` / `cacheWrite1h` gets 1.25x / 2x the input rate (`withClaudeCacheWriteRates`). Non-Claude entries are left as given; an unpriced cache write then bills at the input rate.
|
|
170
234
|
|
|
171
235
|
### Tokens & usage — cost truth
|
|
172
236
|
|
|
173
|
-
Both `complete()` and `stream()` normalize Converse's `TokenUsage` into the neutral `Usage` shape:
|
|
237
|
+
Both `complete()` and `stream()` normalize Converse's `TokenUsage` into the neutral `Usage` shape. With caching, `inputTokens` "represents only the non-cached input tokens" — total input is `inputTokens + cacheReadInputTokens + cacheWriteInputTokens` (AWS prompt-caching guide) — so the adapter marks the usage `inputIncludesCache: false` and cost bills each channel once:
|
|
238
|
+
|
|
239
|
+
| Converse `TokenUsage` field | Neutral `Usage` field | Notes |
|
|
240
|
+
| --------------------------- | -------------------------- | -------------------------------------------------------------------- |
|
|
241
|
+
| `inputTokens` | `usage.input` | **Excludes** cache reads and writes. Bills at `pricing.input`. |
|
|
242
|
+
| — | `usage.inputIncludesCache` | Always `false` on Bedrock. |
|
|
243
|
+
| `outputTokens` | `usage.output` | |
|
|
244
|
+
| `totalTokens` | `usage.total` | Falls back to `input + output` when absent. |
|
|
245
|
+
| `cacheReadInputTokens` | `usage.cachedTokens` | Only when `> 0`. Cache-hit reads — bills at `pricing.cachedInput`. |
|
|
246
|
+
| `cacheWriteInputTokens` | `usage.cacheWriteTokens` | Only when `> 0`. Cache writes — bills at `pricing.cacheWrite`. |
|
|
247
|
+
| `cacheDetails[ttl: "1h"]` | `usage.cacheWrite1hTokens` | The 1-hour share of the writes — bills at `pricing.cacheWrite1h`. |
|
|
248
|
+
| — | `usage.reasoningTokens` | **Never set** — Converse exposes no reasoning-token count. |
|
|
249
|
+
| — | `usage.cost` | Attached on `complete()` and the streaming `done` chunk when priced. |
|
|
250
|
+
|
|
251
|
+
Read-side accounting is populated whenever Bedrock reports it, independent of whether you sent a `cacheControl` breakpoint.
|
|
252
|
+
|
|
253
|
+
## Provider body options and input-token counts
|
|
254
|
+
|
|
255
|
+
Native body fields merge after neutral options. When both values are plain
|
|
256
|
+
objects, their immediate keys merge and caller-provided keys win; untouched
|
|
257
|
+
neutral fields remain. Arrays, scalars and `null` replace the field. This merge
|
|
258
|
+
is one level deep: a nested object explicitly supplied by the caller replaces
|
|
259
|
+
that nested value.
|
|
260
|
+
|
|
261
|
+
`providerOptions.bedrock.body` adds native Converse request fields after the
|
|
262
|
+
neutral options, for completion and streaming:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
const options = {
|
|
266
|
+
reasoning: { effort: "high" as const }, // preserved alongside top_k
|
|
267
|
+
providerOptions: { bedrock: { body: { additionalModelRequestFields: { top_k: 4 } } } },
|
|
268
|
+
};
|
|
269
|
+
await model.complete(messages, options);
|
|
270
|
+
```
|
|
174
271
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
| `totalTokens` | `usage.total` | Falls back to `input + output` when absent. |
|
|
180
|
-
| `cacheReadInputTokens` | `usage.cachedTokens` | Only when `> 0`. Cache-hit reads — price at `pricing.cachedInput`. |
|
|
181
|
-
| `cacheWriteInputTokens` | `usage.cacheWriteTokens` | Only when `> 0`. One-time cache write — price at `pricing.cachedOutput`. |
|
|
182
|
-
| — | `usage.reasoningTokens` | **Never set** — Converse exposes no reasoning-token count. |
|
|
272
|
+
The key stays `bedrock` for custom provider labels. Other provider keys are
|
|
273
|
+
ignored. `BedrockCallOptions` is exported. `modelId`, `messages`, `system` and
|
|
274
|
+
`toolConfig` are protected; attempting to replace them throws
|
|
275
|
+
`InvalidRequestError`. Provider fields are otherwise forwarded without validation.
|
|
183
276
|
|
|
184
|
-
|
|
277
|
+
`model.countTokens(messages, options?)` calls Bedrock `CountTokens` using the same
|
|
278
|
+
Converse messages, system blocks, tool configuration and
|
|
279
|
+
`additionalModelRequestFields` used for generation. Cancellation is forwarded.
|
|
280
|
+
Availability depends on the model and region; provider failures use the adapter's
|
|
281
|
+
normal typed errors. `sdk.count(text)` remains a separate offline estimate.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
if (model.countTokens) {
|
|
285
|
+
const inputTokens = await model.countTokens(messages, options);
|
|
286
|
+
}
|
|
287
|
+
```
|
|
185
288
|
|
|
186
289
|
## When NOT to use this skill
|
|
187
290
|
|
|
@@ -195,4 +298,15 @@ Set `cachedInput` / `cachedOutput` in `ModelPricing` to have cache reads/writes
|
|
|
195
298
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill
|
|
196
299
|
- The `embed-text` topic of the `warlock-js-ai` skill
|
|
197
300
|
|
|
301
|
+
## Adjacent conversation turns
|
|
302
|
+
|
|
303
|
+
Converse messages combine adjacent turns of the same role, retaining every
|
|
304
|
+
content block in order. This keeps parallel tool results in one user turn and
|
|
305
|
+
allows an automatic compaction summary beside an assistant tool-call turn
|
|
306
|
+
without creating consecutive assistant turns. Agent compaction frames a summary
|
|
307
|
+
as user context when it replaces the first non-system turn.
|
|
308
|
+
|
|
309
|
+
Adjacent-turn normalization preserves empty histories and separate system prompts
|
|
310
|
+
without inserting synthetic conversation turns.
|
|
311
|
+
|
|
198
312
|
|
package/llms.txt
CHANGED
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
- [setup-bedrock](@warlock.js/ai-bedrock/setup-bedrock/SKILL.md): Wire @warlock.js/ai-bedrock — new BedrockSDK({region, credentials?, provider?}) for AWS Bedrock Converse API + Titan embeddings. AWS credential chain (
|
|
9
|
+
- [setup-bedrock](@warlock.js/ai-bedrock/setup-bedrock/SKILL.md): Wire @warlock.js/ai-bedrock — new BedrockSDK({region, apiKey?, credentials?, provider?}) for AWS Bedrock Converse API + Titan embeddings. AWS credential chain or an Amazon Bedrock API key (bearer). .model({name, vision?, reasoning?, promptCaching?, pdf?, audio?}) with cost-truth capabilities inferred per family, extended thinking via options.reasoning → Converse thinking budget_tokens, prompt caching via options.cacheControl → cachePoint on tools (Claude), system and the last message, 1h TTL via promptCacheTtl, usage inputIncludesCache: false + cachedTokens/cacheWriteTokens/cacheWrite1hTokens, built-in Claude prices for global./us. profiles (BEDROCK_GLOBAL_PRICING, BEDROCK_US_PRICING, bedrockPricingFor), ServiceUnavailableException → ProviderOverloadedError. Triggers: `apiKey`, `AWS_BEARER_TOKEN_BEDROCK`, `providerOptions`, `BedrockCallOptions`, `countTokens`, `BedrockSDK`, `bedrock.model`, `bedrock.embedder`, `bedrock.count`, `BedrockRuntimeClient`, `reasoning`, `thinking`, `budget_tokens`, `cachePoint`, `cacheControl`, `ai.providerTool`, `systemTool`, `nova_grounding`, `server_tool_use`, `streamChunks`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`; "how do I use AWS Bedrock", "wire Claude/Nova/Llama on Bedrock", "Titan embeddings", "Bedrock Converse API", "Claude 3.7/4 extended thinking on Bedrock", "Bedrock prompt caching cost"; typical import `import { BedrockSDK } from "@warlock.js/ai-bedrock"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; provider choice — the `pick-ai-provider` topic of the `warlock-js-ai` skill; embeddings concepts — the `embed-text` topic of the `warlock-js-ai` skill; competing libs `@aws-sdk/client-bedrock-runtime`, `@ai-sdk/amazon-bedrock`; sibling adapters `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`.
|
package/package.json
CHANGED
|
@@ -11,16 +11,17 @@
|
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/warlockjs/
|
|
14
|
+
"url": "git+https://github.com/warlockjs/framework.git",
|
|
15
|
+
"directory": "packages/ai-bedrock"
|
|
15
16
|
},
|
|
16
17
|
"peerDependencies": {
|
|
17
|
-
"@warlock.js/ai": "5.
|
|
18
|
+
"@warlock.js/ai": "5.31.0"
|
|
18
19
|
},
|
|
19
20
|
"dependencies": {
|
|
20
21
|
"@aws-sdk/client-bedrock-runtime": "^3.1048.0",
|
|
21
|
-
"@warlock.js/logger": "5.
|
|
22
|
+
"@warlock.js/logger": "5.31.0"
|
|
22
23
|
},
|
|
23
|
-
"version": "5.
|
|
24
|
+
"version": "5.31.0",
|
|
24
25
|
"main": "./cjs/index.cjs",
|
|
25
26
|
"module": "./esm/index.mjs",
|
|
26
27
|
"types": "./esm/index.d.mts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-bedrock
|
|
3
|
-
description: 'Wire @warlock.js/ai-bedrock — new BedrockSDK({region, credentials?, provider?}) for AWS Bedrock Converse API + Titan embeddings. AWS credential chain (
|
|
3
|
+
description: 'Wire @warlock.js/ai-bedrock — new BedrockSDK({region, apiKey?, credentials?, provider?}) for AWS Bedrock Converse API + Titan embeddings. AWS credential chain or an Amazon Bedrock API key (bearer). .model({name, vision?, reasoning?, promptCaching?, pdf?, audio?}) with cost-truth capabilities inferred per family, extended thinking via options.reasoning → Converse thinking budget_tokens, prompt caching via options.cacheControl → cachePoint on tools (Claude), system and the last message, 1h TTL via promptCacheTtl, usage inputIncludesCache: false + cachedTokens/cacheWriteTokens/cacheWrite1hTokens, built-in Claude prices for global./us. profiles (BEDROCK_GLOBAL_PRICING, BEDROCK_US_PRICING, bedrockPricingFor), ServiceUnavailableException → ProviderOverloadedError. Triggers: `apiKey`, `AWS_BEARER_TOKEN_BEDROCK`, `providerOptions`, `BedrockCallOptions`, `countTokens`, `BedrockSDK`, `bedrock.model`, `bedrock.embedder`, `bedrock.count`, `BedrockRuntimeClient`, `reasoning`, `thinking`, `budget_tokens`, `cachePoint`, `cacheControl`, `ai.providerTool`, `systemTool`, `nova_grounding`, `server_tool_use`, `streamChunks`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`; "how do I use AWS Bedrock", "wire Claude/Nova/Llama on Bedrock", "Titan embeddings", "Bedrock Converse API", "Claude 3.7/4 extended thinking on Bedrock", "Bedrock prompt caching cost"; typical import `import { BedrockSDK } from "@warlock.js/ai-bedrock"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; provider choice — the `pick-ai-provider` topic of the `warlock-js-ai` skill; embeddings concepts — the `embed-text` topic of the `warlock-js-ai` skill; competing libs `@aws-sdk/client-bedrock-runtime`, `@ai-sdk/amazon-bedrock`; sibling adapters `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `@warlock.js/ai-bedrock`
|
|
@@ -21,32 +21,38 @@ const bedrock2 = new BedrockSDK({
|
|
|
21
21
|
credentials: { accessKeyId: "AKIA...", secretAccessKey: "..." },
|
|
22
22
|
provider: "bedrock-eu",
|
|
23
23
|
});
|
|
24
|
+
|
|
25
|
+
// Amazon Bedrock API key (bearer auth, no AWS credentials):
|
|
26
|
+
const bedrock3 = new BedrockSDK({
|
|
27
|
+
apiKey: process.env.BEDROCK_API_KEY!,
|
|
28
|
+
region: "us-east-1",
|
|
29
|
+
});
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
Bedrock authenticates via the **AWS credential chain
|
|
32
|
+
Bedrock authenticates via the **AWS credential chain** or an **Amazon Bedrock API key**. `apiKey` sends `Authorization: Bearer <key>` instead of a SigV4 signature (the adapter sets the AWS SDK's `token` + `authSchemePreference: ["httpBearerAuth"]`); combining it with `credentials` or `token`, or passing an empty key, throws `InvalidRequestError`. Without `apiKey`, the AWS SDK still reads a key from `AWS_BEARER_TOKEN_BEDROCK` on its own. `region` is required; `credentials` is optional (omit to use the standard provider chain). The whole config object is forwarded to `BedrockRuntimeClient`, so any AWS client option (`endpoint`, `requestHandler`, retry config) is accepted. `provider` defaults to `"bedrock"`.
|
|
27
33
|
|
|
28
34
|
## Producing a model
|
|
29
35
|
|
|
30
36
|
`name` is the Bedrock **model id or inference-profile id**:
|
|
31
37
|
|
|
32
38
|
```ts
|
|
33
|
-
bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" })
|
|
34
|
-
bedrock.model({ name: "us.amazon.nova-pro-v1:0", temperature: 0.2 })
|
|
35
|
-
bedrock.model({ name: "meta.llama3-1-8b-instruct-v1:0", maxTokens: 1024 })
|
|
39
|
+
bedrock.model({ name: "anthropic.claude-sonnet-4-5-20250929-v1:0" });
|
|
40
|
+
bedrock.model({ name: "us.amazon.nova-pro-v1:0", temperature: 0.2 });
|
|
41
|
+
bedrock.model({ name: "meta.llama3-1-8b-instruct-v1:0", maxTokens: 1024 });
|
|
36
42
|
```
|
|
37
43
|
|
|
38
44
|
Uses the model-agnostic **Converse / ConverseStream** API — one wire mapping covers every Bedrock family (Claude, Nova, Llama, Mistral, Cohere) instead of per-family `InvokeModel` body shapes.
|
|
39
45
|
|
|
40
46
|
## Capabilities — what's auto-set
|
|
41
47
|
|
|
42
|
-
| Flag
|
|
43
|
-
|
|
|
44
|
-
| `structuredOutput` | `true` (via Converse `outputConfig.textFormat`)
|
|
45
|
-
| `vision`
|
|
46
|
-
| `reasoning`
|
|
47
|
-
| `promptCaching`
|
|
48
|
-
| `pdf`
|
|
49
|
-
| `audio`
|
|
48
|
+
| Flag | Default |
|
|
49
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
50
|
+
| `structuredOutput` | `true` (via Converse `outputConfig.textFormat`) |
|
|
51
|
+
| `vision` | Inferred from model id substring. `true` for Claude 3/3.5/3.7/4, Nova Lite/Pro/Premier, Llama 3.2-11B/90B, Llama 4. |
|
|
52
|
+
| `reasoning` | Inferred from model id. `true` for Claude 3.7 + Claude 4 (Sonnet/Opus/Haiku) — they expose a configurable thinking budget on Converse. |
|
|
53
|
+
| `promptCaching` | Inferred from model id. `true` for Claude 3.5+/3.7/4/5 and Nova 2 Lite / Micro / Lite / Pro / Premier — the families that honor Converse `cachePoint`. |
|
|
54
|
+
| `pdf` | Inferred from model id. `true` for Claude 3+ and Nova Lite/Pro/Premier (Converse `document` blocks). |
|
|
55
|
+
| `audio` | `false` by default — Converse does not accept audio blocks for the families this adapter targets. Pass `audio: true` for a confirmed audio model. |
|
|
50
56
|
|
|
51
57
|
Explicit config always wins — every flag is overridable per model, e.g. `bedrock.model({ name, reasoning: false, promptCaching: true, pdf: false, audio: true })`.
|
|
52
58
|
|
|
@@ -68,13 +74,38 @@ A thinking budget below `1024` throws before the request. When thinking is enabl
|
|
|
68
74
|
|
|
69
75
|
## Prompt caching
|
|
70
76
|
|
|
71
|
-
For a `promptCaching`-capable model, `ModelCallOptions.cacheControl.breakpoints` (any positive value)
|
|
77
|
+
For a `promptCaching`-capable model, `ModelCallOptions.cacheControl.breakpoints` (any positive value) places a Converse `cachePoint` on every stable segment of the prefix, in the order Bedrock processes them (`tools` → `system` → `messages`, three of the four checkpoints it allows):
|
|
78
|
+
|
|
79
|
+
| Segment | Where the `cachePoint` goes | Models |
|
|
80
|
+
| -------- | --------------------------------------- | ---------------------------------------------------- |
|
|
81
|
+
| tools | after the last `toolConfig.tools` entry | Claude only — Nova accepts no cache point in `tools` |
|
|
82
|
+
| system | after the system blocks | every caching-capable model |
|
|
83
|
+
| messages | appended to the LAST message | every caching-capable model |
|
|
84
|
+
|
|
85
|
+
The lifetime is the per-call `cacheControl.ttl`, else the model's `promptCacheTtl`. `ttl: "1h"` is sent only to models that accept it — Claude Haiku 4.5, Sonnet / Opus 4.5+ and every Claude 5 family; any other model gets the 5-minute default, because AWS warns that the field "can result in a ValidationException" on 5-minute-only models.
|
|
72
86
|
|
|
73
87
|
```ts
|
|
74
|
-
|
|
88
|
+
import { BedrockSDK } from "@warlock.js/ai-bedrock";
|
|
89
|
+
|
|
90
|
+
const bedrock = new BedrockSDK({ region: "us-east-1" });
|
|
91
|
+
const model = bedrock.model({ name: "global.anthropic.claude-sonnet-4-6", promptCacheTtl: "1h" });
|
|
92
|
+
|
|
93
|
+
// tools + system + last message are cached for an hour:
|
|
94
|
+
await model.complete(
|
|
95
|
+
[
|
|
96
|
+
{ role: "system", content: "Long, stable instructions…" },
|
|
97
|
+
{ role: "user", content: "First question" },
|
|
98
|
+
],
|
|
99
|
+
{ cacheControl: { breakpoints: 1 } },
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Per call, the TTL can be overridden:
|
|
103
|
+
await model.complete([{ role: "user", content: "hi" }], {
|
|
104
|
+
cacheControl: { breakpoints: 1, ttl: "5m" },
|
|
105
|
+
});
|
|
75
106
|
```
|
|
76
107
|
|
|
77
|
-
|
|
108
|
+
Source for the placement rules and TTL support: https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html (checked 2026-10-17). No-ops gracefully when the model is not caching-capable or no breakpoint was requested. Read-side accounting works without any breakpoint — see the usage section below.
|
|
78
109
|
|
|
79
110
|
## System prompt
|
|
80
111
|
|
|
@@ -104,6 +135,17 @@ Object-root `responseSchema` + `structuredOutput`-capable → `outputConfig.text
|
|
|
104
135
|
- `contentBlockDelta.delta.text` → `{ type: "delta", content }`
|
|
105
136
|
- `toolUse`: `contentBlockStart` opens an accumulator, `contentBlockDelta.delta.toolUse.input` fragments append, `contentBlockStop` emits one consolidated `{ type: "tool-call", ... }`
|
|
106
137
|
- terminal `{ type: "done", finishReason, usage }` — usage from `metadata.usage` (a `TokenUsage`), including `cachedTokens` / `cacheWriteTokens` when reported (see the usage table below)
|
|
138
|
+
- opt-in (`options.streamChunks`, set by `agent.stream()`): `{ type: "reasoning", delta }` per `reasoningContent.text` delta, `{ type: "tool-args", callId, name, delta }` per client `toolUse.input` delta; no `usage` chunk (usage arrives once at the end)
|
|
139
|
+
|
|
140
|
+
**System tools:** `ai.providerTool({ provider: "bedrock", definition: { systemTool: { name: "nova_grounding" } } })` is appended to `toolConfig.tools` verbatim. `toolUse` blocks with `type: "server_tool_use"` are never dispatched as tool calls.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const grounding = ai.providerTool({
|
|
144
|
+
provider: "bedrock",
|
|
145
|
+
definition: { systemTool: { name: "nova_grounding" } },
|
|
146
|
+
});
|
|
147
|
+
ai.agent({ model: bedrock.model({ name: "us.amazon.nova-premier-v1:0" }), tools: [grounding] });
|
|
148
|
+
```
|
|
107
149
|
|
|
108
150
|
## Finish-reason mapping
|
|
109
151
|
|
|
@@ -114,7 +156,7 @@ Object-root `responseSchema` + `structuredOutput`-capable → `outputConfig.text
|
|
|
114
156
|
```ts
|
|
115
157
|
const embedder = bedrock.embedder({ name: "amazon.titan-embed-text-v2:0" });
|
|
116
158
|
const { vector } = await embedder.embed("Hello world");
|
|
117
|
-
const { vectors } = await embedder.embedMany(["a", "b"]);
|
|
159
|
+
const { vectors } = await embedder.embedMany(["a", "b"]); // N sequential calls
|
|
118
160
|
```
|
|
119
161
|
|
|
120
162
|
Targets the **Titan Text Embeddings** family via `InvokeModel`. **Titan has no batch endpoint** — `embedMany` issues one request per input sequentially and aggregates token usage. Cohere-on-Bedrock batch embeddings use an incompatible body shape and are out of scope — use the OpenAI adapter when batch throughput matters.
|
|
@@ -130,50 +172,111 @@ Raw AWS SDK exceptions are wrapped into the typed `@warlock.js/ai` `AIError` hie
|
|
|
130
172
|
- `ServiceQuotaExceededException` → `QuotaExceededError`
|
|
131
173
|
- `ValidationException` with "too long / context window" → `ContextLengthExceededError`, else `InvalidRequestError`
|
|
132
174
|
- `ModelTimeoutException` / `ETIMEDOUT` → `ProviderTimeoutError`
|
|
133
|
-
-
|
|
175
|
+
- `ServiceUnavailableException` / 503 → `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`) — the service is temporarily unable to serve the request
|
|
176
|
+
- other 5xx / `ModelError` → `ProviderError`
|
|
177
|
+
|
|
178
|
+
Every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"` — AWS publishes no rule for failed requests). `fallbackModel` fails over on `PROVIDER_OVERLOADED` by default.
|
|
134
179
|
|
|
135
180
|
## Token counting
|
|
136
181
|
|
|
137
182
|
```ts
|
|
138
|
-
await bedrock.count("some text")
|
|
183
|
+
await bedrock.count("some text"); // approximate heuristic, offline
|
|
139
184
|
```
|
|
140
185
|
|
|
141
186
|
Per-model tokenizers differ across Bedrock families.
|
|
142
187
|
|
|
143
|
-
## Pricing —
|
|
188
|
+
## Pricing — built-in Claude prices and registry
|
|
144
189
|
|
|
145
|
-
|
|
190
|
+
All rates are **USD per 1,000,000 tokens** (`ModelPricing`: `input`, `output`, optional `cachedInput`, `cacheWrite`, `cacheWrite1h`). Resolution at `model()` time: per-model `pricing` (`bedrock.model({ name, pricing })`) > SDK registry (exact id) > built-in profile price > `undefined` (no cost computed).
|
|
146
191
|
|
|
147
192
|
```ts
|
|
193
|
+
import { ai, totalCost } from "@warlock.js/ai";
|
|
194
|
+
import {
|
|
195
|
+
BEDROCK_GLOBAL_PRICING,
|
|
196
|
+
BedrockSDK,
|
|
197
|
+
bedrockPricingFor,
|
|
198
|
+
withClaudeCacheWriteRates,
|
|
199
|
+
} from "@warlock.js/ai-bedrock";
|
|
200
|
+
|
|
148
201
|
const bedrock = new BedrockSDK({
|
|
149
|
-
region: "
|
|
202
|
+
region: "eu-west-1",
|
|
150
203
|
pricing: {
|
|
151
|
-
//
|
|
152
|
-
"anthropic.claude-sonnet-4-
|
|
153
|
-
"
|
|
204
|
+
// In-Region and non-US geographic ids are not built in — price them yourself.
|
|
205
|
+
"eu.anthropic.claude-sonnet-4-6": { input: 3.3, output: 16.5, cachedInput: 0.33 },
|
|
206
|
+
"amazon.nova-pro-v1:0": { input: 0.8, output: 3.2 }, // your own rates for unlisted models
|
|
154
207
|
},
|
|
155
208
|
});
|
|
156
209
|
|
|
157
|
-
|
|
158
|
-
|
|
210
|
+
bedrock.model({ name: "global.anthropic.claude-sonnet-4-6" }).pricing; // built-in global rate
|
|
211
|
+
bedrock.model({ name: "eu.anthropic.claude-sonnet-4-6" }).pricing; // registry + Claude write rates filled (cacheWrite 4.125, cacheWrite1h 6.6)
|
|
212
|
+
bedrockPricingFor("us.anthropic.claude-haiku-4-5-20251001-v1:0"); // US geographic rate
|
|
213
|
+
withClaudeCacheWriteRates("anthropic.claude-opus-4-8", { input: 5, output: 25 }); // + cacheWrite 6.25, cacheWrite1h 10
|
|
214
|
+
Object.keys(BEDROCK_GLOBAL_PRICING); // the priced Claude model ids
|
|
215
|
+
|
|
216
|
+
const { usage } = await ai
|
|
217
|
+
.agent({ model: bedrock.model({ name: "global.anthropic.claude-sonnet-4-6" }) })
|
|
218
|
+
.execute("hi");
|
|
219
|
+
console.log(usage.cost, totalCost(usage.cost)); // per-channel USD breakdown of THIS run, and its sum
|
|
159
220
|
```
|
|
160
221
|
|
|
161
|
-
|
|
222
|
+
- **Source.** https://aws.amazon.com/bedrock/pricing/ — the page's own price feed for "US East (N. Virginia)", fetched 2026-10-17; model ids from the prompt-caching guide. `BEDROCK_GLOBAL_PRICING` holds the `global.` cross-Region profile rates, `BEDROCK_US_PRICING` the `us.` geographic rates (10% above global for these models). Both are keyed by the bare model id; `bedrockPricingFor(id)` strips the profile prefix.
|
|
223
|
+
- **Covered:** Claude Sonnet 5.5 / 5 / 4.6 / 4.5, Opus 5.5 / 5 / 4.8 / 4.7 / 4.6 / 4.5, Fable 5.1 / 5, Haiku 4.5 — with cache read, 5-minute write (1.25x input) and 1-hour write (2x input).
|
|
224
|
+
- **Deliberately unpriced:** in-Region ids with no profile prefix and other geographies (`eu.`, `apac.`, …) — their rates vary by Region; Claude Haiku 5.5 (not verified); and every non-Claude model (Nova, Llama, Titan, …). Pass `pricing` for them.
|
|
225
|
+
- **Claude write rates are filled.** Any Claude entry (your own included) without `cacheWrite` / `cacheWrite1h` gets 1.25x / 2x the input rate (`withClaudeCacheWriteRates`). Non-Claude entries are left as given; an unpriced cache write then bills at the input rate.
|
|
162
226
|
|
|
163
227
|
### Tokens & usage — cost truth
|
|
164
228
|
|
|
165
|
-
Both `complete()` and `stream()` normalize Converse's `TokenUsage` into the neutral `Usage` shape:
|
|
229
|
+
Both `complete()` and `stream()` normalize Converse's `TokenUsage` into the neutral `Usage` shape. With caching, `inputTokens` "represents only the non-cached input tokens" — total input is `inputTokens + cacheReadInputTokens + cacheWriteInputTokens` (AWS prompt-caching guide) — so the adapter marks the usage `inputIncludesCache: false` and cost bills each channel once:
|
|
230
|
+
|
|
231
|
+
| Converse `TokenUsage` field | Neutral `Usage` field | Notes |
|
|
232
|
+
| --------------------------- | -------------------------- | -------------------------------------------------------------------- |
|
|
233
|
+
| `inputTokens` | `usage.input` | **Excludes** cache reads and writes. Bills at `pricing.input`. |
|
|
234
|
+
| — | `usage.inputIncludesCache` | Always `false` on Bedrock. |
|
|
235
|
+
| `outputTokens` | `usage.output` | |
|
|
236
|
+
| `totalTokens` | `usage.total` | Falls back to `input + output` when absent. |
|
|
237
|
+
| `cacheReadInputTokens` | `usage.cachedTokens` | Only when `> 0`. Cache-hit reads — bills at `pricing.cachedInput`. |
|
|
238
|
+
| `cacheWriteInputTokens` | `usage.cacheWriteTokens` | Only when `> 0`. Cache writes — bills at `pricing.cacheWrite`. |
|
|
239
|
+
| `cacheDetails[ttl: "1h"]` | `usage.cacheWrite1hTokens` | The 1-hour share of the writes — bills at `pricing.cacheWrite1h`. |
|
|
240
|
+
| — | `usage.reasoningTokens` | **Never set** — Converse exposes no reasoning-token count. |
|
|
241
|
+
| — | `usage.cost` | Attached on `complete()` and the streaming `done` chunk when priced. |
|
|
242
|
+
|
|
243
|
+
Read-side accounting is populated whenever Bedrock reports it, independent of whether you sent a `cacheControl` breakpoint.
|
|
244
|
+
|
|
245
|
+
## Provider body options and input-token counts
|
|
246
|
+
|
|
247
|
+
Native body fields merge after neutral options. When both values are plain
|
|
248
|
+
objects, their immediate keys merge and caller-provided keys win; untouched
|
|
249
|
+
neutral fields remain. Arrays, scalars and `null` replace the field. This merge
|
|
250
|
+
is one level deep: a nested object explicitly supplied by the caller replaces
|
|
251
|
+
that nested value.
|
|
252
|
+
|
|
253
|
+
`providerOptions.bedrock.body` adds native Converse request fields after the
|
|
254
|
+
neutral options, for completion and streaming:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
const options = {
|
|
258
|
+
reasoning: { effort: "high" as const }, // preserved alongside top_k
|
|
259
|
+
providerOptions: { bedrock: { body: { additionalModelRequestFields: { top_k: 4 } } } },
|
|
260
|
+
};
|
|
261
|
+
await model.complete(messages, options);
|
|
262
|
+
```
|
|
166
263
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
| `totalTokens` | `usage.total` | Falls back to `input + output` when absent. |
|
|
172
|
-
| `cacheReadInputTokens` | `usage.cachedTokens` | Only when `> 0`. Cache-hit reads — price at `pricing.cachedInput`. |
|
|
173
|
-
| `cacheWriteInputTokens` | `usage.cacheWriteTokens` | Only when `> 0`. One-time cache write — price at `pricing.cachedOutput`. |
|
|
174
|
-
| — | `usage.reasoningTokens` | **Never set** — Converse exposes no reasoning-token count. |
|
|
264
|
+
The key stays `bedrock` for custom provider labels. Other provider keys are
|
|
265
|
+
ignored. `BedrockCallOptions` is exported. `modelId`, `messages`, `system` and
|
|
266
|
+
`toolConfig` are protected; attempting to replace them throws
|
|
267
|
+
`InvalidRequestError`. Provider fields are otherwise forwarded without validation.
|
|
175
268
|
|
|
176
|
-
|
|
269
|
+
`model.countTokens(messages, options?)` calls Bedrock `CountTokens` using the same
|
|
270
|
+
Converse messages, system blocks, tool configuration and
|
|
271
|
+
`additionalModelRequestFields` used for generation. Cancellation is forwarded.
|
|
272
|
+
Availability depends on the model and region; provider failures use the adapter's
|
|
273
|
+
normal typed errors. `sdk.count(text)` remains a separate offline estimate.
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
if (model.countTokens) {
|
|
277
|
+
const inputTokens = await model.countTokens(messages, options);
|
|
278
|
+
}
|
|
279
|
+
```
|
|
177
280
|
|
|
178
281
|
## When NOT to use this skill
|
|
179
282
|
|
|
@@ -186,3 +289,14 @@ Set `cachedInput` / `cachedOutput` in `ModelPricing` to have cache reads/writes
|
|
|
186
289
|
- The `run-ai-agent` topic of the `warlock-js-ai` skill
|
|
187
290
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill
|
|
188
291
|
- The `embed-text` topic of the `warlock-js-ai` skill
|
|
292
|
+
|
|
293
|
+
## Adjacent conversation turns
|
|
294
|
+
|
|
295
|
+
Converse messages combine adjacent turns of the same role, retaining every
|
|
296
|
+
content block in order. This keeps parallel tool results in one user turn and
|
|
297
|
+
allows an automatic compaction summary beside an assistant tool-call turn
|
|
298
|
+
without creating consecutive assistant turns. Agent compaction frames a summary
|
|
299
|
+
as user context when it replaces the first non-system turn.
|
|
300
|
+
|
|
301
|
+
Adjacent-turn normalization preserves empty histories and separate system prompts
|
|
302
|
+
without inserting synthetic conversation turns.
|