@tanstack/ai-anthropic 0.7.4 → 0.8.0

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.
Files changed (49) hide show
  1. package/dist/esm/adapters/summarize.js +5 -4
  2. package/dist/esm/adapters/summarize.js.map +1 -1
  3. package/dist/esm/adapters/text.d.ts +5 -4
  4. package/dist/esm/adapters/text.js +121 -35
  5. package/dist/esm/adapters/text.js.map +1 -1
  6. package/dist/esm/index.d.ts +1 -1
  7. package/dist/esm/model-meta.d.ts +28 -0
  8. package/dist/esm/model-meta.js.map +1 -1
  9. package/dist/esm/tools/bash-tool.d.ts +7 -4
  10. package/dist/esm/tools/bash-tool.js +8 -0
  11. package/dist/esm/tools/bash-tool.js.map +1 -1
  12. package/dist/esm/tools/code-execution-tool.d.ts +7 -4
  13. package/dist/esm/tools/code-execution-tool.js +8 -0
  14. package/dist/esm/tools/code-execution-tool.js.map +1 -1
  15. package/dist/esm/tools/computer-use-tool.d.ts +7 -4
  16. package/dist/esm/tools/computer-use-tool.js +8 -0
  17. package/dist/esm/tools/computer-use-tool.js.map +1 -1
  18. package/dist/esm/tools/custom-tool.d.ts +4 -2
  19. package/dist/esm/tools/custom-tool.js +12 -1
  20. package/dist/esm/tools/custom-tool.js.map +1 -1
  21. package/dist/esm/tools/index.d.ts +8 -1
  22. package/dist/esm/tools/index.js +19 -0
  23. package/dist/esm/tools/index.js.map +1 -0
  24. package/dist/esm/tools/memory-tool.d.ts +7 -4
  25. package/dist/esm/tools/memory-tool.js +9 -1
  26. package/dist/esm/tools/memory-tool.js.map +1 -1
  27. package/dist/esm/tools/text-editor-tool.d.ts +7 -4
  28. package/dist/esm/tools/text-editor-tool.js +9 -1
  29. package/dist/esm/tools/text-editor-tool.js.map +1 -1
  30. package/dist/esm/tools/web-fetch-tool.d.ts +7 -4
  31. package/dist/esm/tools/web-fetch-tool.js +9 -1
  32. package/dist/esm/tools/web-fetch-tool.js.map +1 -1
  33. package/dist/esm/tools/web-search-tool.d.ts +7 -4
  34. package/dist/esm/tools/web-search-tool.js +41 -1
  35. package/dist/esm/tools/web-search-tool.js.map +1 -1
  36. package/package.json +7 -3
  37. package/src/adapters/summarize.ts +8 -4
  38. package/src/adapters/text.ts +155 -40
  39. package/src/index.ts +2 -1
  40. package/src/model-meta.ts +126 -0
  41. package/src/tools/bash-tool.ts +13 -6
  42. package/src/tools/code-execution-tool.ts +17 -6
  43. package/src/tools/computer-use-tool.ts +14 -6
  44. package/src/tools/custom-tool.ts +5 -3
  45. package/src/tools/index.ts +49 -12
  46. package/src/tools/memory-tool.ts +12 -6
  47. package/src/tools/text-editor-tool.ts +14 -6
  48. package/src/tools/web-fetch-tool.ts +15 -7
  49. package/src/tools/web-search-tool.ts +17 -7
@@ -9,6 +9,7 @@ import {
9
9
  import type {
10
10
  ANTHROPIC_MODELS,
11
11
  AnthropicChatModelProviderOptionsByName,
12
+ AnthropicChatModelToolCapabilitiesByName,
12
13
  AnthropicModelInputModalitiesByName,
13
14
  } from '../model-meta'
14
15
  import type {
@@ -45,6 +46,11 @@ import type {
45
46
  } from '../message-types'
46
47
  import type { AnthropicClientConfig } from '../utils'
47
48
 
49
+ /** Cast an event object to StreamChunk. Adapters construct events with string
50
+ * literal types which are structurally compatible with the EventType enum. */
51
+ const asChunk = (chunk: Record<string, unknown>) =>
52
+ chunk as unknown as StreamChunk
53
+
48
54
  /**
49
55
  * Configuration for Anthropic text adapter
50
56
  */
@@ -84,6 +90,11 @@ type ResolveInputModalities<TModel extends string> =
84
90
  ? AnthropicModelInputModalitiesByName[TModel]
85
91
  : readonly ['text', 'image', 'document']
86
92
 
93
+ type ResolveToolCapabilities<TModel extends string> =
94
+ TModel extends keyof AnthropicChatModelToolCapabilitiesByName
95
+ ? NonNullable<AnthropicChatModelToolCapabilitiesByName[TModel]>
96
+ : readonly []
97
+
87
98
  // ===========================
88
99
  // Adapter Implementation
89
100
  // ===========================
@@ -96,14 +107,17 @@ type ResolveInputModalities<TModel extends string> =
96
107
  */
97
108
  export class AnthropicTextAdapter<
98
109
  TModel extends (typeof ANTHROPIC_MODELS)[number],
99
- TProviderOptions extends object = ResolveProviderOptions<TModel>,
110
+ TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,
100
111
  TInputModalities extends ReadonlyArray<Modality> =
101
112
  ResolveInputModalities<TModel>,
113
+ TToolCapabilities extends ReadonlyArray<string> =
114
+ ResolveToolCapabilities<TModel>,
102
115
  > extends BaseTextAdapter<
103
116
  TModel,
104
117
  TProviderOptions,
105
118
  TInputModalities,
106
- AnthropicMessageMetadataByModality
119
+ AnthropicMessageMetadataByModality,
120
+ TToolCapabilities
107
121
  > {
108
122
  readonly kind = 'text' as const
109
123
  readonly name = 'anthropic' as const
@@ -116,7 +130,7 @@ export class AnthropicTextAdapter<
116
130
  }
117
131
 
118
132
  async *chatStream(
119
- options: TextOptions<AnthropicTextProviderOptions>,
133
+ options: TextOptions<TProviderOptions>,
120
134
  ): AsyncIterable<StreamChunk> {
121
135
  try {
122
136
  const requestParams = this.mapCommonOptionsToAnthropic(options)
@@ -129,20 +143,22 @@ export class AnthropicTextAdapter<
129
143
  },
130
144
  )
131
145
 
132
- yield* this.processAnthropicStream(stream, options.model, () =>
146
+ yield* this.processAnthropicStream(stream, options, () =>
133
147
  generateId(this.name),
134
148
  )
135
149
  } catch (error: unknown) {
136
150
  const err = error as Error & { status?: number; code?: string }
137
- yield {
151
+ yield asChunk({
138
152
  type: 'RUN_ERROR',
139
153
  model: options.model,
140
154
  timestamp: Date.now(),
155
+ message: err.message || 'Unknown error occurred',
156
+ code: err.code || String(err.status),
141
157
  error: {
142
158
  message: err.message || 'Unknown error occurred',
143
159
  code: err.code || String(err.status),
144
160
  },
145
- }
161
+ })
146
162
  }
147
163
  }
148
164
 
@@ -153,7 +169,7 @@ export class AnthropicTextAdapter<
153
169
  * The outputSchema is already JSON Schema (converted in the ai layer).
154
170
  */
155
171
  async structuredOutput(
156
- options: StructuredOutputOptions<AnthropicTextProviderOptions>,
172
+ options: StructuredOutputOptions<TProviderOptions>,
157
173
  ): Promise<StructuredOutputResult<unknown>> {
158
174
  const { chatOptions, outputSchema } = options
159
175
 
@@ -523,9 +539,10 @@ export class AnthropicTextAdapter<
523
539
 
524
540
  private async *processAnthropicStream(
525
541
  stream: AsyncIterable<Anthropic_SDK.Beta.BetaRawMessageStreamEvent>,
526
- model: string,
542
+ options: TextOptions<AnthropicTextProviderOptions>,
527
543
  genId: () => string,
528
544
  ): AsyncIterable<StreamChunk> {
545
+ const model = options.model
529
546
  let accumulatedContent = ''
530
547
  let accumulatedThinking = ''
531
548
  const timestamp = Date.now()
@@ -536,9 +553,12 @@ export class AnthropicTextAdapter<
536
553
  let currentToolIndex = -1
537
554
 
538
555
  // AG-UI lifecycle tracking
539
- const runId = genId()
556
+ const runId = options.runId ?? genId()
557
+ const threadId = options.threadId ?? genId()
540
558
  const messageId = genId()
541
559
  let stepId: string | null = null
560
+ let reasoningMessageId: string | null = null
561
+ let hasClosedReasoning = false
542
562
  let hasEmittedRunStarted = false
543
563
  let hasEmittedTextMessageStart = false
544
564
  let hasEmittedRunFinished = false
@@ -550,12 +570,13 @@ export class AnthropicTextAdapter<
550
570
  // Emit RUN_STARTED on first event
551
571
  if (!hasEmittedRunStarted) {
552
572
  hasEmittedRunStarted = true
553
- yield {
573
+ yield asChunk({
554
574
  type: 'RUN_STARTED',
555
575
  runId,
576
+ threadId,
556
577
  model,
557
578
  timestamp,
558
- }
579
+ })
559
580
  }
560
581
 
561
582
  if (event.type === 'content_block_start') {
@@ -570,77 +591,126 @@ export class AnthropicTextAdapter<
570
591
  })
571
592
  } else if (event.content_block.type === 'thinking') {
572
593
  accumulatedThinking = ''
573
- // Emit STEP_STARTED for thinking
594
+ // Emit REASONING and STEP_STARTED for thinking
574
595
  stepId = genId()
575
- yield {
596
+ reasoningMessageId = genId()
597
+
598
+ // Spec REASONING events
599
+ yield asChunk({
600
+ type: 'REASONING_START',
601
+ messageId: reasoningMessageId,
602
+ model,
603
+ timestamp,
604
+ })
605
+ yield asChunk({
606
+ type: 'REASONING_MESSAGE_START',
607
+ messageId: reasoningMessageId,
608
+ role: 'reasoning' as const,
609
+ model,
610
+ timestamp,
611
+ })
612
+
613
+ // Legacy STEP events (kept during transition)
614
+ yield asChunk({
576
615
  type: 'STEP_STARTED',
616
+ stepName: stepId,
577
617
  stepId,
578
618
  model,
579
619
  timestamp,
580
620
  stepType: 'thinking',
581
- }
621
+ })
582
622
  }
583
623
  } else if (event.type === 'content_block_delta') {
584
624
  if (event.delta.type === 'text_delta') {
625
+ // Close reasoning before text starts
626
+ if (reasoningMessageId && !hasClosedReasoning) {
627
+ hasClosedReasoning = true
628
+ yield asChunk({
629
+ type: 'REASONING_MESSAGE_END',
630
+ messageId: reasoningMessageId,
631
+ model,
632
+ timestamp,
633
+ })
634
+ yield asChunk({
635
+ type: 'REASONING_END',
636
+ messageId: reasoningMessageId,
637
+ model,
638
+ timestamp,
639
+ })
640
+ }
641
+
585
642
  // Emit TEXT_MESSAGE_START on first text content
586
643
  if (!hasEmittedTextMessageStart) {
587
644
  hasEmittedTextMessageStart = true
588
- yield {
645
+ yield asChunk({
589
646
  type: 'TEXT_MESSAGE_START',
590
647
  messageId,
591
648
  model,
592
649
  timestamp,
593
650
  role: 'assistant',
594
- }
651
+ })
595
652
  }
596
653
 
597
654
  const delta = event.delta.text
598
655
  accumulatedContent += delta
599
- yield {
656
+ yield asChunk({
600
657
  type: 'TEXT_MESSAGE_CONTENT',
601
658
  messageId,
602
659
  model,
603
660
  timestamp,
604
661
  delta,
605
662
  content: accumulatedContent,
606
- }
663
+ })
607
664
  } else if (event.delta.type === 'thinking_delta') {
608
665
  const delta = event.delta.thinking
609
666
  accumulatedThinking += delta
610
- yield {
667
+
668
+ // Spec REASONING content event
669
+ yield asChunk({
670
+ type: 'REASONING_MESSAGE_CONTENT',
671
+ messageId: reasoningMessageId!,
672
+ delta,
673
+ model,
674
+ timestamp,
675
+ })
676
+
677
+ // Legacy STEP event
678
+ yield asChunk({
611
679
  type: 'STEP_FINISHED',
680
+ stepName: stepId || genId(),
612
681
  stepId: stepId || genId(),
613
682
  model,
614
683
  timestamp,
615
684
  delta,
616
685
  content: accumulatedThinking,
617
- }
686
+ })
618
687
  } else if (event.delta.type === 'input_json_delta') {
619
688
  const existing = toolCallsMap.get(currentToolIndex)
620
689
  if (existing) {
621
690
  // Emit TOOL_CALL_START on first args delta
622
691
  if (!existing.started) {
623
692
  existing.started = true
624
- yield {
693
+ yield asChunk({
625
694
  type: 'TOOL_CALL_START',
626
695
  toolCallId: existing.id,
696
+ toolCallName: existing.name,
627
697
  toolName: existing.name,
628
698
  model,
629
699
  timestamp,
630
700
  index: currentToolIndex,
631
- }
701
+ })
632
702
  }
633
703
 
634
704
  existing.input += event.delta.partial_json
635
705
 
636
- yield {
706
+ yield asChunk({
637
707
  type: 'TOOL_CALL_ARGS',
638
708
  toolCallId: existing.id,
639
709
  model,
640
710
  timestamp,
641
711
  delta: event.delta.partial_json,
642
712
  args: existing.input,
643
- }
713
+ })
644
714
  }
645
715
  }
646
716
  } else if (event.type === 'content_block_stop') {
@@ -650,14 +720,15 @@ export class AnthropicTextAdapter<
650
720
  // If tool call wasn't started yet (no args), start it now
651
721
  if (!existing.started) {
652
722
  existing.started = true
653
- yield {
723
+ yield asChunk({
654
724
  type: 'TOOL_CALL_START',
655
725
  toolCallId: existing.id,
726
+ toolCallName: existing.name,
656
727
  toolName: existing.name,
657
728
  model,
658
729
  timestamp,
659
730
  index: currentToolIndex,
660
- }
731
+ })
661
732
  }
662
733
 
663
734
  // Emit TOOL_CALL_END
@@ -669,14 +740,15 @@ export class AnthropicTextAdapter<
669
740
  parsedInput = {}
670
741
  }
671
742
 
672
- yield {
743
+ yield asChunk({
673
744
  type: 'TOOL_CALL_END',
674
745
  toolCallId: existing.id,
746
+ toolCallName: existing.name,
675
747
  toolName: existing.name,
676
748
  model,
677
749
  timestamp,
678
750
  input: parsedInput,
679
- }
751
+ })
680
752
 
681
753
  // Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls
682
754
  hasEmittedTextMessageStart = false
@@ -684,36 +756,73 @@ export class AnthropicTextAdapter<
684
756
  } else {
685
757
  // Emit TEXT_MESSAGE_END only for text blocks (not tool_use blocks)
686
758
  if (hasEmittedTextMessageStart && accumulatedContent) {
687
- yield {
759
+ yield asChunk({
688
760
  type: 'TEXT_MESSAGE_END',
689
761
  messageId,
690
762
  model,
691
763
  timestamp,
692
- }
764
+ })
693
765
  }
694
766
  }
695
767
  currentBlockType = null
696
768
  } else if (event.type === 'message_stop') {
769
+ // Close reasoning events if still open
770
+ if (reasoningMessageId && !hasClosedReasoning) {
771
+ hasClosedReasoning = true
772
+ yield asChunk({
773
+ type: 'REASONING_MESSAGE_END',
774
+ messageId: reasoningMessageId,
775
+ model,
776
+ timestamp,
777
+ })
778
+ yield asChunk({
779
+ type: 'REASONING_END',
780
+ messageId: reasoningMessageId,
781
+ model,
782
+ timestamp,
783
+ })
784
+ }
785
+
697
786
  // Only emit RUN_FINISHED from message_stop if message_delta didn't already emit one.
698
787
  // message_delta carries the real stop_reason (tool_use, end_turn, etc.),
699
788
  // while message_stop is just a completion signal.
700
789
  if (!hasEmittedRunFinished) {
701
- yield {
790
+ yield asChunk({
702
791
  type: 'RUN_FINISHED',
703
792
  runId,
793
+ threadId,
704
794
  model,
705
795
  timestamp,
706
796
  finishReason: 'stop',
707
- }
797
+ })
708
798
  }
709
799
  } else if (event.type === 'message_delta') {
710
800
  if (event.delta.stop_reason) {
711
801
  hasEmittedRunFinished = true
802
+
803
+ // Close reasoning events if still open
804
+ if (reasoningMessageId && !hasClosedReasoning) {
805
+ hasClosedReasoning = true
806
+ yield asChunk({
807
+ type: 'REASONING_MESSAGE_END',
808
+ messageId: reasoningMessageId,
809
+ model,
810
+ timestamp,
811
+ })
812
+ yield asChunk({
813
+ type: 'REASONING_END',
814
+ messageId: reasoningMessageId,
815
+ model,
816
+ timestamp,
817
+ })
818
+ }
819
+
712
820
  switch (event.delta.stop_reason) {
713
821
  case 'tool_use': {
714
- yield {
822
+ yield asChunk({
715
823
  type: 'RUN_FINISHED',
716
824
  runId,
825
+ threadId,
717
826
  model,
718
827
  timestamp,
719
828
  finishReason: 'tool_calls',
@@ -724,27 +833,31 @@ export class AnthropicTextAdapter<
724
833
  (event.usage.input_tokens || 0) +
725
834
  (event.usage.output_tokens || 0),
726
835
  },
727
- }
836
+ })
728
837
  break
729
838
  }
730
839
  case 'max_tokens': {
731
- yield {
840
+ yield asChunk({
732
841
  type: 'RUN_ERROR',
733
842
  runId,
734
843
  model,
735
844
  timestamp,
845
+ message:
846
+ 'The response was cut off because the maximum token limit was reached.',
847
+ code: 'max_tokens',
736
848
  error: {
737
849
  message:
738
850
  'The response was cut off because the maximum token limit was reached.',
739
851
  code: 'max_tokens',
740
852
  },
741
- }
853
+ })
742
854
  break
743
855
  }
744
856
  default: {
745
- yield {
857
+ yield asChunk({
746
858
  type: 'RUN_FINISHED',
747
859
  runId,
860
+ threadId,
748
861
  model,
749
862
  timestamp,
750
863
  finishReason: 'stop',
@@ -755,7 +868,7 @@ export class AnthropicTextAdapter<
755
868
  (event.usage.input_tokens || 0) +
756
869
  (event.usage.output_tokens || 0),
757
870
  },
758
- }
871
+ })
759
872
  }
760
873
  }
761
874
  }
@@ -764,16 +877,18 @@ export class AnthropicTextAdapter<
764
877
  } catch (error: unknown) {
765
878
  const err = error as Error & { status?: number; code?: string }
766
879
 
767
- yield {
880
+ yield asChunk({
768
881
  type: 'RUN_ERROR',
769
882
  runId,
770
883
  model,
771
884
  timestamp,
885
+ message: err.message || 'Unknown error occurred',
886
+ code: err.code || String(err.status),
772
887
  error: {
773
888
  message: err.message || 'Unknown error occurred',
774
889
  code: err.code || String(err.status),
775
890
  },
776
- }
891
+ })
777
892
  }
778
893
  }
779
894
  }
package/src/index.ts CHANGED
@@ -24,9 +24,10 @@ export {
24
24
  // ============================================================================
25
25
 
26
26
  export type {
27
+ AnthropicChatModel,
27
28
  AnthropicChatModelProviderOptionsByName,
29
+ AnthropicChatModelToolCapabilitiesByName,
28
30
  AnthropicModelInputModalitiesByName,
29
- AnthropicChatModel,
30
31
  } from './model-meta'
31
32
  export { ANTHROPIC_MODELS } from './model-meta'
32
33
  export type {
package/src/model-meta.ts CHANGED
@@ -21,6 +21,15 @@ interface ModelMeta<
21
21
  extended_thinking?: boolean
22
22
  adaptive_thinking?: boolean
23
23
  priority_tier?: boolean
24
+ tools?: Array<
25
+ | 'web_search'
26
+ | 'web_fetch'
27
+ | 'code_execution'
28
+ | 'computer_use'
29
+ | 'bash'
30
+ | 'text_editor'
31
+ | 'memory'
32
+ >
24
33
  }
25
34
  context_window?: number
26
35
  max_output_tokens?: number
@@ -66,6 +75,15 @@ const CLAUDE_OPUS_4_6 = {
66
75
  input: ['text', 'image', 'document'],
67
76
  extended_thinking: true,
68
77
  priority_tier: true,
78
+ tools: [
79
+ 'web_search',
80
+ 'web_fetch',
81
+ 'code_execution',
82
+ 'computer_use',
83
+ 'bash',
84
+ 'text_editor',
85
+ 'memory',
86
+ ],
69
87
  },
70
88
  } as const satisfies ModelMeta<
71
89
  AnthropicContainerOptions &
@@ -96,6 +114,15 @@ const CLAUDE_OPUS_4_5 = {
96
114
  input: ['text', 'image', 'document'],
97
115
  extended_thinking: true,
98
116
  priority_tier: true,
117
+ tools: [
118
+ 'web_search',
119
+ 'web_fetch',
120
+ 'code_execution',
121
+ 'computer_use',
122
+ 'bash',
123
+ 'text_editor',
124
+ 'memory',
125
+ ],
99
126
  },
100
127
  } as const satisfies ModelMeta<
101
128
  AnthropicContainerOptions &
@@ -127,6 +154,15 @@ const CLAUDE_SONNET_4_6 = {
127
154
  extended_thinking: true,
128
155
  adaptive_thinking: true,
129
156
  priority_tier: true,
157
+ tools: [
158
+ 'web_search',
159
+ 'web_fetch',
160
+ 'code_execution',
161
+ 'computer_use',
162
+ 'bash',
163
+ 'text_editor',
164
+ 'memory',
165
+ ],
130
166
  },
131
167
  } as const satisfies ModelMeta<
132
168
  AnthropicContainerOptions &
@@ -157,6 +193,15 @@ const CLAUDE_SONNET_4_5 = {
157
193
  input: ['text', 'image', 'document'],
158
194
  extended_thinking: true,
159
195
  priority_tier: true,
196
+ tools: [
197
+ 'web_search',
198
+ 'web_fetch',
199
+ 'code_execution',
200
+ 'computer_use',
201
+ 'bash',
202
+ 'text_editor',
203
+ 'memory',
204
+ ],
160
205
  },
161
206
  } as const satisfies ModelMeta<
162
207
  AnthropicContainerOptions &
@@ -187,6 +232,15 @@ const CLAUDE_HAIKU_4_5 = {
187
232
  input: ['text', 'image', 'document'],
188
233
  extended_thinking: true,
189
234
  priority_tier: true,
235
+ tools: [
236
+ 'web_search',
237
+ 'web_fetch',
238
+ 'code_execution',
239
+ 'computer_use',
240
+ 'bash',
241
+ 'text_editor',
242
+ 'memory',
243
+ ],
190
244
  },
191
245
  } as const satisfies ModelMeta<
192
246
  AnthropicContainerOptions &
@@ -217,6 +271,15 @@ const CLAUDE_OPUS_4_1 = {
217
271
  input: ['text', 'image', 'document'],
218
272
  extended_thinking: true,
219
273
  priority_tier: true,
274
+ tools: [
275
+ 'web_search',
276
+ 'web_fetch',
277
+ 'code_execution',
278
+ 'computer_use',
279
+ 'bash',
280
+ 'text_editor',
281
+ 'memory',
282
+ ],
220
283
  },
221
284
  } as const satisfies ModelMeta<
222
285
  AnthropicContainerOptions &
@@ -247,6 +310,15 @@ const CLAUDE_SONNET_4 = {
247
310
  input: ['text', 'image', 'document'],
248
311
  extended_thinking: true,
249
312
  priority_tier: true,
313
+ tools: [
314
+ 'web_search',
315
+ 'web_fetch',
316
+ 'code_execution',
317
+ 'computer_use',
318
+ 'bash',
319
+ 'text_editor',
320
+ 'memory',
321
+ ],
250
322
  },
251
323
  } as const satisfies ModelMeta<
252
324
  AnthropicContainerOptions &
@@ -276,6 +348,15 @@ const CLAUDE_SONNET_3_7 = {
276
348
  input: ['text', 'image', 'document'],
277
349
  extended_thinking: true,
278
350
  priority_tier: true,
351
+ tools: [
352
+ 'web_search',
353
+ 'web_fetch',
354
+ 'code_execution',
355
+ 'computer_use',
356
+ 'bash',
357
+ 'text_editor',
358
+ 'memory',
359
+ ],
279
360
  },
280
361
  } as const satisfies ModelMeta<
281
362
  AnthropicContainerOptions &
@@ -306,6 +387,15 @@ const CLAUDE_OPUS_4 = {
306
387
  input: ['text', 'image', 'document'],
307
388
  extended_thinking: true,
308
389
  priority_tier: true,
390
+ tools: [
391
+ 'web_search',
392
+ 'web_fetch',
393
+ 'code_execution',
394
+ 'computer_use',
395
+ 'bash',
396
+ 'text_editor',
397
+ 'memory',
398
+ ],
309
399
  },
310
400
  } as const satisfies ModelMeta<
311
401
  AnthropicContainerOptions &
@@ -336,6 +426,7 @@ const CLAUDE_HAIKU_3_5 = {
336
426
  input: ['text', 'image', 'document'],
337
427
  extended_thinking: false,
338
428
  priority_tier: true,
429
+ tools: ['web_search', 'web_fetch'],
339
430
  },
340
431
  } as const satisfies ModelMeta<
341
432
  AnthropicContainerOptions &
@@ -366,6 +457,7 @@ const CLAUDE_HAIKU_3 = {
366
457
  input: ['text', 'image', 'document'],
367
458
  extended_thinking: false,
368
459
  priority_tier: false,
460
+ tools: ['web_search'],
369
461
  },
370
462
  } as const satisfies ModelMeta<
371
463
  AnthropicContainerOptions &
@@ -432,6 +524,15 @@ const CLAUDE_OPUS_4_6_FAST = {
432
524
  input: ['text', 'image'],
433
525
  extended_thinking: true,
434
526
  priority_tier: true,
527
+ tools: [
528
+ 'web_search',
529
+ 'web_fetch',
530
+ 'code_execution',
531
+ 'computer_use',
532
+ 'bash',
533
+ 'text_editor',
534
+ 'memory',
535
+ ],
435
536
  },
436
537
  pricing: {
437
538
  input: {
@@ -462,6 +563,15 @@ const CLAUDE_OPUS_4_7 = {
462
563
  input: ['text', 'image'],
463
564
  extended_thinking: true,
464
565
  priority_tier: true,
566
+ tools: [
567
+ 'web_search',
568
+ 'web_fetch',
569
+ 'code_execution',
570
+ 'computer_use',
571
+ 'bash',
572
+ 'text_editor',
573
+ 'memory',
574
+ ],
465
575
  },
466
576
  pricing: {
467
577
  input: {
@@ -619,6 +729,22 @@ export type AnthropicChatModelProviderOptionsByName = {
619
729
  AnthropicSamplingOptions
620
730
  }
621
731
 
732
+ export type AnthropicChatModelToolCapabilitiesByName = {
733
+ [CLAUDE_OPUS_4_6.id]: typeof CLAUDE_OPUS_4_6.supports.tools
734
+ [CLAUDE_OPUS_4_5.id]: typeof CLAUDE_OPUS_4_5.supports.tools
735
+ [CLAUDE_SONNET_4_6.id]: typeof CLAUDE_SONNET_4_6.supports.tools
736
+ [CLAUDE_SONNET_4_5.id]: typeof CLAUDE_SONNET_4_5.supports.tools
737
+ [CLAUDE_HAIKU_4_5.id]: typeof CLAUDE_HAIKU_4_5.supports.tools
738
+ [CLAUDE_OPUS_4_1.id]: typeof CLAUDE_OPUS_4_1.supports.tools
739
+ [CLAUDE_SONNET_4.id]: typeof CLAUDE_SONNET_4.supports.tools
740
+ [CLAUDE_SONNET_3_7.id]: typeof CLAUDE_SONNET_3_7.supports.tools
741
+ [CLAUDE_OPUS_4.id]: typeof CLAUDE_OPUS_4.supports.tools
742
+ [CLAUDE_HAIKU_3_5.id]: typeof CLAUDE_HAIKU_3_5.supports.tools
743
+ [CLAUDE_HAIKU_3.id]: typeof CLAUDE_HAIKU_3.supports.tools
744
+ [CLAUDE_OPUS_4_6_FAST.id]: typeof CLAUDE_OPUS_4_6_FAST.supports.tools
745
+ [CLAUDE_OPUS_4_7.id]: typeof CLAUDE_OPUS_4_7.supports.tools
746
+ }
747
+
622
748
  /**
623
749
  * Type-only map from chat model name to its supported input modalities.
624
750
  * All Anthropic Claude models support text, image, and document (PDF) input.