@warlock.js/ai-anthropic 5.30.0 → 5.32.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 +58 -6
- package/cjs/index.cjs +847 -138
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +117 -8
- package/esm/config.type.d.mts.map +1 -1
- package/esm/index.d.mts +9 -3
- package/esm/index.mjs +7 -1
- package/esm/known-output-limits.mjs +46 -0
- package/esm/known-output-limits.mjs.map +1 -0
- package/esm/known-pricing.d.mts +63 -0
- package/esm/known-pricing.d.mts.map +1 -0
- package/esm/known-pricing.mjs +172 -0
- package/esm/known-pricing.mjs.map +1 -0
- package/esm/model.d.mts +90 -20
- package/esm/model.d.mts.map +1 -1
- package/esm/model.mjs +389 -88
- package/esm/model.mjs.map +1 -1
- package/esm/request.type.d.mts +23 -0
- package/esm/request.type.d.mts.map +1 -0
- package/esm/sdk.d.mts +1 -3
- package/esm/sdk.d.mts.map +1 -1
- package/esm/thinking-mode.d.mts +14 -2
- package/esm/thinking-mode.d.mts.map +1 -1
- package/esm/thinking-mode.mjs +102 -2
- package/esm/thinking-mode.mjs.map +1 -1
- package/esm/utils/cache-usage.mjs +62 -0
- package/esm/utils/cache-usage.mjs.map +1 -0
- package/esm/utils/index.d.mts +6 -0
- package/esm/utils/index.mjs +1 -1
- package/esm/utils/map-stop-reason.d.mts +1 -0
- package/esm/utils/provider-blocks.d.mts +37 -0
- package/esm/utils/provider-blocks.d.mts.map +1 -0
- package/esm/utils/provider-blocks.mjs +3 -3
- package/esm/utils/provider-blocks.mjs.map +1 -1
- package/esm/utils/server-tool-usage.mjs +17 -0
- package/esm/utils/server-tool-usage.mjs.map +1 -0
- package/esm/utils/to-anthropic-messages.d.mts +69 -0
- package/esm/utils/to-anthropic-messages.d.mts.map +1 -0
- package/esm/utils/to-anthropic-messages.mjs +12 -4
- package/esm/utils/to-anthropic-messages.mjs.map +1 -1
- package/esm/utils/to-anthropic-tools.d.mts +17 -0
- package/esm/utils/to-anthropic-tools.d.mts.map +1 -0
- package/esm/utils/wrap-anthropic-error.d.mts +1 -0
- package/esm/utils/wrap-anthropic-error.mjs +6 -1
- package/esm/utils/wrap-anthropic-error.mjs.map +1 -1
- package/llms-full.txt +248 -32
- package/llms.txt +1 -1
- package/package.json +3 -3
- package/skills/README.md +1 -1
- package/skills/setup-anthropic/SKILL.md +248 -32
package/llms-full.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
name: setup-anthropic
|
|
11
|
-
description: 'Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, thinkingMode?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default
|
|
11
|
+
description: 'Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, thinkingMode?, promptCaching?, maxTokens?, maxOutputTokens?}). System-prompt hoisting, max_tokens required (default: model max output when streaming, 16384 non-streaming; maxOutputTokens for gateway ids), extended thinking via options.reasoning → adaptive thinking + output_config.effort (current/unknown models) or budget_tokens (Haiku 4.5, 4.6 and older; override with thinkingMode), prompt caching via promptCaching + options.cacheControl (per-call ttl), provider blocks (thinking/compaction) replayed verbatim via ModelResponse.blocks / Message.blocks, providerOptions.anthropic (betas, body fields such as context_management / fallbacks, thinkingDisplay), model.countTokens(), distinct finish reasons (pause_turn, refusal, context_exceeded), built-in Claude list prices (ANTHROPIC_MODEL_PRICING, anthropicPricingFor, withAnthropicCacheWriteRates), cost-truth usage (inputIncludesCache: false, cachedTokens/cacheWriteTokens/cacheWrite1hTokens, usage.cost on complete()), ProviderOverloadedError for 529, no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `maxOutputTokens`, `max_tokens`, `reasoning`, `thinking`, `budget_tokens`, `thinkingMode`, `adaptive`, `cacheControl`, `providerOptions`, `blocks`, `countTokens`, `pause_turn`, `refusal`, `context_management`, `contextManagement`, `serverCompaction`, `clear_tool_uses`, `clear_thinking`, `thinkingBlockBinding`, `block_binding`, `preservedThinking`, `ai.providerTool`, `web_search_20250305`, `bash_20250124`, `text_editor_20250728`, `streamChunks`, `thinking_delta`, `compaction`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `cacheWrite1hTokens`, `inputIncludesCache`, `ANTHROPIC_MODEL_PRICING`, `ProviderOverloadedError`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-7`; "wire claude into warlock agent", "configure anthropic provider", "use claude sonnet", "anthropic gateway baseURL", "claude extended thinking", "anthropic prompt caching cost"; typical import `import { AnthropicSDK } from "@warlock.js/ai-anthropic"`. Skip: embeddings — the `setup-openai` topic of the `warlock-js-ai-openai` skill; sibling adapters `@warlock.js/ai-openai`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `@anthropic-ai/sdk`; Vercel `@ai-sdk/anthropic`.'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# `@warlock.js/ai-anthropic`
|
|
@@ -55,41 +55,95 @@ Explicit config always wins (`structuredOutput`, `vision`, `reasoning`, `thinkin
|
|
|
55
55
|
|
|
56
56
|
## Pricing & cost
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Every model is priced out of the box from the built-in Claude list prices; supply your own rates to override them. Pricing reaches `Usage.cost` on every agent report **and** on the `usage` of a direct `model.complete()` / the streaming `done` chunk, so side calls outside an agent are costed too. Unknown ids stay unpriced (`cost` is `undefined` — honest absence, never a false zero).
|
|
59
|
+
|
|
60
|
+
Resolution at `model()` time: per-model `pricing` > SDK registry entry for that name > built-in `ANTHROPIC_MODEL_PRICING` (alias or dated snapshot id) > `undefined`.
|
|
59
61
|
|
|
60
62
|
```ts
|
|
61
|
-
|
|
63
|
+
import {
|
|
64
|
+
ANTHROPIC_MODEL_PRICING,
|
|
65
|
+
AnthropicSDK,
|
|
66
|
+
anthropicPricingFor,
|
|
67
|
+
withAnthropicCacheWriteRates,
|
|
68
|
+
} from "@warlock.js/ai-anthropic";
|
|
69
|
+
|
|
62
70
|
const anthropic = new AnthropicSDK({
|
|
63
|
-
apiKey,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"claude-sonnet-4-6": { input: 3, output: 15, cachedInput: 0.3 },
|
|
67
|
-
},
|
|
71
|
+
apiKey: process.env.ANTHROPIC_API_KEY ?? "",
|
|
72
|
+
// SDK-level registry — wins over the built-in table, keyed by model name.
|
|
73
|
+
pricing: { "claude-sonnet-4-6": { input: 3, output: 15, cachedInput: 0.3 } },
|
|
68
74
|
});
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
anthropic.model({ name: "claude-sonnet-4-6"
|
|
76
|
+
anthropic.model({ name: "claude-opus-5-5" }).pricing; // built-in: { input: 4, output: 20, cachedInput: 0.2, cacheWrite: 5, cacheWrite1h: 8 }
|
|
77
|
+
anthropic.model({ name: "claude-sonnet-4-6" }).pricing; // registry entry + write rates filled: cacheWrite 3.75, cacheWrite1h 6
|
|
78
|
+
anthropic.model({ name: "claude-haiku-4-5", pricing: { input: 1, output: 5 } }); // per-model override
|
|
79
|
+
|
|
80
|
+
anthropicPricingFor("claude-haiku-4-5-20251001"); // dated snapshot → the alias entry
|
|
81
|
+
withAnthropicCacheWriteRates({ input: 2, output: 10 }); // { input: 2, output: 10, cacheWrite: 2.5, cacheWrite1h: 4 }
|
|
82
|
+
Object.keys(ANTHROPIC_MODEL_PRICING); // the priced ids
|
|
72
83
|
```
|
|
73
84
|
|
|
74
|
-
|
|
85
|
+
- **Source.** `ANTHROPIC_MODEL_PRICING` holds the "Model pricing" table of https://platform.claude.com/docs/en/about-claude/pricing (fetched 2026-10-17): input, output, cache read (`cachedInput`), 5-minute write (`cacheWrite`) and 1-hour write (`cacheWrite1h`), USD per 1M tokens, standard global routing.
|
|
86
|
+
- **Write rates are filled for you.** Anthropic charges 1.25x input for a 5-minute cache write and 2x for a 1-hour write on every Claude model, so any entry without `cacheWrite` / `cacheWrite1h` (your own `{ input, output }` included) gets them from those multipliers (`withAnthropicCacheWriteRates`, exported with `ANTHROPIC_CACHE_WRITE_MULTIPLIER` / `ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER`). The read rate differs per model (0.1x, 0.05x on Opus 5.5 / Sonnet 5.5, 0.025x on Fable 5.1), so it is never derived — set `cachedInput` yourself when you supply pricing, or cache reads bill at the full input rate.
|
|
87
|
+
- **Deliberately unpriced** (pass `pricing` yourself): Claude Haiku 5.5 (priced by prompt length — higher rates above 100,000 prompt tokens, which a flat rate cannot express), US-only inference (`inference_geo: "us"`, 1.1x), fast mode, the Batch API, limited-availability and retired models, and Claude on Bedrock / Vertex (partner-priced — see `@warlock.js/ai-bedrock`).
|
|
75
88
|
|
|
76
89
|
## Tokens & usage accounting
|
|
77
90
|
|
|
78
|
-
Every `ModelResponse.usage` (and the streaming terminal `done`) is normalized to the neutral `Usage` shape. Anthropic
|
|
91
|
+
Every `ModelResponse.usage` (and the streaming terminal `done`) is normalized to the neutral `Usage` shape. Anthropic's `input_tokens` is the **uncached remainder only** — cache reads and writes come on top of it — so the adapter marks the usage `inputIncludesCache: false` and `computeCost` bills each channel exactly once. `total` is computed (`input + output`); the full prompt size is `input + cachedTokens + cacheWriteTokens`.
|
|
92
|
+
|
|
93
|
+
| Neutral field | Anthropic source | Meaning / billing |
|
|
94
|
+
| -------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
95
|
+
| `usage.input` | `input_tokens` | Uncached input. Bills at `input`. |
|
|
96
|
+
| `usage.inputIncludesCache` | — (always `false`) | Tells `computeCost` not to subtract cache tokens from `input`. |
|
|
97
|
+
| `usage.cachedTokens` | `cache_read_input_tokens` | Tokens read from the prompt cache. Bills at `cachedInput` (falls back to `input` when unset). |
|
|
98
|
+
| `usage.cacheWriteTokens` | `cache_creation_input_tokens` | Tokens **written** to the cache. Bills at `cacheWrite` (5-minute, 1.25x input). |
|
|
99
|
+
| `usage.cacheWrite1hTokens` | `cache_creation.ephemeral_1h_input_tokens` | The 1-hour share of the writes. Bills at `cacheWrite1h` (2x input). Without the breakdown, all writes count as 1-hour when every marker asked for `"1h"`. |
|
|
100
|
+
| `usage.reasoningTokens` | `output_tokens_details.thinking_tokens` | The thinking subset of `output_tokens`, informational; billed inside `output`. |
|
|
101
|
+
| `usage.cost` | computed | Per-channel USD (`input`, `output`, `cachedInput`, `cacheWrite`) when the model is priced. Sum with `totalCost(usage.cost)` from `@warlock.js/ai`. |
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { totalCost } from "@warlock.js/ai";
|
|
105
|
+
import { AnthropicSDK } from "@warlock.js/ai-anthropic";
|
|
106
|
+
|
|
107
|
+
const model = new AnthropicSDK({ apiKey: process.env.ANTHROPIC_API_KEY ?? "" }).model({
|
|
108
|
+
name: "claude-sonnet-4-6",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const { usage } = await model.complete([{ role: "user", content: "Summarise this thread." }]);
|
|
79
112
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
113
|
+
// 100 uncached + 50,000 read + 20,000 written + 500 output is billed as
|
|
114
|
+
// 100×3 + 50,000×0.3 + 20,000×3.75 + 500×15 (USD per 1M tokens).
|
|
115
|
+
console.log(
|
|
116
|
+
usage.inputIncludesCache,
|
|
117
|
+
usage.cachedTokens,
|
|
118
|
+
usage.cacheWriteTokens,
|
|
119
|
+
totalCost(usage.cost),
|
|
120
|
+
);
|
|
121
|
+
```
|
|
85
122
|
|
|
86
|
-
|
|
123
|
+
With server-side compaction (`serverCompaction`), the `compaction` entries of `usage.iterations` are added to `input` / `output` / the cache counts, since the top-level counts leave the compaction step out.
|
|
124
|
+
|
|
125
|
+
In streaming, the cache counters are seeded from `message_start` (including the 1-hour breakdown) and then **overwritten by the cumulative counts on `message_delta`** when present and non-zero, so the terminal `done` carries the final tally and its `cost`.
|
|
87
126
|
|
|
88
127
|
## `max_tokens` is required
|
|
89
128
|
|
|
90
|
-
Unlike OpenAI, Anthropic **requires** `max_tokens` on every request. Resolution: per-call `options.maxTokens`
|
|
129
|
+
Unlike OpenAI, Anthropic **requires** `max_tokens` on every request. Resolution: per-call `options.maxTokens` (or the agent's per-run / configured `modelOptions.maxTokens`) > `config.maxTokens` > a default sized for agent work:
|
|
130
|
+
|
|
131
|
+
| Request | Default `max_tokens` |
|
|
132
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
133
|
+
| Streaming (`stream()`) | the model's documented max output: 128K (Claude 5 family, Opus 4.6–4.8, Sonnet 4.6), 64K (Opus / Sonnet / Haiku 4.5) |
|
|
134
|
+
| Non-streaming (`complete()`) | `16384`, capped by the model's max output |
|
|
135
|
+
| Unknown id | `16384`; set `maxOutputTokens` on the model for gateway / proxy ids |
|
|
136
|
+
|
|
137
|
+
The non-streaming default stays at 16384 because `@anthropic-ai/sdk` refuses a non-streaming request whose `max_tokens` implies more than ten minutes (above ~21K tokens) unless the client sets a `timeout`. Limits come from Anthropic's model pages (checked 2026-10-17).
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
anthropic.model({ name: "claude-haiku-4-5" }); // stream 64000, complete 16384
|
|
141
|
+
anthropic.model({ name: "my-gateway/opus", maxOutputTokens: 128_000 });
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
With extended thinking enabled and no explicit cap, the default keeps room for the thinking budget plus 4096 answer tokens (never above the model's max output). In budget mode an explicit `maxTokens` must be greater than `budget_tokens` or the call throws before it reaches Anthropic.
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
A response that still hits the cap (`finishReason: "length"`) ends an agent run as incomplete (`AgentIncompleteError`) unless the agent sets `continueOnOutputLimit`.
|
|
93
147
|
|
|
94
148
|
**Tiny caps + adaptive thinking:** thinking tokens count inside `max_tokens`, so a very small cap can be spent entirely on thinking. Live check: Sonnet 5.5 with `maxTokens: 60` returned `finishReason: "length"` and empty content. For tiny outputs give thinking room (raise `maxTokens`) or turn reasoning off (`reasoning: false` on the model, or no `options.reasoning`).
|
|
95
149
|
|
|
@@ -121,7 +175,7 @@ Adaptive models reject `budget_tokens` with a 400, so the shape matters.
|
|
|
121
175
|
|
|
122
176
|
- **Adaptive:** `reasoning.effort` (`"low" | "medium" | "high"`) → `output_config.effort` of the same name. With only `reasoning.maxTokens` set, effort is `"medium"`; `maxTokens` then only sizes the reserved `max_tokens` room, it is not sent as a budget.
|
|
123
177
|
- **Budget:** `reasoning.maxTokens` → `budget_tokens` verbatim; `reasoning.effort` → a tiered budget (`1024` / `4096` / `12000`) when no `maxTokens` is given. Any resolved budget is floored at Anthropic's `1024` minimum.
|
|
124
|
-
- `reasoning` with neither `effort` nor `maxTokens
|
|
178
|
+
- `reasoning` with neither `effort` nor `maxTokens` emits nothing. `effort: "none"` emits nothing either, except on the Claude 5 models listed below (Sonnet 5.5, Sonnet 5, Haiku 5.5, Opus 5), which each get their own form.
|
|
125
179
|
|
|
126
180
|
### `thinkingMode` override
|
|
127
181
|
|
|
@@ -145,21 +199,40 @@ anthropic.model({ name: "claude-sonnet-4-6", thinkingMode: "adaptive" }); // opt
|
|
|
145
199
|
`temperature` is **not sent** to models after Opus 4.6 (adaptive mode) — they reject any non-default value with a 400. It is also dropped on any request that enables thinking, since Anthropic 400s on thinking plus an explicit temperature. So it is forwarded only in budget mode on requests without thinking; `thinkingMode` decides this too. Set `reasoning: false` on the model config to suppress the thinking param entirely for proxied/legacy targets.
|
|
146
200
|
|
|
147
201
|
```ts
|
|
148
|
-
await agent.execute("Prove it.", { reasoning: { effort: "high" } });
|
|
202
|
+
await agent.execute("Prove it.", { modelOptions: { reasoning: { effort: "high" } } });
|
|
149
203
|
// adaptive model: thinking { type: "adaptive" }, output_config.effort "high"
|
|
150
204
|
// budget model: thinking { type: "enabled", budget_tokens: 12000 }
|
|
151
205
|
await model.complete(messages, { reasoning: { maxTokens: 8000 } });
|
|
152
206
|
// adaptive model: effort "medium"; budget model: budget_tokens 8000
|
|
153
207
|
```
|
|
154
208
|
|
|
155
|
-
**Claude 5 family
|
|
209
|
+
**Claude 5 family:** adaptive thinking runs by default and `budget_tokens` is a 400, so `reasoning.maxTokens` only sizes `max_tokens`. `effort: "none"` is mapped per model:
|
|
156
210
|
|
|
157
211
|
| Model | `effort: "none"` sends | Result |
|
|
158
212
|
| ----------------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
159
213
|
| Sonnet 5.5 | `thinking: { type: "between_tools" }`, alone (no `output_config.effort`, no `display`) | Thinking off. `between_tools` takes no other field and needs effort `high` or below; the model default, `high`, applies. |
|
|
214
|
+
| Sonnet 5, Haiku 5.5 | `thinking: { type: "disabled" }`, alone (no `output_config.effort`, no `display`) | Thinking off. Haiku 5.5 accepts `disabled` only at effort `high` or below; its default, `medium`, applies. |
|
|
215
|
+
| Opus 5 | `thinking: { type: "adaptive" }` + `output_config.effort: "low"` | Thinking stays on at the lowest effort: with `disabled`, Opus 5 can emit a tool call as plain text (never run) and leak thinking tags. |
|
|
160
216
|
| Opus 5.5, Fable 5 / 5.1 | no `thinking` field | No thinking-off form exists, so the model still thinks at its default effort (Opus 5.5: `medium`). Pass `effort: "low"` to think less. |
|
|
161
217
|
|
|
162
|
-
`thinkingDisplay` is applied only to adaptive thinking, never beside `between_tools`.
|
|
218
|
+
`thinkingDisplay` is applied only to adaptive thinking, never beside `between_tools` or `disabled`.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { AnthropicSDK } from "@warlock.js/ai-anthropic";
|
|
222
|
+
|
|
223
|
+
const anthropic = new AnthropicSDK({ apiKey: process.env.ANTHROPIC_API_KEY! });
|
|
224
|
+
const messages = [{ role: "user" as const, content: "Classify: great product!" }];
|
|
225
|
+
|
|
226
|
+
// Sonnet 5 / Haiku 5.5 → thinking: { type: "disabled" }
|
|
227
|
+
await anthropic.model({ name: "claude-haiku-5-5" }).complete(messages, {
|
|
228
|
+
reasoning: { effort: "none" },
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Opus 5 → thinking: { type: "adaptive" }, output_config: { effort: "low" }
|
|
232
|
+
await anthropic.model({ name: "claude-opus-5" }).complete(messages, {
|
|
233
|
+
reasoning: { effort: "none" },
|
|
234
|
+
});
|
|
235
|
+
```
|
|
163
236
|
|
|
164
237
|
`thinking.display` is set with `providerOptions.anthropic.thinkingDisplay` (`"summarized"` for readable summaries; the 5-family default is `"omitted"`, empty thinking text). It is applied whenever the adapter sends `thinking` to an adaptive model, so pair it with a `reasoning` option.
|
|
165
238
|
|
|
@@ -184,30 +257,52 @@ history = [
|
|
|
184
257
|
];
|
|
185
258
|
```
|
|
186
259
|
|
|
260
|
+
Or let `ai.session({ id, store, agent })` store the turns for you (the `keep-agent-conversations` topic of the `warlock-js-ai` skill).
|
|
261
|
+
|
|
187
262
|
## Provider options (`providerOptions.anthropic`)
|
|
188
263
|
|
|
189
264
|
Anthropic-only request options, per call or in the agent's `modelOptions`. Other adapters ignore the key. Type: `AnthropicCallOptions`.
|
|
190
265
|
|
|
191
|
-
| Field
|
|
192
|
-
|
|
|
193
|
-
| `betas`
|
|
194
|
-
| `body`
|
|
195
|
-
| `thinkingDisplay`
|
|
266
|
+
| Field | Effect |
|
|
267
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
268
|
+
| `betas` | Beta flags. When non-empty the request goes through `client.beta.messages` (needed for beta body fields and beta blocks such as `compaction`). |
|
|
269
|
+
| `body` | Extra body fields merged **last** (caller wins): `context_management`, `fallbacks`, `inference_geo`, `tool_choice`, … Not validated, except that `model`, `messages`, `system`, `tools`, `mcp_servers` and `stream` are refused (`InvalidRequestError`). |
|
|
270
|
+
| `thinkingDisplay` | `thinking.display` on adaptive models: `"summarized"`, `"omitted"`, `"updates"` (the last needs its beta). |
|
|
271
|
+
| `contextManagement` | Typed context editing: `clearToolUses` (`trigger: { inputTokens } \| { toolUses }`, `keep`, `clearAtLeast`, `excludeTools`, `clearToolInputs`) → `clear_tool_uses_20250919`; `clearThinking` (`keep: n \| "all"`) → `clear_thinking_20251015`, listed first. Adds beta `context-management-2025-06-27`. |
|
|
272
|
+
| `serverCompaction` | `true` or `{ triggerTokens (≥ 50,000; API default 150,000), instructions }` → `compact_20260112`, beta `compact-2026-01-12`. Can't be combined with `body.context_management` (`InvalidRequestError`). |
|
|
273
|
+
| `thinkingBlockBinding` | `"error"` \| `"drop_block"` → `thinking.block_binding.prefix_mismatch_behavior` + beta `thinking-binding-controls-2026-08-01`; adaptive or budget thinking only (skipped with a debug log on `between_tools`). |
|
|
196
274
|
|
|
197
275
|
```ts
|
|
198
276
|
const agent = ai.agent({
|
|
199
277
|
model: anthropic.model({ name: "claude-opus-5-5" }),
|
|
278
|
+
tools,
|
|
200
279
|
modelOptions: {
|
|
201
280
|
providerOptions: {
|
|
202
281
|
anthropic: {
|
|
203
|
-
|
|
204
|
-
|
|
282
|
+
contextManagement: { clearToolUses: { trigger: { inputTokens: 100_000 }, keep: 5 } },
|
|
283
|
+
serverCompaction: { triggerTokens: 200_000 },
|
|
205
284
|
},
|
|
206
285
|
},
|
|
207
286
|
},
|
|
208
287
|
});
|
|
209
288
|
```
|
|
210
289
|
|
|
290
|
+
The response then starts with a `compaction` block, kept on `blocks` and replayed (the API ignores everything before it). Compaction tokens are billed outside the top-level `input_tokens` / `output_tokens`; the adapter adds the `compaction` entries of `usage.iterations` into `usage`. Leave `pause_after_compaction` off inside an agent: a paused response reads as a final stop.
|
|
291
|
+
|
|
292
|
+
### Preserved thinking after client-side compaction
|
|
293
|
+
|
|
294
|
+
Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5 accept a replayed thinking block only while everything before it is unchanged. The agent's own compaction marks turns it kept after a summary `compaction: "retained"`; on those models (inferred, or `anthropic.model({ name, preservedThinking: true })`) the adapter replays them **without** `thinking` / `redacted_thinking` blocks. Other models (Opus 5, Sonnet 5, Fable 5, Mythos 5.1, 4.x, budget mode) keep them. Setting `thinkingBlockBinding` disables the stripping and lets the API drop (`"drop_block"`) or reject (`"error"`) instead — also the way to recover a stored conversation someone edited:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
const recovering = ai.agent({
|
|
298
|
+
model: anthropic.model({ name: "claude-opus-5-5" }),
|
|
299
|
+
modelOptions: { providerOptions: { anthropic: { thinkingBlockBinding: "drop_block" } } },
|
|
300
|
+
});
|
|
301
|
+
await recovering.execute(question, { history });
|
|
302
|
+
|
|
303
|
+
inferPreservedThinking("claude-opus-5-5"); // true (exported helper)
|
|
304
|
+
```
|
|
305
|
+
|
|
211
306
|
Cache TTL per call: `options.cacheControl.ttl` (`"5m"` | `"1h"`) overrides the model's `promptCacheTtl` for that call.
|
|
212
307
|
|
|
213
308
|
## Prompt caching (`cache_control`)
|
|
@@ -248,6 +343,30 @@ await agent.execute("…", { cacheControl: { breakpoints: 1 } }); // cache the s
|
|
|
248
343
|
- `tool_use` blocks accumulate `input_json_delta` fragments and emit one consolidated `{ type: "tool-call", ... }` at `content_block_stop` (no partial-arg `{}` artifact — input is parsed once, whole)
|
|
249
344
|
- every content block is also assembled by index (text, thinking + signature, server-tool input, beta `compaction_delta`) and returned as `done.blocks` when the turn has a non-neutral block
|
|
250
345
|
- terminal `{ type: "done", finishReason, usage, blocks? }` — `usage.input` from `message_start`, `usage.output` from `message_delta`, `total` computed; `cachedTokens` / `cacheWriteTokens` from `message_start` then the cumulative `message_delta` counts (see [Tokens & usage accounting](#tokens--usage-accounting))
|
|
346
|
+
- opt-in (`options.streamChunks`, set by `agent.stream()`): `{ type: "reasoning", delta }` per non-empty `thinking_delta`, `{ type: "tool-args", callId, name, delta }` per `input_json_delta` of a client `tool_use` block (never for `server_tool_use`), `{ type: "usage", usage }` after `message_start` and each `message_delta` (running totals). Claude 5 models stream thinking text only with `providerOptions.anthropic.thinkingDisplay: "summarized"`.
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
for await (const chunk of model.stream(messages, { streamChunks: true, reasoning: { effort: "high" } })) {
|
|
350
|
+
if (chunk.type === "reasoning") process.stderr.write(chunk.delta);
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Provider-defined tools
|
|
355
|
+
|
|
356
|
+
`ai.providerTool({ provider: "anthropic", definition })` entries are sent verbatim, before the function tools (the prompt-cache breakpoint stays on the last function tool). Server tools (`web_search_20250305`, `web_fetch_20250910`, `code_execution_20250825`) run inside the response and their `server_tool_use` / `*_tool_result` blocks round-trip via `blocks`. Client tools (`bash_20250124`, `text_editor_20250728` named `str_replace_based_edit_tool`, `memory_20250818`) come back as `tool_use` and dispatch to the provider tool's `execute`. Other providers' tools are skipped with a `providerTool.skipped` warning. `providerOptions.anthropic.body` still cannot set `tools`.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
const webSearch = ai.providerTool({
|
|
360
|
+
provider: "anthropic",
|
|
361
|
+
definition: { type: "web_search_20250305", name: "web_search", max_uses: 5 },
|
|
362
|
+
});
|
|
363
|
+
const editor = ai.providerTool({
|
|
364
|
+
provider: "anthropic",
|
|
365
|
+
definition: { type: "text_editor_20250728", name: "str_replace_based_edit_tool" },
|
|
366
|
+
execute: async (input: { command: string; path: string }) => files.edit(input),
|
|
367
|
+
});
|
|
368
|
+
ai.agent({ model: anthropic.model({ name: "claude-sonnet-4-6" }), tools: [webSearch, editor] });
|
|
369
|
+
```
|
|
251
370
|
|
|
252
371
|
## Finish-reason mapping
|
|
253
372
|
|
|
@@ -263,9 +382,72 @@ Raw SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy.
|
|
|
263
382
|
- `rate_limit_error` / 429 → `ProviderRateLimitError` (+`retryAfter` from `retry-after`)
|
|
264
383
|
- `billing_error` → `QuotaExceededError`
|
|
265
384
|
- `invalid_request_error` with "prompt is too long" → `ContextLengthExceededError`, else `InvalidRequestError`
|
|
266
|
-
-
|
|
385
|
+
- `overloaded_error` / 529 → `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`, `retryAfter` from `retry-after`). Also raised for an `overloaded_error` delivered mid-stream as an SSE `error` event, which has no `status`.
|
|
386
|
+
- other 5xx → `ProviderError` (`retryable: true`)
|
|
267
387
|
- Connection timeouts → `ProviderTimeoutError`
|
|
268
388
|
|
|
389
|
+
Every wrapped error carries `status` (the HTTP status, when there was one), `retryable`, and `billed`: `false` for 401 / 402 / 403 (the request never reached a billable account), `"unknown"` otherwise — Anthropic publishes no rule for failed requests, so treat them as possibly billed when you settle a budget. `fallbackModel` fails over on `PROVIDER_OVERLOADED` by default.
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
import { ai, ProviderOverloadedError } from "@warlock.js/ai";
|
|
393
|
+
import { AnthropicSDK } from "@warlock.js/ai-anthropic";
|
|
394
|
+
|
|
395
|
+
const anthropic = new AnthropicSDK({ apiKey: process.env.ANTHROPIC_API_KEY ?? "" });
|
|
396
|
+
const agent = ai.agent({ model: anthropic.model({ name: "claude-sonnet-4-6" }) });
|
|
397
|
+
|
|
398
|
+
const result = await agent.execute("hi");
|
|
399
|
+
|
|
400
|
+
if (result.error instanceof ProviderOverloadedError) {
|
|
401
|
+
console.log(
|
|
402
|
+
result.error.status,
|
|
403
|
+
result.error.retryable,
|
|
404
|
+
result.error.billed,
|
|
405
|
+
result.error.retryAfter,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Build and send an audited request
|
|
411
|
+
|
|
412
|
+
`model.buildRequest(messages, options?)` is synchronous and makes no network call.
|
|
413
|
+
It returns a detached `{ endpoint, body, betas }` snapshot, including thinking,
|
|
414
|
+
cache markers, provider body options and merged tool results. `body.stream` is
|
|
415
|
+
`false` by default; pass `{ ...options, stream: true }` to build a streaming request.
|
|
416
|
+
`betas` identifies the beta header flags; the SDK receives these separately from
|
|
417
|
+
its serialized Messages body.
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
const request = model.buildRequest(messages, options);
|
|
421
|
+
const bodyJSON = JSON.stringify(request.body);
|
|
422
|
+
// Hash or reserve spend against bodyJSON before sending.
|
|
423
|
+
const response = await model.send(request, { signal });
|
|
424
|
+
|
|
425
|
+
const streamingRequest = model.buildRequest(messages, { ...options, stream: true });
|
|
426
|
+
for await (const chunk of model.send(streamingRequest, { signal })) {
|
|
427
|
+
// Consume the same neutral chunks as model.stream().
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
`send()` uses the built endpoint, body and beta flags without rebuilding the
|
|
432
|
+
conversation or applying new defaults. It passes `betas` only when `endpoint` is
|
|
433
|
+
`"beta.messages"`: a request whose `endpoint` is `"messages"` is sent without
|
|
434
|
+
them, even if `betas` was edited by hand. Transport cancellation stays separate
|
|
435
|
+
from the audited body. `complete()`, `stream()` and `countTokens()` use this same
|
|
436
|
+
build path and always select their respective request modes. `buildRequest()`
|
|
437
|
+
throws build failures raw (an `InvalidRequestError` for a reserved `body` key, a
|
|
438
|
+
`DataCloneError` for a `body` value `structuredClone` cannot copy, such as a
|
|
439
|
+
function); `complete()`, `stream()` and `countTokens()` log them like send
|
|
440
|
+
failures and reject with an `AIError`, wrapping anything else in an
|
|
441
|
+
`InvalidRequestError`.
|
|
442
|
+
Treat the snapshot as read-only after hashing it; SDK JSON serialization and beta
|
|
443
|
+
header handling still apply.
|
|
444
|
+
|
|
445
|
+
Hosts with their own transport can import `toAnthropicMessages`,
|
|
446
|
+
`toAnthropicTools`, `toProviderBlocks`, `fromProviderBlocks`,
|
|
447
|
+
`ANTHROPIC_BLOCK_FORMAT` and the `AnthropicMessages` type from the package root.
|
|
448
|
+
`fromProviderBlocks(blocks, toolCalls)` retains the adapter's assistant-block
|
|
449
|
+
allowlist and tool-id validation.
|
|
450
|
+
|
|
269
451
|
## Token counting
|
|
270
452
|
|
|
271
453
|
```ts
|
|
@@ -275,6 +457,13 @@ const model = anthropic.model({ name: "claude-opus-5-5" }); // an AnthropicModel
|
|
|
275
457
|
await model.countTokens(messages, { tools }); // exact, via messages.countTokens (network)
|
|
276
458
|
```
|
|
277
459
|
|
|
460
|
+
For budget preflight, `countInputTokens(model, messages, { tools })` from
|
|
461
|
+
`@warlock.js/ai` returns `{ tokens, source }`. It estimates only when native
|
|
462
|
+
counting is absent or explicitly throws `InvalidRequestError` with
|
|
463
|
+
`reason: "count-unsupported"`; this adapter preserves that signal. System and
|
|
464
|
+
tools are supported natively. Ordinary validation, auth, network and rate-limit
|
|
465
|
+
errors propagate. See the cost/budget guide for reserve mode.
|
|
466
|
+
|
|
278
467
|
`countTokens` sends the same system prompt, tools, thinking and `providerOptions.anthropic.betas` a real call would, keeping only the fields the endpoint accepts.
|
|
279
468
|
|
|
280
469
|
## No embeddings
|
|
@@ -292,4 +481,31 @@ Anthropic ships no first-party embeddings API, so `AnthropicSDK` intentionally d
|
|
|
292
481
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill
|
|
293
482
|
- The `handle-ai-errors` topic of the `warlock-js-ai` skill
|
|
294
483
|
|
|
484
|
+
## Hosted-search usage and fees
|
|
485
|
+
|
|
486
|
+
`complete()` and streaming `done` map the provider's
|
|
487
|
+
`usage.server_tool_use.web_search_requests` / `web_fetch_requests` to
|
|
488
|
+
`usage.serverToolUse.webSearchRequests` / `webFetchRequests`. Streaming
|
|
489
|
+
`message_delta` counts are cumulative snapshots, never added twice. Raw
|
|
490
|
+
`server_tool_use` and search-result blocks remain in `response.blocks` and are
|
|
491
|
+
replayed in history; they never invoke local function handlers.
|
|
492
|
+
|
|
493
|
+
To add request fees to token costs, explicitly compose the verified
|
|
494
|
+
`ANTHROPIC_SERVER_TOOL_PRICING` export into model `pricing.serverTools`:
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
import { ANTHROPIC_SERVER_TOOL_PRICING } from "@warlock.js/ai-anthropic";
|
|
498
|
+
const model = anthropic.model({
|
|
499
|
+
name: "claude-sonnet-4-6",
|
|
500
|
+
pricing: { input: 3, output: 15, serverTools: ANTHROPIC_SERVER_TOOL_PRICING },
|
|
501
|
+
});
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
The [search fee](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool#usage-and-pricing)
|
|
505
|
+
is $0.01 per search; [fetch](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool#usage-and-pricing)
|
|
506
|
+
has no additional request fee (verified 2026-10-18). Tokens remain additional.
|
|
507
|
+
No code-execution request count is inferred from blocks. See
|
|
508
|
+
[hosted-tool costs](https://warlock.js.org/v/latest/ai/recipes/cost-tracking/#hosted-tool-request-fees)
|
|
509
|
+
and [fee reservations](https://warlock.js.org/v/latest/ai/recipes/cost-budgets-and-slo/#reserve-hosted-search-fees).
|
|
510
|
+
|
|
295
511
|
|
package/llms.txt
CHANGED
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
- [setup-anthropic](@warlock.js/ai-anthropic/setup-anthropic/SKILL.md): Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, thinkingMode?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default
|
|
9
|
+
- [setup-anthropic](@warlock.js/ai-anthropic/setup-anthropic/SKILL.md): Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, thinkingMode?, promptCaching?, maxTokens?, maxOutputTokens?}). System-prompt hoisting, max_tokens required (default: model max output when streaming, 16384 non-streaming; maxOutputTokens for gateway ids), extended thinking via options.reasoning → adaptive thinking + output_config.effort (current/unknown models) or budget_tokens (Haiku 4.5, 4.6 and older; override with thinkingMode), prompt caching via promptCaching + options.cacheControl (per-call ttl), provider blocks (thinking/compaction) replayed verbatim via ModelResponse.blocks / Message.blocks, providerOptions.anthropic (betas, body fields such as context_management / fallbacks, thinkingDisplay), model.countTokens(), distinct finish reasons (pause_turn, refusal, context_exceeded), built-in Claude list prices (ANTHROPIC_MODEL_PRICING, anthropicPricingFor, withAnthropicCacheWriteRates), cost-truth usage (inputIncludesCache: false, cachedTokens/cacheWriteTokens/cacheWrite1hTokens, usage.cost on complete()), ProviderOverloadedError for 529, no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `maxOutputTokens`, `max_tokens`, `reasoning`, `thinking`, `budget_tokens`, `thinkingMode`, `adaptive`, `cacheControl`, `providerOptions`, `blocks`, `countTokens`, `pause_turn`, `refusal`, `context_management`, `contextManagement`, `serverCompaction`, `clear_tool_uses`, `clear_thinking`, `thinkingBlockBinding`, `block_binding`, `preservedThinking`, `ai.providerTool`, `web_search_20250305`, `bash_20250124`, `text_editor_20250728`, `streamChunks`, `thinking_delta`, `compaction`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `cacheWrite1hTokens`, `inputIncludesCache`, `ANTHROPIC_MODEL_PRICING`, `ProviderOverloadedError`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-7`; "wire claude into warlock agent", "configure anthropic provider", "use claude sonnet", "anthropic gateway baseURL", "claude extended thinking", "anthropic prompt caching cost"; typical import `import { AnthropicSDK } from "@warlock.js/ai-anthropic"`. Skip: embeddings — the `setup-openai` topic of the `warlock-js-ai-openai` skill; sibling adapters `@warlock.js/ai-openai`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `@anthropic-ai/sdk`; Vercel `@ai-sdk/anthropic`.
|
package/package.json
CHANGED
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
"directory": "packages/ai-anthropic"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@warlock.js/ai": "5.
|
|
18
|
+
"@warlock.js/ai": "5.32.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@anthropic-ai/sdk": "^0.129.0",
|
|
22
|
-
"@warlock.js/logger": "5.
|
|
22
|
+
"@warlock.js/logger": "5.32.0"
|
|
23
23
|
},
|
|
24
|
-
"version": "5.
|
|
24
|
+
"version": "5.32.0",
|
|
25
25
|
"main": "./cjs/index.cjs",
|
|
26
26
|
"module": "./esm/index.mjs",
|
|
27
27
|
"types": "./esm/index.d.mts",
|
package/skills/README.md
CHANGED
|
@@ -6,4 +6,4 @@ Per-task skills. Cross-references name the topic ("the `<topic>` topic"), and fo
|
|
|
6
6
|
|
|
7
7
|
### `setup-anthropic`
|
|
8
8
|
|
|
9
|
-
Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, thinkingMode?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default
|
|
9
|
+
Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, thinkingMode?, promptCaching?, maxTokens?, maxOutputTokens?}). System-prompt hoisting, max_tokens required (default: model max output when streaming, 16384 non-streaming), extended thinking via options.reasoning → adaptive thinking + output_config.effort (current/unknown models) or budget_tokens (Haiku 4.5, 4.6 and older; override with thinkingMode), prompt caching via promptCaching + options.cacheControl with cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Load when wiring a Claude-backed model into a @warlock.js agent.
|