@warlock.js/ai-anthropic 5.25.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 +17 -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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to `@warlock.js/ai-anthropic` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.26.0 - 2026-09-30
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Adaptive Claude reasoning now maps `minimal` to `output_config.effort: "low"` and supports `xhigh` and `max`; budget-mode models map them to 1,024, 24,000, and 32,000 thinking tokens respectively.
|
|
12
|
+
- Claude reasoning-token usage is now included in responses when the API reports it, including streamed responses.
|
|
13
|
+
- Responses stopped because the model context window was exceeded now report a length finish reason.
|
|
14
|
+
- **Behaviour change:** Reasoning now works on current Claude models. Claude Opus 4.7, 4.8, 5 and 5.5, Sonnet 5 and 5.5, Fable 5 and 5.1, and any model id the adapter does not recognise now get `thinking: { type: "adaptive" }` with `output_config.effort` (`low`, `medium` or `high`, taken from `reasoning.effort`; `medium` when only `reasoning.maxTokens` is given). Before, every model got `budget_tokens`, which these models reject with a 400. Claude Haiku 4.5, Opus 4.6, Sonnet 4.6 and older models keep the `budget_tokens` shape. The default `max_tokens` is unchanged in both modes.
|
|
15
|
+
- **Behaviour change:** `temperature` is no longer sent to models released after Claude Opus 4.6 (the same adaptive-thinking models listed above), because they reject any value other than the default with a 400. Haiku 4.5, the 4.6 models and older models still receive it.
|
|
16
|
+
- **Behaviour change:** Claude 5-series models (`claude-opus-5*`, `claude-sonnet-5*`, `claude-fable-5*`, `claude-mythos-5*`) are now recognised as vision-capable, so image attachments are no longer rejected for them.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `thinkingMode: "adaptive" | "budget"` on `anthropic.model({ ... })` overrides the thinking shape inferred from the model name. Use it for gateway model ids that don't follow Anthropic's naming, or to move Opus/Sonnet 4.6 onto adaptive thinking. It also decides whether `temperature` is sent. The `AnthropicThinkingMode` type is exported.
|
|
21
|
+
- `promptCaching: true` now enables Anthropic's request-level automatic cache placement when a call has no explicit cache breakpoint, so the longest reusable prefix is cached. `promptCacheTtl?: "5m" | "1h"` controls the TTL for automatic and explicit cache markers; omission keeps Anthropic's five-minute default.
|
|
22
|
+
|
|
7
23
|
## 5.25.0 - 2026-09-28
|
|
8
24
|
|
|
9
25
|
### Changed
|
|
@@ -55,6 +71,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
55
71
|
### Changed
|
|
56
72
|
|
|
57
73
|
- Lockstep release maintenance and dependency refresh.
|
|
74
|
+
|
|
58
75
|
## 5.20.0 - 2026-09-24
|
|
59
76
|
|
|
60
77
|
### Changed
|
package/cjs/index.cjs
CHANGED
|
@@ -36,13 +36,22 @@ let _warlock_js_logger = require("@warlock.js/logger");
|
|
|
36
36
|
* Model-name prefixes for Claude families that accept image input
|
|
37
37
|
* (vision) on the Messages API.
|
|
38
38
|
*
|
|
39
|
-
* Every Claude 3, Claude 3.5/3.7, and Claude
|
|
39
|
+
* Every Claude 3, Claude 3.5/3.7, Claude 4 and Claude 5 family model is
|
|
40
40
|
* multimodal, so the list covers both the dotted legacy naming
|
|
41
41
|
* (`claude-3-haiku-...`, `claude-3-5-sonnet-...`) and the current
|
|
42
42
|
* `claude-<tier>-4-*` naming (`claude-opus-4-7`, `claude-sonnet-4-6`,
|
|
43
43
|
* `claude-haiku-4-5`). Pre-3 families (`claude-2`, `claude-instant`)
|
|
44
44
|
* are text-only and intentionally absent.
|
|
45
45
|
*
|
|
46
|
+
* The Claude 5 series is multimodal too (claude-api ref, cached
|
|
47
|
+
* 2026-09-25): its vision examples use `claude-opus-5-5`; the models list
|
|
48
|
+
* credits Claude Fable 5.1 with vision and Claude Sonnet 5 with
|
|
49
|
+
* high-resolution vision; Claude Mythos 5.1 has "same capabilities" as
|
|
50
|
+
* Fable 5.1. The tier-5 prefixes cover every 5.x release
|
|
51
|
+
* (`claude-opus-5`, `claude-opus-5-5`, `claude-sonnet-5-5`,
|
|
52
|
+
* `claude-fable-5-1`, …). Opus/Sonnet 4.6–4.8 are already covered by the
|
|
53
|
+
* tier-4 prefixes.
|
|
54
|
+
*
|
|
46
55
|
* Matched as a prefix so dated variants (`claude-opus-4-20250514`) are
|
|
47
56
|
* covered without listing every release tag. Devs can always override
|
|
48
57
|
* per-model via `anthropic.model({ name, vision: true | false })` —
|
|
@@ -53,7 +62,11 @@ const VISION_CAPABLE_PREFIXES = [
|
|
|
53
62
|
"claude-4",
|
|
54
63
|
"claude-opus-4",
|
|
55
64
|
"claude-sonnet-4",
|
|
56
|
-
"claude-haiku-4"
|
|
65
|
+
"claude-haiku-4",
|
|
66
|
+
"claude-opus-5",
|
|
67
|
+
"claude-sonnet-5",
|
|
68
|
+
"claude-fable-5",
|
|
69
|
+
"claude-mythos-5"
|
|
57
70
|
];
|
|
58
71
|
/**
|
|
59
72
|
* Infer whether a given Claude model name supports vision based on the
|
|
@@ -72,19 +85,100 @@ function inferVisionCapability(modelName) {
|
|
|
72
85
|
return VISION_CAPABLE_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
73
86
|
}
|
|
74
87
|
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region ../ai-anthropic/src/thinking-mode.ts
|
|
90
|
+
/**
|
|
91
|
+
* Family prefixes that are budget-mode in their entirety — plain
|
|
92
|
+
* `startsWith` match (dated and `-latest` variants included).
|
|
93
|
+
*/
|
|
94
|
+
const BUDGET_FAMILY_PREFIXES = [
|
|
95
|
+
"claude-3",
|
|
96
|
+
"claude-2",
|
|
97
|
+
"claude-instant",
|
|
98
|
+
"claude-haiku-4"
|
|
99
|
+
];
|
|
100
|
+
/**
|
|
101
|
+
* Individual pre-4.7 releases in the `claude-<tier>-4-*` naming. Matched
|
|
102
|
+
* as a release root: the id must equal the root or continue with a
|
|
103
|
+
* separator that is not a new minor version number, so `claude-opus-4`
|
|
104
|
+
* matches `claude-opus-4-20250514` but NOT `claude-opus-4-7`. Ids from the
|
|
105
|
+
* installed SDK `Model` union (`messages.d.ts:795`) plus the 4.6 pair.
|
|
106
|
+
*/
|
|
107
|
+
const BUDGET_RELEASE_ROOTS = [
|
|
108
|
+
"claude-opus-4",
|
|
109
|
+
"claude-opus-4-0",
|
|
110
|
+
"claude-opus-4-1",
|
|
111
|
+
"claude-opus-4-5",
|
|
112
|
+
"claude-opus-4-6",
|
|
113
|
+
"claude-sonnet-4",
|
|
114
|
+
"claude-sonnet-4-0",
|
|
115
|
+
"claude-sonnet-4-5",
|
|
116
|
+
"claude-sonnet-4-6"
|
|
117
|
+
];
|
|
118
|
+
/**
|
|
119
|
+
* A remainder that starts a new minor version (`-7`, `-10`) — used to
|
|
120
|
+
* stop a release root from swallowing a later release of the same line.
|
|
121
|
+
* Dates (`-20250514`) and tags (`-latest`, `-v1`) are not minor versions.
|
|
122
|
+
*/
|
|
123
|
+
const NEXT_MINOR_VERSION = /^-\d{1,2}(?!\d)/;
|
|
124
|
+
function matchesReleaseRoot(name, root) {
|
|
125
|
+
if (!name.startsWith(root)) return false;
|
|
126
|
+
const rest = name.slice(root.length);
|
|
127
|
+
if (rest === "") return true;
|
|
128
|
+
return (rest.startsWith("-") || rest.startsWith("@")) && !NEXT_MINOR_VERSION.test(rest);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Infer the thinking mode for a Claude model id. Budget for Haiku 4.5, the
|
|
132
|
+
* 4.6 pair, and every older family; adaptive for everything else,
|
|
133
|
+
* including unknown and future ids. Explicit per-model config
|
|
134
|
+
* (`AnthropicModelConfig.thinkingMode`) always wins over this inference.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* inferThinkingMode("claude-opus-5-5"); // → "adaptive"
|
|
138
|
+
* inferThinkingMode("claude-haiku-4-5"); // → "budget"
|
|
139
|
+
* inferThinkingMode("claude-opus-9"); // → "adaptive" (unknown → current API direction)
|
|
140
|
+
*/
|
|
141
|
+
function inferThinkingMode(modelName) {
|
|
142
|
+
const normalized = modelName.toLowerCase();
|
|
143
|
+
if (BUDGET_FAMILY_PREFIXES.some((prefix) => normalized.startsWith(prefix))) return "budget";
|
|
144
|
+
if (BUDGET_RELEASE_ROOTS.some((root) => matchesReleaseRoot(normalized, root))) return "budget";
|
|
145
|
+
return "adaptive";
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Whether a model of this thinking mode accepts an explicit `temperature`.
|
|
149
|
+
*
|
|
150
|
+
* Installed SDK, `MessageCreateParamsBase.temperature`
|
|
151
|
+
* (`messages.d.ts:2036-2040`): "Models released after Claude Opus 4.6 do
|
|
152
|
+
* not support setting temperature. A value of 1.0 will be accepted for
|
|
153
|
+
* backwards compatibility, all other values will be rejected with a 400
|
|
154
|
+
* error." The claude-api ref's per-model table agrees: sampling is
|
|
155
|
+
* "Removed - 400" on Fable 5/5.1, Opus 5.5/5/4.8/4.7 and Sonnet 5, and
|
|
156
|
+
* "Non-default values - 400" on Sonnet 5.5; "Allowed" on Opus 4.6,
|
|
157
|
+
* Sonnet 4.6, Haiku 4.5 and older.
|
|
158
|
+
*
|
|
159
|
+
* That split is exactly the adaptive/budget split in the table above
|
|
160
|
+
* (adaptive = released after Opus 4.6; budget = Opus 4.6 and earlier), so
|
|
161
|
+
* the thinking mode doubles as the sampling-parameter classification.
|
|
162
|
+
*/
|
|
163
|
+
function acceptsTemperature(mode) {
|
|
164
|
+
return mode === "budget";
|
|
165
|
+
}
|
|
166
|
+
|
|
75
167
|
//#endregion
|
|
76
168
|
//#region ../ai-anthropic/src/utils/map-stop-reason.ts
|
|
77
169
|
const stopReasonMap = {
|
|
78
170
|
end_turn: "stop",
|
|
79
171
|
stop_sequence: "stop",
|
|
80
172
|
max_tokens: "length",
|
|
173
|
+
model_context_window_exceeded: "length",
|
|
81
174
|
tool_use: "tool_calls"
|
|
82
175
|
};
|
|
83
176
|
/**
|
|
84
177
|
* Map Anthropic's `stop_reason` to the normalized `FinishReason` union.
|
|
85
178
|
*
|
|
86
|
-
* `end_turn` / `stop_sequence` are both natural stops. `max_tokens`
|
|
87
|
-
*
|
|
179
|
+
* `end_turn` / `stop_sequence` are both natural stops. `max_tokens` and
|
|
180
|
+
* `model_context_window_exceeded` map to `length`. `tool_use` maps to
|
|
181
|
+
* `tool_calls`. Everything else —
|
|
88
182
|
* `refusal` (policy intervention), `pause_turn` (incomplete
|
|
89
183
|
* long-running turn), `null`, or any value a future API version adds —
|
|
90
184
|
* falls through to `"error"` so the agent treats the trip as a
|
|
@@ -468,16 +562,45 @@ const DEFAULT_MAX_TOKENS = 4096;
|
|
|
468
562
|
*/
|
|
469
563
|
const MIN_THINKING_BUDGET = 1024;
|
|
470
564
|
/**
|
|
471
|
-
*
|
|
472
|
-
* `
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
|
|
565
|
+
* Effort used when the caller asks for reasoning with only
|
|
566
|
+
* `reasoning.maxTokens` and no `effort`. `"medium"` is what the adapter
|
|
567
|
+
* has always assumed (the budget lookup fell back to
|
|
568
|
+
* `EFFORT_THINKING_BUDGET.medium`), so adaptive models get the same tier.
|
|
569
|
+
*/
|
|
570
|
+
const DEFAULT_THINKING_EFFORT = "medium";
|
|
571
|
+
/**
|
|
572
|
+
* Map the neutral `ReasoningEffort` level to a thinking token count.
|
|
573
|
+
*
|
|
574
|
+
* - Budget-mode models: sent as `thinking.budget_tokens` when the caller
|
|
575
|
+
* doesn't pass an explicit `reasoning.maxTokens`.
|
|
576
|
+
* - Both modes: reserved on top of `DEFAULT_MAX_TOKENS` when the caller
|
|
577
|
+
* sets no `maxTokens`, because thinking counts toward `max_tokens`
|
|
578
|
+
* (installed SDK `ThinkingConfigParam` docs, `messages.d.ts:1105`).
|
|
579
|
+
* Adaptive models therefore get the same `max_tokens` the budget path
|
|
580
|
+
* has always produced.
|
|
476
581
|
*/
|
|
477
582
|
const EFFORT_THINKING_BUDGET = {
|
|
583
|
+
minimal: 1024,
|
|
478
584
|
low: 1024,
|
|
479
585
|
medium: 4096,
|
|
480
|
-
high: 12e3
|
|
586
|
+
high: 12e3,
|
|
587
|
+
xhigh: 24e3,
|
|
588
|
+
max: 32e3
|
|
589
|
+
};
|
|
590
|
+
/**
|
|
591
|
+
* Map the neutral `ReasoningEffort` level to Anthropic's
|
|
592
|
+
* `output_config.effort` for adaptive-mode models. The installed SDK
|
|
593
|
+
* accepts `low | medium | high | xhigh | max` (`OutputConfig.effort`,
|
|
594
|
+
* `messages.ts:2767`); map every supported value 1:1 and clamp `minimal` to
|
|
595
|
+
* the nearest accepted value, `low`.
|
|
596
|
+
*/
|
|
597
|
+
const EFFORT_TO_OUTPUT_EFFORT = {
|
|
598
|
+
minimal: "low",
|
|
599
|
+
low: "low",
|
|
600
|
+
medium: "medium",
|
|
601
|
+
high: "high",
|
|
602
|
+
xhigh: "xhigh",
|
|
603
|
+
max: "max"
|
|
481
604
|
};
|
|
482
605
|
/**
|
|
483
606
|
* Anthropic-backed implementation of `ModelContract`.
|
|
@@ -525,6 +648,7 @@ var AnthropicModel = class {
|
|
|
525
648
|
this.name = config.name;
|
|
526
649
|
this.provider = provider;
|
|
527
650
|
this.pricing = config.pricing;
|
|
651
|
+
this.thinkingMode = config.thinkingMode ?? inferThinkingMode(config.name);
|
|
528
652
|
this.capabilities = {
|
|
529
653
|
structuredOutput: config.structuredOutput ?? true,
|
|
530
654
|
vision: config.vision ?? inferVisionCapability(config.name),
|
|
@@ -604,6 +728,8 @@ var AnthropicModel = class {
|
|
|
604
728
|
for await (const event of stream) {
|
|
605
729
|
if (event.type === "message_start") {
|
|
606
730
|
usage.input = event.message.usage.input_tokens ?? 0;
|
|
731
|
+
const thinkingTokens = event.message.usage.output_tokens_details?.thinking_tokens;
|
|
732
|
+
if (thinkingTokens !== null && thinkingTokens !== void 0) usage.reasoningTokens = thinkingTokens;
|
|
607
733
|
const cacheRead = event.message.usage.cache_read_input_tokens;
|
|
608
734
|
if (cacheRead !== null && cacheRead !== void 0 && cacheRead > 0) usage.cachedTokens = cacheRead;
|
|
609
735
|
const cacheWrite = event.message.usage.cache_creation_input_tokens;
|
|
@@ -655,6 +781,8 @@ var AnthropicModel = class {
|
|
|
655
781
|
if (event.type === "message_delta") {
|
|
656
782
|
rawStopReason = event.delta.stop_reason ?? rawStopReason;
|
|
657
783
|
usage.output = event.usage.output_tokens ?? usage.output;
|
|
784
|
+
const thinkingTokens = event.usage.output_tokens_details?.thinking_tokens;
|
|
785
|
+
if (thinkingTokens !== null && thinkingTokens !== void 0) usage.reasoningTokens = thinkingTokens;
|
|
658
786
|
const cacheRead = event.usage.cache_read_input_tokens;
|
|
659
787
|
if (cacheRead !== null && cacheRead !== void 0 && cacheRead > 0) usage.cachedTokens = cacheRead;
|
|
660
788
|
const cacheWrite = event.usage.cache_creation_input_tokens;
|
|
@@ -683,9 +811,10 @@ var AnthropicModel = class {
|
|
|
683
811
|
* prompt out of `messages`, resolves `max_tokens` (required by
|
|
684
812
|
* Anthropic) with the documented default, and conditionally attaches
|
|
685
813
|
* temperature, tools, native structured output, extended thinking
|
|
686
|
-
* (`reasoning`), and
|
|
814
|
+
* (`reasoning`), and automatic or explicit prompt-cache control.
|
|
687
815
|
* Temperature is dropped when thinking is enabled, since Anthropic
|
|
688
|
-
* rejects the two together
|
|
816
|
+
* rejects the two together, and always for adaptive-mode models, which
|
|
817
|
+
* reject any explicit temperature (see `acceptsTemperature`).
|
|
689
818
|
*/
|
|
690
819
|
buildParams(messages, options) {
|
|
691
820
|
const { system, messages: anthropicMessages } = toAnthropicMessages(messages);
|
|
@@ -693,17 +822,19 @@ var AnthropicModel = class {
|
|
|
693
822
|
const temperature = options?.temperature ?? this.config.temperature;
|
|
694
823
|
const configuredMaxTokens = options?.maxTokens ?? this.config.maxTokens;
|
|
695
824
|
const thinkingBudget = thinking.thinking?.type === "enabled" ? thinking.thinking.budget_tokens : void 0;
|
|
696
|
-
const maxTokens = configuredMaxTokens ?? (
|
|
825
|
+
const maxTokens = configuredMaxTokens ?? (thinking.reservedTokens !== void 0 ? thinking.reservedTokens + DEFAULT_MAX_TOKENS : DEFAULT_MAX_TOKENS);
|
|
826
|
+
const sendTemperature = temperature !== void 0 && !thinking.thinking && acceptsTemperature(this.thinkingMode);
|
|
697
827
|
if (thinkingBudget !== void 0 && configuredMaxTokens !== void 0 && configuredMaxTokens <= thinkingBudget) throw new Error(`Anthropic maxTokens (${configuredMaxTokens}) must be greater than thinking budget_tokens (${thinkingBudget})`);
|
|
698
828
|
return {
|
|
699
829
|
model: this.name,
|
|
700
830
|
max_tokens: maxTokens,
|
|
701
831
|
messages: anthropicMessages,
|
|
832
|
+
...this.buildAutomaticCacheControl(options?.cacheControl),
|
|
702
833
|
...this.buildSystem(system, options?.cacheControl),
|
|
703
|
-
...
|
|
834
|
+
...sendTemperature ? { temperature } : {},
|
|
704
835
|
...this.buildTools(options?.tools),
|
|
705
|
-
...this.
|
|
706
|
-
...thinking
|
|
836
|
+
...this.buildOutputConfig(options?.responseSchema, thinking.effort),
|
|
837
|
+
...thinking.thinking ? { thinking: thinking.thinking } : {}
|
|
707
838
|
};
|
|
708
839
|
}
|
|
709
840
|
/**
|
|
@@ -724,31 +855,66 @@ var AnthropicModel = class {
|
|
|
724
855
|
if (this.capabilities.promptCaching && breakpoints > 0) return { system: [{
|
|
725
856
|
type: "text",
|
|
726
857
|
text: system,
|
|
727
|
-
cache_control:
|
|
858
|
+
cache_control: this.cacheControl()
|
|
728
859
|
}] };
|
|
729
860
|
return { system };
|
|
730
861
|
}
|
|
731
862
|
/**
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
|
|
863
|
+
* Let Anthropic select the last cacheable block when caching is enabled
|
|
864
|
+
* without a caller-selected breakpoint. An explicit breakpoint remains
|
|
865
|
+
* authoritative, so the request-level form is deliberately omitted then.
|
|
866
|
+
*/
|
|
867
|
+
buildAutomaticCacheControl(cacheControl) {
|
|
868
|
+
const breakpoints = cacheControl?.breakpoints ?? 0;
|
|
869
|
+
return this.config.promptCaching && breakpoints <= 0 ? { cache_control: this.cacheControl() } : {};
|
|
870
|
+
}
|
|
871
|
+
/** Build a typed cache-control marker, omitting TTL for Anthropic's 5-minute default. */
|
|
872
|
+
cacheControl() {
|
|
873
|
+
return {
|
|
874
|
+
type: "ephemeral",
|
|
875
|
+
...this.config.promptCacheTtl ? { ttl: this.config.promptCacheTtl } : {}
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Translate the neutral `reasoning` option into Anthropic's thinking
|
|
880
|
+
* settings, in the shape this model accepts (`thinkingMode`). Emitted
|
|
881
|
+
* only when the model declares the `reasoning` capability AND a
|
|
882
|
+
* reasoning option is supplied; otherwise returns an empty object.
|
|
883
|
+
*
|
|
884
|
+
* - Adaptive mode (Opus 4.7+, Sonnet 5+, Fable 5+, unknown ids):
|
|
885
|
+
* `thinking: { type: "adaptive" }` (installed SDK
|
|
886
|
+
* `ThinkingConfigAdaptive`, `messages.d.ts:1065`) plus
|
|
887
|
+
* `output_config.effort` from the neutral effort, defaulting to
|
|
888
|
+
* `"medium"`. `budget_tokens` is never sent — these models 400 on it
|
|
889
|
+
* (claude-api ref). `reasoning.maxTokens` only sizes the default
|
|
890
|
+
* `max_tokens` headroom.
|
|
891
|
+
* - Budget mode (Haiku 4.5, Opus/Sonnet 4.6, older):
|
|
892
|
+
* `thinking: { type: "enabled", budget_tokens }`. An explicit
|
|
893
|
+
* `reasoning.maxTokens` wins; otherwise the effort maps to a tiered
|
|
894
|
+
* budget. `budget_tokens` must be ≥ 1024 (`ThinkingConfigEnabled`,
|
|
895
|
+
* `messages.d.ts:1084`), so the budget is floored at that minimum.
|
|
736
896
|
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
* requires `budget_tokens` ≥ 1024, so the budget is floored at that
|
|
740
|
-
* minimum. The neutral `effort: "none"` ("run without reasoning") maps
|
|
741
|
-
* to no `thinking` block at all — extended thinking is opt-in here.
|
|
897
|
+
* The neutral `effort: "none"` ("run without reasoning") maps to no
|
|
898
|
+
* `thinking` field at all in both modes.
|
|
742
899
|
*/
|
|
743
900
|
buildThinking(reasoning) {
|
|
744
901
|
if (!this.capabilities.reasoning || !reasoning) return {};
|
|
745
902
|
if (reasoning.effort === "none") return {};
|
|
746
903
|
if (reasoning.maxTokens === void 0 && reasoning.effort === void 0) return {};
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
904
|
+
const effort = reasoning.effort ?? DEFAULT_THINKING_EFFORT;
|
|
905
|
+
const budget = Math.max(MIN_THINKING_BUDGET, reasoning.maxTokens ?? EFFORT_THINKING_BUDGET[effort]);
|
|
906
|
+
if (this.thinkingMode === "adaptive") return {
|
|
907
|
+
thinking: { type: "adaptive" },
|
|
908
|
+
effort: EFFORT_TO_OUTPUT_EFFORT[effort],
|
|
909
|
+
reservedTokens: budget
|
|
910
|
+
};
|
|
911
|
+
return {
|
|
912
|
+
thinking: {
|
|
913
|
+
type: "enabled",
|
|
914
|
+
budget_tokens: budget
|
|
915
|
+
},
|
|
916
|
+
reservedTokens: budget
|
|
917
|
+
};
|
|
752
918
|
}
|
|
753
919
|
/**
|
|
754
920
|
* Spread-friendly tools fragment. Returns an empty object when no
|
|
@@ -768,32 +934,49 @@ var AnthropicModel = class {
|
|
|
768
934
|
if (!mapped) return {};
|
|
769
935
|
if (this.config.promptCaching && mapped.length > 0) {
|
|
770
936
|
const last = mapped.length - 1;
|
|
771
|
-
mapped[last]
|
|
772
|
-
|
|
773
|
-
|
|
937
|
+
const lastTool = mapped[last];
|
|
938
|
+
if (lastTool) mapped[last] = {
|
|
939
|
+
...lastTool,
|
|
940
|
+
cache_control: this.cacheControl()
|
|
774
941
|
};
|
|
775
942
|
}
|
|
776
943
|
return { tools: mapped };
|
|
777
944
|
}
|
|
778
945
|
/**
|
|
946
|
+
* Spread-friendly `output_config` fragment carrying both the native
|
|
947
|
+
* structured-output `format` and the adaptive-thinking `effort`, merged
|
|
948
|
+
* into one object (both live under `OutputConfig`, installed SDK
|
|
949
|
+
* `messages.d.ts:796-806`). Returns an empty object when neither applies,
|
|
950
|
+
* so budget-mode requests carry `output_config` only when a schema asks
|
|
951
|
+
* for it.
|
|
952
|
+
*/
|
|
953
|
+
buildOutputConfig(responseSchema, effort) {
|
|
954
|
+
const format = this.buildStructuredOutputFormat(responseSchema);
|
|
955
|
+
if (!format && !effort) return {};
|
|
956
|
+
return { output_config: {
|
|
957
|
+
...format ? { format } : {},
|
|
958
|
+
...effort ? { effort } : {}
|
|
959
|
+
} };
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
779
962
|
* Translate the neutral `responseSchema` option into Anthropic's
|
|
780
963
|
* native `output_config.format` (JSON-schema structured outputs).
|
|
781
964
|
*
|
|
782
|
-
* Only
|
|
965
|
+
* Only returned when the model declares the `structuredOutput`
|
|
783
966
|
* capability AND the schema is a proper root-object JSON Schema —
|
|
784
967
|
* Anthropic rejects non-object roots. When the capability is off
|
|
785
|
-
* (config override) or the schema is non-object, returns
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
968
|
+
* (config override) or the schema is non-object, returns `undefined`:
|
|
969
|
+
* the agent has already injected a soft schema hint into the system
|
|
970
|
+
* prompt as the fallback, and client-side `validate()` still enforces
|
|
971
|
+
* shape.
|
|
789
972
|
*/
|
|
790
|
-
|
|
791
|
-
if (!responseSchema || !this.capabilities.structuredOutput) return
|
|
792
|
-
if (responseSchema.type !== "object" || typeof responseSchema.properties !== "object") return
|
|
793
|
-
return {
|
|
973
|
+
buildStructuredOutputFormat(responseSchema) {
|
|
974
|
+
if (!responseSchema || !this.capabilities.structuredOutput) return;
|
|
975
|
+
if (responseSchema.type !== "object" || typeof responseSchema.properties !== "object") return;
|
|
976
|
+
return {
|
|
794
977
|
type: "json_schema",
|
|
795
978
|
schema: responseSchema
|
|
796
|
-
}
|
|
979
|
+
};
|
|
797
980
|
}
|
|
798
981
|
/**
|
|
799
982
|
* Concatenate every `text` content block into the single neutral
|
|
@@ -833,24 +1016,24 @@ var AnthropicModel = class {
|
|
|
833
1016
|
* Anthropic reports `input_tokens` / `output_tokens` separately with
|
|
834
1017
|
* no pre-summed total, so `total` is computed. Cache-read tokens are
|
|
835
1018
|
* surfaced as `cachedTokens` and cache-write tokens as
|
|
836
|
-
* `cacheWriteTokens`, each only when non-zero.
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
* `Usage.reasoningTokens` is intentionally left unset here. Populating
|
|
841
|
-
* it would double-count against `output`.
|
|
1019
|
+
* `cacheWriteTokens`, each only when non-zero. Anthropic also reports
|
|
1020
|
+
* `output_tokens_details.thinking_tokens` as the reasoning subset of
|
|
1021
|
+
* its inclusive `output_tokens`; it is surfaced as `reasoningTokens`
|
|
1022
|
+
* when present, without changing the billing total.
|
|
842
1023
|
*/
|
|
843
1024
|
extractUsage(raw) {
|
|
844
1025
|
const input = raw.input_tokens ?? 0;
|
|
845
1026
|
const output = raw.output_tokens ?? 0;
|
|
846
1027
|
const cacheRead = raw.cache_read_input_tokens;
|
|
847
1028
|
const cacheWrite = raw.cache_creation_input_tokens;
|
|
1029
|
+
const thinkingTokens = raw.output_tokens_details?.thinking_tokens;
|
|
848
1030
|
return {
|
|
849
1031
|
input,
|
|
850
1032
|
output,
|
|
851
1033
|
total: input + output,
|
|
852
1034
|
...cacheRead !== null && cacheRead !== void 0 && cacheRead > 0 ? { cachedTokens: cacheRead } : {},
|
|
853
|
-
...cacheWrite !== null && cacheWrite !== void 0 && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}
|
|
1035
|
+
...cacheWrite !== null && cacheWrite !== void 0 && cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {},
|
|
1036
|
+
...thinkingTokens !== null && thinkingTokens !== void 0 ? { reasoningTokens: thinkingTokens } : {}
|
|
854
1037
|
};
|
|
855
1038
|
}
|
|
856
1039
|
/**
|