@ai-sdk/anthropic 3.0.80 → 3.0.82

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.
@@ -243,7 +243,7 @@ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
243
243
  import { generateText } from 'ai';
244
244
 
245
245
  const { text } = await generateText({
246
- model: anthropic('claude-opus-4-7'),
246
+ model: anthropic('claude-opus-4-8'),
247
247
  prompt: 'Research the pros and cons of Rust vs Go for building CLI tools.',
248
248
  providerOptions: {
249
249
  anthropic: {
@@ -293,6 +293,63 @@ const { text } = await generateText({
293
293
 
294
294
  The `inferenceGeo` option accepts `'us'` (US-only infrastructure) or `'global'` (default, any available geography).
295
295
 
296
+ ### Safety Classifiers and Fallbacks
297
+
298
+ 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.
299
+
300
+ 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`.
301
+
302
+ A classifier block looks like this:
303
+
304
+ ```json
305
+ {
306
+ "type": "message",
307
+ "model": "claude-fable-5",
308
+ "content": [],
309
+ "stop_reason": "refusal",
310
+ "stop_details": {
311
+ "type": "refusal",
312
+ "category": "cyber",
313
+ "explanation": "This request triggered restrictions on violative cyber content and was blocked under Anthropic's Usage Policy."
314
+ }
315
+ }
316
+ ```
317
+
318
+ Branch on the finish reason rather than on the presence of `stop_details` — the API may return a refusal with no details at all.
319
+
320
+ To avoid receiving a classifier block, pass the `fallbacks` option. When the primary model's classifiers block a turn, the API automatically retries it server-side on the next model in the chain and returns that model's answer. The required beta header is added for you.
321
+
322
+ ```ts highlight="8-10"
323
+ import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
324
+ import { generateText } from 'ai';
325
+
326
+ const { text } = await generateText({
327
+ model: anthropic('claude-fable-5'),
328
+ prompt: 'Explain the history of cryptography.',
329
+ providerOptions: {
330
+ anthropic: {
331
+ fallbacks: [{ model: 'claude-fable-5' }],
332
+ } satisfies AnthropicLanguageModelOptions,
333
+ },
334
+ });
335
+ ```
336
+
337
+ Each fallback entry requires a `model` and may additionally override `max_tokens`, `thinking`, `output_config`, and `speed` for that attempt only.
338
+
339
+ When a fallback serves the turn, it is recorded in the per-model usage breakdown (`usage.iterations`) as a `fallback_message` entry. The AI SDK exposes this breakdown on `providerMetadata.anthropic.iterations`, so you can detect whether a fallback ran:
340
+
341
+ ```ts
342
+ // set up `result` with a `streamText` call passing `fallbacks` as shown
343
+ // above, then consume the stream
344
+
345
+ const { iterations } = (await result.providerMetadata)?.anthropic ?? {};
346
+ const servedByFallback = iterations?.some(
347
+ iteration => iteration.type === 'fallback_message',
348
+ );
349
+
350
+ console.log('Served by fallback:', servedByFallback);
351
+ ```
352
+
296
353
  ### Reasoning
297
354
 
298
355
  Anthropic models support extended thinking, where Claude shows its reasoning process before providing a final answer.
@@ -342,7 +399,7 @@ Starting with `claude-opus-4-7`, thinking content is omitted from the response b
342
399
 
343
400
  ```ts highlight="5"
344
401
  const { text, reasoningText } = await generateText({
345
- model: anthropic('claude-opus-4-7'),
402
+ model: anthropic('claude-opus-4-8'),
346
403
  providerOptions: {
347
404
  anthropic: {
348
405
  thinking: { type: 'adaptive', display: 'summarized' },
@@ -971,7 +1028,7 @@ const result = await generateText({
971
1028
  'Build a concurrent worker pool in Go with graceful shutdown. Outline the design first.',
972
1029
  tools: {
973
1030
  advisor: anthropic.tools.advisor_20260301({
974
- model: 'claude-opus-4-7',
1031
+ model: 'claude-opus-4-8',
975
1032
  maxUses: 3,
976
1033
  }),
977
1034
  },
@@ -989,7 +1046,7 @@ The advisor tool supports the following configuration options:
989
1046
 
990
1047
  - **model** _string_
991
1048
 
992
- Required. The advisor model ID, such as `claude-opus-4-7`. The advisor model must be at least as capable as the executor model.
1049
+ Required. The advisor model ID, such as `claude-opus-4-8`. The advisor model must be at least as capable as the executor model.
993
1050
 
994
1051
  - **maxUses** _number_
995
1052
 
@@ -1502,6 +1559,8 @@ and the `mediaType` should be set to `'application/pdf'`.
1502
1559
 
1503
1560
  | Model | Image Input | Object Generation | Tool Usage | Computer Use | Web Search | Tool Search | Compaction |
1504
1561
  | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
1562
+ | `claude-fable-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1563
+ | `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} /> |
1505
1564
  | `claude-opus-4-7` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1506
1565
  | `claude-opus-4-6` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
1507
1566
  | `claude-sonnet-4-6` | <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.80",
3
+ "version": "3.0.82",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -8,66 +8,43 @@ import type { JSONObject } from '@ai-sdk/provider';
8
8
  * - `compaction`: a context compaction step (billed at executor rates).
9
9
  * - `message`: an executor sampling iteration (billed at executor rates).
10
10
  * - `advisor_message`: an advisor sub-inference (billed at the advisor
11
- * model's rates; `model` carries the advisor model ID). Advisor token
12
- * usage is NOT rolled into the top-level usage totals because it bills
13
- * at a different rate; inspect this array directly for advisor billing.
11
+ * model's rates). Advisor token usage is NOT rolled into the top-level
12
+ * usage totals because it bills at a different rate; inspect this array
13
+ * directly for advisor billing.
14
+ * - `fallback_message`: a server-side fallback attempt that served the turn.
15
+ * Inspect this array for exact per-model attribution on a turn that fell
16
+ * back.
14
17
  */
15
- export type AnthropicUsageIteration =
16
- | {
17
- type: 'compaction' | 'message';
18
+ export type AnthropicUsageIteration = {
19
+ type: 'compaction' | 'message' | 'advisor_message' | 'fallback_message';
18
20
 
19
- /**
20
- * Number of input tokens consumed in this iteration.
21
- */
22
- inputTokens: number;
23
-
24
- /**
25
- * Number of output tokens generated in this iteration.
26
- */
27
- outputTokens: number;
28
-
29
- /**
30
- * Number of cache-creation input tokens consumed in this iteration.
31
- */
32
- cacheCreationInputTokens?: number;
33
-
34
- /**
35
- * Number of cache-read input tokens consumed in this iteration.
36
- */
37
- cacheReadInputTokens?: number;
38
- }
39
- | {
40
- type: 'advisor_message';
41
-
42
- /**
43
- * The advisor model that produced this iteration.
44
- */
45
- model: string;
21
+ /**
22
+ * The model that produced this iteration. Populated for the per-model
23
+ * attribution cases (the fallback chain and advisor sub-inferences) and
24
+ * absent otherwise.
25
+ */
26
+ model?: string;
46
27
 
47
- /**
48
- * Number of input tokens consumed in this iteration.
49
- */
50
- inputTokens: number;
28
+ /**
29
+ * Number of input tokens consumed in this iteration.
30
+ */
31
+ inputTokens: number;
51
32
 
52
- /**
53
- * Number of output tokens generated in this iteration.
54
- */
55
- outputTokens: number;
33
+ /**
34
+ * Number of output tokens generated in this iteration.
35
+ */
36
+ outputTokens: number;
56
37
 
57
- /**
58
- * Number of cache-creation input tokens consumed by this advisor
59
- * sub-inference. Nonzero when advisor-side caching is enabled and
60
- * the advisor writes a fresh cache entry.
61
- */
62
- cacheCreationInputTokens?: number;
38
+ /**
39
+ * Number of cache-creation input tokens consumed in this iteration.
40
+ */
41
+ cacheCreationInputTokens?: number;
63
42
 
64
- /**
65
- * Number of cache-read input tokens consumed by this advisor
66
- * sub-inference. Nonzero on the second and later advisor calls
67
- * when advisor-side caching is enabled.
68
- */
69
- cacheReadInputTokens?: number;
70
- };
43
+ /**
44
+ * Number of cache-read input tokens consumed in this iteration.
45
+ */
46
+ cacheReadInputTokens?: number;
47
+ };
71
48
 
72
49
  export interface AnthropicMessageMetadata {
73
50
  usage: JSONObject;
@@ -76,6 +53,42 @@ export interface AnthropicMessageMetadata {
76
53
  cacheCreationInputTokens: number | null;
77
54
  stopSequence: string | null;
78
55
 
56
+ /**
57
+ * Details about why the request stopped. Present only when the API returns
58
+ * a `refusal` stop reason together with a `stop_details` object (a
59
+ * classifier block or a model refusal).
60
+ *
61
+ * Branch on the finish reason (`content-filter`), not on this object: the
62
+ * API may return a refusal with no details at all, so this field can be
63
+ * absent even on a refusal and should not be relied upon being present.
64
+ */
65
+ stopDetails?: {
66
+ /**
67
+ * The kind of stop detail. `'refusal'` for classifier blocks and model
68
+ * refusals.
69
+ */
70
+ type: string;
71
+
72
+ /**
73
+ * The classifier category that triggered the block, e.g. `'cyber'` or
74
+ * `'bio'`. Absent for model refusals and other cases.
75
+ */
76
+ category?: string;
77
+
78
+ /**
79
+ * Human-readable explanation of why the request was blocked. May be
80
+ * absent even on a refusal.
81
+ */
82
+ explanation?: string;
83
+
84
+ /**
85
+ * The canonical id of a model to retry directly. Populated only when the
86
+ * request included fallbacks and the fallback attempt could not be made
87
+ * (e.g. the fallback model was rate limited or overloaded).
88
+ */
89
+ recommendedModel?: string;
90
+ };
91
+
79
92
  /**
80
93
  * Usage breakdown by iteration when compaction is triggered.
81
94
  *
@@ -11,13 +11,21 @@ export type AnthropicMessagesPrompt = {
11
11
  messages: AnthropicMessage[];
12
12
  };
13
13
 
14
- export type AnthropicMessage = AnthropicUserMessage | AnthropicAssistantMessage;
14
+ export type AnthropicMessage =
15
+ | AnthropicUserMessage
16
+ | AnthropicAssistantMessage
17
+ | AnthropicSystemMessage;
15
18
 
16
19
  export type AnthropicCacheControl = {
17
20
  type: 'ephemeral';
18
21
  ttl?: '5m' | '1h';
19
22
  };
20
23
 
24
+ export interface AnthropicSystemMessage {
25
+ role: 'system';
26
+ content: Array<AnthropicTextContent>;
27
+ }
28
+
21
29
  export interface AnthropicUserMessage {
22
30
  role: 'user';
23
31
  content: Array<
@@ -593,6 +601,15 @@ export type AnthropicResponseContextManagement = {
593
601
  applied_edits: AnthropicResponseContextManagementEdit[];
594
602
  };
595
603
 
604
+ const anthropicStopDetailsSchema = z.object({
605
+ type: z.string(),
606
+ category: z.string().nullish(),
607
+ explanation: z.string().nullish(),
608
+ recommended_model: z.string().nullish(),
609
+ });
610
+
611
+ export type AnthropicStopDetails = z.infer<typeof anthropicStopDetailsSchema>;
612
+
596
613
  // limited version of the schema, focussed on what is needed for the implementation
597
614
  // this approach limits breakages when the API changes and increases efficiency
598
615
  export const anthropicMessagesResponseSchema = lazySchema(() =>
@@ -893,10 +910,17 @@ export const anthropicMessagesResponseSchema = lazySchema(() =>
893
910
  }),
894
911
  ]),
895
912
  }),
913
+ // Server-side fallback marker. Parsed so the response validates, but
914
+ // dropped from the content output (the AI SDK has no model-hop
915
+ // primitive). The hop remains observable via usage.iterations.
916
+ z.object({
917
+ type: z.literal('fallback'),
918
+ }),
896
919
  ]),
897
920
  ),
898
921
  stop_reason: z.string().nullish(),
899
922
  stop_sequence: z.string().nullish(),
923
+ stop_details: anthropicStopDetailsSchema.nullish(),
900
924
  usage: z.looseObject({
901
925
  input_tokens: z.number(),
902
926
  output_tokens: z.number(),
@@ -904,23 +928,19 @@ export const anthropicMessagesResponseSchema = lazySchema(() =>
904
928
  cache_read_input_tokens: z.number().nullish(),
905
929
  iterations: z
906
930
  .array(
907
- z.union([
908
- z.object({
909
- type: z.union([z.literal('compaction'), z.literal('message')]),
910
- input_tokens: z.number(),
911
- output_tokens: z.number(),
912
- cache_creation_input_tokens: z.number().nullish(),
913
- cache_read_input_tokens: z.number().nullish(),
914
- }),
915
- z.object({
916
- type: z.literal('advisor_message'),
917
- model: z.string(),
918
- input_tokens: z.number(),
919
- output_tokens: z.number(),
920
- cache_creation_input_tokens: z.number().nullish(),
921
- cache_read_input_tokens: z.number().nullish(),
922
- }),
923
- ]),
931
+ z.object({
932
+ type: z.union([
933
+ z.literal('compaction'),
934
+ z.literal('message'),
935
+ z.literal('advisor_message'),
936
+ z.literal('fallback_message'),
937
+ ]),
938
+ model: z.string().nullish(),
939
+ input_tokens: z.number(),
940
+ output_tokens: z.number(),
941
+ cache_creation_input_tokens: z.number().nullish(),
942
+ cache_read_input_tokens: z.number().nullish(),
943
+ }),
924
944
  )
925
945
  .nullish(),
926
946
  }),
@@ -1282,6 +1302,11 @@ export const anthropicMessagesChunkSchema = lazySchema(() =>
1282
1302
  }),
1283
1303
  ]),
1284
1304
  }),
1305
+ // Server-side fallback marker; dropped from content output (see the
1306
+ // response schema). The hop remains observable via usage.iterations.
1307
+ z.object({
1308
+ type: z.literal('fallback'),
1309
+ }),
1285
1310
  ]),
1286
1311
  }),
1287
1312
  z.object({
@@ -1354,6 +1379,7 @@ export const anthropicMessagesChunkSchema = lazySchema(() =>
1354
1379
  delta: z.object({
1355
1380
  stop_reason: z.string().nullish(),
1356
1381
  stop_sequence: z.string().nullish(),
1382
+ stop_details: anthropicStopDetailsSchema.nullish(),
1357
1383
  container: z
1358
1384
  .object({
1359
1385
  expires_at: z.string(),
@@ -1380,26 +1406,19 @@ export const anthropicMessagesChunkSchema = lazySchema(() =>
1380
1406
  cache_read_input_tokens: z.number().nullish(),
1381
1407
  iterations: z
1382
1408
  .array(
1383
- z.union([
1384
- z.object({
1385
- type: z.union([
1386
- z.literal('compaction'),
1387
- z.literal('message'),
1388
- ]),
1389
- input_tokens: z.number(),
1390
- output_tokens: z.number(),
1391
- cache_creation_input_tokens: z.number().nullish(),
1392
- cache_read_input_tokens: z.number().nullish(),
1393
- }),
1394
- z.object({
1395
- type: z.literal('advisor_message'),
1396
- model: z.string(),
1397
- input_tokens: z.number(),
1398
- output_tokens: z.number(),
1399
- cache_creation_input_tokens: z.number().nullish(),
1400
- cache_read_input_tokens: z.number().nullish(),
1401
- }),
1402
- ]),
1409
+ z.object({
1410
+ type: z.union([
1411
+ z.literal('compaction'),
1412
+ z.literal('message'),
1413
+ z.literal('advisor_message'),
1414
+ z.literal('fallback_message'),
1415
+ ]),
1416
+ model: z.string().nullish(),
1417
+ input_tokens: z.number(),
1418
+ output_tokens: z.number(),
1419
+ cache_creation_input_tokens: z.number().nullish(),
1420
+ cache_read_input_tokens: z.number().nullish(),
1421
+ }),
1403
1422
  )
1404
1423
  .nullish(),
1405
1424
  }),
@@ -40,6 +40,7 @@ import {
40
40
  type AnthropicContainer,
41
41
  type AnthropicReasoningMetadata,
42
42
  type AnthropicResponseContextManagement,
43
+ type AnthropicStopDetails,
43
44
  type AnthropicTool,
44
45
  type Citation,
45
46
  } from './anthropic-messages-api';
@@ -438,6 +439,10 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
438
439
  ...(anthropicOptions?.inferenceGeo && {
439
440
  inference_geo: anthropicOptions.inferenceGeo,
440
441
  }),
442
+ ...(anthropicOptions?.fallbacks &&
443
+ anthropicOptions.fallbacks.length > 0 && {
444
+ fallbacks: anthropicOptions.fallbacks,
445
+ }),
441
446
  ...(anthropicOptions?.cacheControl && {
442
447
  cache_control: anthropicOptions.cacheControl,
443
448
  }),
@@ -664,6 +669,10 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
664
669
  betas.add('fast-mode-2026-02-01');
665
670
  }
666
671
 
672
+ if (anthropicOptions?.fallbacks && anthropicOptions.fallbacks.length > 0) {
673
+ betas.add('server-side-fallback-2026-06-01');
674
+ }
675
+
667
676
  const defaultEagerInputStreaming =
668
677
  stream && (anthropicOptions?.toolStreaming ?? true);
669
678
 
@@ -1281,6 +1290,13 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
1281
1290
  }
1282
1291
  break;
1283
1292
  }
1293
+
1294
+ // Server-side fallback marker: the AI SDK has no content primitive for
1295
+ // a model hop, so drop it. The hop is still observable via
1296
+ // usage.iterations.
1297
+ case 'fallback': {
1298
+ break;
1299
+ }
1284
1300
  }
1285
1301
  }
1286
1302
 
@@ -1303,48 +1319,35 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
1303
1319
  },
1304
1320
  warnings,
1305
1321
  providerMetadata: (() => {
1322
+ const stopDetails = mapAnthropicStopDetails(response.stop_details);
1323
+
1306
1324
  const anthropicMetadata = {
1307
1325
  usage: response.usage as JSONObject,
1308
1326
  cacheCreationInputTokens:
1309
1327
  response.usage.cache_creation_input_tokens ?? null,
1310
1328
  stopSequence: response.stop_sequence ?? null,
1329
+ ...(stopDetails != null ? { stopDetails } : {}),
1311
1330
 
1312
1331
  iterations: response.usage.iterations
1313
- ? response.usage.iterations.map(iter =>
1314
- iter.type === 'advisor_message'
1315
- ? ({
1316
- type: iter.type,
1317
- model: iter.model,
1318
- inputTokens: iter.input_tokens,
1319
- outputTokens: iter.output_tokens,
1320
- ...(iter.cache_creation_input_tokens
1321
- ? {
1322
- cacheCreationInputTokens:
1323
- iter.cache_creation_input_tokens,
1324
- }
1325
- : {}),
1326
- ...(iter.cache_read_input_tokens
1327
- ? {
1328
- cacheReadInputTokens: iter.cache_read_input_tokens,
1329
- }
1330
- : {}),
1331
- } satisfies AnthropicUsageIteration)
1332
- : ({
1333
- type: iter.type,
1334
- inputTokens: iter.input_tokens,
1335
- outputTokens: iter.output_tokens,
1336
- ...(iter.cache_creation_input_tokens
1337
- ? {
1338
- cacheCreationInputTokens:
1339
- iter.cache_creation_input_tokens,
1340
- }
1341
- : {}),
1342
- ...(iter.cache_read_input_tokens
1343
- ? {
1344
- cacheReadInputTokens: iter.cache_read_input_tokens,
1345
- }
1346
- : {}),
1347
- } satisfies AnthropicUsageIteration),
1332
+ ? response.usage.iterations.map(
1333
+ iter =>
1334
+ ({
1335
+ type: iter.type,
1336
+ ...(iter.model != null ? { model: iter.model } : {}),
1337
+ inputTokens: iter.input_tokens,
1338
+ outputTokens: iter.output_tokens,
1339
+ ...(iter.cache_creation_input_tokens
1340
+ ? {
1341
+ cacheCreationInputTokens:
1342
+ iter.cache_creation_input_tokens,
1343
+ }
1344
+ : {}),
1345
+ ...(iter.cache_read_input_tokens
1346
+ ? {
1347
+ cacheReadInputTokens: iter.cache_read_input_tokens,
1348
+ }
1349
+ : {}),
1350
+ }) satisfies AnthropicUsageIteration,
1348
1351
  )
1349
1352
  : null,
1350
1353
  container: response.container
@@ -1458,6 +1461,7 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
1458
1461
  let rawUsage: JSONObject | undefined = undefined;
1459
1462
  let cacheCreationInputTokens: number | null = null;
1460
1463
  let stopSequence: string | null = null;
1464
+ let stopDetails: AnthropicMessageMetadata['stopDetails'] = undefined;
1461
1465
  let container: AnthropicMessageMetadata['container'] | null = null;
1462
1466
  let isJsonResponseFromTool = false;
1463
1467
 
@@ -1510,6 +1514,14 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
1510
1514
  case 'content_block_start': {
1511
1515
  const part = value.content_block;
1512
1516
  const contentBlockType = part.type;
1517
+
1518
+ // Server-side fallback marker: the AI SDK has no content
1519
+ // primitive for a model hop, so drop it. The hop is still
1520
+ // observable via usage.iterations.
1521
+ if (contentBlockType === 'fallback') {
1522
+ return;
1523
+ }
1524
+
1513
1525
  blockType = contentBlockType;
1514
1526
 
1515
1527
  switch (contentBlockType) {
@@ -2362,6 +2374,7 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
2362
2374
  };
2363
2375
 
2364
2376
  stopSequence = value.delta.stop_sequence ?? null;
2377
+ stopDetails = mapAnthropicStopDetails(value.delta.stop_details);
2365
2378
  container =
2366
2379
  value.delta.container != null
2367
2380
  ? {
@@ -2395,44 +2408,28 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
2395
2408
  usage: (rawUsage as JSONObject) ?? null,
2396
2409
  cacheCreationInputTokens,
2397
2410
  stopSequence,
2411
+ ...(stopDetails != null ? { stopDetails } : {}),
2398
2412
  iterations: usage.iterations
2399
- ? usage.iterations.map(iter =>
2400
- iter.type === 'advisor_message'
2401
- ? ({
2402
- type: iter.type,
2403
- model: iter.model,
2404
- inputTokens: iter.input_tokens,
2405
- outputTokens: iter.output_tokens,
2406
- ...(iter.cache_creation_input_tokens
2407
- ? {
2408
- cacheCreationInputTokens:
2409
- iter.cache_creation_input_tokens,
2410
- }
2411
- : {}),
2412
- ...(iter.cache_read_input_tokens
2413
- ? {
2414
- cacheReadInputTokens:
2415
- iter.cache_read_input_tokens,
2416
- }
2417
- : {}),
2418
- } satisfies AnthropicUsageIteration)
2419
- : ({
2420
- type: iter.type,
2421
- inputTokens: iter.input_tokens,
2422
- outputTokens: iter.output_tokens,
2423
- ...(iter.cache_creation_input_tokens
2424
- ? {
2425
- cacheCreationInputTokens:
2426
- iter.cache_creation_input_tokens,
2427
- }
2428
- : {}),
2429
- ...(iter.cache_read_input_tokens
2430
- ? {
2431
- cacheReadInputTokens:
2432
- iter.cache_read_input_tokens,
2433
- }
2434
- : {}),
2435
- } satisfies AnthropicUsageIteration),
2413
+ ? usage.iterations.map(
2414
+ iter =>
2415
+ ({
2416
+ type: iter.type,
2417
+ ...(iter.model != null ? { model: iter.model } : {}),
2418
+ inputTokens: iter.input_tokens,
2419
+ outputTokens: iter.output_tokens,
2420
+ ...(iter.cache_creation_input_tokens
2421
+ ? {
2422
+ cacheCreationInputTokens:
2423
+ iter.cache_creation_input_tokens,
2424
+ }
2425
+ : {}),
2426
+ ...(iter.cache_read_input_tokens
2427
+ ? {
2428
+ cacheReadInputTokens:
2429
+ iter.cache_read_input_tokens,
2430
+ }
2431
+ : {}),
2432
+ }) satisfies AnthropicUsageIteration,
2436
2433
  )
2437
2434
  : null,
2438
2435
  container,
@@ -2528,7 +2525,11 @@ function getModelCapabilities(modelId: string): {
2528
2525
  rejectsSamplingParameters: boolean;
2529
2526
  isKnownModel: boolean;
2530
2527
  } {
2531
- if (modelId.includes('claude-opus-4-7')) {
2528
+ if (
2529
+ modelId.includes('claude-opus-4-8') ||
2530
+ modelId.includes('claude-opus-4-7') ||
2531
+ modelId.includes('claude-fable-5')
2532
+ ) {
2532
2533
  return {
2533
2534
  maxOutputTokens: 128000,
2534
2535
  supportsStructuredOutput: true,
@@ -2653,3 +2654,22 @@ function mapAnthropicResponseContextManagement(
2653
2654
  }
2654
2655
  : null;
2655
2656
  }
2657
+
2658
+ function mapAnthropicStopDetails(
2659
+ stopDetails: AnthropicStopDetails | null | undefined,
2660
+ ): AnthropicMessageMetadata['stopDetails'] | undefined {
2661
+ if (stopDetails == null) {
2662
+ return undefined;
2663
+ }
2664
+
2665
+ return {
2666
+ type: stopDetails.type,
2667
+ ...(stopDetails.category != null ? { category: stopDetails.category } : {}),
2668
+ ...(stopDetails.explanation != null
2669
+ ? { explanation: stopDetails.explanation }
2670
+ : {}),
2671
+ ...(stopDetails.recommended_model != null
2672
+ ? { recommendedModel: stopDetails.recommended_model }
2673
+ : {}),
2674
+ };
2675
+ }