@ai-sdk/anthropic 3.0.124 → 3.0.125

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.
@@ -189,9 +189,10 @@ const result = streamText({
189
189
  });
190
190
  ```
191
191
 
192
- For `claude-opus-5-5` and `claude-fable-5-1`, the default `"auto"` mode uses
193
- native structured outputs through `output_config.format`. These models reject
194
- forced tool use, so the `"jsonTool"` mode cannot be used with them. If you
192
+ For `claude-sonnet-5-5`, `claude-opus-5-5`, and `claude-fable-5-1`, the
193
+ default `"auto"` mode uses native structured outputs through
194
+ `output_config.format`. These models reject forced tool use, so the
195
+ `"jsonTool"` mode cannot be used with them. If you
195
196
  request `"jsonTool"` anyway, the provider falls back to `"outputFormat"` and
196
197
  emits a warning. Likewise, a `required` or named `toolChoice` is downgraded to
197
198
  `auto` with a warning; instruct the model to use the tool in your prompt and
@@ -199,7 +200,7 @@ verify that a tool call was made.
199
200
 
200
201
  ### Effort
201
202
 
202
- 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.
203
+ 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.
203
204
 
204
205
  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.
205
206
 
@@ -210,6 +211,16 @@ carrying over the setting you used on `claude-opus-5`. Set `maxOutputTokens`
210
211
  with room for thinking as well as the reply; thinking counts toward the limit
211
212
  even when its content is not returned.
212
213
 
214
+ On `claude-sonnet-5-5`, thinking cannot be turned off either, and the API
215
+ default effort is `high`. Its effort levels are not equivalent to those of
216
+ `claude-sonnet-5`, so test several levels rather than carrying over your
217
+ current setting. For agentic coding and other multi-step tool use, start at
218
+ `medium` for well-specified tasks and move to `high` for harder ones. The
219
+ lowest thinking setting, [`between_tools`](#between-tools-thinking), is only
220
+ accepted at `low`, `medium`, and `high` effort. When you combine it with
221
+ `effort: 'xhigh'` or `effort: 'max'`, the AI SDK lowers the effort to `high`
222
+ and emits a warning.
223
+
213
224
  ```ts highlight="8-10"
214
225
  import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
215
226
  import { generateText } from 'ai';
@@ -314,6 +325,8 @@ The `inferenceGeo` option accepts `'us'` (US-only infrastructure) or `'global'`
314
325
 
315
326
  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.
316
327
 
328
+ 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.
329
+
317
330
  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`.
318
331
 
319
332
  A classifier block looks like this:
@@ -431,14 +444,20 @@ const { text } = await generateText({
431
444
 
432
445
  ##### Adaptive-Only Models
433
446
 
434
- `claude-opus-5-5`, `claude-fable-5`, and `claude-fable-5-1` always run adaptive
435
- thinking. The API rejects `thinking: { type: 'disabled' }` and budget-based
436
- `thinking: { type: 'enabled' }` for these models. To keep existing code working,
437
- the provider:
447
+ `claude-sonnet-5-5`, `claude-opus-5-5`, `claude-fable-5`, and
448
+ `claude-fable-5-1` always run adaptive thinking. The API rejects
449
+ `thinking: { type: 'disabled' }` and budget-based
450
+ `thinking: { type: 'enabled' }` for these models. To keep existing code
451
+ working, the provider:
438
452
 
439
453
  - removes `thinking: { type: 'disabled' }` and emits a warning,
440
454
  - converts `thinking: { type: 'enabled', budgetTokens }` to `{ type: 'adaptive' }` and emits a warning.
441
455
 
456
+ On `claude-sonnet-5-5`, which supports
457
+ [`between_tools` thinking](#between-tools-thinking), the provider instead
458
+ replaces `thinking: { type: 'disabled' }` with `thinking: { type: 'between_tools' }`
459
+ and emits a warning.
460
+
442
461
  Use `effort` to control how much these models think. On `claude-opus-5-5`, set
443
462
  `effort: 'low'` when time to first token matters, and move to `medium` if
444
463
  quality drops:
@@ -463,6 +482,42 @@ const { text } = await generateText({
463
482
  setting, thinking blocks are returned with empty text.
464
483
  </Note>
465
484
 
485
+ ##### Between-Tools Thinking
486
+
487
+ `claude-sonnet-5-5` supports `thinking: { type: 'between_tools' }`, its lowest
488
+ thinking setting. The model does no upfront thinking, but the short progress
489
+ notes it writes between tool calls are still returned as thinking blocks, each
490
+ with a short summary. They are available as reasoning parts and are sent back
491
+ unchanged on the next step. `between_tools` accepts no other thinking options
492
+ (such as `display` or `blockBinding`) and is only accepted at `low`, `medium`,
493
+ and `high` effort. Per-message effort changes via
494
+ [mid-conversation system messages](#mid-conversation-system-controls) are not
495
+ supported with `between_tools`.
496
+
497
+ ```ts highlight="16-17"
498
+ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
499
+ import { generateText, stepCountIs, tool } from 'ai';
500
+ import { z } from 'zod';
501
+
502
+ const { text, steps } = await generateText({
503
+ model: anthropic('claude-sonnet-5-5'),
504
+ stopWhen: stepCountIs(5),
505
+ tools: {
506
+ weather: tool({
507
+ inputSchema: z.object({ city: z.string() }),
508
+ execute: async ({ city }) => ({ city, temperature: 72 }),
509
+ }),
510
+ },
511
+ providerOptions: {
512
+ anthropic: {
513
+ thinking: { type: 'between_tools' },
514
+ effort: 'low',
515
+ } satisfies AnthropicLanguageModelOptions,
516
+ },
517
+ prompt: 'Compare the weather in San Francisco and New York.',
518
+ });
519
+ ```
520
+
466
521
  ##### Thinking Display (Opus 4.7+)
467
522
 
468
523
  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'`:
@@ -490,11 +545,11 @@ console.log(text);
490
545
 
491
546
  ##### Thinking Updates
492
547
 
493
- Use `display: 'updates'` with `claude-opus-5-5` or `claude-fable-5-1` to stream
494
- thinking summaries between tool calls. These models return progress notes
495
- between tool calls as thinking blocks rather than text, so without this setting
496
- a long tool-calling turn can look silent. The provider adds the required
497
- `thinking-display-updates-2026-08-18` beta header automatically:
548
+ Use `display: 'updates'` with `claude-sonnet-5-5`, `claude-opus-5-5`, or
549
+ `claude-fable-5-1` to stream thinking summaries between tool calls. These models
550
+ return progress notes between tool calls as thinking blocks rather than text, so
551
+ without this setting a long tool-calling turn can look silent. The provider adds
552
+ the required `thinking-display-updates-2026-08-18` beta header automatically:
498
553
 
499
554
  ```ts highlight="12-16"
500
555
  import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
@@ -519,11 +574,13 @@ const result = streamText({
519
574
 
520
575
  ##### Thinking Block Binding
521
576
 
522
- Fable 5.1 can recover from a thinking-block prefix mismatch by dropping the
523
- mismatched block. Set `blockBinding.prefixMismatchBehavior` to `drop_block`, or
524
- set it to `error` to reject the request. You can provide block binding by itself
525
- to preserve the model's default thinking mode, or combine it with adaptive
526
- thinking.
577
+ Fable 5.1, Opus 5.5, and Sonnet 5.5 can recover from a thinking-block prefix
578
+ mismatch by dropping the mismatched block. Set
579
+ `blockBinding.prefixMismatchBehavior` to `drop_block`, or set it to `error` to
580
+ reject the request. You can provide block binding by itself to preserve the
581
+ model's default thinking mode, or combine it with adaptive thinking. Block
582
+ binding is not available with `between_tools` thinking; keep the message
583
+ history append-only instead.
527
584
 
528
585
  ```ts highlight="7-11"
529
586
  const result = await generateText({
@@ -1038,19 +1095,20 @@ const computerTool = anthropic.tools.computer_20251124({
1038
1095
  ```
1039
1096
 
1040
1097
  <Note>
1041
- Use `computerToolset_20260801` for Claude Opus 5.5 (required), Opus 5, Sonnet
1042
- 5, Fable 5, Fable 5.1, and Opus 4.8. Use `computer_20251124` for Claude Opus
1043
- 4.5 through Opus 4.7, which support the zoom action. Use `computer_20250124`
1044
- for Claude Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus 4, and Sonnet 3.7.
1098
+ Use `computerToolset_20260801` for Claude Sonnet 5.5 and Opus 5.5 (required),
1099
+ Opus 5, Sonnet 5, Fable 5, Fable 5.1, and Opus 4.8. Use `computer_20251124`
1100
+ for Claude Opus 4.5 through Opus 4.7, which support the zoom action. Use
1101
+ `computer_20250124` for Claude Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4, Opus
1102
+ 4, and Sonnet 3.7.
1045
1103
  </Note>
1046
1104
 
1047
1105
  #### Computer Toolset
1048
1106
 
1049
1107
  Newer models use the computer toolset instead of a versioned computer tool.
1050
- `claude-opus-5-5` accepts computer use only through the toolset and rejects the
1051
- older `computer_*` tool types with a 400. The toolset does not require a beta
1052
- header and has no display size parameters: coordinates are always in the pixel
1053
- space of the screenshots you return. Zoom is enabled by default, and Claude can
1108
+ `claude-sonnet-5-5` and `claude-opus-5-5` accept computer use only through the
1109
+ toolset and reject the older `computer_*` tool types with a 400. The toolset
1110
+ does not require a beta header and has no display size parameters: coordinates
1111
+ are always in the pixel space of the screenshots you return. Zoom is enabled by default, and Claude can
1054
1112
  return several actions in one turn, each as its own tool call.
1055
1113
 
1056
1114
  The API returns each action as a separate `tool_use` block with
@@ -1376,10 +1434,10 @@ This sends `tool_reference` blocks to Anthropic, which loads the corresponding d
1376
1434
 
1377
1435
  ### Mid-Conversation System Controls
1378
1436
 
1379
- With `claude-opus-5-5` and `claude-fable-5-1`, use an empty system message to
1380
- change effort from the next user turn. A separate system message containing text
1381
- can provide a turn-scoped reminder with `clearAt: 'next_user_message'`: its text
1382
- applies until the next user message. Keep the reminder after a user turn and
1437
+ With `claude-sonnet-5-5`, `claude-opus-5-5`, and `claude-fable-5-1`, use an
1438
+ empty system message to change effort from the next user turn. A separate
1439
+ system message containing text can provide a turn-scoped reminder with
1440
+ `clearAt: 'next_user_message'`: its text applies until the next user message. Keep the reminder after a user turn and
1383
1441
  before an assistant turn, or at the end of the messages array.
1384
1442
  The provider adds the required
1385
1443
  `mid-conversation-system-clear-at-2026-08-21` and
@@ -1742,6 +1800,18 @@ In this flow:
1742
1800
  `code_execution_20260120` or `code_execution_20250825` tool.
1743
1801
  </Note>
1744
1802
 
1803
+ #### Pruning Programmatic Tool History
1804
+
1805
+ When pruning removes a code execution call but keeps a tool call that references
1806
+ it through `caller.toolId`, the provider omits the dangling caller metadata from
1807
+ history before a subsequent user message and emits a warning. The retained tool
1808
+ calls and results are still sent to Anthropic; the removed code execution history
1809
+ is not restored.
1810
+
1811
+ Tool-result messages do not end a turn. Caller metadata in an active tool
1812
+ continuation is preserved, so keep the source code execution call when returning
1813
+ programmatic tool results.
1814
+
1745
1815
  #### Container Persistence
1746
1816
 
1747
1817
  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.
@@ -1889,6 +1959,7 @@ and the `mediaType` should be set to `'application/pdf'`.
1889
1959
  | `claude-fable-5-1` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1890
1960
  | `claude-opus-5-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1891
1961
  | `claude-opus-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1962
+ | `claude-sonnet-5-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1892
1963
  | `claude-sonnet-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1893
1964
  | `claude-fable-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1894
1965
  | `claude-opus-4-8` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/anthropic",
3
- "version": "3.0.124",
3
+ "version": "3.0.125",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -341,6 +341,7 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
341
341
  rejectsThinkingDisabledAboveHighEffort,
342
342
  rejectsThinkingDisabled,
343
343
  rejectsForcedToolUse,
344
+ supportsBetweenToolsThinking,
344
345
  isKnownModel,
345
346
  } = getModelCapabilities(this.modelId);
346
347
 
@@ -495,7 +496,16 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
495
496
  const requestedType =
496
497
  'type' in requestedThinking ? requestedThinking.type : undefined;
497
498
 
498
- if (requestedType === 'disabled') {
499
+ if (requestedType === 'disabled' && supportsBetweenToolsThinking) {
500
+ warnings.push({
501
+ type: 'unsupported',
502
+ feature: 'providerOptions.anthropic.thinking',
503
+ details:
504
+ `thinking cannot be disabled for ${this.modelId}. ` +
505
+ `Using 'between_tools' thinking, the lowest thinking setting, instead.`,
506
+ });
507
+ anthropicOptions.thinking = { type: 'between_tools' };
508
+ } else if (requestedType === 'disabled') {
499
509
  warnings.push({
500
510
  type: 'unsupported',
501
511
  feature: 'providerOptions.anthropic.thinking',
@@ -539,8 +549,27 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
539
549
  anthropicOptions.effort = 'high';
540
550
  }
541
551
 
552
+ // `between_tools` thinking is only accepted at `low`, `medium`, and
553
+ // `high` effort. Lower the effort to `high` to keep the minimal thinking
554
+ // setting instead of sending a request that the API would reject.
555
+ if (
556
+ thinkingType === 'between_tools' &&
557
+ (anthropicOptions.effort === 'xhigh' || anthropicOptions.effort === 'max')
558
+ ) {
559
+ warnings.push({
560
+ type: 'unsupported',
561
+ feature: 'providerOptions.anthropic.effort',
562
+ details:
563
+ `effort '${anthropicOptions.effort}' is not supported with 'between_tools' thinking. ` +
564
+ `The effort has been lowered to 'high'.`,
565
+ });
566
+ anthropicOptions.effort = 'high';
567
+ }
568
+
542
569
  const isThinking =
543
- thinkingType === 'enabled' || thinkingType === 'adaptive';
570
+ thinkingType === 'enabled' ||
571
+ thinkingType === 'adaptive' ||
572
+ thinkingType === 'between_tools';
544
573
  // `disabled` must still be forwarded to the API: some models (e.g. Sonnet 5)
545
574
  // default thinking on, so omitting it would leave thinking enabled and
546
575
  // consume the max_tokens budget.
@@ -2917,9 +2946,25 @@ export function getModelCapabilities(modelId: string): {
2917
2946
  * Forced tool use (`tool_choice` `any` or a named tool) is rejected with a 400.
2918
2947
  */
2919
2948
  rejectsForcedToolUse: boolean;
2949
+ /**
2950
+ * Supports `thinking.type` `between_tools`, the lowest thinking setting on
2951
+ * models that reject disabled thinking.
2952
+ */
2953
+ supportsBetweenToolsThinking: boolean;
2920
2954
  isKnownModel: boolean;
2921
2955
  } {
2922
- if (modelId.includes('claude-opus-5-5')) {
2956
+ if (modelId.includes('claude-sonnet-5-5')) {
2957
+ return {
2958
+ maxOutputTokens: 128000,
2959
+ supportsStructuredOutput: true,
2960
+ rejectsSamplingParameters: true,
2961
+ rejectsThinkingDisabledAboveHighEffort: true,
2962
+ rejectsThinkingDisabled: true,
2963
+ rejectsForcedToolUse: true,
2964
+ supportsBetweenToolsThinking: true,
2965
+ isKnownModel: true,
2966
+ };
2967
+ } else if (modelId.includes('claude-opus-5-5')) {
2923
2968
  return {
2924
2969
  maxOutputTokens: 128000,
2925
2970
  supportsStructuredOutput: true,
@@ -2927,6 +2972,7 @@ export function getModelCapabilities(modelId: string): {
2927
2972
  rejectsThinkingDisabledAboveHighEffort: true,
2928
2973
  rejectsThinkingDisabled: true,
2929
2974
  rejectsForcedToolUse: true,
2975
+ supportsBetweenToolsThinking: false,
2930
2976
  isKnownModel: true,
2931
2977
  };
2932
2978
  } else if (modelId.includes('claude-opus-5')) {
@@ -2937,6 +2983,7 @@ export function getModelCapabilities(modelId: string): {
2937
2983
  rejectsThinkingDisabledAboveHighEffort: true,
2938
2984
  rejectsThinkingDisabled: false,
2939
2985
  rejectsForcedToolUse: false,
2986
+ supportsBetweenToolsThinking: false,
2940
2987
  isKnownModel: true,
2941
2988
  };
2942
2989
  } else if (modelId.includes('claude-fable-5-1')) {
@@ -2947,6 +2994,7 @@ export function getModelCapabilities(modelId: string): {
2947
2994
  rejectsThinkingDisabledAboveHighEffort: false,
2948
2995
  rejectsThinkingDisabled: true,
2949
2996
  rejectsForcedToolUse: true,
2997
+ supportsBetweenToolsThinking: false,
2950
2998
  isKnownModel: true,
2951
2999
  };
2952
3000
  } else if (modelId.includes('claude-fable-5')) {
@@ -2957,6 +3005,7 @@ export function getModelCapabilities(modelId: string): {
2957
3005
  rejectsThinkingDisabledAboveHighEffort: false,
2958
3006
  rejectsThinkingDisabled: true,
2959
3007
  rejectsForcedToolUse: false,
3008
+ supportsBetweenToolsThinking: false,
2960
3009
  isKnownModel: true,
2961
3010
  };
2962
3011
  } else if (
@@ -2971,6 +3020,7 @@ export function getModelCapabilities(modelId: string): {
2971
3020
  rejectsThinkingDisabledAboveHighEffort: false,
2972
3021
  rejectsThinkingDisabled: false,
2973
3022
  rejectsForcedToolUse: false,
3023
+ supportsBetweenToolsThinking: false,
2974
3024
  isKnownModel: true,
2975
3025
  };
2976
3026
  } else if (
@@ -2984,6 +3034,7 @@ export function getModelCapabilities(modelId: string): {
2984
3034
  rejectsThinkingDisabledAboveHighEffort: false,
2985
3035
  rejectsThinkingDisabled: false,
2986
3036
  rejectsForcedToolUse: false,
3037
+ supportsBetweenToolsThinking: false,
2987
3038
  isKnownModel: true,
2988
3039
  };
2989
3040
  } else if (
@@ -2998,6 +3049,7 @@ export function getModelCapabilities(modelId: string): {
2998
3049
  rejectsThinkingDisabledAboveHighEffort: false,
2999
3050
  rejectsThinkingDisabled: false,
3000
3051
  rejectsForcedToolUse: false,
3052
+ supportsBetweenToolsThinking: false,
3001
3053
  isKnownModel: true,
3002
3054
  };
3003
3055
  } else if (modelId.includes('claude-opus-4-1')) {
@@ -3008,6 +3060,7 @@ export function getModelCapabilities(modelId: string): {
3008
3060
  rejectsThinkingDisabledAboveHighEffort: false,
3009
3061
  rejectsThinkingDisabled: false,
3010
3062
  rejectsForcedToolUse: false,
3063
+ supportsBetweenToolsThinking: false,
3011
3064
  isKnownModel: true,
3012
3065
  };
3013
3066
  } else if (modelId.includes('claude-sonnet-4-')) {
@@ -3018,6 +3071,7 @@ export function getModelCapabilities(modelId: string): {
3018
3071
  rejectsThinkingDisabledAboveHighEffort: false,
3019
3072
  rejectsThinkingDisabled: false,
3020
3073
  rejectsForcedToolUse: false,
3074
+ supportsBetweenToolsThinking: false,
3021
3075
  isKnownModel: true,
3022
3076
  };
3023
3077
  } else if (modelId.includes('claude-opus-4-')) {
@@ -3028,6 +3082,7 @@ export function getModelCapabilities(modelId: string): {
3028
3082
  rejectsThinkingDisabledAboveHighEffort: false,
3029
3083
  rejectsThinkingDisabled: false,
3030
3084
  rejectsForcedToolUse: false,
3085
+ supportsBetweenToolsThinking: false,
3031
3086
  isKnownModel: true,
3032
3087
  };
3033
3088
  } else if (modelId.includes('claude-3-haiku')) {
@@ -3038,6 +3093,7 @@ export function getModelCapabilities(modelId: string): {
3038
3093
  rejectsThinkingDisabledAboveHighEffort: false,
3039
3094
  rejectsThinkingDisabled: false,
3040
3095
  rejectsForcedToolUse: false,
3096
+ supportsBetweenToolsThinking: false,
3041
3097
  isKnownModel: true,
3042
3098
  };
3043
3099
  } else if (
@@ -3050,6 +3106,7 @@ export function getModelCapabilities(modelId: string): {
3050
3106
  rejectsThinkingDisabledAboveHighEffort: false,
3051
3107
  rejectsThinkingDisabled: false,
3052
3108
  rejectsForcedToolUse: false,
3109
+ supportsBetweenToolsThinking: false,
3053
3110
  isKnownModel: false,
3054
3111
  };
3055
3112
  } else if (modelId.includes('claude-')) {
@@ -3063,6 +3120,7 @@ export function getModelCapabilities(modelId: string): {
3063
3120
  rejectsThinkingDisabledAboveHighEffort: true,
3064
3121
  rejectsThinkingDisabled: false,
3065
3122
  rejectsForcedToolUse: false,
3123
+ supportsBetweenToolsThinking: false,
3066
3124
  isKnownModel: false,
3067
3125
  };
3068
3126
  } else {
@@ -3075,6 +3133,7 @@ export function getModelCapabilities(modelId: string): {
3075
3133
  rejectsThinkingDisabledAboveHighEffort: false,
3076
3134
  rejectsThinkingDisabled: false,
3077
3135
  rejectsForcedToolUse: false,
3136
+ supportsBetweenToolsThinking: false,
3078
3137
  isKnownModel: false,
3079
3138
  };
3080
3139
  }
@@ -24,6 +24,7 @@ export type AnthropicMessagesModelId =
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
  /**
@@ -147,6 +148,9 @@ export const anthropicLanguageModelOptions = z.object({
147
148
  * `claude-fable-5-1`) reject `enabled` and `disabled`. For those models the
148
149
  * provider drops the unsupported setting, emits a warning, and sends an
149
150
  * adaptive thinking request. Use `effort` to control how much they think.
151
+ *
152
+ * `claude-sonnet-5-5` supports `between_tools`, its lowest thinking setting,
153
+ * and the provider uses it in place of `disabled` for that model.
150
154
  */
151
155
  thinking: z
152
156
  .union([
@@ -177,6 +181,14 @@ export const anthropicLanguageModelOptions = z.object({
177
181
  z.object({
178
182
  type: z.literal('disabled'),
179
183
  }),
184
+ z.object({
185
+ /**
186
+ * for `claude-sonnet-5-5`: no upfront thinking, but progress notes
187
+ * between tool calls are returned as summarized thinking blocks.
188
+ * Only supported at `low`, `medium`, and `high` effort.
189
+ */
190
+ type: z.literal('between_tools'),
191
+ }),
180
192
  ]),
181
193
  /**
182
194
  * Configures prefix mismatch recovery without changing the model's
@@ -139,6 +139,7 @@ export async function convertToAnthropicMessagesPrompt({
139
139
 
140
140
  let system: AnthropicMessagesPrompt['system'] = undefined;
141
141
  const messages: AnthropicMessagesPrompt['messages'] = [];
142
+ let lastUserMessageIndex = -1;
142
143
 
143
144
  async function shouldEnableCitations(
144
145
  providerMetadata: SharedV3ProviderMetadata | undefined,
@@ -300,6 +301,10 @@ export async function convertToAnthropicMessagesPrompt({
300
301
  const { role, content } = message;
301
302
  switch (role) {
302
303
  case 'user': {
304
+ if (content.length > 0) {
305
+ lastUserMessageIndex = messages.length;
306
+ }
307
+
303
308
  for (let j = 0; j < content.length; j++) {
304
309
  const part = content[j];
305
310
 
@@ -1313,6 +1318,55 @@ export async function convertToAnthropicMessagesPrompt({
1313
1318
  }
1314
1319
  }
1315
1320
 
1321
+ // Pruning can remove a code execution call while retaining tool calls that
1322
+ // reference it. Check the converted blocks, since unsupported source calls
1323
+ // may also have been omitted during conversion.
1324
+ const codeExecutionToolCallIds = new Set<string>();
1325
+ for (const message of messages) {
1326
+ if (message.role !== 'assistant') {
1327
+ continue;
1328
+ }
1329
+ for (const part of message.content) {
1330
+ if (part.type === 'server_tool_use' && part.name === 'code_execution') {
1331
+ codeExecutionToolCallIds.add(part.id);
1332
+ }
1333
+ }
1334
+ }
1335
+
1336
+ // Only normalize history before a subsequent user message. Tool-result
1337
+ // messages do not end a turn: their caller metadata must remain intact so
1338
+ // Anthropic can resume an active code execution.
1339
+ const warnedToolCallIds = new Set<string>();
1340
+ for (let i = 0; i < lastUserMessageIndex; i++) {
1341
+ const message = messages[i];
1342
+ if (message.role !== 'assistant') {
1343
+ continue;
1344
+ }
1345
+ for (const part of message.content) {
1346
+ if (!('caller' in part)) {
1347
+ continue;
1348
+ }
1349
+ const caller = part.caller;
1350
+ if (
1351
+ caller == null ||
1352
+ caller.type === 'direct' ||
1353
+ codeExecutionToolCallIds.has(caller.tool_id)
1354
+ ) {
1355
+ continue;
1356
+ }
1357
+
1358
+ const toolCallId = 'id' in part ? part.id : part.tool_use_id;
1359
+ delete part.caller;
1360
+ if (!warnedToolCallIds.has(toolCallId)) {
1361
+ warnedToolCallIds.add(toolCallId);
1362
+ warnings.push({
1363
+ type: 'other',
1364
+ message: `Omitted caller metadata for tool ${toolCallId} because source code execution tool ${caller.tool_id} is missing from the conversation history.`,
1365
+ });
1366
+ }
1367
+ }
1368
+ }
1369
+
1316
1370
  return {
1317
1371
  prompt: { system, messages },
1318
1372
  betas,