@ai-sdk/anthropic 3.0.17 → 3.0.19
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.
- package/CHANGELOG.md +12 -0
- package/dist/index.js +57 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -30
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +56 -29
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +56 -29
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/__fixtures__/anthropic-code-execution-20250825.1.chunks.txt +248 -0
- package/src/__fixtures__/anthropic-code-execution-20250825.1.json +70 -0
- package/src/__fixtures__/anthropic-code-execution-20250825.2.chunks.txt +984 -0
- package/src/__fixtures__/anthropic-code-execution-20250825.2.json +111 -0
- package/src/__fixtures__/anthropic-code-execution-20250825.pptx-skill.chunks.txt +691 -0
- package/src/__fixtures__/anthropic-code-execution-20250825.pptx-skill.json +1801 -0
- package/src/__fixtures__/anthropic-json-other-tool.1.chunks.txt +13 -0
- package/src/__fixtures__/anthropic-json-other-tool.1.json +26 -0
- package/src/__fixtures__/anthropic-json-output-format.1.chunks.txt +120 -0
- package/src/__fixtures__/anthropic-json-output-format.1.json +25 -0
- package/src/__fixtures__/anthropic-json-tool.1.chunks.txt +9 -0
- package/src/__fixtures__/anthropic-json-tool.1.json +37 -0
- package/src/__fixtures__/anthropic-json-tool.2.chunks.txt +14 -0
- package/src/__fixtures__/anthropic-mcp.1.chunks.txt +17 -0
- package/src/__fixtures__/anthropic-mcp.1.json +39 -0
- package/src/__fixtures__/anthropic-memory-20250818.1.json +28 -0
- package/src/__fixtures__/anthropic-message-delta-input-tokens.chunks.txt +8 -0
- package/src/__fixtures__/anthropic-programmatic-tool-calling.1.chunks.txt +278 -0
- package/src/__fixtures__/anthropic-programmatic-tool-calling.1.json +106 -0
- package/src/__fixtures__/anthropic-tool-no-args.chunks.txt +13 -0
- package/src/__fixtures__/anthropic-tool-no-args.json +31 -0
- package/src/__fixtures__/anthropic-tool-search-bm25.1.chunks.txt +47 -0
- package/src/__fixtures__/anthropic-tool-search-bm25.1.json +67 -0
- package/src/__fixtures__/anthropic-tool-search-regex.1.chunks.txt +51 -0
- package/src/__fixtures__/anthropic-tool-search-regex.1.json +65 -0
- package/src/__fixtures__/anthropic-web-fetch-tool.1.chunks.txt +64 -0
- package/src/__fixtures__/anthropic-web-fetch-tool.1.json +54 -0
- package/src/__fixtures__/anthropic-web-fetch-tool.2.json +56 -0
- package/src/__fixtures__/anthropic-web-fetch-tool.error.json +46 -0
- package/src/__fixtures__/anthropic-web-search-tool.1.chunks.txt +120 -0
- package/src/__fixtures__/anthropic-web-search-tool.1.json +181 -0
- package/src/__snapshots__/anthropic-messages-language-model.test.ts.snap +16719 -0
- package/src/anthropic-error.test.ts +42 -0
- package/src/anthropic-error.ts +26 -0
- package/src/anthropic-message-metadata.ts +105 -0
- package/src/anthropic-messages-api.ts +1188 -0
- package/src/anthropic-messages-language-model.test.ts +7170 -0
- package/src/anthropic-messages-language-model.ts +2067 -0
- package/src/anthropic-messages-options.ts +213 -0
- package/src/anthropic-prepare-tools.test.ts +1219 -0
- package/src/anthropic-prepare-tools.ts +341 -0
- package/src/anthropic-provider.test.ts +162 -0
- package/src/anthropic-provider.ts +152 -0
- package/src/anthropic-tools.ts +182 -0
- package/src/convert-anthropic-messages-usage.ts +32 -0
- package/src/convert-to-anthropic-messages-prompt.test.ts +2902 -0
- package/src/convert-to-anthropic-messages-prompt.ts +1050 -0
- package/src/forward-anthropic-container-id-from-last-step.ts +38 -0
- package/src/get-cache-control.ts +63 -0
- package/src/index.ts +10 -0
- package/src/internal/index.ts +4 -0
- package/src/map-anthropic-stop-reason.ts +28 -0
- package/src/tool/bash_20241022.ts +33 -0
- package/src/tool/bash_20250124.ts +33 -0
- package/src/tool/code-execution_20250522.ts +61 -0
- package/src/tool/code-execution_20250825.ts +281 -0
- package/src/tool/computer_20241022.ts +87 -0
- package/src/tool/computer_20250124.ts +130 -0
- package/src/tool/memory_20250818.ts +62 -0
- package/src/tool/text-editor_20241022.ts +63 -0
- package/src/tool/text-editor_20250124.ts +63 -0
- package/src/tool/text-editor_20250429.ts +64 -0
- package/src/tool/text-editor_20250728.ts +80 -0
- package/src/tool/tool-search-bm25_20251119.ts +98 -0
- package/src/tool/tool-search-regex_20251119.ts +110 -0
- package/src/tool/web-fetch-20250910.ts +145 -0
- package/src/tool/web-search_20250305.ts +136 -0
- package/src/version.ts +6 -0
|
@@ -0,0 +1,1050 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SharedV3Warning,
|
|
3
|
+
LanguageModelV3DataContent,
|
|
4
|
+
LanguageModelV3Message,
|
|
5
|
+
LanguageModelV3Prompt,
|
|
6
|
+
SharedV3ProviderMetadata,
|
|
7
|
+
UnsupportedFunctionalityError,
|
|
8
|
+
} from '@ai-sdk/provider';
|
|
9
|
+
import {
|
|
10
|
+
convertToBase64,
|
|
11
|
+
parseProviderOptions,
|
|
12
|
+
validateTypes,
|
|
13
|
+
isNonNullable,
|
|
14
|
+
ToolNameMapping,
|
|
15
|
+
} from '@ai-sdk/provider-utils';
|
|
16
|
+
import {
|
|
17
|
+
AnthropicAssistantMessage,
|
|
18
|
+
AnthropicMessagesPrompt,
|
|
19
|
+
anthropicReasoningMetadataSchema,
|
|
20
|
+
AnthropicToolResultContent,
|
|
21
|
+
AnthropicUserMessage,
|
|
22
|
+
AnthropicWebFetchToolResultContent,
|
|
23
|
+
} from './anthropic-messages-api';
|
|
24
|
+
import { anthropicFilePartProviderOptions } from './anthropic-messages-options';
|
|
25
|
+
import { CacheControlValidator } from './get-cache-control';
|
|
26
|
+
import { codeExecution_20250522OutputSchema } from './tool/code-execution_20250522';
|
|
27
|
+
import { codeExecution_20250825OutputSchema } from './tool/code-execution_20250825';
|
|
28
|
+
import { toolSearchRegex_20251119OutputSchema as toolSearchOutputSchema } from './tool/tool-search-regex_20251119';
|
|
29
|
+
import { webFetch_20250910OutputSchema } from './tool/web-fetch-20250910';
|
|
30
|
+
import { webSearch_20250305OutputSchema } from './tool/web-search_20250305';
|
|
31
|
+
|
|
32
|
+
function convertToString(data: LanguageModelV3DataContent): string {
|
|
33
|
+
if (typeof data === 'string') {
|
|
34
|
+
return Buffer.from(data, 'base64').toString('utf-8');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (data instanceof Uint8Array) {
|
|
38
|
+
return new TextDecoder().decode(data);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (data instanceof URL) {
|
|
42
|
+
throw new UnsupportedFunctionalityError({
|
|
43
|
+
functionality: 'URL-based text documents are not supported for citations',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new UnsupportedFunctionalityError({
|
|
48
|
+
functionality: `unsupported data type for text documents: ${typeof data}`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Checks if data is a URL (either a URL object or a URL string).
|
|
54
|
+
*/
|
|
55
|
+
function isUrlData(
|
|
56
|
+
data: LanguageModelV3DataContent,
|
|
57
|
+
): data is URL | (string & { __brand: 'url-string' }) {
|
|
58
|
+
return data instanceof URL || isUrlString(data);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function isUrlString(data: LanguageModelV3DataContent): boolean {
|
|
62
|
+
return typeof data === 'string' && /^https?:\/\//i.test(data);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getUrlString(data: LanguageModelV3DataContent): string {
|
|
66
|
+
return data instanceof URL ? data.toString() : (data as string);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function convertToAnthropicMessagesPrompt({
|
|
70
|
+
prompt,
|
|
71
|
+
sendReasoning,
|
|
72
|
+
warnings,
|
|
73
|
+
cacheControlValidator,
|
|
74
|
+
toolNameMapping,
|
|
75
|
+
}: {
|
|
76
|
+
prompt: LanguageModelV3Prompt;
|
|
77
|
+
sendReasoning: boolean;
|
|
78
|
+
warnings: SharedV3Warning[];
|
|
79
|
+
cacheControlValidator?: CacheControlValidator;
|
|
80
|
+
toolNameMapping: ToolNameMapping;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
prompt: AnthropicMessagesPrompt;
|
|
83
|
+
betas: Set<string>;
|
|
84
|
+
}> {
|
|
85
|
+
const betas = new Set<string>();
|
|
86
|
+
const blocks = groupIntoBlocks(prompt);
|
|
87
|
+
const validator = cacheControlValidator || new CacheControlValidator();
|
|
88
|
+
|
|
89
|
+
let system: AnthropicMessagesPrompt['system'] = undefined;
|
|
90
|
+
const messages: AnthropicMessagesPrompt['messages'] = [];
|
|
91
|
+
|
|
92
|
+
async function shouldEnableCitations(
|
|
93
|
+
providerMetadata: SharedV3ProviderMetadata | undefined,
|
|
94
|
+
): Promise<boolean> {
|
|
95
|
+
const anthropicOptions = await parseProviderOptions({
|
|
96
|
+
provider: 'anthropic',
|
|
97
|
+
providerOptions: providerMetadata,
|
|
98
|
+
schema: anthropicFilePartProviderOptions,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return anthropicOptions?.citations?.enabled ?? false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function getDocumentMetadata(
|
|
105
|
+
providerMetadata: SharedV3ProviderMetadata | undefined,
|
|
106
|
+
): Promise<{ title?: string; context?: string }> {
|
|
107
|
+
const anthropicOptions = await parseProviderOptions({
|
|
108
|
+
provider: 'anthropic',
|
|
109
|
+
providerOptions: providerMetadata,
|
|
110
|
+
schema: anthropicFilePartProviderOptions,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
title: anthropicOptions?.title,
|
|
115
|
+
context: anthropicOptions?.context,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
120
|
+
const block = blocks[i];
|
|
121
|
+
const isLastBlock = i === blocks.length - 1;
|
|
122
|
+
const type = block.type;
|
|
123
|
+
|
|
124
|
+
switch (type) {
|
|
125
|
+
case 'system': {
|
|
126
|
+
if (system != null) {
|
|
127
|
+
throw new UnsupportedFunctionalityError({
|
|
128
|
+
functionality:
|
|
129
|
+
'Multiple system messages that are separated by user/assistant messages',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
system = block.messages.map(({ content, providerOptions }) => ({
|
|
134
|
+
type: 'text',
|
|
135
|
+
text: content,
|
|
136
|
+
cache_control: validator.getCacheControl(providerOptions, {
|
|
137
|
+
type: 'system message',
|
|
138
|
+
canCache: true,
|
|
139
|
+
}),
|
|
140
|
+
}));
|
|
141
|
+
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
case 'user': {
|
|
146
|
+
// combines all user and tool messages in this block into a single message:
|
|
147
|
+
const anthropicContent: AnthropicUserMessage['content'] = [];
|
|
148
|
+
|
|
149
|
+
for (const message of block.messages) {
|
|
150
|
+
const { role, content } = message;
|
|
151
|
+
switch (role) {
|
|
152
|
+
case 'user': {
|
|
153
|
+
for (let j = 0; j < content.length; j++) {
|
|
154
|
+
const part = content[j];
|
|
155
|
+
|
|
156
|
+
// cache control: first add cache control from part.
|
|
157
|
+
// for the last part of a message,
|
|
158
|
+
// check also if the message has cache control.
|
|
159
|
+
const isLastPart = j === content.length - 1;
|
|
160
|
+
|
|
161
|
+
const cacheControl =
|
|
162
|
+
validator.getCacheControl(part.providerOptions, {
|
|
163
|
+
type: 'user message part',
|
|
164
|
+
canCache: true,
|
|
165
|
+
}) ??
|
|
166
|
+
(isLastPart
|
|
167
|
+
? validator.getCacheControl(message.providerOptions, {
|
|
168
|
+
type: 'user message',
|
|
169
|
+
canCache: true,
|
|
170
|
+
})
|
|
171
|
+
: undefined);
|
|
172
|
+
|
|
173
|
+
switch (part.type) {
|
|
174
|
+
case 'text': {
|
|
175
|
+
anthropicContent.push({
|
|
176
|
+
type: 'text',
|
|
177
|
+
text: part.text,
|
|
178
|
+
cache_control: cacheControl,
|
|
179
|
+
});
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
case 'file': {
|
|
184
|
+
if (part.mediaType.startsWith('image/')) {
|
|
185
|
+
anthropicContent.push({
|
|
186
|
+
type: 'image',
|
|
187
|
+
source: isUrlData(part.data)
|
|
188
|
+
? {
|
|
189
|
+
type: 'url',
|
|
190
|
+
url: getUrlString(part.data),
|
|
191
|
+
}
|
|
192
|
+
: {
|
|
193
|
+
type: 'base64',
|
|
194
|
+
media_type:
|
|
195
|
+
part.mediaType === 'image/*'
|
|
196
|
+
? 'image/jpeg'
|
|
197
|
+
: part.mediaType,
|
|
198
|
+
data: convertToBase64(part.data),
|
|
199
|
+
},
|
|
200
|
+
cache_control: cacheControl,
|
|
201
|
+
});
|
|
202
|
+
} else if (part.mediaType === 'application/pdf') {
|
|
203
|
+
betas.add('pdfs-2024-09-25');
|
|
204
|
+
|
|
205
|
+
const enableCitations = await shouldEnableCitations(
|
|
206
|
+
part.providerOptions,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const metadata = await getDocumentMetadata(
|
|
210
|
+
part.providerOptions,
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
anthropicContent.push({
|
|
214
|
+
type: 'document',
|
|
215
|
+
source: isUrlData(part.data)
|
|
216
|
+
? {
|
|
217
|
+
type: 'url',
|
|
218
|
+
url: getUrlString(part.data),
|
|
219
|
+
}
|
|
220
|
+
: {
|
|
221
|
+
type: 'base64',
|
|
222
|
+
media_type: 'application/pdf',
|
|
223
|
+
data: convertToBase64(part.data),
|
|
224
|
+
},
|
|
225
|
+
title: metadata.title ?? part.filename,
|
|
226
|
+
...(metadata.context && { context: metadata.context }),
|
|
227
|
+
...(enableCitations && {
|
|
228
|
+
citations: { enabled: true },
|
|
229
|
+
}),
|
|
230
|
+
cache_control: cacheControl,
|
|
231
|
+
});
|
|
232
|
+
} else if (part.mediaType === 'text/plain') {
|
|
233
|
+
const enableCitations = await shouldEnableCitations(
|
|
234
|
+
part.providerOptions,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const metadata = await getDocumentMetadata(
|
|
238
|
+
part.providerOptions,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
anthropicContent.push({
|
|
242
|
+
type: 'document',
|
|
243
|
+
source: isUrlData(part.data)
|
|
244
|
+
? {
|
|
245
|
+
type: 'url',
|
|
246
|
+
url: getUrlString(part.data),
|
|
247
|
+
}
|
|
248
|
+
: {
|
|
249
|
+
type: 'text',
|
|
250
|
+
media_type: 'text/plain',
|
|
251
|
+
data: convertToString(part.data),
|
|
252
|
+
},
|
|
253
|
+
title: metadata.title ?? part.filename,
|
|
254
|
+
...(metadata.context && { context: metadata.context }),
|
|
255
|
+
...(enableCitations && {
|
|
256
|
+
citations: { enabled: true },
|
|
257
|
+
}),
|
|
258
|
+
cache_control: cacheControl,
|
|
259
|
+
});
|
|
260
|
+
} else {
|
|
261
|
+
throw new UnsupportedFunctionalityError({
|
|
262
|
+
functionality: `media type: ${part.mediaType}`,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
case 'tool': {
|
|
274
|
+
for (let i = 0; i < content.length; i++) {
|
|
275
|
+
const part = content[i];
|
|
276
|
+
|
|
277
|
+
if (part.type === 'tool-approval-response') {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// cache control: first add cache control from part.
|
|
282
|
+
// for the last part of a message,
|
|
283
|
+
// check also if the message has cache control.
|
|
284
|
+
const isLastPart = i === content.length - 1;
|
|
285
|
+
|
|
286
|
+
const cacheControl =
|
|
287
|
+
validator.getCacheControl(part.providerOptions, {
|
|
288
|
+
type: 'tool result part',
|
|
289
|
+
canCache: true,
|
|
290
|
+
}) ??
|
|
291
|
+
(isLastPart
|
|
292
|
+
? validator.getCacheControl(message.providerOptions, {
|
|
293
|
+
type: 'tool result message',
|
|
294
|
+
canCache: true,
|
|
295
|
+
})
|
|
296
|
+
: undefined);
|
|
297
|
+
|
|
298
|
+
const output = part.output;
|
|
299
|
+
let contentValue: AnthropicToolResultContent['content'];
|
|
300
|
+
switch (output.type) {
|
|
301
|
+
case 'content':
|
|
302
|
+
contentValue = output.value
|
|
303
|
+
.map(contentPart => {
|
|
304
|
+
switch (contentPart.type) {
|
|
305
|
+
case 'text':
|
|
306
|
+
return {
|
|
307
|
+
type: 'text' as const,
|
|
308
|
+
text: contentPart.text,
|
|
309
|
+
};
|
|
310
|
+
case 'image-data': {
|
|
311
|
+
return {
|
|
312
|
+
type: 'image' as const,
|
|
313
|
+
source: {
|
|
314
|
+
type: 'base64' as const,
|
|
315
|
+
media_type: contentPart.mediaType,
|
|
316
|
+
data: contentPart.data,
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
case 'image-url': {
|
|
321
|
+
return {
|
|
322
|
+
type: 'image' as const,
|
|
323
|
+
source: {
|
|
324
|
+
type: 'url' as const,
|
|
325
|
+
url: contentPart.url,
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
case 'file-url': {
|
|
330
|
+
return {
|
|
331
|
+
type: 'document' as const,
|
|
332
|
+
source: {
|
|
333
|
+
type: 'url' as const,
|
|
334
|
+
url: contentPart.url,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
case 'file-data': {
|
|
339
|
+
if (contentPart.mediaType === 'application/pdf') {
|
|
340
|
+
betas.add('pdfs-2024-09-25');
|
|
341
|
+
return {
|
|
342
|
+
type: 'document' as const,
|
|
343
|
+
source: {
|
|
344
|
+
type: 'base64' as const,
|
|
345
|
+
media_type: contentPart.mediaType,
|
|
346
|
+
data: contentPart.data,
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
warnings.push({
|
|
352
|
+
type: 'other',
|
|
353
|
+
message: `unsupported tool content part type: ${contentPart.type} with media type: ${contentPart.mediaType}`,
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
default: {
|
|
359
|
+
warnings.push({
|
|
360
|
+
type: 'other',
|
|
361
|
+
message: `unsupported tool content part type: ${contentPart.type}`,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
return undefined;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
.filter(isNonNullable);
|
|
369
|
+
break;
|
|
370
|
+
case 'text':
|
|
371
|
+
case 'error-text':
|
|
372
|
+
contentValue = output.value;
|
|
373
|
+
break;
|
|
374
|
+
case 'execution-denied':
|
|
375
|
+
contentValue = output.reason ?? 'Tool execution denied.';
|
|
376
|
+
break;
|
|
377
|
+
case 'json':
|
|
378
|
+
case 'error-json':
|
|
379
|
+
default:
|
|
380
|
+
contentValue = JSON.stringify(output.value);
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
anthropicContent.push({
|
|
385
|
+
type: 'tool_result',
|
|
386
|
+
tool_use_id: part.toolCallId,
|
|
387
|
+
content: contentValue,
|
|
388
|
+
is_error:
|
|
389
|
+
output.type === 'error-text' || output.type === 'error-json'
|
|
390
|
+
? true
|
|
391
|
+
: undefined,
|
|
392
|
+
cache_control: cacheControl,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
default: {
|
|
399
|
+
const _exhaustiveCheck: never = role;
|
|
400
|
+
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
messages.push({ role: 'user', content: anthropicContent });
|
|
406
|
+
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
case 'assistant': {
|
|
411
|
+
// combines multiple assistant messages in this block into a single message:
|
|
412
|
+
const anthropicContent: AnthropicAssistantMessage['content'] = [];
|
|
413
|
+
|
|
414
|
+
const mcpToolUseIds = new Set<string>();
|
|
415
|
+
|
|
416
|
+
for (let j = 0; j < block.messages.length; j++) {
|
|
417
|
+
const message = block.messages[j];
|
|
418
|
+
const isLastMessage = j === block.messages.length - 1;
|
|
419
|
+
const { content } = message;
|
|
420
|
+
|
|
421
|
+
for (let k = 0; k < content.length; k++) {
|
|
422
|
+
const part = content[k];
|
|
423
|
+
const isLastContentPart = k === content.length - 1;
|
|
424
|
+
|
|
425
|
+
// cache control: first add cache control from part.
|
|
426
|
+
// for the last part of a message,
|
|
427
|
+
// check also if the message has cache control.
|
|
428
|
+
const cacheControl =
|
|
429
|
+
validator.getCacheControl(part.providerOptions, {
|
|
430
|
+
type: 'assistant message part',
|
|
431
|
+
canCache: true,
|
|
432
|
+
}) ??
|
|
433
|
+
(isLastContentPart
|
|
434
|
+
? validator.getCacheControl(message.providerOptions, {
|
|
435
|
+
type: 'assistant message',
|
|
436
|
+
canCache: true,
|
|
437
|
+
})
|
|
438
|
+
: undefined);
|
|
439
|
+
|
|
440
|
+
switch (part.type) {
|
|
441
|
+
case 'text': {
|
|
442
|
+
anthropicContent.push({
|
|
443
|
+
type: 'text',
|
|
444
|
+
text:
|
|
445
|
+
// trim the last text part if it's the last message in the block
|
|
446
|
+
// because Anthropic does not allow trailing whitespace
|
|
447
|
+
// in pre-filled assistant responses
|
|
448
|
+
isLastBlock && isLastMessage && isLastContentPart
|
|
449
|
+
? part.text.trim()
|
|
450
|
+
: part.text,
|
|
451
|
+
|
|
452
|
+
cache_control: cacheControl,
|
|
453
|
+
});
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
case 'reasoning': {
|
|
458
|
+
if (sendReasoning) {
|
|
459
|
+
const reasoningMetadata = await parseProviderOptions({
|
|
460
|
+
provider: 'anthropic',
|
|
461
|
+
providerOptions: part.providerOptions,
|
|
462
|
+
schema: anthropicReasoningMetadataSchema,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
if (reasoningMetadata != null) {
|
|
466
|
+
if (reasoningMetadata.signature != null) {
|
|
467
|
+
// Note: thinking blocks cannot have cache_control directly
|
|
468
|
+
// They are cached implicitly when in previous assistant turns
|
|
469
|
+
// Validate to provide helpful error message
|
|
470
|
+
validator.getCacheControl(part.providerOptions, {
|
|
471
|
+
type: 'thinking block',
|
|
472
|
+
canCache: false,
|
|
473
|
+
});
|
|
474
|
+
anthropicContent.push({
|
|
475
|
+
type: 'thinking',
|
|
476
|
+
thinking: part.text,
|
|
477
|
+
signature: reasoningMetadata.signature,
|
|
478
|
+
});
|
|
479
|
+
} else if (reasoningMetadata.redactedData != null) {
|
|
480
|
+
// Note: redacted thinking blocks cannot have cache_control directly
|
|
481
|
+
// They are cached implicitly when in previous assistant turns
|
|
482
|
+
// Validate to provide helpful error message
|
|
483
|
+
validator.getCacheControl(part.providerOptions, {
|
|
484
|
+
type: 'redacted thinking block',
|
|
485
|
+
canCache: false,
|
|
486
|
+
});
|
|
487
|
+
anthropicContent.push({
|
|
488
|
+
type: 'redacted_thinking',
|
|
489
|
+
data: reasoningMetadata.redactedData,
|
|
490
|
+
});
|
|
491
|
+
} else {
|
|
492
|
+
warnings.push({
|
|
493
|
+
type: 'other',
|
|
494
|
+
message: 'unsupported reasoning metadata',
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
} else {
|
|
498
|
+
warnings.push({
|
|
499
|
+
type: 'other',
|
|
500
|
+
message: 'unsupported reasoning metadata',
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
} else {
|
|
504
|
+
warnings.push({
|
|
505
|
+
type: 'other',
|
|
506
|
+
message:
|
|
507
|
+
'sending reasoning content is disabled for this model',
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
case 'tool-call': {
|
|
514
|
+
if (part.providerExecuted) {
|
|
515
|
+
const providerToolName = toolNameMapping.toProviderToolName(
|
|
516
|
+
part.toolName,
|
|
517
|
+
);
|
|
518
|
+
const isMcpToolUse =
|
|
519
|
+
part.providerOptions?.anthropic?.type === 'mcp-tool-use';
|
|
520
|
+
|
|
521
|
+
if (isMcpToolUse) {
|
|
522
|
+
mcpToolUseIds.add(part.toolCallId);
|
|
523
|
+
|
|
524
|
+
const serverName =
|
|
525
|
+
part.providerOptions?.anthropic?.serverName;
|
|
526
|
+
|
|
527
|
+
if (serverName == null || typeof serverName !== 'string') {
|
|
528
|
+
warnings.push({
|
|
529
|
+
type: 'other',
|
|
530
|
+
message:
|
|
531
|
+
'mcp tool use server name is required and must be a string',
|
|
532
|
+
});
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
anthropicContent.push({
|
|
537
|
+
type: 'mcp_tool_use',
|
|
538
|
+
id: part.toolCallId,
|
|
539
|
+
name: part.toolName,
|
|
540
|
+
input: part.input,
|
|
541
|
+
server_name: serverName,
|
|
542
|
+
cache_control: cacheControl,
|
|
543
|
+
});
|
|
544
|
+
} else if (
|
|
545
|
+
// code execution 20250825:
|
|
546
|
+
providerToolName === 'code_execution' &&
|
|
547
|
+
part.input != null &&
|
|
548
|
+
typeof part.input === 'object' &&
|
|
549
|
+
'type' in part.input &&
|
|
550
|
+
typeof part.input.type === 'string' &&
|
|
551
|
+
(part.input.type === 'bash_code_execution' ||
|
|
552
|
+
part.input.type === 'text_editor_code_execution')
|
|
553
|
+
) {
|
|
554
|
+
anthropicContent.push({
|
|
555
|
+
type: 'server_tool_use',
|
|
556
|
+
id: part.toolCallId,
|
|
557
|
+
name: part.input.type, // map back to subtool name
|
|
558
|
+
input: part.input,
|
|
559
|
+
cache_control: cacheControl,
|
|
560
|
+
});
|
|
561
|
+
} else if (
|
|
562
|
+
// code execution 20250825 programmatic tool calling:
|
|
563
|
+
// Strip the fake 'programmatic-tool-call' type before sending to Anthropic
|
|
564
|
+
providerToolName === 'code_execution' &&
|
|
565
|
+
part.input != null &&
|
|
566
|
+
typeof part.input === 'object' &&
|
|
567
|
+
'type' in part.input &&
|
|
568
|
+
part.input.type === 'programmatic-tool-call'
|
|
569
|
+
) {
|
|
570
|
+
const { type: _, ...inputWithoutType } = part.input as {
|
|
571
|
+
type: string;
|
|
572
|
+
code: string;
|
|
573
|
+
};
|
|
574
|
+
anthropicContent.push({
|
|
575
|
+
type: 'server_tool_use',
|
|
576
|
+
id: part.toolCallId,
|
|
577
|
+
name: 'code_execution',
|
|
578
|
+
input: inputWithoutType,
|
|
579
|
+
cache_control: cacheControl,
|
|
580
|
+
});
|
|
581
|
+
} else {
|
|
582
|
+
if (
|
|
583
|
+
providerToolName === 'code_execution' || // code execution 20250522
|
|
584
|
+
providerToolName === 'web_fetch' ||
|
|
585
|
+
providerToolName === 'web_search'
|
|
586
|
+
) {
|
|
587
|
+
anthropicContent.push({
|
|
588
|
+
type: 'server_tool_use',
|
|
589
|
+
id: part.toolCallId,
|
|
590
|
+
name: providerToolName,
|
|
591
|
+
input: part.input,
|
|
592
|
+
cache_control: cacheControl,
|
|
593
|
+
});
|
|
594
|
+
} else if (
|
|
595
|
+
providerToolName === 'tool_search_tool_regex' ||
|
|
596
|
+
providerToolName === 'tool_search_tool_bm25'
|
|
597
|
+
) {
|
|
598
|
+
anthropicContent.push({
|
|
599
|
+
type: 'server_tool_use',
|
|
600
|
+
id: part.toolCallId,
|
|
601
|
+
name: providerToolName,
|
|
602
|
+
input: part.input,
|
|
603
|
+
cache_control: cacheControl,
|
|
604
|
+
});
|
|
605
|
+
} else {
|
|
606
|
+
warnings.push({
|
|
607
|
+
type: 'other',
|
|
608
|
+
message: `provider executed tool call for tool ${part.toolName} is not supported`,
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
break;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Extract caller info from provider options for programmatic tool calling
|
|
617
|
+
const callerOptions = part.providerOptions?.anthropic as
|
|
618
|
+
| { caller?: { type: string; toolId?: string } }
|
|
619
|
+
| undefined;
|
|
620
|
+
const caller = callerOptions?.caller
|
|
621
|
+
? callerOptions.caller.type === 'code_execution_20250825' &&
|
|
622
|
+
callerOptions.caller.toolId
|
|
623
|
+
? {
|
|
624
|
+
type: 'code_execution_20250825' as const,
|
|
625
|
+
tool_id: callerOptions.caller.toolId,
|
|
626
|
+
}
|
|
627
|
+
: callerOptions.caller.type === 'direct'
|
|
628
|
+
? { type: 'direct' as const }
|
|
629
|
+
: undefined
|
|
630
|
+
: undefined;
|
|
631
|
+
|
|
632
|
+
anthropicContent.push({
|
|
633
|
+
type: 'tool_use',
|
|
634
|
+
id: part.toolCallId,
|
|
635
|
+
name: part.toolName,
|
|
636
|
+
input: part.input,
|
|
637
|
+
...(caller && { caller }),
|
|
638
|
+
cache_control: cacheControl,
|
|
639
|
+
});
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
case 'tool-result': {
|
|
644
|
+
const providerToolName = toolNameMapping.toProviderToolName(
|
|
645
|
+
part.toolName,
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
if (mcpToolUseIds.has(part.toolCallId)) {
|
|
649
|
+
const output = part.output;
|
|
650
|
+
|
|
651
|
+
if (output.type !== 'json' && output.type !== 'error-json') {
|
|
652
|
+
warnings.push({
|
|
653
|
+
type: 'other',
|
|
654
|
+
message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
anthropicContent.push({
|
|
661
|
+
type: 'mcp_tool_result',
|
|
662
|
+
tool_use_id: part.toolCallId,
|
|
663
|
+
is_error: output.type === 'error-json',
|
|
664
|
+
content: output.value as unknown as
|
|
665
|
+
| string
|
|
666
|
+
| Array<{ type: 'text'; text: string }>,
|
|
667
|
+
cache_control: cacheControl,
|
|
668
|
+
});
|
|
669
|
+
} else if (providerToolName === 'code_execution') {
|
|
670
|
+
const output = part.output;
|
|
671
|
+
|
|
672
|
+
// Handle error types for code_execution tools (e.g., from programmatic tool calling)
|
|
673
|
+
if (
|
|
674
|
+
output.type === 'error-text' ||
|
|
675
|
+
output.type === 'error-json'
|
|
676
|
+
) {
|
|
677
|
+
let errorInfo: { type?: string; errorCode?: string } = {};
|
|
678
|
+
try {
|
|
679
|
+
if (typeof output.value === 'string') {
|
|
680
|
+
errorInfo = JSON.parse(output.value);
|
|
681
|
+
} else if (
|
|
682
|
+
typeof output.value === 'object' &&
|
|
683
|
+
output.value !== null
|
|
684
|
+
) {
|
|
685
|
+
errorInfo = output.value as typeof errorInfo;
|
|
686
|
+
}
|
|
687
|
+
} catch {}
|
|
688
|
+
|
|
689
|
+
if (errorInfo.type === 'code_execution_tool_result_error') {
|
|
690
|
+
anthropicContent.push({
|
|
691
|
+
type: 'code_execution_tool_result',
|
|
692
|
+
tool_use_id: part.toolCallId,
|
|
693
|
+
content: {
|
|
694
|
+
type: 'code_execution_tool_result_error' as const,
|
|
695
|
+
error_code: errorInfo.errorCode ?? 'unknown',
|
|
696
|
+
},
|
|
697
|
+
cache_control: cacheControl,
|
|
698
|
+
});
|
|
699
|
+
} else {
|
|
700
|
+
anthropicContent.push({
|
|
701
|
+
type: 'bash_code_execution_tool_result',
|
|
702
|
+
tool_use_id: part.toolCallId,
|
|
703
|
+
cache_control: cacheControl,
|
|
704
|
+
content: {
|
|
705
|
+
type: 'bash_code_execution_tool_result_error' as const,
|
|
706
|
+
error_code: errorInfo.errorCode ?? 'unknown',
|
|
707
|
+
},
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
if (output.type !== 'json') {
|
|
714
|
+
warnings.push({
|
|
715
|
+
type: 'other',
|
|
716
|
+
message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (
|
|
723
|
+
output.value == null ||
|
|
724
|
+
typeof output.value !== 'object' ||
|
|
725
|
+
!('type' in output.value) ||
|
|
726
|
+
typeof output.value.type !== 'string'
|
|
727
|
+
) {
|
|
728
|
+
warnings.push({
|
|
729
|
+
type: 'other',
|
|
730
|
+
message: `provider executed tool result output value is not a valid code execution result for tool ${part.toolName}`,
|
|
731
|
+
});
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// to distinguish between code execution 20250522 and 20250825,
|
|
736
|
+
// we check if a type property is present in the output.value
|
|
737
|
+
if (output.value.type === 'code_execution_result') {
|
|
738
|
+
// code execution 20250522
|
|
739
|
+
const codeExecutionOutput = await validateTypes({
|
|
740
|
+
value: output.value,
|
|
741
|
+
schema: codeExecution_20250522OutputSchema,
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
anthropicContent.push({
|
|
745
|
+
type: 'code_execution_tool_result',
|
|
746
|
+
tool_use_id: part.toolCallId,
|
|
747
|
+
content: {
|
|
748
|
+
type: codeExecutionOutput.type,
|
|
749
|
+
stdout: codeExecutionOutput.stdout,
|
|
750
|
+
stderr: codeExecutionOutput.stderr,
|
|
751
|
+
return_code: codeExecutionOutput.return_code,
|
|
752
|
+
content: codeExecutionOutput.content ?? [],
|
|
753
|
+
},
|
|
754
|
+
cache_control: cacheControl,
|
|
755
|
+
});
|
|
756
|
+
} else {
|
|
757
|
+
// code execution 20250825
|
|
758
|
+
const codeExecutionOutput = await validateTypes({
|
|
759
|
+
value: output.value,
|
|
760
|
+
schema: codeExecution_20250825OutputSchema,
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
if (codeExecutionOutput.type === 'code_execution_result') {
|
|
764
|
+
// Programmatic tool calling result - same format as 20250522
|
|
765
|
+
anthropicContent.push({
|
|
766
|
+
type: 'code_execution_tool_result',
|
|
767
|
+
tool_use_id: part.toolCallId,
|
|
768
|
+
content: {
|
|
769
|
+
type: codeExecutionOutput.type,
|
|
770
|
+
stdout: codeExecutionOutput.stdout,
|
|
771
|
+
stderr: codeExecutionOutput.stderr,
|
|
772
|
+
return_code: codeExecutionOutput.return_code,
|
|
773
|
+
content: codeExecutionOutput.content ?? [],
|
|
774
|
+
},
|
|
775
|
+
cache_control: cacheControl,
|
|
776
|
+
});
|
|
777
|
+
} else if (
|
|
778
|
+
codeExecutionOutput.type ===
|
|
779
|
+
'bash_code_execution_result' ||
|
|
780
|
+
codeExecutionOutput.type ===
|
|
781
|
+
'bash_code_execution_tool_result_error'
|
|
782
|
+
) {
|
|
783
|
+
anthropicContent.push({
|
|
784
|
+
type: 'bash_code_execution_tool_result',
|
|
785
|
+
tool_use_id: part.toolCallId,
|
|
786
|
+
cache_control: cacheControl,
|
|
787
|
+
content: codeExecutionOutput,
|
|
788
|
+
});
|
|
789
|
+
} else {
|
|
790
|
+
anthropicContent.push({
|
|
791
|
+
type: 'text_editor_code_execution_tool_result',
|
|
792
|
+
tool_use_id: part.toolCallId,
|
|
793
|
+
cache_control: cacheControl,
|
|
794
|
+
content: codeExecutionOutput,
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (providerToolName === 'web_fetch') {
|
|
802
|
+
const output = part.output;
|
|
803
|
+
|
|
804
|
+
if (output.type === 'error-json') {
|
|
805
|
+
let errorValue: { errorCode?: string } = {};
|
|
806
|
+
try {
|
|
807
|
+
if (typeof output.value === 'string') {
|
|
808
|
+
errorValue = JSON.parse(output.value);
|
|
809
|
+
} else if (
|
|
810
|
+
typeof output.value === 'object' &&
|
|
811
|
+
output.value !== null
|
|
812
|
+
) {
|
|
813
|
+
errorValue = output.value as typeof errorValue;
|
|
814
|
+
}
|
|
815
|
+
} catch {
|
|
816
|
+
// If parsing fails, treat the value as-is
|
|
817
|
+
const extractedErrorCode = (
|
|
818
|
+
output.value as Record<string, unknown>
|
|
819
|
+
)?.errorCode;
|
|
820
|
+
errorValue = {
|
|
821
|
+
errorCode:
|
|
822
|
+
typeof extractedErrorCode === 'string'
|
|
823
|
+
? extractedErrorCode
|
|
824
|
+
: 'unknown',
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
anthropicContent.push({
|
|
829
|
+
type: 'web_fetch_tool_result',
|
|
830
|
+
tool_use_id: part.toolCallId,
|
|
831
|
+
content: {
|
|
832
|
+
type: 'web_fetch_tool_result_error',
|
|
833
|
+
error_code: errorValue.errorCode ?? 'unknown',
|
|
834
|
+
},
|
|
835
|
+
cache_control: cacheControl,
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (output.type !== 'json') {
|
|
842
|
+
warnings.push({
|
|
843
|
+
type: 'other',
|
|
844
|
+
message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
const webFetchOutput = await validateTypes({
|
|
851
|
+
value: output.value,
|
|
852
|
+
schema: webFetch_20250910OutputSchema,
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
anthropicContent.push({
|
|
856
|
+
type: 'web_fetch_tool_result',
|
|
857
|
+
tool_use_id: part.toolCallId,
|
|
858
|
+
content: {
|
|
859
|
+
type: 'web_fetch_result',
|
|
860
|
+
url: webFetchOutput.url,
|
|
861
|
+
retrieved_at: webFetchOutput.retrievedAt,
|
|
862
|
+
content: {
|
|
863
|
+
type: 'document',
|
|
864
|
+
title: webFetchOutput.content.title,
|
|
865
|
+
citations: webFetchOutput.content.citations,
|
|
866
|
+
source: {
|
|
867
|
+
type: webFetchOutput.content.source.type,
|
|
868
|
+
media_type: webFetchOutput.content.source.mediaType,
|
|
869
|
+
data: webFetchOutput.content.source.data,
|
|
870
|
+
} as Extract<
|
|
871
|
+
AnthropicWebFetchToolResultContent['content'],
|
|
872
|
+
{ type: 'web_fetch_result' }
|
|
873
|
+
>['content']['source'],
|
|
874
|
+
},
|
|
875
|
+
},
|
|
876
|
+
cache_control: cacheControl,
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (providerToolName === 'web_search') {
|
|
883
|
+
const output = part.output;
|
|
884
|
+
|
|
885
|
+
if (output.type !== 'json') {
|
|
886
|
+
warnings.push({
|
|
887
|
+
type: 'other',
|
|
888
|
+
message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const webSearchOutput = await validateTypes({
|
|
895
|
+
value: output.value,
|
|
896
|
+
schema: webSearch_20250305OutputSchema,
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
anthropicContent.push({
|
|
900
|
+
type: 'web_search_tool_result',
|
|
901
|
+
tool_use_id: part.toolCallId,
|
|
902
|
+
content: webSearchOutput.map(result => ({
|
|
903
|
+
url: result.url,
|
|
904
|
+
title: result.title,
|
|
905
|
+
page_age: result.pageAge,
|
|
906
|
+
encrypted_content: result.encryptedContent,
|
|
907
|
+
type: result.type,
|
|
908
|
+
})),
|
|
909
|
+
cache_control: cacheControl,
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
break;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if (
|
|
916
|
+
providerToolName === 'tool_search_tool_regex' ||
|
|
917
|
+
providerToolName === 'tool_search_tool_bm25'
|
|
918
|
+
) {
|
|
919
|
+
const output = part.output;
|
|
920
|
+
|
|
921
|
+
if (output.type !== 'json') {
|
|
922
|
+
warnings.push({
|
|
923
|
+
type: 'other',
|
|
924
|
+
message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const toolSearchOutput = await validateTypes({
|
|
931
|
+
value: output.value,
|
|
932
|
+
schema: toolSearchOutputSchema,
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// Convert tool references back to API format
|
|
936
|
+
const toolReferences = toolSearchOutput.map(ref => ({
|
|
937
|
+
type: 'tool_reference' as const,
|
|
938
|
+
tool_name: ref.toolName,
|
|
939
|
+
}));
|
|
940
|
+
|
|
941
|
+
anthropicContent.push({
|
|
942
|
+
type: 'tool_search_tool_result',
|
|
943
|
+
tool_use_id: part.toolCallId,
|
|
944
|
+
content: {
|
|
945
|
+
type: 'tool_search_tool_search_result',
|
|
946
|
+
tool_references: toolReferences,
|
|
947
|
+
},
|
|
948
|
+
cache_control: cacheControl,
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
warnings.push({
|
|
955
|
+
type: 'other',
|
|
956
|
+
message: `provider executed tool result for tool ${part.toolName} is not supported`,
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
messages.push({ role: 'assistant', content: anthropicContent });
|
|
966
|
+
|
|
967
|
+
break;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
default: {
|
|
971
|
+
const _exhaustiveCheck: never = type;
|
|
972
|
+
throw new Error(`content type: ${_exhaustiveCheck}`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
return {
|
|
978
|
+
prompt: { system, messages },
|
|
979
|
+
betas,
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
type SystemBlock = {
|
|
984
|
+
type: 'system';
|
|
985
|
+
messages: Array<LanguageModelV3Message & { role: 'system' }>;
|
|
986
|
+
};
|
|
987
|
+
type AssistantBlock = {
|
|
988
|
+
type: 'assistant';
|
|
989
|
+
messages: Array<LanguageModelV3Message & { role: 'assistant' }>;
|
|
990
|
+
};
|
|
991
|
+
type UserBlock = {
|
|
992
|
+
type: 'user';
|
|
993
|
+
messages: Array<LanguageModelV3Message & { role: 'user' | 'tool' }>;
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
function groupIntoBlocks(
|
|
997
|
+
prompt: LanguageModelV3Prompt,
|
|
998
|
+
): Array<SystemBlock | AssistantBlock | UserBlock> {
|
|
999
|
+
const blocks: Array<SystemBlock | AssistantBlock | UserBlock> = [];
|
|
1000
|
+
let currentBlock: SystemBlock | AssistantBlock | UserBlock | undefined =
|
|
1001
|
+
undefined;
|
|
1002
|
+
|
|
1003
|
+
for (const message of prompt) {
|
|
1004
|
+
const { role } = message;
|
|
1005
|
+
switch (role) {
|
|
1006
|
+
case 'system': {
|
|
1007
|
+
if (currentBlock?.type !== 'system') {
|
|
1008
|
+
currentBlock = { type: 'system', messages: [] };
|
|
1009
|
+
blocks.push(currentBlock);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
currentBlock.messages.push(message);
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
case 'assistant': {
|
|
1016
|
+
if (currentBlock?.type !== 'assistant') {
|
|
1017
|
+
currentBlock = { type: 'assistant', messages: [] };
|
|
1018
|
+
blocks.push(currentBlock);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
currentBlock.messages.push(message);
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
case 'user': {
|
|
1025
|
+
if (currentBlock?.type !== 'user') {
|
|
1026
|
+
currentBlock = { type: 'user', messages: [] };
|
|
1027
|
+
blocks.push(currentBlock);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
currentBlock.messages.push(message);
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
case 'tool': {
|
|
1034
|
+
if (currentBlock?.type !== 'user') {
|
|
1035
|
+
currentBlock = { type: 'user', messages: [] };
|
|
1036
|
+
blocks.push(currentBlock);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
currentBlock.messages.push(message);
|
|
1040
|
+
break;
|
|
1041
|
+
}
|
|
1042
|
+
default: {
|
|
1043
|
+
const _exhaustiveCheck: never = role;
|
|
1044
|
+
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return blocks;
|
|
1050
|
+
}
|