@ai-sdk/anthropic 4.0.66 → 4.0.67
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 +13 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +103 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +7 -2
- package/dist/internal/index.js +102 -3
- package/dist/internal/index.js.map +1 -1
- package/docs/05-anthropic.mdx +111 -40
- package/package.json +1 -1
- package/src/anthropic-language-model-options.ts +12 -0
- package/src/anthropic-language-model.ts +73 -3
- package/src/convert-to-anthropic-prompt.ts +54 -0
package/docs/05-anthropic.mdx
CHANGED
|
@@ -179,7 +179,7 @@ import { streamText, tool } from 'ai';
|
|
|
179
179
|
import { z } from 'zod';
|
|
180
180
|
|
|
181
181
|
const result = streamText({
|
|
182
|
-
model: anthropic('claude-sonnet-5'),
|
|
182
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
183
183
|
tools: {
|
|
184
184
|
writeFile: tool({
|
|
185
185
|
description: 'Write content to a file',
|
|
@@ -197,9 +197,10 @@ const result = streamText({
|
|
|
197
197
|
});
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
For `claude-opus-5-5
|
|
201
|
-
native structured outputs through
|
|
202
|
-
forced tool use, so the
|
|
200
|
+
For `claude-sonnet-5-5`, `claude-opus-5-5`, and `claude-fable-5-1`, the
|
|
201
|
+
default `"auto"` mode uses native structured outputs through
|
|
202
|
+
`output_config.format`. These models reject forced tool use, so the
|
|
203
|
+
`"jsonTool"` mode cannot be used with them. If you
|
|
203
204
|
request `"jsonTool"` anyway, the provider falls back to `"outputFormat"` and
|
|
204
205
|
emits a warning. Likewise, a `required` or named `toolChoice` is downgraded to
|
|
205
206
|
`auto` with a warning; instruct the model to use the tool in your prompt and
|
|
@@ -207,7 +208,7 @@ verify that a tool call was made.
|
|
|
207
208
|
|
|
208
209
|
### Effort
|
|
209
210
|
|
|
210
|
-
Anthropic introduced an `effort` option with `claude-opus-4-5` that affects thinking, text responses, and function calls. Effort defaults to `high` and you can set it to `medium` or `low` to save tokens and to lower time-to-last-token latency (TTLT). `claude-opus-4-7`, `claude-opus-4-8`, `claude-opus-5`, `claude-opus-5-5`, `claude-fable-5`, `claude-fable-5-1`, and `claude-sonnet-5` additionally support `xhigh` for maximum reasoning effort.
|
|
211
|
+
Anthropic introduced an `effort` option with `claude-opus-4-5` that affects thinking, text responses, and function calls. Effort defaults to `high` and you can set it to `medium` or `low` to save tokens and to lower time-to-last-token latency (TTLT). `claude-opus-4-7`, `claude-opus-4-8`, `claude-opus-5`, `claude-opus-5-5`, `claude-fable-5`, `claude-fable-5-1`, `claude-sonnet-5`, and `claude-sonnet-5-5` additionally support `xhigh` for maximum reasoning effort.
|
|
211
212
|
|
|
212
213
|
On `claude-opus-5`, thinking can only be disabled at effort levels up to and including `high`. When you combine `thinking: { type: 'disabled' }` with `effort: 'xhigh'` or `effort: 'max'`, the AI SDK lowers the effort to `high` and emits a warning instead of sending a request that the API would reject.
|
|
213
214
|
|
|
@@ -218,6 +219,16 @@ carrying over the setting you used on `claude-opus-5`. Set `maxOutputTokens`
|
|
|
218
219
|
with room for thinking as well as the reply; thinking counts toward the limit
|
|
219
220
|
even when its content is not returned.
|
|
220
221
|
|
|
222
|
+
On `claude-sonnet-5-5`, thinking cannot be turned off either, and the API
|
|
223
|
+
default effort is `high`. Its effort levels are not equivalent to those of
|
|
224
|
+
`claude-sonnet-5`, so test several levels rather than carrying over your
|
|
225
|
+
current setting. For agentic coding and other multi-step tool use, start at
|
|
226
|
+
`medium` for well-specified tasks and move to `high` for harder ones. The
|
|
227
|
+
lowest thinking setting, [`between_tools`](#between-tools-thinking), is only
|
|
228
|
+
accepted at `low`, `medium`, and `high` effort. When you combine it with
|
|
229
|
+
`effort: 'xhigh'` or `effort: 'max'`, the AI SDK lowers the effort to `high`
|
|
230
|
+
and emits a warning.
|
|
231
|
+
|
|
221
232
|
```ts highlight="8-10"
|
|
222
233
|
import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
|
|
223
234
|
import { generateText } from 'ai';
|
|
@@ -322,6 +333,8 @@ The `inferenceGeo` option accepts `'us'` (US-only infrastructure) or `'global'`
|
|
|
322
333
|
|
|
323
334
|
Claude Fable 5 has safeguards that limit its performance in certain areas like cybersecurity, biology, and chemistry, and automated safety checks are run on every request.
|
|
324
335
|
|
|
336
|
+
Claude Sonnet 5.5 also has safety classifiers enabled, including for cybersecurity, biology, and reasoning extraction. Requests that ask the model to reproduce its internal reasoning in the response text can be declined with the `reasoning_extraction` category; use `thinking: { type: 'adaptive', display: 'summarized' }` and read the reasoning parts instead.
|
|
337
|
+
|
|
325
338
|
When one of these checks blocks a request, the API does not answer it. Instead it returns a classifier block: a `200` response with a `refusal` stop reason and an optional `stop_details` object describing the category that triggered the block. The AI SDK surfaces this as a `content-filter` finish reason, with the details available on `providerMetadata.anthropic.stopDetails`.
|
|
326
339
|
|
|
327
340
|
A classifier block looks like this:
|
|
@@ -405,7 +418,7 @@ import { generateText, tool } from 'ai';
|
|
|
405
418
|
import { z } from 'zod';
|
|
406
419
|
|
|
407
420
|
const result = await generateText({
|
|
408
|
-
model: anthropic('claude-sonnet-5'),
|
|
421
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
409
422
|
prompt: 'Use the bash tool to run: echo hello',
|
|
410
423
|
tools: { bash: tool({ inputSchema: z.object({ command: z.string() }) }) },
|
|
411
424
|
providerOptions: {
|
|
@@ -491,15 +504,21 @@ const { text } = await generateText({
|
|
|
491
504
|
|
|
492
505
|
##### Adaptive-Only Models
|
|
493
506
|
|
|
494
|
-
`claude-
|
|
495
|
-
thinking. The API rejects
|
|
496
|
-
`thinking: { type: '
|
|
497
|
-
|
|
507
|
+
`claude-sonnet-5-5`, `claude-opus-5-5`, `claude-fable-5`, and
|
|
508
|
+
`claude-fable-5-1` always run adaptive thinking. The API rejects
|
|
509
|
+
`thinking: { type: 'disabled' }` and budget-based
|
|
510
|
+
`thinking: { type: 'enabled' }` for these models. To keep existing code
|
|
511
|
+
working, the provider:
|
|
498
512
|
|
|
499
513
|
- removes `thinking: { type: 'disabled' }` and emits a warning,
|
|
500
514
|
- converts `thinking: { type: 'enabled', budgetTokens }` to `{ type: 'adaptive' }` and emits a warning,
|
|
501
515
|
- maps the top-level `reasoning: 'none'` option to `effort: 'low'` and emits a warning.
|
|
502
516
|
|
|
517
|
+
On `claude-sonnet-5-5`, which supports
|
|
518
|
+
[`between_tools` thinking](#between-tools-thinking), the provider instead
|
|
519
|
+
replaces `thinking: { type: 'disabled' }` with `thinking: { type: 'between_tools' }`
|
|
520
|
+
(with a warning) and maps `reasoning: 'none'` to `between_tools` thinking.
|
|
521
|
+
|
|
503
522
|
Use `effort` to control how much these models think. On `claude-opus-5-5`, set
|
|
504
523
|
`effort: 'low'` when time to first token matters, and move to `medium` if
|
|
505
524
|
quality drops:
|
|
@@ -524,6 +543,42 @@ const { text } = await generateText({
|
|
|
524
543
|
setting, thinking blocks are returned with empty text.
|
|
525
544
|
</Note>
|
|
526
545
|
|
|
546
|
+
##### Between-Tools Thinking
|
|
547
|
+
|
|
548
|
+
`claude-sonnet-5-5` supports `thinking: { type: 'between_tools' }`, its lowest
|
|
549
|
+
thinking setting. The model does no upfront thinking, but the short progress
|
|
550
|
+
notes it writes between tool calls are still returned as thinking blocks, each
|
|
551
|
+
with a short summary. They are available as reasoning parts and are sent back
|
|
552
|
+
unchanged on the next step. `between_tools` accepts no other thinking options
|
|
553
|
+
(such as `display` or `blockBinding`) and is only accepted at `low`, `medium`,
|
|
554
|
+
and `high` effort. Per-message effort changes via
|
|
555
|
+
[mid-conversation system messages](#mid-conversation-system-controls) are not
|
|
556
|
+
supported with `between_tools`.
|
|
557
|
+
|
|
558
|
+
```ts highlight="16-17"
|
|
559
|
+
import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
|
|
560
|
+
import { generateText, isStepCount, tool } from 'ai';
|
|
561
|
+
import { z } from 'zod';
|
|
562
|
+
|
|
563
|
+
const { text, steps } = await generateText({
|
|
564
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
565
|
+
stopWhen: isStepCount(5),
|
|
566
|
+
tools: {
|
|
567
|
+
weather: tool({
|
|
568
|
+
inputSchema: z.object({ city: z.string() }),
|
|
569
|
+
execute: async ({ city }) => ({ city, temperature: 72 }),
|
|
570
|
+
}),
|
|
571
|
+
},
|
|
572
|
+
providerOptions: {
|
|
573
|
+
anthropic: {
|
|
574
|
+
thinking: { type: 'between_tools' },
|
|
575
|
+
effort: 'low',
|
|
576
|
+
} satisfies AnthropicLanguageModelOptions,
|
|
577
|
+
},
|
|
578
|
+
prompt: 'Compare the weather in San Francisco and New York.',
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
527
582
|
##### Thinking Display (Opus 4.7+)
|
|
528
583
|
|
|
529
584
|
Starting with `claude-opus-4-7`, thinking content is omitted from the response by default — thinking blocks are present in the stream but their text is empty. To receive reasoning output, set `display: 'summarized'`:
|
|
@@ -551,11 +606,11 @@ console.log(text);
|
|
|
551
606
|
|
|
552
607
|
##### Thinking Updates
|
|
553
608
|
|
|
554
|
-
Use `display: 'updates'` with `claude-
|
|
555
|
-
thinking summaries between tool calls. These models
|
|
556
|
-
between tool calls as thinking blocks rather than text, so
|
|
557
|
-
a long tool-calling turn can look silent. The provider adds
|
|
558
|
-
`thinking-display-updates-2026-08-18` beta header automatically:
|
|
609
|
+
Use `display: 'updates'` with `claude-sonnet-5-5`, `claude-opus-5-5`, or
|
|
610
|
+
`claude-fable-5-1` to stream thinking summaries between tool calls. These models
|
|
611
|
+
return progress notes between tool calls as thinking blocks rather than text, so
|
|
612
|
+
without this setting a long tool-calling turn can look silent. The provider adds
|
|
613
|
+
the required `thinking-display-updates-2026-08-18` beta header automatically:
|
|
559
614
|
|
|
560
615
|
```ts highlight="12-16"
|
|
561
616
|
import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
|
|
@@ -580,11 +635,13 @@ const result = streamText({
|
|
|
580
635
|
|
|
581
636
|
##### Thinking Binding Controls
|
|
582
637
|
|
|
583
|
-
Fable 5.1 can recover from a thinking-block prefix
|
|
584
|
-
mismatched block. Set
|
|
585
|
-
set it to `error` to
|
|
586
|
-
|
|
587
|
-
thinking.
|
|
638
|
+
Fable 5.1, Opus 5.5, and Sonnet 5.5 can recover from a thinking-block prefix
|
|
639
|
+
mismatch by dropping the mismatched block. Set
|
|
640
|
+
`blockBinding.prefixMismatchBehavior` to `drop_block`, or set it to `error` to
|
|
641
|
+
reject the request. You can provide block binding by itself to preserve the
|
|
642
|
+
model's default thinking mode, or combine it with adaptive thinking. Block
|
|
643
|
+
binding is not available with `between_tools` thinking; keep the message
|
|
644
|
+
history append-only instead.
|
|
588
645
|
|
|
589
646
|
```ts highlight="7-11"
|
|
590
647
|
const result = await generateText({
|
|
@@ -930,7 +987,7 @@ import { generateText } from 'ai';
|
|
|
930
987
|
const errorMessage = '... long error message ...';
|
|
931
988
|
|
|
932
989
|
const result = await generateText({
|
|
933
|
-
model: anthropic('claude-sonnet-5'),
|
|
990
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
934
991
|
messages: [
|
|
935
992
|
{
|
|
936
993
|
role: 'user',
|
|
@@ -964,7 +1021,7 @@ You can also use cache control on system messages by providing multiple system m
|
|
|
964
1021
|
|
|
965
1022
|
```ts highlight="3,7-9"
|
|
966
1023
|
const result = await generateText({
|
|
967
|
-
model: anthropic('claude-sonnet-5'),
|
|
1024
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
968
1025
|
messages: [
|
|
969
1026
|
{
|
|
970
1027
|
role: 'system',
|
|
@@ -1206,19 +1263,20 @@ const computerTool = anthropic.tools.computer_20251124({
|
|
|
1206
1263
|
```
|
|
1207
1264
|
|
|
1208
1265
|
<Note>
|
|
1209
|
-
Use `computerToolset_20260801` for Claude Opus 5.5 (required),
|
|
1210
|
-
5, Fable 5, Fable 5.1, and Opus 4.8. Use `computer_20251124`
|
|
1211
|
-
4.5 through Opus 4.7, which support the zoom action. Use
|
|
1212
|
-
for Claude Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus
|
|
1266
|
+
Use `computerToolset_20260801` for Claude Sonnet 5.5 and Opus 5.5 (required),
|
|
1267
|
+
Opus 5, Sonnet 5, Fable 5, Fable 5.1, and Opus 4.8. Use `computer_20251124`
|
|
1268
|
+
for Claude Opus 4.5 through Opus 4.7, which support the zoom action. Use
|
|
1269
|
+
`computer_20250124` for Claude Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus
|
|
1270
|
+
4, and Sonnet 3.7.
|
|
1213
1271
|
</Note>
|
|
1214
1272
|
|
|
1215
1273
|
#### Computer Toolset
|
|
1216
1274
|
|
|
1217
1275
|
Newer models use the computer toolset instead of a versioned computer tool.
|
|
1218
|
-
`claude-opus-5-5`
|
|
1219
|
-
older `computer_*` tool types with a 400. The toolset
|
|
1220
|
-
header and has no display size parameters: coordinates
|
|
1221
|
-
space of the screenshots you return. Zoom is enabled by default, and Claude can
|
|
1276
|
+
`claude-sonnet-5-5` and `claude-opus-5-5` accept computer use only through the
|
|
1277
|
+
toolset and reject the older `computer_*` tool types with a 400. The toolset
|
|
1278
|
+
does not require a beta header and has no display size parameters: coordinates
|
|
1279
|
+
are always in the pixel space of the screenshots you return. Zoom is enabled by default, and Claude can
|
|
1222
1280
|
return several actions in one turn, each as its own tool call.
|
|
1223
1281
|
|
|
1224
1282
|
The API returns each action as a separate `tool_use` block with
|
|
@@ -1478,7 +1536,7 @@ import { generateText, tool } from 'ai';
|
|
|
1478
1536
|
import { z } from 'zod';
|
|
1479
1537
|
|
|
1480
1538
|
const result = await generateText({
|
|
1481
|
-
model: anthropic('claude-sonnet-5'),
|
|
1539
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
1482
1540
|
prompt: 'What is the weather in San Francisco?',
|
|
1483
1541
|
tools: {
|
|
1484
1542
|
toolSearch: anthropic.tools.toolSearchBm25_20251119(),
|
|
@@ -1508,7 +1566,7 @@ For more precise tool matching, you can use the regex variant:
|
|
|
1508
1566
|
|
|
1509
1567
|
```ts
|
|
1510
1568
|
const result = await generateText({
|
|
1511
|
-
model: anthropic('claude-sonnet-5'),
|
|
1569
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
1512
1570
|
prompt: 'Get the weather data',
|
|
1513
1571
|
tools: {
|
|
1514
1572
|
toolSearch: anthropic.tools.toolSearchRegex_20251119(),
|
|
@@ -1529,7 +1587,7 @@ import { generateText, tool } from 'ai';
|
|
|
1529
1587
|
import { z } from 'zod';
|
|
1530
1588
|
|
|
1531
1589
|
const result = await generateText({
|
|
1532
|
-
model: anthropic('claude-sonnet-5'),
|
|
1590
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
1533
1591
|
prompt: 'What is the weather in San Francisco?',
|
|
1534
1592
|
tools: {
|
|
1535
1593
|
// Custom search tool
|
|
@@ -1572,10 +1630,10 @@ This sends `tool_reference` blocks to Anthropic, which loads the corresponding d
|
|
|
1572
1630
|
|
|
1573
1631
|
### Mid-Conversation System Controls
|
|
1574
1632
|
|
|
1575
|
-
With `claude-opus-5-5
|
|
1576
|
-
change effort from the next user turn. A separate
|
|
1577
|
-
can provide a turn-scoped reminder with
|
|
1578
|
-
applies until the next user message. Keep the reminder after a user turn and
|
|
1633
|
+
With `claude-sonnet-5-5`, `claude-opus-5-5`, and `claude-fable-5-1`, use an
|
|
1634
|
+
empty system message to change effort from the next user turn. A separate
|
|
1635
|
+
system message containing text can provide a turn-scoped reminder with
|
|
1636
|
+
`clearAt: 'next_user_message'`: its text applies until the next user message. Keep the reminder after a user turn and
|
|
1579
1637
|
before an assistant turn, or at the end of the messages array.
|
|
1580
1638
|
The provider adds the required
|
|
1581
1639
|
`mid-conversation-system-clear-at-2026-08-21` and
|
|
@@ -1711,7 +1769,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
|
|
|
1711
1769
|
import { generateText } from 'ai';
|
|
1712
1770
|
|
|
1713
1771
|
const result = await generateText({
|
|
1714
|
-
model: anthropic('claude-sonnet-5'),
|
|
1772
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
1715
1773
|
prompt: `Call the echo tool with "hello world". what does it respond with back?`,
|
|
1716
1774
|
providerOptions: {
|
|
1717
1775
|
anthropic: {
|
|
@@ -1993,6 +2051,18 @@ In this flow:
|
|
|
1993
2051
|
`code_execution_20260120` or `code_execution_20250825` tool.
|
|
1994
2052
|
</Note>
|
|
1995
2053
|
|
|
2054
|
+
#### Pruning Programmatic Tool History
|
|
2055
|
+
|
|
2056
|
+
When pruning removes a code execution call but keeps a tool call that references
|
|
2057
|
+
it through `caller.toolId`, the provider omits the dangling caller metadata from
|
|
2058
|
+
history before a subsequent user message and emits a warning. The retained tool
|
|
2059
|
+
calls and results are still sent to Anthropic; the removed code execution history
|
|
2060
|
+
is not restored.
|
|
2061
|
+
|
|
2062
|
+
Tool-result messages do not end a turn. Caller metadata in an active tool
|
|
2063
|
+
continuation is preserved, so keep the source code execution call when returning
|
|
2064
|
+
programmatic tool results.
|
|
2065
|
+
|
|
1996
2066
|
#### Container Persistence
|
|
1997
2067
|
|
|
1998
2068
|
When using programmatic tool calling across multiple steps, you need to preserve the container ID between steps using `prepareStep`. You can use the `forwardAnthropicContainerIdFromLastStep` helper function to do this automatically. The container ID is available in `providerMetadata.anthropic.container.id` after each step completes.
|
|
@@ -2082,7 +2152,7 @@ Option 1: URL-based PDF document
|
|
|
2082
2152
|
|
|
2083
2153
|
```ts
|
|
2084
2154
|
const result = await generateText({
|
|
2085
|
-
model: anthropic('claude-sonnet-5'),
|
|
2155
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
2086
2156
|
messages: [
|
|
2087
2157
|
{
|
|
2088
2158
|
role: 'user',
|
|
@@ -2108,7 +2178,7 @@ Option 2: Base64-encoded PDF document
|
|
|
2108
2178
|
|
|
2109
2179
|
```ts
|
|
2110
2180
|
const result = await generateText({
|
|
2111
|
-
model: anthropic('claude-sonnet-5'),
|
|
2181
|
+
model: anthropic('claude-sonnet-5-5'),
|
|
2112
2182
|
messages: [
|
|
2113
2183
|
{
|
|
2114
2184
|
role: 'user',
|
|
@@ -2139,6 +2209,7 @@ and the `mediaType` should be set to `'application/pdf'`.
|
|
|
2139
2209
|
| ------------------- | ----------- | ----------------- | ---------- | ------------ | ---------- | ----------- | ---------- |
|
|
2140
2210
|
| `claude-opus-5-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
2141
2211
|
| `claude-opus-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
2212
|
+
| `claude-sonnet-5-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
2142
2213
|
| `claude-sonnet-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
2143
2214
|
| `claude-fable-5-1` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
2144
2215
|
| `claude-fable-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ export type AnthropicModelId =
|
|
|
24
24
|
| 'claude-fable-5'
|
|
25
25
|
| 'claude-fable-5-1'
|
|
26
26
|
| 'claude-sonnet-5'
|
|
27
|
+
| 'claude-sonnet-5-5'
|
|
27
28
|
| (string & {});
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -150,6 +151,9 @@ export const anthropicLanguageModelOptions = z.object({
|
|
|
150
151
|
* `claude-fable-5-1`) reject `enabled` and `disabled`. For those models the
|
|
151
152
|
* provider drops the unsupported setting, emits a warning, and sends an
|
|
152
153
|
* adaptive thinking request. Use `effort` to control how much they think.
|
|
154
|
+
*
|
|
155
|
+
* `claude-sonnet-5-5` supports `between_tools`, its lowest thinking setting,
|
|
156
|
+
* and the provider uses it in place of `disabled` for that model.
|
|
153
157
|
*/
|
|
154
158
|
thinking: z
|
|
155
159
|
.union([
|
|
@@ -182,6 +186,14 @@ export const anthropicLanguageModelOptions = z.object({
|
|
|
182
186
|
z.object({
|
|
183
187
|
type: z.literal('disabled'),
|
|
184
188
|
}),
|
|
189
|
+
z.object({
|
|
190
|
+
/**
|
|
191
|
+
* for `claude-sonnet-5-5`: no upfront thinking, but progress notes
|
|
192
|
+
* between tool calls are returned as summarized thinking blocks.
|
|
193
|
+
* Only supported at `low`, `medium`, and `high` effort.
|
|
194
|
+
*/
|
|
195
|
+
type: z.literal('between_tools'),
|
|
196
|
+
}),
|
|
185
197
|
]),
|
|
186
198
|
z.object({
|
|
187
199
|
type: z.never().optional(),
|
|
@@ -407,6 +407,7 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
407
407
|
rejectsThinkingDisabledAboveHighEffort,
|
|
408
408
|
rejectsThinkingDisabled,
|
|
409
409
|
rejectsForcedToolUse,
|
|
410
|
+
supportsBetweenToolsThinking,
|
|
410
411
|
isKnownModel,
|
|
411
412
|
} = getModelCapabilities(modelId);
|
|
412
413
|
|
|
@@ -573,6 +574,7 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
573
574
|
supportsAdaptiveThinking,
|
|
574
575
|
supportsXhighEffort,
|
|
575
576
|
rejectsThinkingDisabled,
|
|
577
|
+
supportsBetweenToolsThinking,
|
|
576
578
|
maxOutputTokensForModel,
|
|
577
579
|
warnings,
|
|
578
580
|
});
|
|
@@ -595,7 +597,16 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
595
597
|
if (rejectsThinkingDisabled && anthropicOptions?.thinking != null) {
|
|
596
598
|
const thinking = anthropicOptions.thinking;
|
|
597
599
|
|
|
598
|
-
if (thinking.type === 'disabled') {
|
|
600
|
+
if (thinking.type === 'disabled' && supportsBetweenToolsThinking) {
|
|
601
|
+
warnings.push({
|
|
602
|
+
type: 'unsupported',
|
|
603
|
+
feature: 'providerOptions.anthropic.thinking',
|
|
604
|
+
details:
|
|
605
|
+
`thinking cannot be disabled for ${modelId}. ` +
|
|
606
|
+
`Using 'between_tools' thinking, the lowest thinking setting, instead.`,
|
|
607
|
+
});
|
|
608
|
+
anthropicOptions.thinking = { type: 'between_tools' };
|
|
609
|
+
} else if (thinking.type === 'disabled') {
|
|
599
610
|
warnings.push({
|
|
600
611
|
type: 'unsupported',
|
|
601
612
|
feature: 'providerOptions.anthropic.thinking',
|
|
@@ -635,9 +646,28 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
635
646
|
anthropicOptions.effort = 'high';
|
|
636
647
|
}
|
|
637
648
|
|
|
649
|
+
// `between_tools` thinking is only accepted at `low`, `medium`, and
|
|
650
|
+
// `high` effort. Lower the effort to `high` to keep the minimal thinking
|
|
651
|
+
// setting instead of sending a request that the API would reject.
|
|
652
|
+
if (
|
|
653
|
+
anthropicOptions?.thinking?.type === 'between_tools' &&
|
|
654
|
+
(anthropicOptions.effort === 'xhigh' || anthropicOptions.effort === 'max')
|
|
655
|
+
) {
|
|
656
|
+
warnings.push({
|
|
657
|
+
type: 'unsupported',
|
|
658
|
+
feature: 'providerOptions.anthropic.effort',
|
|
659
|
+
details:
|
|
660
|
+
`effort '${anthropicOptions.effort}' is not supported with 'between_tools' thinking. ` +
|
|
661
|
+
`The effort has been lowered to 'high'.`,
|
|
662
|
+
});
|
|
663
|
+
anthropicOptions.effort = 'high';
|
|
664
|
+
}
|
|
665
|
+
|
|
638
666
|
const thinkingType = anthropicOptions?.thinking?.type;
|
|
639
667
|
const isThinking =
|
|
640
|
-
thinkingType === 'enabled' ||
|
|
668
|
+
thinkingType === 'enabled' ||
|
|
669
|
+
thinkingType === 'adaptive' ||
|
|
670
|
+
thinkingType === 'between_tools';
|
|
641
671
|
const thinkingBlockBinding =
|
|
642
672
|
anthropicOptions?.thinking != null &&
|
|
643
673
|
'blockBinding' in anthropicOptions.thinking
|
|
@@ -3127,9 +3157,27 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3127
3157
|
* Forced tool use (`tool_choice` `any` or a named tool) is rejected with a 400.
|
|
3128
3158
|
*/
|
|
3129
3159
|
rejectsForcedToolUse: boolean;
|
|
3160
|
+
/**
|
|
3161
|
+
* Supports `thinking.type` `between_tools`, the lowest thinking setting on
|
|
3162
|
+
* models that reject disabled thinking.
|
|
3163
|
+
*/
|
|
3164
|
+
supportsBetweenToolsThinking: boolean;
|
|
3130
3165
|
isKnownModel: boolean;
|
|
3131
3166
|
} {
|
|
3132
|
-
if (modelId.includes('claude-
|
|
3167
|
+
if (modelId.includes('claude-sonnet-5-5')) {
|
|
3168
|
+
return {
|
|
3169
|
+
maxOutputTokens: 128000,
|
|
3170
|
+
supportsStructuredOutput: true,
|
|
3171
|
+
supportsAdaptiveThinking: true,
|
|
3172
|
+
rejectsSamplingParameters: true,
|
|
3173
|
+
supportsXhighEffort: true,
|
|
3174
|
+
rejectsThinkingDisabledAboveHighEffort: true,
|
|
3175
|
+
rejectsThinkingDisabled: true,
|
|
3176
|
+
rejectsForcedToolUse: true,
|
|
3177
|
+
supportsBetweenToolsThinking: true,
|
|
3178
|
+
isKnownModel: true,
|
|
3179
|
+
};
|
|
3180
|
+
} else if (modelId.includes('claude-opus-5-5')) {
|
|
3133
3181
|
return {
|
|
3134
3182
|
maxOutputTokens: 128000,
|
|
3135
3183
|
supportsStructuredOutput: true,
|
|
@@ -3139,6 +3187,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3139
3187
|
rejectsThinkingDisabledAboveHighEffort: true,
|
|
3140
3188
|
rejectsThinkingDisabled: true,
|
|
3141
3189
|
rejectsForcedToolUse: true,
|
|
3190
|
+
supportsBetweenToolsThinking: false,
|
|
3142
3191
|
isKnownModel: true,
|
|
3143
3192
|
};
|
|
3144
3193
|
} else if (modelId.includes('claude-opus-5')) {
|
|
@@ -3151,6 +3200,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3151
3200
|
rejectsThinkingDisabledAboveHighEffort: true,
|
|
3152
3201
|
rejectsThinkingDisabled: false,
|
|
3153
3202
|
rejectsForcedToolUse: false,
|
|
3203
|
+
supportsBetweenToolsThinking: false,
|
|
3154
3204
|
isKnownModel: true,
|
|
3155
3205
|
};
|
|
3156
3206
|
} else if (modelId.includes('claude-fable-5-1')) {
|
|
@@ -3163,6 +3213,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3163
3213
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3164
3214
|
rejectsThinkingDisabled: true,
|
|
3165
3215
|
rejectsForcedToolUse: true,
|
|
3216
|
+
supportsBetweenToolsThinking: false,
|
|
3166
3217
|
isKnownModel: true,
|
|
3167
3218
|
};
|
|
3168
3219
|
} else if (modelId.includes('claude-fable-5')) {
|
|
@@ -3175,6 +3226,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3175
3226
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3176
3227
|
rejectsThinkingDisabled: true,
|
|
3177
3228
|
rejectsForcedToolUse: false,
|
|
3229
|
+
supportsBetweenToolsThinking: false,
|
|
3178
3230
|
isKnownModel: true,
|
|
3179
3231
|
};
|
|
3180
3232
|
} else if (
|
|
@@ -3191,6 +3243,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3191
3243
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3192
3244
|
rejectsThinkingDisabled: false,
|
|
3193
3245
|
rejectsForcedToolUse: false,
|
|
3246
|
+
supportsBetweenToolsThinking: false,
|
|
3194
3247
|
isKnownModel: true,
|
|
3195
3248
|
};
|
|
3196
3249
|
} else if (
|
|
@@ -3206,6 +3259,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3206
3259
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3207
3260
|
rejectsThinkingDisabled: false,
|
|
3208
3261
|
rejectsForcedToolUse: false,
|
|
3262
|
+
supportsBetweenToolsThinking: false,
|
|
3209
3263
|
isKnownModel: true,
|
|
3210
3264
|
};
|
|
3211
3265
|
} else if (
|
|
@@ -3222,6 +3276,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3222
3276
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3223
3277
|
rejectsThinkingDisabled: false,
|
|
3224
3278
|
rejectsForcedToolUse: false,
|
|
3279
|
+
supportsBetweenToolsThinking: false,
|
|
3225
3280
|
isKnownModel: true,
|
|
3226
3281
|
};
|
|
3227
3282
|
} else if (modelId.includes('claude-opus-4-1')) {
|
|
@@ -3234,6 +3289,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3234
3289
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3235
3290
|
rejectsThinkingDisabled: false,
|
|
3236
3291
|
rejectsForcedToolUse: false,
|
|
3292
|
+
supportsBetweenToolsThinking: false,
|
|
3237
3293
|
isKnownModel: true,
|
|
3238
3294
|
};
|
|
3239
3295
|
} else if (/claude-sonnet-4(?:-|@)/.test(modelId)) {
|
|
@@ -3246,6 +3302,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3246
3302
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3247
3303
|
rejectsThinkingDisabled: false,
|
|
3248
3304
|
rejectsForcedToolUse: false,
|
|
3305
|
+
supportsBetweenToolsThinking: false,
|
|
3249
3306
|
isKnownModel: true,
|
|
3250
3307
|
};
|
|
3251
3308
|
} else if (/claude-opus-4(?:-|@)/.test(modelId)) {
|
|
@@ -3258,6 +3315,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3258
3315
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3259
3316
|
rejectsThinkingDisabled: false,
|
|
3260
3317
|
rejectsForcedToolUse: false,
|
|
3318
|
+
supportsBetweenToolsThinking: false,
|
|
3261
3319
|
isKnownModel: true,
|
|
3262
3320
|
};
|
|
3263
3321
|
} else if (modelId.includes('claude-3-haiku')) {
|
|
@@ -3270,6 +3328,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3270
3328
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3271
3329
|
rejectsThinkingDisabled: false,
|
|
3272
3330
|
rejectsForcedToolUse: false,
|
|
3331
|
+
supportsBetweenToolsThinking: false,
|
|
3273
3332
|
isKnownModel: true,
|
|
3274
3333
|
};
|
|
3275
3334
|
} else if (
|
|
@@ -3284,6 +3343,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3284
3343
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3285
3344
|
rejectsThinkingDisabled: false,
|
|
3286
3345
|
rejectsForcedToolUse: false,
|
|
3346
|
+
supportsBetweenToolsThinking: false,
|
|
3287
3347
|
isKnownModel: false,
|
|
3288
3348
|
};
|
|
3289
3349
|
} else if (modelId.includes('claude-')) {
|
|
@@ -3299,6 +3359,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3299
3359
|
rejectsThinkingDisabledAboveHighEffort: true,
|
|
3300
3360
|
rejectsThinkingDisabled: false,
|
|
3301
3361
|
rejectsForcedToolUse: false,
|
|
3362
|
+
supportsBetweenToolsThinking: false,
|
|
3302
3363
|
isKnownModel: false,
|
|
3303
3364
|
};
|
|
3304
3365
|
} else {
|
|
@@ -3313,6 +3374,7 @@ export function getModelCapabilities(modelId: string): {
|
|
|
3313
3374
|
rejectsThinkingDisabledAboveHighEffort: false,
|
|
3314
3375
|
rejectsThinkingDisabled: false,
|
|
3315
3376
|
rejectsForcedToolUse: false,
|
|
3377
|
+
supportsBetweenToolsThinking: false,
|
|
3316
3378
|
isKnownModel: false,
|
|
3317
3379
|
};
|
|
3318
3380
|
}
|
|
@@ -3356,6 +3418,7 @@ function resolveAnthropicReasoningConfig({
|
|
|
3356
3418
|
supportsAdaptiveThinking,
|
|
3357
3419
|
supportsXhighEffort,
|
|
3358
3420
|
rejectsThinkingDisabled,
|
|
3421
|
+
supportsBetweenToolsThinking,
|
|
3359
3422
|
maxOutputTokensForModel,
|
|
3360
3423
|
warnings,
|
|
3361
3424
|
}: {
|
|
@@ -3364,6 +3427,7 @@ function resolveAnthropicReasoningConfig({
|
|
|
3364
3427
|
supportsAdaptiveThinking: boolean;
|
|
3365
3428
|
supportsXhighEffort: boolean;
|
|
3366
3429
|
rejectsThinkingDisabled: boolean;
|
|
3430
|
+
supportsBetweenToolsThinking: boolean;
|
|
3367
3431
|
maxOutputTokensForModel: number;
|
|
3368
3432
|
warnings: SharedV4Warning[];
|
|
3369
3433
|
}): Pick<AnthropicLanguageModelOptions, 'thinking' | 'effort'> | undefined {
|
|
@@ -3372,6 +3436,12 @@ function resolveAnthropicReasoningConfig({
|
|
|
3372
3436
|
}
|
|
3373
3437
|
|
|
3374
3438
|
if (reasoning === 'none') {
|
|
3439
|
+
// `between_tools` is the lowest thinking setting on models that support
|
|
3440
|
+
// it: no upfront thinking, only short progress notes between tool calls.
|
|
3441
|
+
if (supportsBetweenToolsThinking) {
|
|
3442
|
+
return { thinking: { type: 'between_tools' } };
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3375
3445
|
// Models that always run adaptive thinking cannot disable it. Use low
|
|
3376
3446
|
// effort to keep thinking short instead of sending a request that the
|
|
3377
3447
|
// API would reject.
|
|
@@ -105,6 +105,7 @@ export async function convertToAnthropicPrompt({
|
|
|
105
105
|
|
|
106
106
|
let system: AnthropicPrompt['system'] = undefined;
|
|
107
107
|
const messages: AnthropicPrompt['messages'] = [];
|
|
108
|
+
let lastUserMessageIndex = -1;
|
|
108
109
|
|
|
109
110
|
async function shouldEnableCitations(
|
|
110
111
|
providerMetadata: SharedV4ProviderMetadata | undefined,
|
|
@@ -291,6 +292,10 @@ export async function convertToAnthropicPrompt({
|
|
|
291
292
|
const { role, content } = message;
|
|
292
293
|
switch (role) {
|
|
293
294
|
case 'user': {
|
|
295
|
+
if (content.length > 0) {
|
|
296
|
+
lastUserMessageIndex = messages.length;
|
|
297
|
+
}
|
|
298
|
+
|
|
294
299
|
for (let j = 0; j < content.length; j++) {
|
|
295
300
|
const part = content[j];
|
|
296
301
|
|
|
@@ -1427,6 +1432,55 @@ export async function convertToAnthropicPrompt({
|
|
|
1427
1432
|
}
|
|
1428
1433
|
}
|
|
1429
1434
|
|
|
1435
|
+
// Pruning can remove a code execution call while retaining tool calls that
|
|
1436
|
+
// reference it. Check the converted blocks, since unsupported source calls
|
|
1437
|
+
// may also have been omitted during conversion.
|
|
1438
|
+
const codeExecutionToolCallIds = new Set<string>();
|
|
1439
|
+
for (const message of messages) {
|
|
1440
|
+
if (message.role !== 'assistant') {
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
for (const part of message.content) {
|
|
1444
|
+
if (part.type === 'server_tool_use' && part.name === 'code_execution') {
|
|
1445
|
+
codeExecutionToolCallIds.add(part.id);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// Only normalize history before a subsequent user message. Tool-result
|
|
1451
|
+
// messages do not end a turn: their caller metadata must remain intact so
|
|
1452
|
+
// Anthropic can resume an active code execution.
|
|
1453
|
+
const warnedToolCallIds = new Set<string>();
|
|
1454
|
+
for (let i = 0; i < lastUserMessageIndex; i++) {
|
|
1455
|
+
const message = messages[i];
|
|
1456
|
+
if (message.role !== 'assistant') {
|
|
1457
|
+
continue;
|
|
1458
|
+
}
|
|
1459
|
+
for (const part of message.content) {
|
|
1460
|
+
if (!('caller' in part)) {
|
|
1461
|
+
continue;
|
|
1462
|
+
}
|
|
1463
|
+
const caller = part.caller;
|
|
1464
|
+
if (
|
|
1465
|
+
caller == null ||
|
|
1466
|
+
caller.type === 'direct' ||
|
|
1467
|
+
codeExecutionToolCallIds.has(caller.tool_id)
|
|
1468
|
+
) {
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
const toolCallId = 'id' in part ? part.id : part.tool_use_id;
|
|
1473
|
+
delete part.caller;
|
|
1474
|
+
if (!warnedToolCallIds.has(toolCallId)) {
|
|
1475
|
+
warnedToolCallIds.add(toolCallId);
|
|
1476
|
+
warnings.push({
|
|
1477
|
+
type: 'other',
|
|
1478
|
+
message: `Omitted caller metadata for tool ${toolCallId} because source code execution tool ${caller.tool_id} is missing from the conversation history.`,
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1430
1484
|
return {
|
|
1431
1485
|
prompt: { system, messages },
|
|
1432
1486
|
betas,
|