@ai-sdk/anthropic 3.0.19 → 3.0.21

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.
@@ -3020,6 +3020,104 @@ describe('AnthropicMessagesLanguageModel', () => {
3020
3020
  expect(result.content).toMatchSnapshot();
3021
3021
  });
3022
3022
  });
3023
+
3024
+ describe('deferred result - bm25 variant', () => {
3025
+ it('should correctly map tool_search_tool_result when result comes without server_tool_use in same response', async () => {
3026
+ prepareJsonFixtureResponse('anthropic-tool-search-deferred-bm25.2');
3027
+
3028
+ const result = await provider('claude-sonnet-4-5').doGenerate({
3029
+ prompt: [
3030
+ {
3031
+ role: 'user',
3032
+ content: [
3033
+ {
3034
+ type: 'text',
3035
+ text: 'What is the weather in San Francisco?',
3036
+ },
3037
+ ],
3038
+ },
3039
+ ],
3040
+ tools: [
3041
+ {
3042
+ type: 'provider',
3043
+ id: 'anthropic.tool_search_bm25_20251119',
3044
+ name: 'tool_search',
3045
+ args: {},
3046
+ },
3047
+ {
3048
+ type: 'function',
3049
+ name: 'get_weather',
3050
+ description: 'Get the current weather at a specific location',
3051
+ inputSchema: {
3052
+ type: 'object',
3053
+ properties: {
3054
+ location: { type: 'string' },
3055
+ },
3056
+ },
3057
+ providerOptions: {
3058
+ anthropic: { deferLoading: true },
3059
+ },
3060
+ },
3061
+ ],
3062
+ });
3063
+
3064
+ // The tool result should be correctly mapped to 'tool_search' (the user's custom name)
3065
+ // even though serverToolCalls map is empty (no server_tool_use in this response)
3066
+ const toolResult = result.content.find(
3067
+ part => part.type === 'tool-result',
3068
+ );
3069
+ expect(toolResult).toBeDefined();
3070
+ expect(toolResult?.toolName).toBe('tool_search');
3071
+ });
3072
+ });
3073
+
3074
+ describe('deferred result - regex variant', () => {
3075
+ it('should correctly map tool_search_tool_result when result comes without server_tool_use in same response', async () => {
3076
+ prepareJsonFixtureResponse('anthropic-tool-search-deferred-regex.2');
3077
+
3078
+ const result = await provider('claude-sonnet-4-5').doGenerate({
3079
+ prompt: [
3080
+ {
3081
+ role: 'user',
3082
+ content: [
3083
+ {
3084
+ type: 'text',
3085
+ text: 'Find weather data in NYC',
3086
+ },
3087
+ ],
3088
+ },
3089
+ ],
3090
+ tools: [
3091
+ {
3092
+ type: 'provider',
3093
+ id: 'anthropic.tool_search_regex_20251119',
3094
+ name: 'tool_search',
3095
+ args: {},
3096
+ },
3097
+ {
3098
+ type: 'function',
3099
+ name: 'get_temp_data',
3100
+ description: 'For a location',
3101
+ inputSchema: {
3102
+ type: 'object',
3103
+ properties: {
3104
+ location: { type: 'string' },
3105
+ },
3106
+ },
3107
+ providerOptions: {
3108
+ anthropic: { deferLoading: true },
3109
+ },
3110
+ },
3111
+ ],
3112
+ });
3113
+
3114
+ const toolResult = result.content.find(
3115
+ part => part.type === 'tool-result',
3116
+ );
3117
+ expect(toolResult).toBeDefined();
3118
+ expect(toolResult?.toolName).toBe('tool_search');
3119
+ });
3120
+ });
3023
3121
  });
3024
3122
 
3025
3123
  describe('mcp servers', () => {
@@ -6845,6 +6943,106 @@ describe('AnthropicMessagesLanguageModel', () => {
6845
6943
  ).toMatchSnapshot();
6846
6944
  });
6847
6945
  });
6946
+
6947
+ describe('deferred result - bm25 variant', () => {
6948
+ it('should correctly map tool_search_tool_result when result comes without server_tool_use in same response', async () => {
6949
+ prepareChunksFixtureResponse('anthropic-tool-search-deferred-bm25');
6950
+
6951
+ const result = await provider('claude-sonnet-4-5').doStream({
6952
+ prompt: [
6953
+ {
6954
+ role: 'user',
6955
+ content: [
6956
+ {
6957
+ type: 'text',
6958
+ text: 'What is the weather in San Francisco?',
6959
+ },
6960
+ ],
6961
+ },
6962
+ ],
6963
+ tools: [
6964
+ {
6965
+ type: 'provider',
6966
+ id: 'anthropic.tool_search_bm25_20251119',
6967
+ name: 'tool_search',
6968
+ args: {},
6969
+ },
6970
+ {
6971
+ type: 'function',
6972
+ name: 'get_weather',
6973
+ description: 'Get the current weather at a specific location',
6974
+ inputSchema: {
6975
+ type: 'object',
6976
+ properties: {
6977
+ location: { type: 'string' },
6978
+ },
6979
+ },
6980
+ providerOptions: {
6981
+ anthropic: { deferLoading: true },
6982
+ },
6983
+ },
6984
+ ],
6985
+ });
6986
+
6987
+ const chunks = await convertReadableStreamToArray(result.stream);
6988
+
6989
+ const toolResultChunk = chunks.find(
6990
+ chunk => chunk.type === 'tool-result',
6991
+ );
6992
+ expect(toolResultChunk).toBeDefined();
6993
+ expect(toolResultChunk?.toolName).toBe('tool_search');
6994
+ });
6995
+ });
6996
+
6997
+ describe('deferred result - regex variant', () => {
6998
+ it('should correctly map tool_search_tool_result when result comes without server_tool_use in same response', async () => {
6999
+ prepareChunksFixtureResponse('anthropic-tool-search-deferred-regex');
7000
+
7001
+ const result = await provider('claude-sonnet-4-5').doStream({
7002
+ prompt: [
7003
+ {
7004
+ role: 'user',
7005
+ content: [
7006
+ {
7007
+ type: 'text',
7008
+ text: 'Find weather data in NYC',
7009
+ },
7010
+ ],
7011
+ },
7012
+ ],
7013
+ tools: [
7014
+ {
7015
+ type: 'provider',
7016
+ id: 'anthropic.tool_search_regex_20251119',
7017
+ name: 'tool_search',
7018
+ args: {},
7019
+ },
7020
+ {
7021
+ type: 'function',
7022
+ name: 'get_temp_data',
7023
+ description: 'For a location',
7024
+ inputSchema: {
7025
+ type: 'object',
7026
+ properties: {
7027
+ location: { type: 'string' },
7028
+ },
7029
+ },
7030
+ providerOptions: {
7031
+ anthropic: { deferLoading: true },
7032
+ },
7033
+ },
7034
+ ],
7035
+ });
7036
+
7037
+ const chunks = await convertReadableStreamToArray(result.stream);
7038
+
7039
+ const toolResultChunk = chunks.find(
7040
+ chunk => chunk.type === 'tool-result',
7041
+ );
7042
+ expect(toolResultChunk).toBeDefined();
7043
+ expect(toolResultChunk?.toolName).toBe('tool_search');
7044
+ });
7045
+ });
6848
7046
  });
6849
7047
 
6850
7048
  it('should throw an api error when the server is returning a 529 overloaded error', async () => {
@@ -987,8 +987,25 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
987
987
 
988
988
  // tool search tool results:
989
989
  case 'tool_search_tool_result': {
990
- const providerToolName =
991
- serverToolCalls[part.tool_use_id] ?? 'tool_search_tool_regex';
990
+ let providerToolName = serverToolCalls[part.tool_use_id];
991
+
992
+ if (providerToolName == null) {
993
+ const bm25CustomName = toolNameMapping.toCustomToolName(
994
+ 'tool_search_tool_bm25',
995
+ );
996
+ const regexCustomName = toolNameMapping.toCustomToolName(
997
+ 'tool_search_tool_regex',
998
+ );
999
+
1000
+ if (bm25CustomName !== 'tool_search_tool_bm25') {
1001
+ providerToolName = 'tool_search_tool_bm25';
1002
+ } else if (regexCustomName !== 'tool_search_tool_regex') {
1003
+ providerToolName = 'tool_search_tool_regex';
1004
+ } else {
1005
+ providerToolName = 'tool_search_tool_regex';
1006
+ }
1007
+ }
1008
+
992
1009
  if (part.content.type === 'tool_search_tool_search_result') {
993
1010
  content.push({
994
1011
  type: 'tool-result',
@@ -1480,9 +1497,25 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
1480
1497
 
1481
1498
  // tool search tool results:
1482
1499
  case 'tool_search_tool_result': {
1483
- const providerToolName =
1484
- serverToolCalls[part.tool_use_id] ??
1485
- 'tool_search_tool_regex';
1500
+ let providerToolName = serverToolCalls[part.tool_use_id];
1501
+
1502
+ if (providerToolName == null) {
1503
+ const bm25CustomName = toolNameMapping.toCustomToolName(
1504
+ 'tool_search_tool_bm25',
1505
+ );
1506
+ const regexCustomName = toolNameMapping.toCustomToolName(
1507
+ 'tool_search_tool_regex',
1508
+ );
1509
+
1510
+ if (bm25CustomName !== 'tool_search_tool_bm25') {
1511
+ providerToolName = 'tool_search_tool_bm25';
1512
+ } else if (regexCustomName !== 'tool_search_tool_regex') {
1513
+ providerToolName = 'tool_search_tool_regex';
1514
+ } else {
1515
+ providerToolName = 'tool_search_tool_regex';
1516
+ }
1517
+ }
1518
+
1486
1519
  if (part.content.type === 'tool_search_tool_search_result') {
1487
1520
  controller.enqueue({
1488
1521
  type: 'tool-result',
@@ -64,6 +64,7 @@ const factory = createProviderToolFactoryWithOutputSchema<
64
64
  id: 'anthropic.tool_search_bm25_20251119',
65
65
  inputSchema: toolSearchBm25_20251119InputSchema,
66
66
  outputSchema: toolSearchBm25_20251119OutputSchema,
67
+ supportsDeferredResults: true,
67
68
  });
68
69
 
69
70
  /**
@@ -76,6 +76,7 @@ const factory = createProviderToolFactoryWithOutputSchema<
76
76
  id: 'anthropic.tool_search_regex_20251119',
77
77
  inputSchema: toolSearchRegex_20251119InputSchema,
78
78
  outputSchema: toolSearchRegex_20251119OutputSchema,
79
+ supportsDeferredResults: true,
79
80
  });
80
81
 
81
82
  /**