@ai-sdk/anthropic 4.0.0-beta.5 → 4.0.0-beta.67

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 (56) hide show
  1. package/CHANGELOG.md +500 -4
  2. package/README.md +2 -0
  3. package/dist/index.d.ts +265 -68
  4. package/dist/index.js +2636 -1427
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +234 -62
  7. package/dist/internal/index.js +2605 -1413
  8. package/dist/internal/index.js.map +1 -1
  9. package/docs/05-anthropic.mdx +303 -20
  10. package/package.json +16 -17
  11. package/src/{anthropic-messages-api.ts → anthropic-api.ts} +158 -17
  12. package/src/anthropic-error.ts +1 -1
  13. package/src/anthropic-files.ts +95 -0
  14. package/src/{anthropic-messages-options.ts → anthropic-language-model-options.ts} +104 -11
  15. package/src/{anthropic-messages-language-model.ts → anthropic-language-model.ts} +494 -96
  16. package/src/anthropic-message-metadata.ts +69 -9
  17. package/src/anthropic-prepare-tools.ts +31 -7
  18. package/src/anthropic-provider.ts +42 -13
  19. package/src/anthropic-tools.ts +31 -0
  20. package/src/convert-anthropic-usage.ts +109 -0
  21. package/src/{convert-to-anthropic-messages-prompt.ts → convert-to-anthropic-prompt.ts} +376 -198
  22. package/src/forward-anthropic-container-id-from-last-step.ts +2 -2
  23. package/src/get-cache-control.ts +5 -2
  24. package/src/index.ts +1 -1
  25. package/src/internal/index.ts +13 -2
  26. package/src/map-anthropic-stop-reason.ts +1 -1
  27. package/src/sanitize-json-schema.ts +203 -0
  28. package/src/skills/anthropic-skills-api.ts +44 -0
  29. package/src/skills/anthropic-skills.ts +132 -0
  30. package/src/tool/advisor_20260301.ts +128 -0
  31. package/src/tool/bash_20241022.ts +84 -13
  32. package/src/tool/bash_20250124.ts +84 -13
  33. package/src/tool/code-execution_20250522.ts +2 -2
  34. package/src/tool/code-execution_20250825.ts +2 -2
  35. package/src/tool/code-execution_20260120.ts +2 -2
  36. package/src/tool/computer_20241022.ts +2 -2
  37. package/src/tool/computer_20250124.ts +2 -2
  38. package/src/tool/computer_20251124.ts +2 -2
  39. package/src/tool/memory_20250818.ts +2 -2
  40. package/src/tool/text-editor_20241022.ts +2 -2
  41. package/src/tool/text-editor_20250124.ts +2 -2
  42. package/src/tool/text-editor_20250429.ts +2 -2
  43. package/src/tool/text-editor_20250728.ts +6 -3
  44. package/src/tool/tool-search-bm25_20251119.ts +2 -2
  45. package/src/tool/tool-search-regex_20251119.ts +2 -2
  46. package/src/tool/web-fetch-20250910.ts +2 -2
  47. package/src/tool/web-fetch-20260209.ts +2 -2
  48. package/src/tool/web-search_20250305.ts +2 -2
  49. package/src/tool/web-search_20260209.ts +2 -2
  50. package/dist/index.d.mts +0 -1090
  51. package/dist/index.mjs +0 -5244
  52. package/dist/index.mjs.map +0 -1
  53. package/dist/internal/index.d.mts +0 -969
  54. package/dist/internal/index.mjs +0 -5136
  55. package/dist/internal/index.mjs.map +0 -1
  56. package/src/convert-anthropic-messages-usage.ts +0 -73
@@ -1,29 +1,32 @@
1
1
  import {
2
- SharedV4Warning,
3
- LanguageModelV4DataContent,
4
- LanguageModelV4Message,
5
- LanguageModelV4Prompt,
6
- SharedV4ProviderMetadata,
7
2
  UnsupportedFunctionalityError,
3
+ type SharedV4Warning,
4
+ type LanguageModelV4Message,
5
+ type LanguageModelV4Prompt,
6
+ type SharedV4ProviderMetadata,
8
7
  } from '@ai-sdk/provider';
9
8
  import {
10
9
  convertBase64ToUint8Array,
11
10
  convertToBase64,
11
+ getTopLevelMediaType,
12
12
  parseProviderOptions,
13
+ resolveFullMediaType,
14
+ resolveProviderReference,
13
15
  validateTypes,
14
16
  isNonNullable,
15
- ToolNameMapping,
17
+ type ToolNameMapping,
16
18
  } from '@ai-sdk/provider-utils';
17
19
  import {
18
- AnthropicAssistantMessage,
19
- AnthropicMessagesPrompt,
20
20
  anthropicReasoningMetadataSchema,
21
- AnthropicToolResultContent,
22
- AnthropicUserMessage,
23
- AnthropicWebFetchToolResultContent,
24
- } from './anthropic-messages-api';
25
- import { anthropicFilePartProviderOptions } from './anthropic-messages-options';
21
+ type AnthropicAssistantMessage,
22
+ type AnthropicPrompt,
23
+ type AnthropicToolResultContent,
24
+ type AnthropicUserMessage,
25
+ type AnthropicWebFetchToolResultContent,
26
+ } from './anthropic-api';
27
+ import { anthropicFilePartProviderOptions } from './anthropic-language-model-options';
26
28
  import { CacheControlValidator } from './get-cache-control';
29
+ import { advisor_20260301OutputSchema } from './tool/advisor_20260301';
27
30
  import { codeExecution_20250522OutputSchema } from './tool/code-execution_20250522';
28
31
  import { codeExecution_20250825OutputSchema } from './tool/code-execution_20250825';
29
32
  import { codeExecution_20260120OutputSchema } from './tool/code-execution_20260120';
@@ -31,44 +34,37 @@ import { toolSearchRegex_20251119OutputSchema as toolSearchOutputSchema } from '
31
34
  import { webFetch_20250910OutputSchema } from './tool/web-fetch-20250910';
32
35
  import { webSearch_20250305OutputSchema } from './tool/web-search_20250305';
33
36
 
34
- function convertToString(data: LanguageModelV4DataContent): string {
37
+ function convertBytesDataToString(data: Uint8Array | string): string {
35
38
  if (typeof data === 'string') {
36
39
  return new TextDecoder().decode(convertBase64ToUint8Array(data));
37
40
  }
38
-
39
- if (data instanceof Uint8Array) {
40
- return new TextDecoder().decode(data);
41
- }
42
-
43
- if (data instanceof URL) {
44
- throw new UnsupportedFunctionalityError({
45
- functionality: 'URL-based text documents are not supported for citations',
46
- });
47
- }
48
-
49
- throw new UnsupportedFunctionalityError({
50
- functionality: `unsupported data type for text documents: ${typeof data}`,
51
- });
41
+ return new TextDecoder().decode(data);
52
42
  }
53
43
 
54
44
  /**
55
- * Checks if data is a URL (either a URL object or a URL string).
45
+ * Extract error information from a provider tool error result value.
46
+ * Handles both stringified JSON and plain object forms.
56
47
  */
57
- function isUrlData(
58
- data: LanguageModelV4DataContent,
59
- ): data is URL | (string & { __brand: 'url-string' }) {
60
- return data instanceof URL || isUrlString(data);
61
- }
62
-
63
- function isUrlString(data: LanguageModelV4DataContent): boolean {
64
- return typeof data === 'string' && /^https?:\/\//i.test(data);
65
- }
66
-
67
- function getUrlString(data: LanguageModelV4DataContent): string {
68
- return data instanceof URL ? data.toString() : (data as string);
48
+ function extractErrorValue(value: unknown): { errorCode?: string } {
49
+ try {
50
+ if (typeof value === 'string') {
51
+ return JSON.parse(value);
52
+ } else if (typeof value === 'object' && value !== null) {
53
+ return value as { errorCode?: string };
54
+ }
55
+ } catch {
56
+ const extractedErrorCode = (value as Record<string, unknown>)?.errorCode;
57
+ return {
58
+ errorCode:
59
+ typeof extractedErrorCode === 'string'
60
+ ? extractedErrorCode
61
+ : 'unavailable',
62
+ };
63
+ }
64
+ return {};
69
65
  }
70
66
 
71
- export async function convertToAnthropicMessagesPrompt({
67
+ export async function convertToAnthropicPrompt({
72
68
  prompt,
73
69
  sendReasoning,
74
70
  warnings,
@@ -81,15 +77,15 @@ export async function convertToAnthropicMessagesPrompt({
81
77
  cacheControlValidator?: CacheControlValidator;
82
78
  toolNameMapping: ToolNameMapping;
83
79
  }): Promise<{
84
- prompt: AnthropicMessagesPrompt;
80
+ prompt: AnthropicPrompt;
85
81
  betas: Set<string>;
86
82
  }> {
87
83
  const betas = new Set<string>();
88
84
  const blocks = groupIntoBlocks(prompt);
89
85
  const validator = cacheControlValidator || new CacheControlValidator();
90
86
 
91
- let system: AnthropicMessagesPrompt['system'] = undefined;
92
- const messages: AnthropicMessagesPrompt['messages'] = [];
87
+ let system: AnthropicPrompt['system'] = undefined;
88
+ const messages: AnthropicPrompt['messages'] = [];
93
89
 
94
90
  async function shouldEnableCitations(
95
91
  providerMetadata: SharedV4ProviderMetadata | undefined,
@@ -103,6 +99,18 @@ export async function convertToAnthropicMessagesPrompt({
103
99
  return anthropicOptions?.citations?.enabled ?? false;
104
100
  }
105
101
 
102
+ async function shouldUseContainerUpload(
103
+ providerMetadata: SharedV4ProviderMetadata | undefined,
104
+ ): Promise<boolean> {
105
+ const anthropicOptions = await parseProviderOptions({
106
+ provider: 'anthropic',
107
+ providerOptions: providerMetadata,
108
+ schema: anthropicFilePartProviderOptions,
109
+ });
110
+
111
+ return anthropicOptions?.containerUpload ?? false;
112
+ }
113
+
106
114
  async function getDocumentMetadata(
107
115
  providerMetadata: SharedV4ProviderMetadata | undefined,
108
116
  ): Promise<{ title?: string; context?: string }> {
@@ -125,15 +133,8 @@ export async function convertToAnthropicMessagesPrompt({
125
133
 
126
134
  switch (type) {
127
135
  case 'system': {
128
- if (system != null) {
129
- throw new UnsupportedFunctionalityError({
130
- functionality:
131
- 'Multiple system messages that are separated by user/assistant messages',
132
- });
133
- }
134
-
135
- system = block.messages.map(({ content, providerOptions }) => ({
136
- type: 'text',
136
+ const content = block.messages.map(({ content, providerOptions }) => ({
137
+ type: 'text' as const,
137
138
  text: content,
138
139
  cache_control: validator.getCacheControl(providerOptions, {
139
140
  type: 'system message',
@@ -141,6 +142,13 @@ export async function convertToAnthropicMessagesPrompt({
141
142
  }),
142
143
  }));
143
144
 
145
+ if (system == null) {
146
+ system = content;
147
+ } else {
148
+ messages.push({ role: 'system', content });
149
+ betas.add('mid-conversation-system-2026-04-07');
150
+ }
151
+
144
152
  break;
145
153
  }
146
154
 
@@ -183,86 +191,163 @@ export async function convertToAnthropicMessagesPrompt({
183
191
  }
184
192
 
185
193
  case 'file': {
186
- if (part.mediaType.startsWith('image/')) {
187
- anthropicContent.push({
188
- type: 'image',
189
- source: isUrlData(part.data)
190
- ? {
191
- type: 'url',
192
- url: getUrlString(part.data),
193
- }
194
- : {
195
- type: 'base64',
196
- media_type:
197
- part.mediaType === 'image/*'
198
- ? 'image/jpeg'
199
- : part.mediaType,
200
- data: convertToBase64(part.data),
201
- },
202
- cache_control: cacheControl,
203
- });
204
- } else if (part.mediaType === 'application/pdf') {
205
- betas.add('pdfs-2024-09-25');
206
-
207
- const enableCitations = await shouldEnableCitations(
208
- part.providerOptions,
209
- );
210
-
211
- const metadata = await getDocumentMetadata(
212
- part.providerOptions,
213
- );
214
-
215
- anthropicContent.push({
216
- type: 'document',
217
- source: isUrlData(part.data)
218
- ? {
219
- type: 'url',
220
- url: getUrlString(part.data),
221
- }
222
- : {
223
- type: 'base64',
224
- media_type: 'application/pdf',
225
- data: convertToBase64(part.data),
226
- },
227
- title: metadata.title ?? part.filename,
228
- ...(metadata.context && { context: metadata.context }),
229
- ...(enableCitations && {
230
- citations: { enabled: true },
231
- }),
232
- cache_control: cacheControl,
233
- });
234
- } else if (part.mediaType === 'text/plain') {
235
- const enableCitations = await shouldEnableCitations(
236
- part.providerOptions,
237
- );
238
-
239
- const metadata = await getDocumentMetadata(
240
- part.providerOptions,
241
- );
242
-
243
- anthropicContent.push({
244
- type: 'document',
245
- source: isUrlData(part.data)
246
- ? {
247
- type: 'url',
248
- url: getUrlString(part.data),
249
- }
250
- : {
251
- type: 'text',
252
- media_type: 'text/plain',
253
- data: convertToString(part.data),
254
- },
255
- title: metadata.title ?? part.filename,
256
- ...(metadata.context && { context: metadata.context }),
257
- ...(enableCitations && {
258
- citations: { enabled: true },
259
- }),
260
- cache_control: cacheControl,
261
- });
262
- } else {
263
- throw new UnsupportedFunctionalityError({
264
- functionality: `media type: ${part.mediaType}`,
265
- });
194
+ switch (part.data.type) {
195
+ case 'reference': {
196
+ const fileId = resolveProviderReference({
197
+ reference: part.data.reference,
198
+ provider: 'anthropic',
199
+ });
200
+ betas.add('files-api-2025-04-14');
201
+
202
+ if (
203
+ await shouldUseContainerUpload(part.providerOptions)
204
+ ) {
205
+ anthropicContent.push({
206
+ type: 'container_upload',
207
+ file_id: fileId,
208
+ });
209
+ } else if (
210
+ getTopLevelMediaType(part.mediaType) === 'image'
211
+ ) {
212
+ anthropicContent.push({
213
+ type: 'image',
214
+ source: { type: 'file', file_id: fileId },
215
+ cache_control: cacheControl,
216
+ });
217
+ } else {
218
+ anthropicContent.push({
219
+ type: 'document',
220
+ source: { type: 'file', file_id: fileId },
221
+ cache_control: cacheControl,
222
+ });
223
+ }
224
+ break;
225
+ }
226
+ case 'text': {
227
+ const enableCitations = await shouldEnableCitations(
228
+ part.providerOptions,
229
+ );
230
+
231
+ const metadata = await getDocumentMetadata(
232
+ part.providerOptions,
233
+ );
234
+
235
+ anthropicContent.push({
236
+ type: 'document',
237
+ source: {
238
+ type: 'text',
239
+ media_type: 'text/plain',
240
+ data: part.data.text,
241
+ },
242
+ title: metadata.title ?? part.filename,
243
+ ...(metadata.context && {
244
+ context: metadata.context,
245
+ }),
246
+ ...(enableCitations && {
247
+ citations: { enabled: true },
248
+ }),
249
+ cache_control: cacheControl,
250
+ });
251
+ break;
252
+ }
253
+ case 'url':
254
+ case 'data': {
255
+ const topLevel = getTopLevelMediaType(part.mediaType);
256
+ if (topLevel === 'image') {
257
+ anthropicContent.push({
258
+ type: 'image',
259
+ source:
260
+ part.data.type === 'url'
261
+ ? {
262
+ type: 'url',
263
+ url: part.data.url.toString(),
264
+ }
265
+ : {
266
+ type: 'base64',
267
+ media_type: resolveFullMediaType({ part }),
268
+ data: convertToBase64(part.data.data),
269
+ },
270
+ cache_control: cacheControl,
271
+ });
272
+ } else if (
273
+ topLevel === 'application' &&
274
+ (part.data.type === 'url'
275
+ ? part.mediaType === 'application/pdf'
276
+ : resolveFullMediaType({ part }) ===
277
+ 'application/pdf')
278
+ ) {
279
+ betas.add('pdfs-2024-09-25');
280
+
281
+ const enableCitations = await shouldEnableCitations(
282
+ part.providerOptions,
283
+ );
284
+
285
+ const metadata = await getDocumentMetadata(
286
+ part.providerOptions,
287
+ );
288
+
289
+ anthropicContent.push({
290
+ type: 'document',
291
+ source:
292
+ part.data.type === 'url'
293
+ ? {
294
+ type: 'url',
295
+ url: part.data.url.toString(),
296
+ }
297
+ : {
298
+ type: 'base64',
299
+ media_type: 'application/pdf',
300
+ data: convertToBase64(part.data.data),
301
+ },
302
+ title: metadata.title ?? part.filename,
303
+ ...(metadata.context && {
304
+ context: metadata.context,
305
+ }),
306
+ ...(enableCitations && {
307
+ citations: { enabled: true },
308
+ }),
309
+ cache_control: cacheControl,
310
+ });
311
+ } else if (part.mediaType === 'text/plain') {
312
+ const enableCitations = await shouldEnableCitations(
313
+ part.providerOptions,
314
+ );
315
+
316
+ const metadata = await getDocumentMetadata(
317
+ part.providerOptions,
318
+ );
319
+
320
+ anthropicContent.push({
321
+ type: 'document',
322
+ source:
323
+ part.data.type === 'url'
324
+ ? {
325
+ type: 'url',
326
+ url: part.data.url.toString(),
327
+ }
328
+ : {
329
+ type: 'text',
330
+ media_type: 'text/plain',
331
+ data: convertBytesDataToString(
332
+ part.data.data,
333
+ ),
334
+ },
335
+ title: metadata.title ?? part.filename,
336
+ ...(metadata.context && {
337
+ context: metadata.context,
338
+ }),
339
+ ...(enableCitations && {
340
+ citations: { enabled: true },
341
+ }),
342
+ cache_control: cacheControl,
343
+ });
344
+ } else {
345
+ throw new UnsupportedFunctionalityError({
346
+ functionality: `media type: ${part.mediaType}`,
347
+ });
348
+ }
349
+ break;
350
+ }
266
351
  }
267
352
 
268
353
  break;
@@ -280,9 +365,19 @@ export async function convertToAnthropicMessagesPrompt({
280
365
  continue;
281
366
  }
282
367
 
368
+ const output = part.output;
369
+ const outputProviderOptions =
370
+ 'providerOptions' in output
371
+ ? output.providerOptions
372
+ : output.type === 'content'
373
+ ? output.value.find(
374
+ contentPart => contentPart.providerOptions != null,
375
+ )?.providerOptions
376
+ : undefined;
377
+
283
378
  // cache control: first add cache control from part.
284
- // for the last part of a message,
285
- // check also if the message has cache control.
379
+ // then from tool result output, and for the last part of a
380
+ // message, check also if the message has cache control.
286
381
  const isLastPart = i === content.length - 1;
287
382
 
288
383
  const cacheControl =
@@ -290,6 +385,10 @@ export async function convertToAnthropicMessagesPrompt({
290
385
  type: 'tool result part',
291
386
  canCache: true,
292
387
  }) ??
388
+ validator.getCacheControl(outputProviderOptions, {
389
+ type: 'tool result output',
390
+ canCache: true,
391
+ }) ??
293
392
  (isLastPart
294
393
  ? validator.getCacheControl(message.providerOptions, {
295
394
  type: 'tool result message',
@@ -297,7 +396,6 @@ export async function convertToAnthropicMessagesPrompt({
297
396
  })
298
397
  : undefined);
299
398
 
300
- const output = part.output;
301
399
  let contentValue: AnthropicToolResultContent['content'];
302
400
  switch (output.type) {
303
401
  case 'content':
@@ -309,50 +407,73 @@ export async function convertToAnthropicMessagesPrompt({
309
407
  type: 'text' as const,
310
408
  text: contentPart.text,
311
409
  };
312
- case 'image-data': {
313
- return {
314
- type: 'image' as const,
315
- source: {
316
- type: 'base64' as const,
317
- media_type: contentPart.mediaType,
318
- data: contentPart.data,
319
- },
320
- };
321
- }
322
- case 'image-url': {
323
- return {
324
- type: 'image' as const,
325
- source: {
326
- type: 'url' as const,
327
- url: contentPart.url,
328
- },
329
- };
330
- }
331
- case 'file-url': {
332
- return {
333
- type: 'document' as const,
334
- source: {
335
- type: 'url' as const,
336
- url: contentPart.url,
337
- },
338
- };
339
- }
340
- case 'file-data': {
341
- if (contentPart.mediaType === 'application/pdf') {
342
- betas.add('pdfs-2024-09-25');
410
+ case 'file': {
411
+ const topLevel = getTopLevelMediaType(
412
+ contentPart.mediaType,
413
+ );
414
+
415
+ if (contentPart.data.type === 'url') {
416
+ if (topLevel === 'image') {
417
+ return {
418
+ type: 'image' as const,
419
+ source: {
420
+ type: 'url' as const,
421
+ url: contentPart.data.url.toString(),
422
+ },
423
+ };
424
+ }
343
425
  return {
344
426
  type: 'document' as const,
345
427
  source: {
346
- type: 'base64' as const,
347
- media_type: contentPart.mediaType,
348
- data: contentPart.data,
428
+ type: 'url' as const,
429
+ url: contentPart.data.url.toString(),
349
430
  },
350
431
  };
351
432
  }
352
433
 
434
+ if (contentPart.data.type === 'data') {
435
+ if (topLevel === 'image') {
436
+ return {
437
+ type: 'image' as const,
438
+ source: {
439
+ type: 'base64' as const,
440
+ media_type: resolveFullMediaType({
441
+ part: contentPart,
442
+ }),
443
+ data: convertToBase64(
444
+ contentPart.data.data,
445
+ ),
446
+ },
447
+ };
448
+ }
449
+ if (
450
+ resolveFullMediaType({ part: contentPart }) ===
451
+ 'application/pdf'
452
+ ) {
453
+ betas.add('pdfs-2024-09-25');
454
+ return {
455
+ type: 'document' as const,
456
+ source: {
457
+ type: 'base64' as const,
458
+ media_type: 'application/pdf',
459
+ data: convertToBase64(
460
+ contentPart.data.data,
461
+ ),
462
+ },
463
+ };
464
+ }
465
+
466
+ warnings.push({
467
+ type: 'other',
468
+ message: `unsupported tool content part type: ${contentPart.type} with media type: ${contentPart.mediaType}`,
469
+ });
470
+
471
+ return undefined;
472
+ }
473
+
353
474
  warnings.push({
354
475
  type: 'other',
355
- message: `unsupported tool content part type: ${contentPart.type} with media type: ${contentPart.mediaType}`,
476
+ message: `unsupported tool content part type: ${contentPart.type} with data type: ${contentPart.data.type}`,
356
477
  });
357
478
 
358
479
  return undefined;
@@ -377,7 +498,7 @@ export async function convertToAnthropicMessagesPrompt({
377
498
  default: {
378
499
  warnings.push({
379
500
  type: 'other',
380
- message: `unsupported tool content part type: ${contentPart.type}`,
501
+ message: `unsupported tool content part type: ${(contentPart as { type: string }).type}`,
381
502
  });
382
503
 
383
504
  return undefined;
@@ -391,7 +512,8 @@ export async function convertToAnthropicMessagesPrompt({
391
512
  contentValue = output.value;
392
513
  break;
393
514
  case 'execution-denied':
394
- contentValue = output.reason ?? 'Tool execution denied.';
515
+ contentValue =
516
+ output.reason ?? 'Tool call execution denied.';
395
517
  break;
396
518
  case 'json':
397
519
  case 'error-json':
@@ -634,6 +756,15 @@ export async function convertToAnthropicMessagesPrompt({
634
756
  input: part.input,
635
757
  cache_control: cacheControl,
636
758
  });
759
+ } else if (providerToolName === 'advisor') {
760
+ // The advisor server_tool_use.input is always {}.
761
+ anthropicContent.push({
762
+ type: 'server_tool_use',
763
+ id: part.toolCallId,
764
+ name: 'advisor',
765
+ input: {},
766
+ cache_control: cacheControl,
767
+ });
637
768
  } else {
638
769
  warnings.push({
639
770
  type: 'other',
@@ -865,35 +996,14 @@ export async function convertToAnthropicMessagesPrompt({
865
996
  const output = part.output;
866
997
 
867
998
  if (output.type === 'error-json') {
868
- let errorValue: { errorCode?: string } = {};
869
- try {
870
- if (typeof output.value === 'string') {
871
- errorValue = JSON.parse(output.value);
872
- } else if (
873
- typeof output.value === 'object' &&
874
- output.value !== null
875
- ) {
876
- errorValue = output.value as typeof errorValue;
877
- }
878
- } catch {
879
- // If parsing fails, treat the value as-is
880
- const extractedErrorCode = (
881
- output.value as Record<string, unknown>
882
- )?.errorCode;
883
- errorValue = {
884
- errorCode:
885
- typeof extractedErrorCode === 'string'
886
- ? extractedErrorCode
887
- : 'unavailable',
888
- };
889
- }
890
-
891
999
  anthropicContent.push({
892
1000
  type: 'web_fetch_tool_result',
893
1001
  tool_use_id: part.toolCallId,
894
1002
  content: {
895
1003
  type: 'web_fetch_tool_result_error',
896
- error_code: errorValue.errorCode ?? 'unavailable',
1004
+ error_code:
1005
+ extractErrorValue(output.value).errorCode ??
1006
+ 'unavailable',
897
1007
  },
898
1008
  cache_control: cacheControl,
899
1009
  });
@@ -948,6 +1058,22 @@ export async function convertToAnthropicMessagesPrompt({
948
1058
  if (providerToolName === 'web_search') {
949
1059
  const output = part.output;
950
1060
 
1061
+ if (output.type === 'error-json') {
1062
+ anthropicContent.push({
1063
+ type: 'web_search_tool_result',
1064
+ tool_use_id: part.toolCallId,
1065
+ content: {
1066
+ type: 'web_search_tool_result_error',
1067
+ error_code:
1068
+ extractErrorValue(output.value).errorCode ??
1069
+ 'unavailable',
1070
+ },
1071
+ cache_control: cacheControl,
1072
+ });
1073
+
1074
+ break;
1075
+ }
1076
+
951
1077
  if (output.type !== 'json') {
952
1078
  warnings.push({
953
1079
  type: 'other',
@@ -1020,6 +1146,58 @@ export async function convertToAnthropicMessagesPrompt({
1020
1146
  break;
1021
1147
  }
1022
1148
 
1149
+ if (providerToolName === 'advisor') {
1150
+ const output = part.output;
1151
+
1152
+ if (output.type !== 'json' && output.type !== 'error-json') {
1153
+ warnings.push({
1154
+ type: 'other',
1155
+ message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
1156
+ });
1157
+
1158
+ break;
1159
+ }
1160
+
1161
+ const advisorOutput = await validateTypes({
1162
+ value: output.value,
1163
+ schema: advisor_20260301OutputSchema,
1164
+ });
1165
+
1166
+ if (advisorOutput.type === 'advisor_result') {
1167
+ anthropicContent.push({
1168
+ type: 'advisor_tool_result',
1169
+ tool_use_id: part.toolCallId,
1170
+ content: {
1171
+ type: 'advisor_result',
1172
+ text: advisorOutput.text,
1173
+ },
1174
+ cache_control: cacheControl,
1175
+ });
1176
+ } else if (advisorOutput.type === 'advisor_redacted_result') {
1177
+ anthropicContent.push({
1178
+ type: 'advisor_tool_result',
1179
+ tool_use_id: part.toolCallId,
1180
+ content: {
1181
+ type: 'advisor_redacted_result',
1182
+ encrypted_content: advisorOutput.encryptedContent,
1183
+ },
1184
+ cache_control: cacheControl,
1185
+ });
1186
+ } else {
1187
+ anthropicContent.push({
1188
+ type: 'advisor_tool_result',
1189
+ tool_use_id: part.toolCallId,
1190
+ content: {
1191
+ type: 'advisor_tool_result_error',
1192
+ error_code: advisorOutput.errorCode,
1193
+ },
1194
+ cache_control: cacheControl,
1195
+ });
1196
+ }
1197
+
1198
+ break;
1199
+ }
1200
+
1023
1201
  warnings.push({
1024
1202
  type: 'other',
1025
1203
  message: `provider executed tool result for tool ${part.toolName} is not supported`,