@ai-sdk/anthropic 4.0.92 → 4.0.94

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.
@@ -355,10 +355,21 @@ default `"auto"` mode uses native structured outputs through
355
355
  `output_config.format`. These models reject forced tool use, so the
356
356
  `"jsonTool"` mode cannot be used with them. If you
357
357
  request `"jsonTool"` anyway, the provider falls back to `"outputFormat"` and
358
- emits a warning. Likewise, a `required` or named `toolChoice` is downgraded to
358
+ emits a warning. The same fallback applies when these models are served through
359
+ providers that otherwise default to the JSON tool, such as the Amazon Bedrock
360
+ Anthropic and Google Vertex Anthropic providers. On those providers, schemas
361
+ that native structured outputs cannot represent keep the JSON tool:
362
+ self-referencing schemas, schemas with more than 10 optional properties, and
363
+ schemas with open objects such as maps (`additionalProperties` set to a schema
364
+ or `true`), which native structured outputs would return as `{}`.
365
+ Likewise, a `required` or named `toolChoice` is downgraded to
359
366
  `auto` with a warning; instruct the model to use the tool in your prompt and
360
367
  verify that a tool call was made.
361
368
 
369
+ When the JSON tool cannot be forced (for example with manual thinking) and the
370
+ model answers in text without calling it, the text of its final answer is
371
+ returned. Text before a tool call is still dropped.
372
+
362
373
  ### Effort
363
374
 
364
375
  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`, `claude-sonnet-5-5`, and `claude-haiku-5-5` additionally support `xhigh` for maximum reasoning effort.
@@ -2410,6 +2421,8 @@ and the `mediaType` should be set to `'application/pdf'`.
2410
2421
 
2411
2422
  ### Model Capabilities
2412
2423
 
2424
+ {/* model-capabilities:anthropic-language:start */}
2425
+
2413
2426
  | Model | Image Input | Object Generation | Tool Usage | Computer Use | Web Search | Tool Search | Compaction |
2414
2427
  | ------------------- | ----------- | ----------------- | ---------- | ------------ | ---------- | ----------- | ---------- |
2415
2428
  | `claude-opus-5-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
@@ -2422,13 +2435,15 @@ and the `mediaType` should be set to `'application/pdf'`.
2422
2435
  | `claude-opus-4-8` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
2423
2436
  | `claude-opus-4-7` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
2424
2437
  | `claude-opus-4-6` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
2425
- | `claude-sonnet-4-6` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | |
2426
- | `claude-opus-4-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | |
2427
- | `claude-haiku-4-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | | |
2428
- | `claude-sonnet-4-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | |
2429
- | `claude-opus-4-1` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | | |
2430
- | `claude-opus-4-0` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | | |
2431
- | `claude-sonnet-4-0` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | | |
2438
+ | `claude-sonnet-4-6` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
2439
+ | `claude-opus-4-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
2440
+ | `claude-haiku-4-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
2441
+ | `claude-sonnet-4-5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
2442
+ | `claude-opus-4-1` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
2443
+ | `claude-opus-4-0` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
2444
+ | `claude-sonnet-4-0` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
2445
+
2446
+ {/* model-capabilities:anthropic-language:end */}
2432
2447
 
2433
2448
  <Note>
2434
2449
  The table above lists popular models. Please see the [Anthropic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/anthropic",
3
- "version": "4.0.92",
3
+ "version": "4.0.94",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.34",
39
- "@ai-sdk/provider-utils": "5.0.71"
38
+ "@ai-sdk/provider": "4.0.35",
39
+ "@ai-sdk/provider-utils": "5.0.72"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.4",
@@ -42,6 +42,7 @@ import {
42
42
  type Resolvable,
43
43
  } from '@ai-sdk/provider-utils';
44
44
  import { anthropicFailedResponseHandler } from './anthropic-error';
45
+ import { getAnthropicModelCapabilities } from './anthropic-model-catalog';
45
46
  import type {
46
47
  AnthropicMessageMetadata,
47
48
  AnthropicUsageIteration,
@@ -76,6 +77,7 @@ import {
76
77
  import { CacheControlValidator } from './get-cache-control';
77
78
  import { mapAnthropicStopReason } from './map-anthropic-stop-reason';
78
79
  import { sanitizeJsonSchema } from './sanitize-json-schema';
80
+ import { supportsNativeStructuredOutputSchema } from './supports-native-structured-output-schema';
79
81
 
80
82
  function createAnthropicStreamError(error: {
81
83
  message: string;
@@ -278,6 +280,47 @@ export type AnthropicLanguageModelConfig = {
278
280
  cacheControlProviderOptionsName?: string;
279
281
  };
280
282
 
283
+ const TEXT_OR_THINKING_BLOCK_TYPES = new Set<string>([
284
+ 'redacted_thinking',
285
+ 'text',
286
+ 'thinking',
287
+ ]);
288
+
289
+ function isContinuationStopReason(
290
+ stopReason: string | null | undefined,
291
+ ): boolean {
292
+ return stopReason === 'pause_turn' || stopReason === 'tool_use';
293
+ }
294
+
295
+ /**
296
+ * Text parts to return when the JSON response tool is in use: the text after
297
+ * the last tool call or result, and only if the tool was never called.
298
+ */
299
+ function getJsonResponseToolFallbackText<
300
+ PART extends { type: string; name?: unknown },
301
+ >(
302
+ content: ReadonlyArray<PART>,
303
+ stopReason: string | null | undefined,
304
+ ): Set<PART> {
305
+ const text = new Set<PART>();
306
+ if (isContinuationStopReason(stopReason)) {
307
+ return text;
308
+ }
309
+
310
+ for (const part of content) {
311
+ if (part.type === 'tool_use' && part.name === 'json') {
312
+ return new Set();
313
+ }
314
+ if (part.type === 'text') {
315
+ text.add(part);
316
+ } else if (!TEXT_OR_THINKING_BLOCK_TYPES.has(part.type)) {
317
+ text.clear();
318
+ }
319
+ }
320
+
321
+ return text;
322
+ }
323
+
281
324
  export class AnthropicLanguageModel implements LanguageModelV4 {
282
325
  readonly specificationVersion = 'v4';
283
326
 
@@ -435,7 +478,7 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
435
478
  rejectsForcedToolUse,
436
479
  supportsBetweenToolsThinking,
437
480
  isKnownModel,
438
- } = getModelCapabilities(modelId);
481
+ } = getAnthropicModelCapabilities(modelId);
439
482
 
440
483
  if (!isKnownModel && maxOutputTokens == null) {
441
484
  warnings.push({
@@ -492,13 +535,15 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
492
535
 
493
536
  // The JSON response tool relies on forced tool use, which some models
494
537
  // reject (e.g. Opus 5.5, Fable 5.1). Fall back to native structured
495
- // outputs when the model supports them.
538
+ // outputs even when the provider disables them by default (Bedrock,
539
+ // Vertex), unless they would reject the schema or lose data from it.
496
540
  if (
497
541
  !useStructuredOutput &&
498
542
  rejectsForcedToolUse &&
499
- supportsStructuredOutput &&
543
+ modelSupportsStructuredOutput &&
500
544
  responseFormat?.type === 'json' &&
501
- responseFormat.schema != null
545
+ responseFormat.schema != null &&
546
+ supportsNativeStructuredOutputSchema(responseFormat.schema)
502
547
  ) {
503
548
  warnings.push({
504
549
  type: 'unsupported',
@@ -1309,11 +1354,20 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
1309
1354
  Array.isArray(part.content) &&
1310
1355
  part.content.length > 0,
1311
1356
  );
1357
+ // The JSON response tool call becomes the text, so other text is dropped,
1358
+ // unless the model never called the tool and answered in text instead.
1359
+ const jsonResponseToolFallbackText = usesJsonResponseTool
1360
+ ? getJsonResponseToolFallbackText(response.content, response.stop_reason)
1361
+ : undefined;
1362
+
1312
1363
  // map response content to content array
1313
1364
  for (const part of response.content) {
1314
1365
  switch (part.type) {
1315
1366
  case 'text': {
1316
- if (!usesJsonResponseTool) {
1367
+ if (
1368
+ jsonResponseToolFallbackText == null ||
1369
+ jsonResponseToolFallbackText.has(part)
1370
+ ) {
1317
1371
  const citations = part.citations ?? [];
1318
1372
 
1319
1373
  content.push({
@@ -2002,6 +2056,26 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
2002
2056
  let safeguardResults: AnthropicMessageMetadata['safeguardResults'];
2003
2057
  let container: AnthropicMessageMetadata['container'] | null = null;
2004
2058
  let isJsonResponseFromTool = false;
2059
+ // Text held back while the JSON response tool is in use: it is only the
2060
+ // answer if no tool block follows it and the model never calls the tool.
2061
+ type HeldBackText = { id: string; text: string; citations: Citation[] };
2062
+ const heldBackText: HeldBackText[] = [];
2063
+ const heldBackTextByIndex = new Map<number, HeldBackText>();
2064
+ const createTextEnd = (
2065
+ id: string,
2066
+ citations: Citation[],
2067
+ ): LanguageModelV4StreamPart => ({
2068
+ type: 'text-end',
2069
+ id,
2070
+ ...(citations.length > 0 && {
2071
+ citations: citations.map(citation =>
2072
+ mapAnthropicCitation(citation, citationDocuments),
2073
+ ),
2074
+ providerMetadata: {
2075
+ anthropic: { citations },
2076
+ } satisfies AnthropicTextProviderMetadata,
2077
+ }),
2078
+ });
2005
2079
  let hasWebSearchResults = false;
2006
2080
  const fallbackWebCitations: Citation[] = [];
2007
2081
  let isMessageOpen = false;
@@ -2079,11 +2153,23 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
2079
2153
 
2080
2154
  blockType = contentBlockType;
2081
2155
 
2156
+ // text before a tool call or result is preamble, not the answer:
2157
+ if (!TEXT_OR_THINKING_BLOCK_TYPES.has(contentBlockType)) {
2158
+ heldBackText.length = 0;
2159
+ }
2160
+
2082
2161
  switch (contentBlockType) {
2083
2162
  case 'text': {
2084
2163
  // when a json response tool is used, the tool call is returned as text,
2085
- // so we ignore the text content:
2164
+ // so the text content is held back until we know whether it was called:
2086
2165
  if (usesJsonResponseTool) {
2166
+ const entry = {
2167
+ id: String(value.index),
2168
+ text: '',
2169
+ citations: [],
2170
+ };
2171
+ heldBackText.push(entry);
2172
+ heldBackTextByIndex.set(value.index, entry);
2087
2173
  return;
2088
2174
  }
2089
2175
 
@@ -2662,20 +2748,12 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
2662
2748
 
2663
2749
  switch (contentBlock.type) {
2664
2750
  case 'text': {
2665
- controller.enqueue({
2666
- type: 'text-end',
2667
- id: String(value.index),
2668
- ...(contentBlock.citations.length > 0 && {
2669
- citations: contentBlock.citations.map(citation =>
2670
- mapAnthropicCitation(citation, citationDocuments),
2671
- ),
2672
- providerMetadata: {
2673
- anthropic: {
2674
- citations: contentBlock.citations,
2675
- },
2676
- } satisfies AnthropicTextProviderMetadata,
2677
- }),
2678
- });
2751
+ controller.enqueue(
2752
+ createTextEnd(
2753
+ String(value.index),
2754
+ contentBlock.citations,
2755
+ ),
2756
+ );
2679
2757
  break;
2680
2758
  }
2681
2759
 
@@ -2798,8 +2876,12 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
2798
2876
  switch (deltaType) {
2799
2877
  case 'text_delta': {
2800
2878
  // when a json response tool is used, the tool call is returned as text,
2801
- // so we ignore the text content:
2879
+ // so the text content is held back until we know whether it was called:
2802
2880
  if (usesJsonResponseTool) {
2881
+ const entry = heldBackTextByIndex.get(value.index);
2882
+ if (entry != null) {
2883
+ entry.text += value.delta.text;
2884
+ }
2803
2885
  return; // excluding the text-start will also exclude the text-end
2804
2886
  }
2805
2887
 
@@ -2913,6 +2995,9 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
2913
2995
  if (contentBlock?.type === 'text') {
2914
2996
  contentBlock.citations.push(citation);
2915
2997
  }
2998
+ heldBackTextByIndex
2999
+ .get(value.index)
3000
+ ?.citations.push(citation);
2916
3001
 
2917
3002
  if (citation.type === 'web_search_result_location') {
2918
3003
  fallbackWebCitations.push(citation);
@@ -2958,6 +3043,7 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
2958
3043
 
2959
3044
  isMessageOpen = true;
2960
3045
  activeMessageId = value.message.id;
3046
+ heldBackTextByIndex.clear();
2961
3047
 
2962
3048
  usage.input_tokens = value.message.usage.input_tokens;
2963
3049
  usage.cache_read_input_tokens =
@@ -3192,6 +3278,22 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
3192
3278
  }
3193
3279
  }
3194
3280
  fallbackWebCitations.length = 0;
3281
+
3282
+ // a message that hands off to a tool or continuation is not the
3283
+ // final answer, so its held-back text is discarded:
3284
+ if (
3285
+ !isJsonResponseFromTool &&
3286
+ !isContinuationStopReason(finishReason.raw)
3287
+ ) {
3288
+ for (const { id, text, citations } of heldBackText) {
3289
+ if (text.length === 0) continue;
3290
+ controller.enqueue({ type: 'text-start', id });
3291
+ controller.enqueue({ type: 'text-delta', id, delta: text });
3292
+ controller.enqueue(createTextEnd(id, citations));
3293
+ }
3294
+ }
3295
+ heldBackText.length = 0;
3296
+
3195
3297
  controller.enqueue({
3196
3298
  type: 'finish',
3197
3299
  finishReason,
@@ -3328,285 +3430,7 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
3328
3430
  }
3329
3431
  }
3330
3432
 
3331
- /**
3332
- * Returns the capabilities of a Claude model that are used for defaults and feature selection.
3333
- *
3334
- * @see https://docs.claude.com/en/docs/about-claude/models/overview#model-comparison-table
3335
- * @see https://platform.claude.com/docs/en/build-with-claude/structured-outputs
3336
- */
3337
- export function getModelCapabilities(modelId: string): {
3338
- maxOutputTokens: number;
3339
- supportsStructuredOutput: boolean;
3340
- supportsAdaptiveThinking: boolean;
3341
- rejectsSamplingParameters: boolean;
3342
- supportsXhighEffort: boolean;
3343
- rejectsThinkingDisabledAboveHighEffort: boolean;
3344
- /**
3345
- * Thinking is always adaptive: `thinking.type` `disabled` and `enabled`
3346
- * are rejected with a 400.
3347
- */
3348
- rejectsThinkingDisabled: boolean;
3349
- /**
3350
- * Budget-based thinking (`thinking.type` `enabled` with `budget_tokens`) is
3351
- * rejected with a 400. Only adaptive thinking is supported.
3352
- */
3353
- rejectsBudgetThinking: boolean;
3354
- /**
3355
- * Forced tool use (`tool_choice` `any` or a named tool) is rejected with a 400.
3356
- */
3357
- rejectsForcedToolUse: boolean;
3358
- /**
3359
- * Supports `thinking.type` `between_tools`, the lowest thinking setting on
3360
- * models that reject disabled thinking.
3361
- */
3362
- supportsBetweenToolsThinking: boolean;
3363
- isKnownModel: boolean;
3364
- } {
3365
- if (modelId.includes('claude-sonnet-5-5')) {
3366
- return {
3367
- maxOutputTokens: 128000,
3368
- supportsStructuredOutput: true,
3369
- supportsAdaptiveThinking: true,
3370
- rejectsSamplingParameters: true,
3371
- supportsXhighEffort: true,
3372
- rejectsThinkingDisabledAboveHighEffort: true,
3373
- rejectsThinkingDisabled: true,
3374
- rejectsBudgetThinking: true,
3375
- rejectsForcedToolUse: true,
3376
- supportsBetweenToolsThinking: true,
3377
- isKnownModel: true,
3378
- };
3379
- } else if (modelId.includes('claude-opus-5-5')) {
3380
- return {
3381
- maxOutputTokens: 128000,
3382
- supportsStructuredOutput: true,
3383
- supportsAdaptiveThinking: true,
3384
- rejectsSamplingParameters: true,
3385
- supportsXhighEffort: true,
3386
- rejectsThinkingDisabledAboveHighEffort: true,
3387
- rejectsThinkingDisabled: true,
3388
- rejectsBudgetThinking: true,
3389
- rejectsForcedToolUse: true,
3390
- supportsBetweenToolsThinking: false,
3391
- isKnownModel: true,
3392
- };
3393
- } else if (modelId.includes('claude-haiku-5-5')) {
3394
- // Thinking can be turned off, but only up to `high` effort.
3395
- return {
3396
- maxOutputTokens: 128000,
3397
- supportsStructuredOutput: true,
3398
- supportsAdaptiveThinking: true,
3399
- rejectsSamplingParameters: true,
3400
- supportsXhighEffort: true,
3401
- rejectsThinkingDisabledAboveHighEffort: true,
3402
- rejectsThinkingDisabled: false,
3403
- rejectsBudgetThinking: true,
3404
- rejectsForcedToolUse: false,
3405
- supportsBetweenToolsThinking: false,
3406
- isKnownModel: true,
3407
- };
3408
- } else if (modelId.includes('claude-opus-5')) {
3409
- return {
3410
- maxOutputTokens: 128000,
3411
- supportsStructuredOutput: true,
3412
- supportsAdaptiveThinking: true,
3413
- rejectsSamplingParameters: true,
3414
- supportsXhighEffort: true,
3415
- rejectsThinkingDisabledAboveHighEffort: true,
3416
- rejectsThinkingDisabled: false,
3417
- rejectsBudgetThinking: false,
3418
- rejectsForcedToolUse: false,
3419
- supportsBetweenToolsThinking: false,
3420
- isKnownModel: true,
3421
- };
3422
- } else if (modelId.includes('claude-fable-5-1')) {
3423
- return {
3424
- maxOutputTokens: 128000,
3425
- supportsStructuredOutput: true,
3426
- supportsAdaptiveThinking: true,
3427
- rejectsSamplingParameters: true,
3428
- supportsXhighEffort: true,
3429
- rejectsThinkingDisabledAboveHighEffort: false,
3430
- rejectsThinkingDisabled: true,
3431
- rejectsBudgetThinking: true,
3432
- rejectsForcedToolUse: true,
3433
- supportsBetweenToolsThinking: false,
3434
- isKnownModel: true,
3435
- };
3436
- } else if (modelId.includes('claude-fable-5')) {
3437
- return {
3438
- maxOutputTokens: 128000,
3439
- supportsStructuredOutput: true,
3440
- supportsAdaptiveThinking: true,
3441
- rejectsSamplingParameters: true,
3442
- supportsXhighEffort: true,
3443
- rejectsThinkingDisabledAboveHighEffort: false,
3444
- rejectsThinkingDisabled: true,
3445
- rejectsBudgetThinking: true,
3446
- rejectsForcedToolUse: false,
3447
- supportsBetweenToolsThinking: false,
3448
- isKnownModel: true,
3449
- };
3450
- } else if (
3451
- modelId.includes('claude-opus-4-8') ||
3452
- modelId.includes('claude-opus-4-7') ||
3453
- modelId.includes('claude-sonnet-5')
3454
- ) {
3455
- return {
3456
- maxOutputTokens: 128000,
3457
- supportsStructuredOutput: true,
3458
- supportsAdaptiveThinking: true,
3459
- rejectsSamplingParameters: true,
3460
- supportsXhighEffort: true,
3461
- rejectsThinkingDisabledAboveHighEffort: false,
3462
- rejectsThinkingDisabled: false,
3463
- rejectsBudgetThinking: false,
3464
- rejectsForcedToolUse: false,
3465
- supportsBetweenToolsThinking: false,
3466
- isKnownModel: true,
3467
- };
3468
- } else if (
3469
- modelId.includes('claude-sonnet-4-6') ||
3470
- modelId.includes('claude-opus-4-6')
3471
- ) {
3472
- return {
3473
- maxOutputTokens: 128000,
3474
- supportsStructuredOutput: true,
3475
- supportsAdaptiveThinking: true,
3476
- rejectsSamplingParameters: false,
3477
- supportsXhighEffort: false,
3478
- rejectsThinkingDisabledAboveHighEffort: false,
3479
- rejectsThinkingDisabled: false,
3480
- rejectsBudgetThinking: false,
3481
- rejectsForcedToolUse: false,
3482
- supportsBetweenToolsThinking: false,
3483
- isKnownModel: true,
3484
- };
3485
- } else if (
3486
- modelId.includes('claude-sonnet-4-5') ||
3487
- modelId.includes('claude-opus-4-5') ||
3488
- modelId.includes('claude-haiku-4-5')
3489
- ) {
3490
- return {
3491
- maxOutputTokens: 64000,
3492
- supportsStructuredOutput: true,
3493
- supportsAdaptiveThinking: false,
3494
- rejectsSamplingParameters: false,
3495
- supportsXhighEffort: false,
3496
- rejectsThinkingDisabledAboveHighEffort: false,
3497
- rejectsThinkingDisabled: false,
3498
- rejectsBudgetThinking: false,
3499
- rejectsForcedToolUse: false,
3500
- supportsBetweenToolsThinking: false,
3501
- isKnownModel: true,
3502
- };
3503
- } else if (modelId.includes('claude-opus-4-1')) {
3504
- return {
3505
- maxOutputTokens: 32000,
3506
- supportsStructuredOutput: true,
3507
- supportsAdaptiveThinking: false,
3508
- rejectsSamplingParameters: false,
3509
- supportsXhighEffort: false,
3510
- rejectsThinkingDisabledAboveHighEffort: false,
3511
- rejectsThinkingDisabled: false,
3512
- rejectsBudgetThinking: false,
3513
- rejectsForcedToolUse: false,
3514
- supportsBetweenToolsThinking: false,
3515
- isKnownModel: true,
3516
- };
3517
- } else if (/claude-sonnet-4(?:-|@)/.test(modelId)) {
3518
- return {
3519
- maxOutputTokens: 64000,
3520
- supportsStructuredOutput: false,
3521
- supportsAdaptiveThinking: false,
3522
- rejectsSamplingParameters: false,
3523
- supportsXhighEffort: false,
3524
- rejectsThinkingDisabledAboveHighEffort: false,
3525
- rejectsThinkingDisabled: false,
3526
- rejectsBudgetThinking: false,
3527
- rejectsForcedToolUse: false,
3528
- supportsBetweenToolsThinking: false,
3529
- isKnownModel: true,
3530
- };
3531
- } else if (/claude-opus-4(?:-|@)/.test(modelId)) {
3532
- return {
3533
- maxOutputTokens: 32000,
3534
- supportsStructuredOutput: false,
3535
- supportsAdaptiveThinking: false,
3536
- rejectsSamplingParameters: false,
3537
- supportsXhighEffort: false,
3538
- rejectsThinkingDisabledAboveHighEffort: false,
3539
- rejectsThinkingDisabled: false,
3540
- rejectsBudgetThinking: false,
3541
- rejectsForcedToolUse: false,
3542
- supportsBetweenToolsThinking: false,
3543
- isKnownModel: true,
3544
- };
3545
- } else if (modelId.includes('claude-3-haiku')) {
3546
- return {
3547
- maxOutputTokens: 4096,
3548
- supportsStructuredOutput: false,
3549
- supportsAdaptiveThinking: false,
3550
- rejectsSamplingParameters: false,
3551
- supportsXhighEffort: false,
3552
- rejectsThinkingDisabledAboveHighEffort: false,
3553
- rejectsThinkingDisabled: false,
3554
- rejectsBudgetThinking: false,
3555
- rejectsForcedToolUse: false,
3556
- supportsBetweenToolsThinking: false,
3557
- isKnownModel: true,
3558
- };
3559
- } else if (
3560
- /claude-(?:instant(?:-|$)|v?2(?=$|[-.:])|3(?=$|[-.]))/.test(modelId)
3561
- ) {
3562
- return {
3563
- maxOutputTokens: 4096,
3564
- supportsStructuredOutput: false,
3565
- supportsAdaptiveThinking: false,
3566
- rejectsSamplingParameters: false,
3567
- supportsXhighEffort: false,
3568
- rejectsThinkingDisabledAboveHighEffort: false,
3569
- rejectsThinkingDisabled: false,
3570
- rejectsBudgetThinking: false,
3571
- rejectsForcedToolUse: false,
3572
- supportsBetweenToolsThinking: false,
3573
- isKnownModel: false,
3574
- };
3575
- } else if (modelId.includes('claude-')) {
3576
- // Known and legacy Claude families are handled above, so any remaining
3577
- // Claude ID is assumed to be newer than the known list. Keep it unknown so
3578
- // callers still receive the maxOutputTokens compatibility warning.
3579
- return {
3580
- maxOutputTokens: 128000,
3581
- supportsStructuredOutput: true,
3582
- supportsAdaptiveThinking: true,
3583
- rejectsSamplingParameters: true,
3584
- supportsXhighEffort: true,
3585
- rejectsThinkingDisabledAboveHighEffort: true,
3586
- rejectsThinkingDisabled: false,
3587
- rejectsBudgetThinking: false,
3588
- rejectsForcedToolUse: false,
3589
- supportsBetweenToolsThinking: false,
3590
- isKnownModel: false,
3591
- };
3592
- } else {
3593
- // Non-Claude models (e.g. served through Anthropic-compatible APIs)
3594
- // keep conservative defaults.
3595
- return {
3596
- maxOutputTokens: 4096,
3597
- supportsStructuredOutput: false,
3598
- supportsAdaptiveThinking: false,
3599
- rejectsSamplingParameters: false,
3600
- supportsXhighEffort: false,
3601
- rejectsThinkingDisabledAboveHighEffort: false,
3602
- rejectsThinkingDisabled: false,
3603
- rejectsBudgetThinking: false,
3604
- rejectsForcedToolUse: false,
3605
- supportsBetweenToolsThinking: false,
3606
- isKnownModel: false,
3607
- };
3608
- }
3609
- }
3433
+ export { getAnthropicModelCapabilities as getModelCapabilities } from './anthropic-model-catalog';
3610
3434
 
3611
3435
  export function hasDynamicFilteringWebToolWithoutCodeExecution(
3612
3436
  tools: AnthropicTool[] | undefined,