@ai-sdk/anthropic 4.0.78 → 4.0.79
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 +13 -0
- package/dist/index.d.ts +349 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -19
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +2 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +78 -16
- package/dist/internal/index.js.map +1 -1
- package/docs/05-anthropic.mdx +34 -0
- package/package.json +3 -3
- package/src/anthropic-api.ts +1 -0
- package/src/anthropic-batch.ts +20 -7
- package/src/anthropic-language-model.ts +57 -26
- package/src/anthropic-prepare-tools.ts +6 -2
- package/src/anthropic-provider-metadata.ts +16 -0
- package/src/convert-to-anthropic-prompt.ts +24 -0
- package/src/index.ts +4 -0
- package/src/map-anthropic-citation.ts +51 -0
package/docs/05-anthropic.mdx
CHANGED
|
@@ -1420,6 +1420,40 @@ const result = await generateText({
|
|
|
1420
1420
|
settings](https://console.anthropic.com/settings/privacy).
|
|
1421
1421
|
</Note>
|
|
1422
1422
|
|
|
1423
|
+
#### Sources and Citations
|
|
1424
|
+
|
|
1425
|
+
`result.sources` and source stream events expose web-search results. Inline
|
|
1426
|
+
references are attached separately to generated text as `part.citations`, and
|
|
1427
|
+
to streamed text as `text-end.citations`. This shared citation representation
|
|
1428
|
+
includes the referenced URL or document and its supporting passage. If web-search
|
|
1429
|
+
results are unavailable, web citations also provide source references for
|
|
1430
|
+
compatibility. Indexed document references retain their existing document source
|
|
1431
|
+
parts when the original prompt supplies document information.
|
|
1432
|
+
|
|
1433
|
+
Raw citations remain available as
|
|
1434
|
+
`text.providerMetadata.anthropic.citations`, including on streamed `text-end`
|
|
1435
|
+
events. Import `AnthropicTextProviderMetadata` and `AnthropicCitation` for typed
|
|
1436
|
+
access. `AnthropicCitation` is a union of `web_search_result_location`,
|
|
1437
|
+
`search_result_location`, `page_location`, `char_location`, and
|
|
1438
|
+
`content_block_location`. Document page, character, and block locations refer to
|
|
1439
|
+
the source document, rather than the generated answer.
|
|
1440
|
+
|
|
1441
|
+
```ts
|
|
1442
|
+
import type { AnthropicTextProviderMetadata } from '@ai-sdk/anthropic';
|
|
1443
|
+
|
|
1444
|
+
for (const part of result.content) {
|
|
1445
|
+
if (part.type === 'text') {
|
|
1446
|
+
console.log(part.citations);
|
|
1447
|
+
const metadata = part.providerMetadata as
|
|
1448
|
+
| AnthropicTextProviderMetadata
|
|
1449
|
+
| undefined;
|
|
1450
|
+
for (const citation of metadata?.anthropic.citations ?? []) {
|
|
1451
|
+
console.log(citation.type, citation.cited_text);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
```
|
|
1456
|
+
|
|
1423
1457
|
#### Configuration Options
|
|
1424
1458
|
|
|
1425
1459
|
Use `webSearch_20260318` for dynamic filtering and response inclusion control.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/anthropic",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.79",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@ai-sdk/provider": "4.0.
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
38
|
+
"@ai-sdk/provider": "4.0.27",
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.59"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@ai-sdk/test-server": "2.0.4",
|
package/src/anthropic-api.ts
CHANGED
|
@@ -594,6 +594,7 @@ export type AnthropicSpeed = 'fast' | 'standard';
|
|
|
594
594
|
|
|
595
595
|
export type AnthropicToolChoice =
|
|
596
596
|
| { type: 'auto' | 'any'; disable_parallel_tool_use?: boolean }
|
|
597
|
+
| { type: 'none' }
|
|
597
598
|
| { type: 'tool'; name: string; disable_parallel_tool_use?: boolean };
|
|
598
599
|
|
|
599
600
|
export type AnthropicContainer = {
|
package/src/anthropic-batch.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapAnthropicCitation } from './map-anthropic-citation';
|
|
1
2
|
import {
|
|
2
3
|
InvalidArgumentError,
|
|
3
4
|
InvalidResponseDataError,
|
|
@@ -44,8 +45,8 @@ import {
|
|
|
44
45
|
} from './anthropic-api';
|
|
45
46
|
import { anthropicFailedResponseHandler } from './anthropic-error';
|
|
46
47
|
import {
|
|
47
|
-
AnthropicLanguageModel,
|
|
48
48
|
createCitationSource,
|
|
49
|
+
AnthropicLanguageModel,
|
|
49
50
|
type AnthropicLanguageModelConfig,
|
|
50
51
|
} from './anthropic-language-model';
|
|
51
52
|
import {
|
|
@@ -746,6 +747,12 @@ function convertAnthropicBatchResponse(
|
|
|
746
747
|
> = {};
|
|
747
748
|
const serverToolCalls: Record<string, string> = {};
|
|
748
749
|
|
|
750
|
+
const hasWebSearchResults = response.content.some(
|
|
751
|
+
part =>
|
|
752
|
+
part.type === 'web_search_tool_result' &&
|
|
753
|
+
Array.isArray(part.content) &&
|
|
754
|
+
part.content.length > 0,
|
|
755
|
+
);
|
|
749
756
|
for (const part of response.content) {
|
|
750
757
|
switch (part.type) {
|
|
751
758
|
case 'text':
|
|
@@ -754,6 +761,12 @@ function convertAnthropicBatchResponse(
|
|
|
754
761
|
content.push({
|
|
755
762
|
type: 'text',
|
|
756
763
|
text: part.text,
|
|
764
|
+
...(citations != null &&
|
|
765
|
+
citations.length > 0 && {
|
|
766
|
+
citations: citations.map(citation =>
|
|
767
|
+
mapAnthropicCitation(citation, []),
|
|
768
|
+
),
|
|
769
|
+
}),
|
|
757
770
|
...(citations != null &&
|
|
758
771
|
citations.length > 0 && {
|
|
759
772
|
providerMetadata: {
|
|
@@ -762,12 +775,12 @@ function convertAnthropicBatchResponse(
|
|
|
762
775
|
}),
|
|
763
776
|
});
|
|
764
777
|
for (const citation of part.citations ?? []) {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
content.push(source);
|
|
778
|
+
if (
|
|
779
|
+
citation.type === 'web_search_result_location' &&
|
|
780
|
+
!hasWebSearchResults
|
|
781
|
+
) {
|
|
782
|
+
const source = createCitationSource(citation, [], generateId);
|
|
783
|
+
if (source) content.push(source);
|
|
771
784
|
}
|
|
772
785
|
}
|
|
773
786
|
break;
|
|
@@ -46,6 +46,8 @@ import type {
|
|
|
46
46
|
AnthropicMessageMetadata,
|
|
47
47
|
AnthropicUsageIteration,
|
|
48
48
|
} from './anthropic-message-metadata';
|
|
49
|
+
import { mapAnthropicCitation } from './map-anthropic-citation';
|
|
50
|
+
import type { AnthropicTextProviderMetadata } from './anthropic-provider-metadata';
|
|
49
51
|
import {
|
|
50
52
|
anthropicChunkSchema,
|
|
51
53
|
anthropicResponseSchema,
|
|
@@ -130,8 +132,8 @@ export function createCitationSource(
|
|
|
130
132
|
): LanguageModelV4Source | undefined {
|
|
131
133
|
if (citation.type === 'web_search_result_location') {
|
|
132
134
|
return {
|
|
133
|
-
type: 'source'
|
|
134
|
-
sourceType: 'url'
|
|
135
|
+
type: 'source',
|
|
136
|
+
sourceType: 'url',
|
|
135
137
|
id: generateId(),
|
|
136
138
|
url: citation.url,
|
|
137
139
|
title: citation.title ?? undefined,
|
|
@@ -140,7 +142,7 @@ export function createCitationSource(
|
|
|
140
142
|
citedText: citation.cited_text,
|
|
141
143
|
encryptedIndex: citation.encrypted_index,
|
|
142
144
|
},
|
|
143
|
-
}
|
|
145
|
+
},
|
|
144
146
|
};
|
|
145
147
|
}
|
|
146
148
|
|
|
@@ -1253,31 +1255,45 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
1253
1255
|
const serverToolCalls: Record<string, string> = {}; // tool_use_id -> provider tool name
|
|
1254
1256
|
let isJsonResponseFromTool = false;
|
|
1255
1257
|
|
|
1258
|
+
const hasWebSearchResults = response.content.some(
|
|
1259
|
+
part =>
|
|
1260
|
+
part.type === 'web_search_tool_result' &&
|
|
1261
|
+
Array.isArray(part.content) &&
|
|
1262
|
+
part.content.length > 0,
|
|
1263
|
+
);
|
|
1256
1264
|
// map response content to content array
|
|
1257
1265
|
for (const part of response.content) {
|
|
1258
1266
|
switch (part.type) {
|
|
1259
1267
|
case 'text': {
|
|
1260
1268
|
if (!usesJsonResponseTool) {
|
|
1261
|
-
const
|
|
1262
|
-
citation => citation.type === 'web_search_result_location',
|
|
1263
|
-
);
|
|
1269
|
+
const citations = part.citations ?? [];
|
|
1264
1270
|
|
|
1265
1271
|
content.push({
|
|
1266
1272
|
type: 'text',
|
|
1267
1273
|
text: part.text,
|
|
1268
|
-
...(
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
+
...(citations.length > 0 && {
|
|
1275
|
+
citations: citations.map(citation =>
|
|
1276
|
+
mapAnthropicCitation(citation, citationDocuments),
|
|
1277
|
+
),
|
|
1278
|
+
}),
|
|
1279
|
+
...(citations.length > 0 && {
|
|
1280
|
+
providerMetadata: {
|
|
1281
|
+
anthropic: {
|
|
1282
|
+
citations,
|
|
1274
1283
|
},
|
|
1275
|
-
}
|
|
1284
|
+
} satisfies AnthropicTextProviderMetadata,
|
|
1285
|
+
}),
|
|
1276
1286
|
});
|
|
1277
1287
|
|
|
1278
1288
|
// Process citations if present
|
|
1279
1289
|
if (part.citations) {
|
|
1280
1290
|
for (const citation of part.citations) {
|
|
1291
|
+
if (
|
|
1292
|
+
citation.type === 'web_search_result_location' &&
|
|
1293
|
+
hasWebSearchResults
|
|
1294
|
+
) {
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1281
1297
|
const source = createCitationSource(
|
|
1282
1298
|
citation,
|
|
1283
1299
|
citationDocuments,
|
|
@@ -1926,6 +1942,8 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
1926
1942
|
let safeguardResults: AnthropicMessageMetadata['safeguardResults'];
|
|
1927
1943
|
let container: AnthropicMessageMetadata['container'] | null = null;
|
|
1928
1944
|
let isJsonResponseFromTool = false;
|
|
1945
|
+
let hasWebSearchResults = false;
|
|
1946
|
+
const fallbackWebCitations: Citation[] = [];
|
|
1929
1947
|
let isMessageOpen = false;
|
|
1930
1948
|
let activeMessageId: string | null | undefined;
|
|
1931
1949
|
let hasInvalidMessageSequence = false;
|
|
@@ -2345,6 +2363,7 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
2345
2363
|
});
|
|
2346
2364
|
|
|
2347
2365
|
for (const result of part.content) {
|
|
2366
|
+
hasWebSearchResults = true;
|
|
2348
2367
|
controller.enqueue({
|
|
2349
2368
|
type: 'source',
|
|
2350
2369
|
sourceType: 'url',
|
|
@@ -2587,11 +2606,14 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
2587
2606
|
type: 'text-end',
|
|
2588
2607
|
id: String(value.index),
|
|
2589
2608
|
...(contentBlock.citations.length > 0 && {
|
|
2609
|
+
citations: contentBlock.citations.map(citation =>
|
|
2610
|
+
mapAnthropicCitation(citation, citationDocuments),
|
|
2611
|
+
),
|
|
2590
2612
|
providerMetadata: {
|
|
2591
2613
|
anthropic: {
|
|
2592
2614
|
citations: contentBlock.citations,
|
|
2593
2615
|
},
|
|
2594
|
-
},
|
|
2616
|
+
} satisfies AnthropicTextProviderMetadata,
|
|
2595
2617
|
}),
|
|
2596
2618
|
});
|
|
2597
2619
|
break;
|
|
@@ -2828,21 +2850,19 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
2828
2850
|
const citation = value.delta.citation;
|
|
2829
2851
|
const contentBlock = contentBlocks[value.index];
|
|
2830
2852
|
|
|
2831
|
-
if (
|
|
2832
|
-
contentBlock?.type === 'text' &&
|
|
2833
|
-
citation.type === 'web_search_result_location'
|
|
2834
|
-
) {
|
|
2853
|
+
if (contentBlock?.type === 'text') {
|
|
2835
2854
|
contentBlock.citations.push(citation);
|
|
2836
2855
|
}
|
|
2837
2856
|
|
|
2838
|
-
|
|
2839
|
-
citation
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2857
|
+
if (citation.type === 'web_search_result_location') {
|
|
2858
|
+
fallbackWebCitations.push(citation);
|
|
2859
|
+
} else {
|
|
2860
|
+
const source = createCitationSource(
|
|
2861
|
+
citation,
|
|
2862
|
+
citationDocuments,
|
|
2863
|
+
generateId,
|
|
2864
|
+
);
|
|
2865
|
+
if (source) controller.enqueue(source);
|
|
2846
2866
|
}
|
|
2847
2867
|
|
|
2848
2868
|
return;
|
|
@@ -3101,6 +3121,17 @@ export class AnthropicLanguageModel implements LanguageModelV4 {
|
|
|
3101
3121
|
providerMetadata[providerOptionsName] = anthropicMetadata;
|
|
3102
3122
|
}
|
|
3103
3123
|
|
|
3124
|
+
if (!hasWebSearchResults) {
|
|
3125
|
+
for (const citation of fallbackWebCitations) {
|
|
3126
|
+
const source = createCitationSource(
|
|
3127
|
+
citation,
|
|
3128
|
+
citationDocuments,
|
|
3129
|
+
generateId,
|
|
3130
|
+
);
|
|
3131
|
+
if (source) controller.enqueue(source);
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
fallbackWebCitations.length = 0;
|
|
3104
3135
|
controller.enqueue({
|
|
3105
3136
|
type: 'finish',
|
|
3106
3137
|
finishReason,
|
|
@@ -515,8 +515,12 @@ export async function prepareTools({
|
|
|
515
515
|
betas,
|
|
516
516
|
};
|
|
517
517
|
case 'none':
|
|
518
|
-
|
|
519
|
-
|
|
518
|
+
return {
|
|
519
|
+
tools: anthropicTools,
|
|
520
|
+
toolChoice: { type: 'none' },
|
|
521
|
+
toolWarnings,
|
|
522
|
+
betas,
|
|
523
|
+
};
|
|
520
524
|
case 'tool':
|
|
521
525
|
if (rejectsForcedToolUse) {
|
|
522
526
|
toolWarnings.push({
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Citation } from './anthropic-api';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Citation metadata returned by Anthropic for generated text.
|
|
5
|
+
*/
|
|
6
|
+
export type AnthropicCitation = Citation;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Anthropic provider metadata attached to generated text that contains
|
|
10
|
+
* citations.
|
|
11
|
+
*/
|
|
12
|
+
export type AnthropicTextProviderMetadata = {
|
|
13
|
+
anthropic: {
|
|
14
|
+
citations: AnthropicCitation[];
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -1342,6 +1342,30 @@ export async function convertToAnthropicPrompt({
|
|
|
1342
1342
|
) {
|
|
1343
1343
|
const output = part.output;
|
|
1344
1344
|
|
|
1345
|
+
if (
|
|
1346
|
+
output.type === 'error-json' ||
|
|
1347
|
+
(output.type === 'json' &&
|
|
1348
|
+
output.value != null &&
|
|
1349
|
+
typeof output.value === 'object' &&
|
|
1350
|
+
!Array.isArray(output.value) &&
|
|
1351
|
+
'type' in output.value &&
|
|
1352
|
+
output.value.type === 'tool_search_tool_result_error')
|
|
1353
|
+
) {
|
|
1354
|
+
anthropicContent.push({
|
|
1355
|
+
type: 'tool_search_tool_result',
|
|
1356
|
+
tool_use_id: part.toolCallId,
|
|
1357
|
+
content: {
|
|
1358
|
+
type: 'tool_search_tool_result_error',
|
|
1359
|
+
error_code:
|
|
1360
|
+
extractErrorValue(output.value).errorCode ??
|
|
1361
|
+
'unavailable',
|
|
1362
|
+
},
|
|
1363
|
+
cache_control: cacheControl,
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
break;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1345
1369
|
if (output.type !== 'json') {
|
|
1346
1370
|
warnings.push({
|
|
1347
1371
|
type: 'other',
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,10 @@ export type {
|
|
|
2
2
|
AnthropicMessageMetadata,
|
|
3
3
|
AnthropicUsageIteration,
|
|
4
4
|
} from './anthropic-message-metadata';
|
|
5
|
+
export type {
|
|
6
|
+
AnthropicCitation,
|
|
7
|
+
AnthropicTextProviderMetadata,
|
|
8
|
+
} from './anthropic-provider-metadata';
|
|
5
9
|
export type {
|
|
6
10
|
AnthropicLanguageModelOptions,
|
|
7
11
|
/** @deprecated Use `AnthropicLanguageModelOptions` instead. */
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { LanguageModelV4Citation } from '@ai-sdk/provider';
|
|
2
|
+
import type { Citation } from './anthropic-api';
|
|
3
|
+
|
|
4
|
+
export type CitationDocument = {
|
|
5
|
+
title: string;
|
|
6
|
+
filename?: string;
|
|
7
|
+
mediaType: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function mapAnthropicCitation(
|
|
11
|
+
citation: Citation,
|
|
12
|
+
documents: Array<CitationDocument>,
|
|
13
|
+
): LanguageModelV4Citation {
|
|
14
|
+
if (
|
|
15
|
+
citation.type === 'web_search_result_location' ||
|
|
16
|
+
citation.type === 'search_result_location'
|
|
17
|
+
) {
|
|
18
|
+
const url =
|
|
19
|
+
citation.type === 'web_search_result_location'
|
|
20
|
+
? citation.url
|
|
21
|
+
: citation.source;
|
|
22
|
+
return {
|
|
23
|
+
source: {
|
|
24
|
+
type: 'source',
|
|
25
|
+
sourceType: 'url',
|
|
26
|
+
id: url,
|
|
27
|
+
url,
|
|
28
|
+
title: citation.title ?? undefined,
|
|
29
|
+
providerMetadata: { anthropic: { ...citation } },
|
|
30
|
+
},
|
|
31
|
+
citedText: citation.cited_text,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const document = documents[citation.document_index];
|
|
36
|
+
return {
|
|
37
|
+
source: {
|
|
38
|
+
type: 'source',
|
|
39
|
+
sourceType: 'document',
|
|
40
|
+
id: citation.file_id ?? String(citation.document_index),
|
|
41
|
+
mediaType: document?.mediaType ?? 'text/plain',
|
|
42
|
+
title:
|
|
43
|
+
citation.document_title ??
|
|
44
|
+
document?.title ??
|
|
45
|
+
`Document ${citation.document_index}`,
|
|
46
|
+
filename: document?.filename,
|
|
47
|
+
providerMetadata: { anthropic: { ...citation } },
|
|
48
|
+
},
|
|
49
|
+
citedText: citation.cited_text,
|
|
50
|
+
};
|
|
51
|
+
}
|