@ai-sdk/anthropic 4.0.62 → 4.0.65

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.
@@ -64,18 +64,18 @@ You can use the following optional settings to customize the Anthropic provider
64
64
  ## Language Models
65
65
 
66
66
  You can create models that call the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post) using the provider instance.
67
- The first argument is the model id, e.g. `claude-3-haiku-20240307`.
67
+ The first argument is the model id, e.g. `claude-haiku-4-5`.
68
68
  Some models have multi-modal capabilities.
69
69
 
70
70
  ```ts
71
- const model = anthropic('claude-3-haiku-20240307');
71
+ const model = anthropic('claude-haiku-4-5');
72
72
  ```
73
73
 
74
74
  You can also use the following aliases for model creation:
75
75
 
76
- - `anthropic.languageModel('claude-3-haiku-20240307')` - Creates a language model
77
- - `anthropic.chat('claude-3-haiku-20240307')` - Alias for `languageModel`
78
- - `anthropic.messages('claude-3-haiku-20240307')` - Alias for `languageModel`
76
+ - `anthropic.languageModel('claude-haiku-4-5')` - Creates a language model
77
+ - `anthropic.chat('claude-haiku-4-5')` - Alias for `languageModel`
78
+ - `anthropic.messages('claude-haiku-4-5')` - Alias for `languageModel`
79
79
 
80
80
  You can use Anthropic language models to generate text with the `generateText` function:
81
81
 
@@ -84,7 +84,7 @@ import { anthropic } from '@ai-sdk/anthropic';
84
84
  import { generateText } from 'ai';
85
85
 
86
86
  const { text } = await generateText({
87
- model: anthropic('claude-3-haiku-20240307'),
87
+ model: anthropic('claude-haiku-4-5'),
88
88
  prompt: 'Write a vegetarian lasagna recipe for 4 people.',
89
89
  });
90
90
  ```
@@ -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-4-20250514'),
182
+ model: anthropic('claude-sonnet-5'),
183
183
  tools: {
184
184
  writeFile: tool({
185
185
  description: 'Write content to a file',
@@ -223,7 +223,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
223
223
  import { generateText } from 'ai';
224
224
 
225
225
  const { text, usage } = await generateText({
226
- model: anthropic('claude-opus-4-20250514'),
226
+ model: anthropic('claude-opus-5-5'),
227
227
  prompt: 'How many people will live in the world in 2040?',
228
228
  providerOptions: {
229
229
  anthropic: {
@@ -268,7 +268,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
268
268
  import { generateText } from 'ai';
269
269
 
270
270
  const { text } = await generateText({
271
- model: anthropic('claude-opus-4-8'),
271
+ model: anthropic('claude-opus-5-5'),
272
272
  prompt: 'Research the pros and cons of Rust vs Go for building CLI tools.',
273
273
  providerOptions: {
274
274
  anthropic: {
@@ -306,7 +306,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
306
306
  import { generateText } from 'ai';
307
307
 
308
308
  const { text } = await generateText({
309
- model: anthropic('claude-opus-4-6'),
309
+ model: anthropic('claude-opus-5-5'),
310
310
  prompt: 'Summarize the key points of this document.',
311
311
  providerOptions: {
312
312
  anthropic: {
@@ -351,7 +351,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
351
351
  import { generateText } from 'ai';
352
352
 
353
353
  const { text } = await generateText({
354
- model: anthropic('claude-fable-5'),
354
+ model: anthropic('claude-fable-5-1'),
355
355
  prompt: 'Explain the history of cryptography.',
356
356
  providerOptions: {
357
357
  anthropic: {
@@ -368,11 +368,11 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
368
368
  import { generateText } from 'ai';
369
369
 
370
370
  const { text } = await generateText({
371
- model: anthropic('claude-fable-5'),
371
+ model: anthropic('claude-fable-5-1'),
372
372
  prompt: 'Explain the history of cryptography.',
373
373
  providerOptions: {
374
374
  anthropic: {
375
- fallbacks: [{ model: 'claude-fable-5' }],
375
+ fallbacks: [{ model: 'claude-fable-5-1' }],
376
376
  } satisfies AnthropicLanguageModelOptions,
377
377
  },
378
378
  });
@@ -405,7 +405,7 @@ import { generateText, tool } from 'ai';
405
405
  import { z } from 'zod';
406
406
 
407
407
  const result = await generateText({
408
- model: anthropic('claude-sonnet-4-5'),
408
+ model: anthropic('claude-sonnet-5'),
409
409
  prompt: 'Use the bash tool to run: echo hello',
410
410
  tools: { bash: tool({ inputSchema: z.object({ command: z.string() }) }) },
411
411
  providerOptions: {
@@ -715,7 +715,89 @@ const result = await generateText({
715
715
  });
716
716
  ```
717
717
 
718
- #### Compaction
718
+ #### On-Demand Compaction
719
+
720
+ Use the `compaction` provider option to ask Anthropic to summarize the supplied
721
+ conversation immediately. The provider automatically adds the
722
+ `compact-2026-09-04` beta header.
723
+
724
+ ```ts highlight="10-15,21-22"
725
+ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
726
+ import { generateText, ModelMessage } from 'ai';
727
+
728
+ const history: ModelMessage[] = [
729
+ { role: 'user', content: 'Help me design a recipe application.' },
730
+ { role: 'assistant', content: 'Start with Recipe and Ingredient.' },
731
+ { role: 'user', content: 'Recipe also needs a title and servings.' },
732
+ ];
733
+
734
+ const summary = await generateText({
735
+ model: anthropic('claude-opus-5'),
736
+ messages: history,
737
+ maxOutputTokens: 4096,
738
+ providerOptions: {
739
+ anthropic: {
740
+ compaction: {
741
+ type: 'summarize',
742
+ instructions: 'Preserve all agreed entities and fields.',
743
+ },
744
+ } satisfies AnthropicLanguageModelOptions,
745
+ },
746
+ });
747
+
748
+ if (summary.rawFinishReason === 'compaction') {
749
+ const [compactionMessage] = summary.finalStep.response.messages;
750
+
751
+ const continuation = await generateText({
752
+ model: anthropic('claude-opus-5'),
753
+ messages: [
754
+ compactionMessage,
755
+ { role: 'user', content: 'Which fields should be required?' },
756
+ ],
757
+ });
758
+
759
+ console.log(continuation.text);
760
+ }
761
+ ```
762
+
763
+ Anthropic returns the summary as a text part whose
764
+ `providerMetadata.anthropic.type` is `compaction`. Its opaque signature is
765
+ available as `providerMetadata.anthropic.signature`. Response messages copy
766
+ that metadata to `providerOptions`, so passing
767
+ `summary.finalStep.response.messages` back to the AI SDK preserves the signed
768
+ block and automatically adds the beta header on the continuation request.
769
+
770
+ Check `rawFinishReason` before reading the response block. Anthropic can return
771
+ a successful HTTP response without a summary when summarization ends for
772
+ another reason, such as `max_tokens`, `model_context_window_exceeded`,
773
+ `tool_use`, `refusal`, or `end_turn`. In that case, keep the existing history
774
+ and retry later; the unsuccessful summarization is still included in
775
+ `providerMetadata.anthropic.iterations`.
776
+
777
+ Send exactly one signed compaction block on continuation requests. It must be
778
+ the first content block in `messages` and must be replayed without changing its
779
+ text or signature. Remove the messages it summarizes before continuing. Keep
780
+ the same system prompt and tool definitions on the compaction request that you
781
+ use for the conversation, especially when preserving later thinking blocks.
782
+
783
+ Before requesting compaction, resolve any unfinished tool call from the last
784
+ assistant turn. Do not combine `compaction` with `contextManagement`,
785
+ `stopSequences`, structured output, a required or named `toolChoice`, or a
786
+ `taskBudget.remaining` value. Also omit `taskBudget.remaining` from later
787
+ requests that carry the signed block.
788
+
789
+ On-demand compaction usage is reported in
790
+ `providerMetadata.anthropic.iterations`. Sum the iteration usage when
791
+ calculating the tokens consumed by the summarization request.
792
+
793
+ On-demand compaction can also be initiated in a Message Batch. Configure the
794
+ `compaction` provider option on the individual batch request; the provider
795
+ automatically adds `compact-2026-09-04` to the batch beta header.
796
+
797
+ For more details, see
798
+ [Anthropic's on-demand compaction documentation](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand).
799
+
800
+ #### Threshold Compaction
719
801
 
720
802
  The `compact_20260112` edit type automatically summarizes earlier conversation context when token limits are reached. This is useful for long-running conversations where you want to preserve the essence of earlier exchanges while staying within token limits.
721
803
 
@@ -724,7 +806,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
724
806
  import { streamText } from 'ai';
725
807
 
726
808
  const result = streamText({
727
- model: anthropic('claude-opus-4-6'),
809
+ model: anthropic('claude-opus-5-5'),
728
810
  messages: conversationHistory,
729
811
  providerOptions: {
730
812
  anthropic: {
@@ -848,7 +930,7 @@ import { generateText } from 'ai';
848
930
  const errorMessage = '... long error message ...';
849
931
 
850
932
  const result = await generateText({
851
- model: anthropic('claude-sonnet-4-5'),
933
+ model: anthropic('claude-sonnet-5'),
852
934
  messages: [
853
935
  {
854
936
  role: 'user',
@@ -882,7 +964,7 @@ You can also use cache control on system messages by providing multiple system m
882
964
 
883
965
  ```ts highlight="3,7-9"
884
966
  const result = await generateText({
885
- model: anthropic('claude-sonnet-4-5'),
967
+ model: anthropic('claude-sonnet-5'),
886
968
  messages: [
887
969
  {
888
970
  role: 'system',
@@ -1219,7 +1301,7 @@ const webSearchTool = anthropic.tools.webSearch_20260318({
1219
1301
  });
1220
1302
 
1221
1303
  const result = await generateText({
1222
- model: anthropic('claude-opus-5'),
1304
+ model: anthropic('claude-opus-5-5'),
1223
1305
  prompt: 'What are the latest developments in AI?',
1224
1306
  tools: {
1225
1307
  web_search: webSearchTool,
@@ -1278,7 +1360,7 @@ const webSearchTool = anthropic.tools.webSearch_20260318({
1278
1360
  });
1279
1361
 
1280
1362
  const result = await generateText({
1281
- model: anthropic('claude-opus-5'),
1363
+ model: anthropic('claude-opus-5-5'),
1282
1364
  prompt: 'Find local news about technology',
1283
1365
  tools: {
1284
1366
  web_search: webSearchTool,
@@ -1304,7 +1386,7 @@ import { anthropic } from '@ai-sdk/anthropic';
1304
1386
  import { generateText } from 'ai';
1305
1387
 
1306
1388
  const result = await generateText({
1307
- model: anthropic('claude-opus-5'),
1389
+ model: anthropic('claude-opus-5-5'),
1308
1390
  prompt:
1309
1391
  'What is this page about? https://en.wikipedia.org/wiki/Maglemosian_culture',
1310
1392
  tools: {
@@ -1396,7 +1478,7 @@ import { generateText, tool } from 'ai';
1396
1478
  import { z } from 'zod';
1397
1479
 
1398
1480
  const result = await generateText({
1399
- model: anthropic('claude-sonnet-4-5'),
1481
+ model: anthropic('claude-sonnet-5'),
1400
1482
  prompt: 'What is the weather in San Francisco?',
1401
1483
  tools: {
1402
1484
  toolSearch: anthropic.tools.toolSearchBm25_20251119(),
@@ -1426,7 +1508,7 @@ For more precise tool matching, you can use the regex variant:
1426
1508
 
1427
1509
  ```ts
1428
1510
  const result = await generateText({
1429
- model: anthropic('claude-sonnet-4-5'),
1511
+ model: anthropic('claude-sonnet-5'),
1430
1512
  prompt: 'Get the weather data',
1431
1513
  tools: {
1432
1514
  toolSearch: anthropic.tools.toolSearchRegex_20251119(),
@@ -1447,7 +1529,7 @@ import { generateText, tool } from 'ai';
1447
1529
  import { z } from 'zod';
1448
1530
 
1449
1531
  const result = await generateText({
1450
- model: anthropic('claude-sonnet-4-5'),
1532
+ model: anthropic('claude-sonnet-5'),
1451
1533
  prompt: 'What is the weather in San Francisco?',
1452
1534
  tools: {
1453
1535
  // Custom search tool
@@ -1490,13 +1572,16 @@ This sends `tool_reference` blocks to Anthropic, which loads the corresponding d
1490
1572
 
1491
1573
  ### Mid-Conversation System Controls
1492
1574
 
1493
- With `claude-opus-5-5` and `claude-fable-5-1`, a mid-conversation system message
1494
- can be cleared before the next user message with `clearAt: 'next_user_message'`,
1495
- or set the effort for the next turn without invalidating the prompt cache. The provider adds the required
1575
+ With `claude-opus-5-5` and `claude-fable-5-1`, use an empty system message to
1576
+ change effort from the next user turn. A separate system message containing text
1577
+ can provide a turn-scoped reminder with `clearAt: 'next_user_message'`: its text
1578
+ applies until the next user message. Keep the reminder after a user turn and
1579
+ before an assistant turn, or at the end of the messages array.
1580
+ The provider adds the required
1496
1581
  `mid-conversation-system-clear-at-2026-08-21` and
1497
1582
  `mid-conversation-output-config-2026-07-01` beta headers automatically.
1498
1583
 
1499
- ```ts highlight="17-25"
1584
+ ```ts highlight="16-24,29-37"
1500
1585
  import { anthropic } from '@ai-sdk/anthropic';
1501
1586
  import { generateText } from 'ai';
1502
1587
 
@@ -1514,10 +1599,9 @@ const result = await generateText({
1514
1599
  },
1515
1600
  {
1516
1601
  role: 'system',
1517
- content: 'For the next turn, verify every compatibility claim.',
1602
+ content: '',
1518
1603
  providerOptions: {
1519
1604
  anthropic: {
1520
- clearAt: 'next_user_message',
1521
1605
  effort: 'high',
1522
1606
  },
1523
1607
  },
@@ -1526,19 +1610,39 @@ const result = await generateText({
1526
1610
  role: 'user',
1527
1611
  content: 'Complete the plan.',
1528
1612
  },
1613
+ {
1614
+ role: 'system',
1615
+ content: 'For this turn, verify every compatibility claim.',
1616
+ providerOptions: {
1617
+ anthropic: {
1618
+ clearAt: 'next_user_message',
1619
+ },
1620
+ },
1621
+ },
1529
1622
  ],
1530
1623
  });
1531
1624
  ```
1532
1625
 
1533
1626
  An effort-only system message can use an empty content array at the API level;
1534
1627
  in an AI SDK prompt, set `content: ''`. The provider serializes it as
1535
- `content: []`.
1628
+ `content: []`. These effort-only messages can appear first or later in the
1629
+ conversation, including consecutively. The provider preserves their order. The new
1630
+ level applies from the next user turn until a later message changes it.
1631
+ Initial instruction text is sent in the top-level `system` field.
1632
+
1633
+ Consecutive inline system messages are evaluated as a group. If an effort-only
1634
+ message is adjacent to a system message containing text, the whole group must
1635
+ follow Anthropic's [content placement rules](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#limitations).
1636
+
1637
+ Turn-scoped messages with `clearAt` support text only. Put effort updates in a
1638
+ separate message, as in the example above.
1536
1639
 
1537
1640
  <Note>
1538
- `clearAt` and per-message `effort` apply only to mid-conversation system
1539
- messages. When used on the initial system message, the provider ignores them
1540
- and emits a warning. Use the top-level `effort` provider option to configure
1541
- effort for the full request.
1641
+ `clearAt` applies only to mid-conversation system messages. On initial system
1642
+ messages, the provider ignores `clearAt` and effort attached to non-empty
1643
+ content and emits a warning. Use an empty system message for an initial
1644
+ per-message effort setting, or the top-level `effort` provider option to
1645
+ configure effort for the full request.
1542
1646
  </Note>
1543
1647
 
1544
1648
  ### Mid-Conversation Tool Changes
@@ -1607,7 +1711,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
1607
1711
  import { generateText } from 'ai';
1608
1712
 
1609
1713
  const result = await generateText({
1610
- model: anthropic('claude-sonnet-4-5'),
1714
+ model: anthropic('claude-sonnet-5'),
1611
1715
  prompt: `Call the echo tool with "hello world". what does it respond with back?`,
1612
1716
  providerOptions: {
1613
1717
  anthropic: {
@@ -1679,7 +1783,7 @@ Web search errors throw exceptions that you can catch:
1679
1783
  ```ts
1680
1784
  try {
1681
1785
  const result = await generateText({
1682
- model: anthropic('claude-opus-4-20250514'),
1786
+ model: anthropic('claude-opus-5-5'),
1683
1787
  prompt: 'Search for something',
1684
1788
  tools: {
1685
1789
  web_search: webSearchTool,
@@ -1698,7 +1802,7 @@ Web search errors are delivered as error parts in the stream:
1698
1802
 
1699
1803
  ```ts
1700
1804
  const result = await streamText({
1701
- model: anthropic('claude-opus-4-20250514'),
1805
+ model: anthropic('claude-opus-5-5'),
1702
1806
  prompt: 'Search for something',
1703
1807
  tools: {
1704
1808
  web_search: webSearchTool,
@@ -1793,7 +1897,7 @@ Code execution errors are delivered as tool result parts in the response:
1793
1897
 
1794
1898
  ```ts
1795
1899
  const result = await generateText({
1796
- model: anthropic('claude-opus-4-20250514'),
1900
+ model: anthropic('claude-opus-5-5'),
1797
1901
  prompt: 'Execute some Python script',
1798
1902
  tools: {
1799
1903
  code_execution: codeExecutionTool,
@@ -1818,7 +1922,7 @@ Code execution errors are delivered as error parts in the stream:
1818
1922
 
1819
1923
  ```ts
1820
1924
  const result = await streamText({
1821
- model: anthropic('claude-opus-4-20250514'),
1925
+ model: anthropic('claude-opus-5-5'),
1822
1926
  prompt: 'Execute some Python script',
1823
1927
  tools: {
1824
1928
  code_execution: codeExecutionTool,
@@ -1978,7 +2082,7 @@ Option 1: URL-based PDF document
1978
2082
 
1979
2083
  ```ts
1980
2084
  const result = await generateText({
1981
- model: anthropic('claude-sonnet-4-5'),
2085
+ model: anthropic('claude-sonnet-5'),
1982
2086
  messages: [
1983
2087
  {
1984
2088
  role: 'user',
@@ -2004,7 +2108,7 @@ Option 2: Base64-encoded PDF document
2004
2108
 
2005
2109
  ```ts
2006
2110
  const result = await generateText({
2007
- model: anthropic('claude-sonnet-4-5'),
2111
+ model: anthropic('claude-sonnet-5'),
2008
2112
  messages: [
2009
2113
  {
2010
2114
  role: 'user',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/anthropic",
3
- "version": "4.0.62",
3
+ "version": "4.0.65",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -36,10 +36,10 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@ai-sdk/provider": "4.0.18",
39
- "@ai-sdk/provider-utils": "5.0.47"
39
+ "@ai-sdk/provider-utils": "5.0.49"
40
40
  },
41
41
  "devDependencies": {
42
- "@ai-sdk/test-server": "2.0.1",
42
+ "@ai-sdk/test-server": "2.0.2",
43
43
  "@types/node": "22.19.19",
44
44
  "@vercel/ai-tsconfig": "0.0.0",
45
45
  "tsup": "^8.5.1",
@@ -78,6 +78,7 @@ export interface AnthropicAssistantMessage {
78
78
  export interface AnthropicCompactionContent {
79
79
  type: 'compaction';
80
80
  content: string;
81
+ signature?: string;
81
82
  cache_control?: AnthropicCacheControl;
82
83
  }
83
84
 
@@ -805,6 +806,7 @@ export const anthropicResponseSchema = lazySchema(() =>
805
806
  z.object({
806
807
  type: z.literal('compaction'),
807
808
  content: z.string().nullish(),
809
+ signature: z.string().nullish(),
808
810
  }),
809
811
  z.object({
810
812
  type: z.literal('tool_use'),
@@ -1187,6 +1189,7 @@ export const anthropicChunkSchema = lazySchema(() =>
1187
1189
  z.object({
1188
1190
  type: z.literal('compaction'),
1189
1191
  content: z.string().nullish(),
1192
+ signature: z.string().nullish(),
1190
1193
  }),
1191
1194
  z.object({
1192
1195
  type: z.literal('server_tool_use'),
@@ -806,7 +806,12 @@ function convertAnthropicBatchResponse(
806
806
  content.push({
807
807
  type: 'text',
808
808
  text: part.content,
809
- providerMetadata: { anthropic: { type: 'compaction' } },
809
+ providerMetadata: {
810
+ anthropic: {
811
+ type: 'compaction',
812
+ ...(part.signature != null && { signature: part.signature }),
813
+ },
814
+ },
810
815
  });
811
816
  break;
812
817
  case 'tool_use':
@@ -82,9 +82,10 @@ export const anthropicSystemMessageProviderOptions = z.object({
82
82
  clearAt: z.literal('next_user_message').optional(),
83
83
 
84
84
  /**
85
- * Sets the model effort for the turn that follows this mid-conversation
86
- * system message. The required `mid-conversation-output-config-2026-07-01`
87
- * beta is added automatically.
85
+ * Sets the model effort from the next user turn until a later message
86
+ * changes it. An effort-only system message with empty content can appear
87
+ * first. The required `mid-conversation-output-config-2026-07-01` beta is
88
+ * added automatically.
88
89
  */
89
90
  effort: z.enum(['low', 'medium', 'high', 'xhigh', 'max']).optional(),
90
91
 
@@ -384,6 +385,19 @@ export const anthropicLanguageModelOptions = z.object({
384
385
  )
385
386
  .optional(),
386
387
 
388
+ /**
389
+ * Requests an on-demand summary of the supplied conversation.
390
+ *
391
+ * The required `compact-2026-09-04` beta is added automatically.
392
+ * Cannot be combined with `contextManagement`.
393
+ */
394
+ compaction: z
395
+ .object({
396
+ type: z.literal('summarize'),
397
+ instructions: z.string().optional(),
398
+ })
399
+ .optional(),
400
+
387
401
  contextManagement: z
388
402
  .object({
389
403
  edits: z.array(
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  APICallError,
3
+ InvalidArgumentError,
3
4
  InvalidResponseDataError,
4
5
  type JSONObject,
5
6
  type LanguageModelV4,
@@ -508,6 +509,15 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
508
509
  }
509
510
 
510
511
  const contextManagement = anthropicOptions?.contextManagement;
512
+ const compaction = anthropicOptions?.compaction;
513
+
514
+ if (contextManagement != null && compaction != null) {
515
+ throw new InvalidArgumentError({
516
+ argument: 'providerOptions',
517
+ message:
518
+ 'Anthropic provider options `compaction` and `contextManagement` cannot be used together.',
519
+ });
520
+ }
511
521
 
512
522
  // Create a shared cache control validator to track breakpoints across tools and messages
513
523
  const cacheControlValidator = new CacheControlValidator();
@@ -779,6 +789,15 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
779
789
  })),
780
790
  }),
781
791
 
792
+ ...(compaction && {
793
+ compaction: {
794
+ type: compaction.type,
795
+ ...(compaction.instructions !== undefined && {
796
+ instructions: compaction.instructions,
797
+ }),
798
+ },
799
+ }),
800
+
782
801
  ...(contextManagement && {
783
802
  context_management: {
784
803
  edits: contextManagement.edits
@@ -925,6 +944,10 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
925
944
  betas.add('dangerous-tool-use-2026-09-03');
926
945
  }
927
946
 
947
+ if (compaction) {
948
+ betas.add('compact-2026-09-04');
949
+ }
950
+
928
951
  if (contextManagement) {
929
952
  betas.add('context-management-2025-06-27');
930
953
 
@@ -1271,6 +1294,9 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
1271
1294
  providerMetadata: {
1272
1295
  anthropic: {
1273
1296
  type: 'compaction',
1297
+ ...(part.signature != null && {
1298
+ signature: part.signature,
1299
+ }),
1274
1300
  },
1275
1301
  },
1276
1302
  });
@@ -1971,9 +1997,27 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
1971
1997
  providerMetadata: {
1972
1998
  anthropic: {
1973
1999
  type: 'compaction',
2000
+ ...(part.signature != null && {
2001
+ signature: part.signature,
2002
+ }),
1974
2003
  },
1975
2004
  },
1976
2005
  });
2006
+
2007
+ // On-demand compaction blocks arrive complete in
2008
+ // content_block_start, without compaction_delta events.
2009
+ if (
2010
+ part.signature != null &&
2011
+ part.content != null &&
2012
+ part.content !== ''
2013
+ ) {
2014
+ controller.enqueue({
2015
+ type: 'text-delta',
2016
+ id: String(value.index),
2017
+ delta: part.content,
2018
+ });
2019
+ }
2020
+
1977
2021
  return;
1978
2022
  }
1979
2023
 
@@ -204,11 +204,6 @@ export async function convertToAnthropicPrompt({
204
204
  });
205
205
  }
206
206
 
207
- // The first block becomes the top-level system prompt. Later system
208
- // blocks are sent as inline system messages — always when they carry
209
- // tool changes (which are only valid mid-conversation), and otherwise
210
- // only when a top-level system prompt already exists (preserving the
211
- // existing hoisting behavior for plain text).
212
207
  const toolChangeCount = convertedMessages.reduce(
213
208
  (count, message) => count + message.toolChangeCount,
214
209
  0,
@@ -230,12 +225,26 @@ export async function convertToAnthropicPrompt({
230
225
  });
231
226
  }
232
227
 
228
+ // Initial instruction text goes in the top-level system field.
229
+ // Effort-only messages stay in the messages array.
233
230
  for (const message of convertedMessages) {
234
- if (message.clearAt != null || message.effort != null) {
231
+ if (
232
+ message.content.length === 0 &&
233
+ message.clearAt == null &&
234
+ message.effort != null
235
+ ) {
236
+ messages.push({
237
+ role: 'system',
238
+ content: [],
239
+ output_config: { effort: message.effort },
240
+ });
241
+ betas.add('mid-conversation-output-config-2026-07-01');
242
+ } else if (message.clearAt != null || message.effort != null) {
235
243
  warnings.push({
236
244
  type: 'other',
237
245
  message:
238
- 'clearAt and effort on the initial system message are not supported by Anthropic. ' +
246
+ 'clearAt and effort on this initial system message are not supported by Anthropic. ' +
247
+ 'Use a separate effort-only system message with empty content to set effort. ' +
239
248
  'These options have been ignored.',
240
249
  });
241
250
  }
@@ -711,7 +720,11 @@ export async function convertToAnthropicPrompt({
711
720
  case 'text': {
712
721
  // Check if this is a compaction block (via providerMetadata)
713
722
  const textMetadata = part.providerOptions?.anthropic as
714
- | { type?: string; citations?: Citation[] }
723
+ | {
724
+ type?: string;
725
+ citations?: Citation[];
726
+ signature?: string;
727
+ }
715
728
  | undefined;
716
729
 
717
730
  if (textMetadata?.type === 'compaction') {
@@ -719,9 +732,16 @@ export async function convertToAnthropicPrompt({
719
732
  break;
720
733
  }
721
734
 
735
+ if (typeof textMetadata.signature === 'string') {
736
+ betas.add('compact-2026-09-04');
737
+ }
738
+
722
739
  anthropicContent.push({
723
740
  type: 'compaction',
724
741
  content: part.text,
742
+ ...(typeof textMetadata.signature === 'string' && {
743
+ signature: textMetadata.signature,
744
+ }),
725
745
  cache_control: cacheControl,
726
746
  });
727
747
  } else {