@warlock.js/ai-anthropic 5.24.0 → 5.26.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 +23 -0
- package/cjs/index.cjs +234 -51
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +43 -16
- package/esm/config.type.d.mts.map +1 -1
- package/esm/index.d.mts +2 -1
- package/esm/known-vision-models.mjs +15 -2
- package/esm/known-vision-models.mjs.map +1 -1
- package/esm/model.mjs +137 -47
- package/esm/model.mjs.map +1 -1
- package/esm/thinking-mode.d.mts +17 -0
- package/esm/thinking-mode.d.mts.map +1 -0
- package/esm/thinking-mode.mjs +81 -0
- package/esm/thinking-mode.mjs.map +1 -0
- package/esm/utils/map-stop-reason.mjs +4 -2
- package/esm/utils/map-stop-reason.mjs.map +1 -1
- package/llms-full.txt +73 -32
- package/llms.txt +1 -1
- package/package.json +4 -4
- package/skills/README.md +1 -1
- package/skills/setup-anthropic/SKILL.md +73 -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?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default 4096), extended thinking via options.reasoning → thinking budget_tokens, prompt caching via promptCaching + options.cacheControl, cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `reasoning`, `thinking`, `budget_tokens`, `cacheControl`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `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 — `@warlock.js/ai-openai/setup-openai/SKILL.md`; 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`.'
|
|
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 4096), 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, cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `reasoning`, `thinking`, `budget_tokens`, `thinkingMode`, `adaptive`, `cacheControl`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `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 — `@warlock.js/ai-openai/setup-openai/SKILL.md`; 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`
|
|
@@ -35,23 +35,23 @@ const proxied = new AnthropicSDK({
|
|
|
35
35
|
## Producing a model
|
|
36
36
|
|
|
37
37
|
```ts
|
|
38
|
-
anthropic.model({ name: "claude-sonnet-4-6" })
|
|
39
|
-
anthropic.model({ name: "claude-haiku-4-5", temperature: 0.2 }) // sampling controls
|
|
40
|
-
anthropic.model({ name: "claude-opus-4-7", maxTokens: 8192 })
|
|
38
|
+
anthropic.model({ name: "claude-sonnet-4-6" }); // common case
|
|
39
|
+
anthropic.model({ name: "claude-haiku-4-5", temperature: 0.2 }); // sampling controls
|
|
40
|
+
anthropic.model({ name: "claude-opus-4-7", maxTokens: 8192 }); // raise the cap
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
## Capabilities — what's auto-set
|
|
44
44
|
|
|
45
|
-
| Flag
|
|
46
|
-
|
|
|
47
|
-
| `structuredOutput` | `true` (via Anthropic's native `output_config.format`)
|
|
48
|
-
| `vision`
|
|
49
|
-
| `reasoning`
|
|
50
|
-
| `promptCaching`
|
|
51
|
-
| `pdf`
|
|
52
|
-
| `audio`
|
|
45
|
+
| Flag | Default |
|
|
46
|
+
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `structuredOutput` | `true` (via Anthropic's native `output_config.format`) |
|
|
48
|
+
| `vision` | Inferred from model name. `true` for Claude 3 / 3.5 / 3.7 / 4 and Claude 5-series (`claude-opus-5*`, `claude-sonnet-5*`, `claude-fable-5*`, `claude-mythos-5*`); `false` for pre-3 and unknown ids. |
|
|
49
|
+
| `reasoning` | `true` — forwarded in the shape the model accepts (see [Extended thinking](#extended-thinking-reasoning)). Override with `reasoning: false` for legacy/proxied targets that reject the `thinking` param. |
|
|
50
|
+
| `promptCaching` | `true` — the adapter places `cache_control` breakpoints and reports both cache reads (`Usage.cachedTokens`) and writes (`Usage.cacheWriteTokens`). |
|
|
51
|
+
| `pdf` | `true` — the Messages API accepts PDF/document content blocks on vision-capable models. |
|
|
52
|
+
| `audio` | absent (`false`) — Anthropic has no audio-input block, so the agent rejects audio attachments upfront. |
|
|
53
53
|
|
|
54
|
-
Explicit config always wins (`structuredOutput`, `vision`, `reasoning`).
|
|
54
|
+
Explicit config always wins (`structuredOutput`, `vision`, `reasoning`, `thinkingMode`).
|
|
55
55
|
|
|
56
56
|
## Pricing & cost
|
|
57
57
|
|
|
@@ -62,7 +62,7 @@ Pricing is opt-in. Supply USD-per-million-token rates and every report this SDK'
|
|
|
62
62
|
const anthropic = new AnthropicSDK({
|
|
63
63
|
apiKey,
|
|
64
64
|
pricing: {
|
|
65
|
-
"claude-haiku-4-5":
|
|
65
|
+
"claude-haiku-4-5": { input: 1, output: 5, cachedInput: 0.1 },
|
|
66
66
|
"claude-sonnet-4-6": { input: 3, output: 15, cachedInput: 0.3 },
|
|
67
67
|
},
|
|
68
68
|
});
|
|
@@ -77,11 +77,11 @@ Resolution at `model()` time: per-model `pricing` > SDK registry entry for that
|
|
|
77
77
|
|
|
78
78
|
Every `ModelResponse.usage` (and the streaming terminal `done`) is normalized to the neutral `Usage` shape. Anthropic reports `input_tokens` / `output_tokens` separately with no pre-summed total, so `total` is computed (`input + output`). The two cache channels are surfaced only when non-zero:
|
|
79
79
|
|
|
80
|
-
| Neutral field
|
|
81
|
-
|
|
|
82
|
-
| `usage.cachedTokens`
|
|
83
|
-
| `usage.cacheWriteTokens` | `cache_creation_input_tokens` | Input tokens **written** to the cache on this call (the ~1.25x write surcharge). Bills at `cachedOutput` when set.
|
|
84
|
-
| `usage.reasoningTokens`
|
|
80
|
+
| Neutral field | Anthropic source | Meaning / billing |
|
|
81
|
+
| ------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| `usage.cachedTokens` | `cache_read_input_tokens` | Subset of input served from the prompt cache. Bills at `cachedInput` (falls back to `input` when unset). |
|
|
83
|
+
| `usage.cacheWriteTokens` | `cache_creation_input_tokens` | Input tokens **written** to the cache on this call (the ~1.25x write surcharge). Bills at `cachedOutput` when set. |
|
|
84
|
+
| `usage.reasoningTokens` | — _(not reported separately)_ | Anthropic bills extended-thinking tokens **inside** `output_tokens`, so this stays unset — populating it would double-count against `output`. |
|
|
85
85
|
|
|
86
86
|
In streaming, `cachedTokens` / `cacheWriteTokens` are seeded from `message_start` and then **overwritten by the cumulative counts on `message_delta`** when those are present and non-zero, so the terminal `done` carries the final tally.
|
|
87
87
|
|
|
@@ -89,7 +89,9 @@ In streaming, `cachedTokens` / `cacheWriteTokens` are seeded from `message_start
|
|
|
89
89
|
|
|
90
90
|
Unlike OpenAI, Anthropic **requires** `max_tokens` on every request. Resolution: per-call `options.maxTokens` > `config.maxTokens` > **default `4096`**. A caller who never sets a cap still gets a complete answer instead of a 400.
|
|
91
91
|
|
|
92
|
-
With extended thinking enabled and no explicit cap, the adapter reserves answer room: `max_tokens = thinking budget + 4096`.
|
|
92
|
+
With extended thinking enabled and no explicit cap, the adapter reserves answer room in both modes: `max_tokens = thinking budget + 4096`. In budget mode an explicit `maxTokens` must be greater than `budget_tokens` or the call throws before it reaches Anthropic.
|
|
93
|
+
|
|
94
|
+
**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`).
|
|
93
95
|
|
|
94
96
|
## System prompt
|
|
95
97
|
|
|
@@ -108,31 +110,70 @@ When the agent passes `responseSchema` and the model is `structuredOutput`-capab
|
|
|
108
110
|
|
|
109
111
|
## Extended thinking (reasoning)
|
|
110
112
|
|
|
111
|
-
When the model is `reasoning`-capable (default `true`) and the agent passes `options.reasoning`, the adapter forwards Anthropic
|
|
113
|
+
When the model is `reasoning`-capable (default `true`) and the agent passes `options.reasoning`, the adapter forwards Anthropic thinking in one of two shapes, chosen per model (`thinkingMode`):
|
|
114
|
+
|
|
115
|
+
| Mode | Models (inferred from the name) | Wire shape |
|
|
116
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
|
117
|
+
| `"adaptive"` | Current Claude models — Opus 4.7 / 4.8 / 5 / 5.5, Sonnet 5 / 5.5, Fable 5 / 5.1 — **and any id the adapter does not recognise** | `thinking: { type: "adaptive" }` + `output_config.effort` |
|
|
118
|
+
| `"budget"` | Haiku 4.5, Opus 4.6, Sonnet 4.6, and every older model (Claude 3.x, 4.0 / 4.1 / 4.5, 2, instant) | `thinking: { type: "enabled", budget_tokens }` |
|
|
119
|
+
|
|
120
|
+
Adaptive models reject `budget_tokens` with a 400, so the shape matters.
|
|
121
|
+
|
|
122
|
+
- **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
|
+
- **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`, or `effort: "none"`, emits nothing.
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
- `reasoning.effort` (`"low" | "medium" | "high"`) → a tiered budget (`1024` / `4096` / `12000`) when no explicit `maxTokens` is given.
|
|
115
|
-
- Any resolved budget is floored at Anthropic's `1024`-token minimum.
|
|
116
|
-
- `reasoning` with neither `effort` nor `maxTokens` emits nothing.
|
|
126
|
+
### `thinkingMode` override
|
|
117
127
|
|
|
118
|
-
|
|
128
|
+
`anthropic.model({ name, thinkingMode: "adaptive" | "budget" })` beats the name-based detection. Use it when the id does not look like an Anthropic id: region-prefixed / Bedrock-style ids (`us.anthropic.claude-…`) and custom or gateway ids are _unrecognised_, so they default to adaptive. If they front an older model (Haiku 4.5, 4.6 or earlier) set `thinkingMode: "budget"`. It can also move Opus/Sonnet 4.6 onto adaptive. The `AnthropicThinkingMode` type is exported.
|
|
119
129
|
|
|
120
130
|
```ts
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
import { AnthropicSDK, type AnthropicThinkingMode } from "@warlock.js/ai-anthropic";
|
|
132
|
+
|
|
133
|
+
const anthropic = new AnthropicSDK({ apiKey: process.env.ANTHROPIC_API_KEY! });
|
|
134
|
+
|
|
135
|
+
const mode: AnthropicThinkingMode = "budget";
|
|
136
|
+
|
|
137
|
+
anthropic.model({ name: "claude-opus-5-5" }); // adaptive (detected)
|
|
138
|
+
anthropic.model({ name: "claude-haiku-4-5" }); // budget (detected)
|
|
139
|
+
anthropic.model({ name: "us.anthropic.claude-haiku-4-5", thinkingMode: mode }); // region-prefixed id of an older model
|
|
140
|
+
anthropic.model({ name: "claude-sonnet-4-6", thinkingMode: "adaptive" }); // opt 4.6 into adaptive
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Temperature
|
|
144
|
+
|
|
145
|
+
`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
|
+
|
|
147
|
+
```ts
|
|
148
|
+
await agent.execute("Prove it.", { reasoning: { effort: "high" } });
|
|
149
|
+
// adaptive model: thinking { type: "adaptive" }, output_config.effort "high"
|
|
150
|
+
// budget model: thinking { type: "enabled", budget_tokens: 12000 }
|
|
151
|
+
await model.complete(messages, { reasoning: { maxTokens: 8000 } });
|
|
152
|
+
// adaptive model: effort "medium"; budget model: budget_tokens 8000
|
|
123
153
|
```
|
|
124
154
|
|
|
125
155
|
When a thinking-enabled response also makes tool calls, its signed `thinking` and `redacted_thinking` blocks are retained in each call's `providerMetadata.anthropic.thinkingBlocks`. The adapter replays those opaque blocks automatically on the next assistant turn, preserving Anthropic's required signatures; application code should leave that metadata intact when persisting message history.
|
|
126
156
|
|
|
127
157
|
## Prompt caching (`cache_control`)
|
|
128
158
|
|
|
159
|
+
Caching is opt-in: `model({ promptCaching: true })` sends request-level
|
|
160
|
+
`cache_control: { type: "ephemeral" }` when a call has no explicit
|
|
161
|
+
`options.cacheControl.breakpoints`. Anthropic then marks the last cacheable
|
|
162
|
+
block itself, caching the longest reusable request prefix (including growing
|
|
163
|
+
message history). A caller-supplied breakpoint remains authoritative, so its
|
|
164
|
+
request has no top-level automatic marker.
|
|
165
|
+
|
|
166
|
+
Set `promptCacheTtl: "1h"` on the model to apply a one-hour TTL to automatic
|
|
167
|
+
caching and emitted explicit markers. Omit it (or use `"5m"`) for Anthropic's
|
|
168
|
+
default five-minute TTL; the one-hour cache has a higher write cost.
|
|
169
|
+
|
|
129
170
|
Two independent breakpoint sites, both reported back via `usage.cachedTokens` / `usage.cacheWriteTokens`:
|
|
130
171
|
|
|
131
|
-
- **Tools** — set `model({ promptCaching: true })` to mark the
|
|
132
|
-
- **System prompt** — a per-call `options.cacheControl.breakpoints >= 1` emits the system prompt as a `TextBlockParam` carrying `cache_control: ephemeral` (the longest stable prefix on a turn). Without the hint the system prompt stays a plain string (
|
|
172
|
+
- **Tools** — set `model({ promptCaching: true })` to mark the _last_ tool definition with `cache_control: ephemeral`. One breakpoint caches the whole tool prefix; off by default since a write costs ~1.25x and only pays off across multiple trips.
|
|
173
|
+
- **System prompt** — a per-call `options.cacheControl.breakpoints >= 1` emits the system prompt as a `TextBlockParam` carrying `cache_control: ephemeral` (the longest stable prefix on a turn). Without the hint the system prompt stays a plain string with no marker of its own, but with `promptCaching: true` the automatic request-level marker still caches the longest reusable prefix, system prompt included (a live check read back 10,090 cached tokens of a large system prompt on the second call). With `promptCaching` off and no hint, nothing is cached, so a one-shot call never pays the write surcharge. A system prompt with per-turn placeholders changes the prefix each turn: write surcharge, no reads. No system prompt → no block.
|
|
133
174
|
|
|
134
175
|
```ts
|
|
135
|
-
await agent.execute("…", { cacheControl: { breakpoints: 1 } });
|
|
176
|
+
await agent.execute("…", { cacheControl: { breakpoints: 1 } }); // cache the system prefix
|
|
136
177
|
```
|
|
137
178
|
|
|
138
179
|
## Multipart messages (vision)
|
|
@@ -169,7 +210,7 @@ Raw SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy.
|
|
|
169
210
|
## Token counting
|
|
170
211
|
|
|
171
212
|
```ts
|
|
172
|
-
await anthropic.count("some text")
|
|
213
|
+
await anthropic.count("some text"); // approximate heuristic, offline
|
|
173
214
|
```
|
|
174
215
|
|
|
175
216
|
## No embeddings
|
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?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default 4096), extended thinking via options.reasoning → thinking budget_tokens, prompt caching via promptCaching + options.cacheControl, cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `reasoning`, `thinking`, `budget_tokens`, `cacheControl`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `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 — `@warlock.js/ai-openai/setup-openai/SKILL.md`; 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`.
|
|
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 4096), 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, cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `reasoning`, `thinking`, `budget_tokens`, `thinkingMode`, `adaptive`, `cacheControl`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `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 — `@warlock.js/ai-openai/setup-openai/SKILL.md`; 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
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"url": "https://github.com/warlockjs/ai-anthropic"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@warlock.js/ai": "5.
|
|
17
|
+
"@warlock.js/ai": "5.26.0"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@anthropic-ai/sdk": "^0.
|
|
21
|
-
"@warlock.js/logger": "5.
|
|
20
|
+
"@anthropic-ai/sdk": "^0.129.0",
|
|
21
|
+
"@warlock.js/logger": "5.26.0"
|
|
22
22
|
},
|
|
23
|
-
"version": "5.
|
|
23
|
+
"version": "5.26.0",
|
|
24
24
|
"main": "./cjs/index.cjs",
|
|
25
25
|
"module": "./esm/index.mjs",
|
|
26
26
|
"types": "./esm/index.d.mts",
|
package/skills/README.md
CHANGED
|
@@ -6,4 +6,4 @@ Per-task skills. All cross-references use the form `@warlock.js/<pkg>/<skill>/SK
|
|
|
6
6
|
|
|
7
7
|
### [`setup-anthropic/`](./setup-anthropic/SKILL.md)
|
|
8
8
|
|
|
9
|
-
Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default 4096), extended thinking via options.reasoning → thinking budget_tokens, 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.
|
|
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 4096), 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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-anthropic
|
|
3
|
-
description: 'Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, reasoning?, promptCaching?, maxTokens?}). System-prompt hoisting, max_tokens required (default 4096), extended thinking via options.reasoning → thinking budget_tokens, prompt caching via promptCaching + options.cacheControl, cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `reasoning`, `thinking`, `budget_tokens`, `cacheControl`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `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 — `@warlock.js/ai-openai/setup-openai/SKILL.md`; 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`.'
|
|
3
|
+
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 4096), 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, cost-truth usage (cachedTokens/cacheWriteTokens), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `reasoning`, `thinking`, `budget_tokens`, `thinkingMode`, `adaptive`, `cacheControl`, `promptCaching`, `cachedTokens`, `cacheWriteTokens`, `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 — `@warlock.js/ai-openai/setup-openai/SKILL.md`; 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`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `@warlock.js/ai-anthropic`
|
|
@@ -27,23 +27,23 @@ const proxied = new AnthropicSDK({
|
|
|
27
27
|
## Producing a model
|
|
28
28
|
|
|
29
29
|
```ts
|
|
30
|
-
anthropic.model({ name: "claude-sonnet-4-6" })
|
|
31
|
-
anthropic.model({ name: "claude-haiku-4-5", temperature: 0.2 }) // sampling controls
|
|
32
|
-
anthropic.model({ name: "claude-opus-4-7", maxTokens: 8192 })
|
|
30
|
+
anthropic.model({ name: "claude-sonnet-4-6" }); // common case
|
|
31
|
+
anthropic.model({ name: "claude-haiku-4-5", temperature: 0.2 }); // sampling controls
|
|
32
|
+
anthropic.model({ name: "claude-opus-4-7", maxTokens: 8192 }); // raise the cap
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
## Capabilities — what's auto-set
|
|
36
36
|
|
|
37
|
-
| Flag
|
|
38
|
-
|
|
|
39
|
-
| `structuredOutput` | `true` (via Anthropic's native `output_config.format`)
|
|
40
|
-
| `vision`
|
|
41
|
-
| `reasoning`
|
|
42
|
-
| `promptCaching`
|
|
43
|
-
| `pdf`
|
|
44
|
-
| `audio`
|
|
37
|
+
| Flag | Default |
|
|
38
|
+
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| `structuredOutput` | `true` (via Anthropic's native `output_config.format`) |
|
|
40
|
+
| `vision` | Inferred from model name. `true` for Claude 3 / 3.5 / 3.7 / 4 and Claude 5-series (`claude-opus-5*`, `claude-sonnet-5*`, `claude-fable-5*`, `claude-mythos-5*`); `false` for pre-3 and unknown ids. |
|
|
41
|
+
| `reasoning` | `true` — forwarded in the shape the model accepts (see [Extended thinking](#extended-thinking-reasoning)). Override with `reasoning: false` for legacy/proxied targets that reject the `thinking` param. |
|
|
42
|
+
| `promptCaching` | `true` — the adapter places `cache_control` breakpoints and reports both cache reads (`Usage.cachedTokens`) and writes (`Usage.cacheWriteTokens`). |
|
|
43
|
+
| `pdf` | `true` — the Messages API accepts PDF/document content blocks on vision-capable models. |
|
|
44
|
+
| `audio` | absent (`false`) — Anthropic has no audio-input block, so the agent rejects audio attachments upfront. |
|
|
45
45
|
|
|
46
|
-
Explicit config always wins (`structuredOutput`, `vision`, `reasoning`).
|
|
46
|
+
Explicit config always wins (`structuredOutput`, `vision`, `reasoning`, `thinkingMode`).
|
|
47
47
|
|
|
48
48
|
## Pricing & cost
|
|
49
49
|
|
|
@@ -54,7 +54,7 @@ Pricing is opt-in. Supply USD-per-million-token rates and every report this SDK'
|
|
|
54
54
|
const anthropic = new AnthropicSDK({
|
|
55
55
|
apiKey,
|
|
56
56
|
pricing: {
|
|
57
|
-
"claude-haiku-4-5":
|
|
57
|
+
"claude-haiku-4-5": { input: 1, output: 5, cachedInput: 0.1 },
|
|
58
58
|
"claude-sonnet-4-6": { input: 3, output: 15, cachedInput: 0.3 },
|
|
59
59
|
},
|
|
60
60
|
});
|
|
@@ -69,11 +69,11 @@ Resolution at `model()` time: per-model `pricing` > SDK registry entry for that
|
|
|
69
69
|
|
|
70
70
|
Every `ModelResponse.usage` (and the streaming terminal `done`) is normalized to the neutral `Usage` shape. Anthropic reports `input_tokens` / `output_tokens` separately with no pre-summed total, so `total` is computed (`input + output`). The two cache channels are surfaced only when non-zero:
|
|
71
71
|
|
|
72
|
-
| Neutral field
|
|
73
|
-
|
|
|
74
|
-
| `usage.cachedTokens`
|
|
75
|
-
| `usage.cacheWriteTokens` | `cache_creation_input_tokens` | Input tokens **written** to the cache on this call (the ~1.25x write surcharge). Bills at `cachedOutput` when set.
|
|
76
|
-
| `usage.reasoningTokens`
|
|
72
|
+
| Neutral field | Anthropic source | Meaning / billing |
|
|
73
|
+
| ------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| `usage.cachedTokens` | `cache_read_input_tokens` | Subset of input served from the prompt cache. Bills at `cachedInput` (falls back to `input` when unset). |
|
|
75
|
+
| `usage.cacheWriteTokens` | `cache_creation_input_tokens` | Input tokens **written** to the cache on this call (the ~1.25x write surcharge). Bills at `cachedOutput` when set. |
|
|
76
|
+
| `usage.reasoningTokens` | — _(not reported separately)_ | Anthropic bills extended-thinking tokens **inside** `output_tokens`, so this stays unset — populating it would double-count against `output`. |
|
|
77
77
|
|
|
78
78
|
In streaming, `cachedTokens` / `cacheWriteTokens` are seeded from `message_start` and then **overwritten by the cumulative counts on `message_delta`** when those are present and non-zero, so the terminal `done` carries the final tally.
|
|
79
79
|
|
|
@@ -81,7 +81,9 @@ In streaming, `cachedTokens` / `cacheWriteTokens` are seeded from `message_start
|
|
|
81
81
|
|
|
82
82
|
Unlike OpenAI, Anthropic **requires** `max_tokens` on every request. Resolution: per-call `options.maxTokens` > `config.maxTokens` > **default `4096`**. A caller who never sets a cap still gets a complete answer instead of a 400.
|
|
83
83
|
|
|
84
|
-
With extended thinking enabled and no explicit cap, the adapter reserves answer room: `max_tokens = thinking budget + 4096`.
|
|
84
|
+
With extended thinking enabled and no explicit cap, the adapter reserves answer room in both modes: `max_tokens = thinking budget + 4096`. In budget mode an explicit `maxTokens` must be greater than `budget_tokens` or the call throws before it reaches Anthropic.
|
|
85
|
+
|
|
86
|
+
**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`).
|
|
85
87
|
|
|
86
88
|
## System prompt
|
|
87
89
|
|
|
@@ -100,31 +102,70 @@ When the agent passes `responseSchema` and the model is `structuredOutput`-capab
|
|
|
100
102
|
|
|
101
103
|
## Extended thinking (reasoning)
|
|
102
104
|
|
|
103
|
-
When the model is `reasoning`-capable (default `true`) and the agent passes `options.reasoning`, the adapter forwards Anthropic
|
|
105
|
+
When the model is `reasoning`-capable (default `true`) and the agent passes `options.reasoning`, the adapter forwards Anthropic thinking in one of two shapes, chosen per model (`thinkingMode`):
|
|
106
|
+
|
|
107
|
+
| Mode | Models (inferred from the name) | Wire shape |
|
|
108
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
|
109
|
+
| `"adaptive"` | Current Claude models — Opus 4.7 / 4.8 / 5 / 5.5, Sonnet 5 / 5.5, Fable 5 / 5.1 — **and any id the adapter does not recognise** | `thinking: { type: "adaptive" }` + `output_config.effort` |
|
|
110
|
+
| `"budget"` | Haiku 4.5, Opus 4.6, Sonnet 4.6, and every older model (Claude 3.x, 4.0 / 4.1 / 4.5, 2, instant) | `thinking: { type: "enabled", budget_tokens }` |
|
|
111
|
+
|
|
112
|
+
Adaptive models reject `budget_tokens` with a 400, so the shape matters.
|
|
113
|
+
|
|
114
|
+
- **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.
|
|
115
|
+
- **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.
|
|
116
|
+
- `reasoning` with neither `effort` nor `maxTokens`, or `effort: "none"`, emits nothing.
|
|
104
117
|
|
|
105
|
-
|
|
106
|
-
- `reasoning.effort` (`"low" | "medium" | "high"`) → a tiered budget (`1024` / `4096` / `12000`) when no explicit `maxTokens` is given.
|
|
107
|
-
- Any resolved budget is floored at Anthropic's `1024`-token minimum.
|
|
108
|
-
- `reasoning` with neither `effort` nor `maxTokens` emits nothing.
|
|
118
|
+
### `thinkingMode` override
|
|
109
119
|
|
|
110
|
-
|
|
120
|
+
`anthropic.model({ name, thinkingMode: "adaptive" | "budget" })` beats the name-based detection. Use it when the id does not look like an Anthropic id: region-prefixed / Bedrock-style ids (`us.anthropic.claude-…`) and custom or gateway ids are _unrecognised_, so they default to adaptive. If they front an older model (Haiku 4.5, 4.6 or earlier) set `thinkingMode: "budget"`. It can also move Opus/Sonnet 4.6 onto adaptive. The `AnthropicThinkingMode` type is exported.
|
|
111
121
|
|
|
112
122
|
```ts
|
|
113
|
-
|
|
114
|
-
|
|
123
|
+
import { AnthropicSDK, type AnthropicThinkingMode } from "@warlock.js/ai-anthropic";
|
|
124
|
+
|
|
125
|
+
const anthropic = new AnthropicSDK({ apiKey: process.env.ANTHROPIC_API_KEY! });
|
|
126
|
+
|
|
127
|
+
const mode: AnthropicThinkingMode = "budget";
|
|
128
|
+
|
|
129
|
+
anthropic.model({ name: "claude-opus-5-5" }); // adaptive (detected)
|
|
130
|
+
anthropic.model({ name: "claude-haiku-4-5" }); // budget (detected)
|
|
131
|
+
anthropic.model({ name: "us.anthropic.claude-haiku-4-5", thinkingMode: mode }); // region-prefixed id of an older model
|
|
132
|
+
anthropic.model({ name: "claude-sonnet-4-6", thinkingMode: "adaptive" }); // opt 4.6 into adaptive
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Temperature
|
|
136
|
+
|
|
137
|
+
`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.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
await agent.execute("Prove it.", { reasoning: { effort: "high" } });
|
|
141
|
+
// adaptive model: thinking { type: "adaptive" }, output_config.effort "high"
|
|
142
|
+
// budget model: thinking { type: "enabled", budget_tokens: 12000 }
|
|
143
|
+
await model.complete(messages, { reasoning: { maxTokens: 8000 } });
|
|
144
|
+
// adaptive model: effort "medium"; budget model: budget_tokens 8000
|
|
115
145
|
```
|
|
116
146
|
|
|
117
147
|
When a thinking-enabled response also makes tool calls, its signed `thinking` and `redacted_thinking` blocks are retained in each call's `providerMetadata.anthropic.thinkingBlocks`. The adapter replays those opaque blocks automatically on the next assistant turn, preserving Anthropic's required signatures; application code should leave that metadata intact when persisting message history.
|
|
118
148
|
|
|
119
149
|
## Prompt caching (`cache_control`)
|
|
120
150
|
|
|
151
|
+
Caching is opt-in: `model({ promptCaching: true })` sends request-level
|
|
152
|
+
`cache_control: { type: "ephemeral" }` when a call has no explicit
|
|
153
|
+
`options.cacheControl.breakpoints`. Anthropic then marks the last cacheable
|
|
154
|
+
block itself, caching the longest reusable request prefix (including growing
|
|
155
|
+
message history). A caller-supplied breakpoint remains authoritative, so its
|
|
156
|
+
request has no top-level automatic marker.
|
|
157
|
+
|
|
158
|
+
Set `promptCacheTtl: "1h"` on the model to apply a one-hour TTL to automatic
|
|
159
|
+
caching and emitted explicit markers. Omit it (or use `"5m"`) for Anthropic's
|
|
160
|
+
default five-minute TTL; the one-hour cache has a higher write cost.
|
|
161
|
+
|
|
121
162
|
Two independent breakpoint sites, both reported back via `usage.cachedTokens` / `usage.cacheWriteTokens`:
|
|
122
163
|
|
|
123
|
-
- **Tools** — set `model({ promptCaching: true })` to mark the
|
|
124
|
-
- **System prompt** — a per-call `options.cacheControl.breakpoints >= 1` emits the system prompt as a `TextBlockParam` carrying `cache_control: ephemeral` (the longest stable prefix on a turn). Without the hint the system prompt stays a plain string (
|
|
164
|
+
- **Tools** — set `model({ promptCaching: true })` to mark the _last_ tool definition with `cache_control: ephemeral`. One breakpoint caches the whole tool prefix; off by default since a write costs ~1.25x and only pays off across multiple trips.
|
|
165
|
+
- **System prompt** — a per-call `options.cacheControl.breakpoints >= 1` emits the system prompt as a `TextBlockParam` carrying `cache_control: ephemeral` (the longest stable prefix on a turn). Without the hint the system prompt stays a plain string with no marker of its own, but with `promptCaching: true` the automatic request-level marker still caches the longest reusable prefix, system prompt included (a live check read back 10,090 cached tokens of a large system prompt on the second call). With `promptCaching` off and no hint, nothing is cached, so a one-shot call never pays the write surcharge. A system prompt with per-turn placeholders changes the prefix each turn: write surcharge, no reads. No system prompt → no block.
|
|
125
166
|
|
|
126
167
|
```ts
|
|
127
|
-
await agent.execute("…", { cacheControl: { breakpoints: 1 } });
|
|
168
|
+
await agent.execute("…", { cacheControl: { breakpoints: 1 } }); // cache the system prefix
|
|
128
169
|
```
|
|
129
170
|
|
|
130
171
|
## Multipart messages (vision)
|
|
@@ -161,7 +202,7 @@ Raw SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy.
|
|
|
161
202
|
## Token counting
|
|
162
203
|
|
|
163
204
|
```ts
|
|
164
|
-
await anthropic.count("some text")
|
|
205
|
+
await anthropic.count("some text"); // approximate heuristic, offline
|
|
165
206
|
```
|
|
166
207
|
|
|
167
208
|
## No embeddings
|