@ai-sdk/anthropic 2.0.0-alpha.10 → 2.0.0-alpha.11

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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # @ai-sdk/anthropic
2
2
 
3
+ ## 2.0.0-alpha.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 25f3454: feat(provider/anthropic): add PDF citation support with document sources for streamText
8
+ - Updated dependencies [c1e6647]
9
+ - @ai-sdk/provider@2.0.0-alpha.11
10
+ - @ai-sdk/provider-utils@3.0.0-alpha.11
11
+
3
12
  ## 2.0.0-alpha.10
4
13
 
5
14
  ### Patch Changes
package/dist/index.js CHANGED
@@ -58,6 +58,29 @@ var webSearchLocationSchema = import_zod2.z.object({
58
58
  country: import_zod2.z.string(),
59
59
  timezone: import_zod2.z.string().optional()
60
60
  });
61
+ var anthropicFilePartProviderOptions = import_zod2.z.object({
62
+ /**
63
+ * Citation configuration for this document.
64
+ * When enabled, this document will generate citations in the response.
65
+ */
66
+ citations: import_zod2.z.object({
67
+ /**
68
+ * Enable citations for this document
69
+ */
70
+ enabled: import_zod2.z.boolean()
71
+ }).optional(),
72
+ /**
73
+ * Custom title for the document.
74
+ * If not provided, the filename will be used.
75
+ */
76
+ title: import_zod2.z.string().optional(),
77
+ /**
78
+ * Context about the document that will be passed to the model
79
+ * but not used towards cited content.
80
+ * Useful for storing document metadata as text or stringified JSON.
81
+ */
82
+ context: import_zod2.z.string().optional()
83
+ });
61
84
  var anthropicProviderOptions = import_zod2.z.object({
62
85
  /**
63
86
  Include reasoning content in requests sent to the model. Defaults to `true`.
@@ -235,7 +258,7 @@ async function convertToAnthropicMessagesPrompt({
235
258
  sendReasoning,
236
259
  warnings
237
260
  }) {
238
- var _a, _b, _c;
261
+ var _a, _b, _c, _d;
239
262
  const betas = /* @__PURE__ */ new Set();
240
263
  const blocks = groupIntoBlocks(prompt);
241
264
  let system = void 0;
@@ -246,6 +269,26 @@ async function convertToAnthropicMessagesPrompt({
246
269
  const cacheControlValue = (_a2 = anthropic2 == null ? void 0 : anthropic2.cacheControl) != null ? _a2 : anthropic2 == null ? void 0 : anthropic2.cache_control;
247
270
  return cacheControlValue;
248
271
  }
272
+ async function shouldEnableCitations(providerMetadata) {
273
+ var _a2, _b2;
274
+ const anthropicOptions = await (0, import_provider_utils2.parseProviderOptions)({
275
+ provider: "anthropic",
276
+ providerOptions: providerMetadata,
277
+ schema: anthropicFilePartProviderOptions
278
+ });
279
+ return (_b2 = (_a2 = anthropicOptions == null ? void 0 : anthropicOptions.citations) == null ? void 0 : _a2.enabled) != null ? _b2 : false;
280
+ }
281
+ async function getDocumentMetadata(providerMetadata) {
282
+ const anthropicOptions = await (0, import_provider_utils2.parseProviderOptions)({
283
+ provider: "anthropic",
284
+ providerOptions: providerMetadata,
285
+ schema: anthropicFilePartProviderOptions
286
+ });
287
+ return {
288
+ title: anthropicOptions == null ? void 0 : anthropicOptions.title,
289
+ context: anthropicOptions == null ? void 0 : anthropicOptions.context
290
+ };
291
+ }
249
292
  for (let i = 0; i < blocks.length; i++) {
250
293
  const block = blocks[i];
251
294
  const isLastBlock = i === blocks.length - 1;
@@ -299,6 +342,12 @@ async function convertToAnthropicMessagesPrompt({
299
342
  });
300
343
  } else if (part.mediaType === "application/pdf") {
301
344
  betas.add("pdfs-2024-09-25");
345
+ const enableCitations = await shouldEnableCitations(
346
+ part.providerOptions
347
+ );
348
+ const metadata = await getDocumentMetadata(
349
+ part.providerOptions
350
+ );
302
351
  anthropicContent.push({
303
352
  type: "document",
304
353
  source: part.data instanceof URL ? {
@@ -309,6 +358,11 @@ async function convertToAnthropicMessagesPrompt({
309
358
  media_type: "application/pdf",
310
359
  data: (0, import_provider_utils2.convertToBase64)(part.data)
311
360
  },
361
+ title: (_b = metadata.title) != null ? _b : part.filename,
362
+ ...metadata.context && { context: metadata.context },
363
+ ...enableCitations && {
364
+ citations: { enabled: true }
365
+ },
312
366
  cache_control: cacheControl
313
367
  });
314
368
  } else {
@@ -326,7 +380,7 @@ async function convertToAnthropicMessagesPrompt({
326
380
  for (let i2 = 0; i2 < content.length; i2++) {
327
381
  const part = content[i2];
328
382
  const isLastPart = i2 === content.length - 1;
329
- const cacheControl = (_b = getCacheControl(part.providerOptions)) != null ? _b : isLastPart ? getCacheControl(message.providerOptions) : void 0;
383
+ const cacheControl = (_c = getCacheControl(part.providerOptions)) != null ? _c : isLastPart ? getCacheControl(message.providerOptions) : void 0;
330
384
  const toolResultContent = part.content != null ? part.content.map((part2) => {
331
385
  var _a2;
332
386
  switch (part2.type) {
@@ -376,7 +430,7 @@ async function convertToAnthropicMessagesPrompt({
376
430
  for (let k = 0; k < content.length; k++) {
377
431
  const part = content[k];
378
432
  const isLastContentPart = k === content.length - 1;
379
- const cacheControl = (_c = getCacheControl(part.providerOptions)) != null ? _c : isLastContentPart ? getCacheControl(message.providerOptions) : void 0;
433
+ const cacheControl = (_d = getCacheControl(part.providerOptions)) != null ? _d : isLastContentPart ? getCacheControl(message.providerOptions) : void 0;
380
434
  switch (part.type) {
381
435
  case "text": {
382
436
  anthropicContent.push({
@@ -525,6 +579,40 @@ function mapAnthropicStopReason({
525
579
  }
526
580
 
527
581
  // src/anthropic-messages-language-model.ts
582
+ function processPageLocationCitation(citation, citationDocuments, generateId3, onSource) {
583
+ if (citation.type === "page_location") {
584
+ const source = createCitationSource(
585
+ citation,
586
+ citationDocuments,
587
+ generateId3
588
+ );
589
+ if (source) {
590
+ onSource(source);
591
+ }
592
+ }
593
+ }
594
+ function createCitationSource(citation, citationDocuments, generateId3) {
595
+ var _a;
596
+ const documentInfo = citationDocuments[citation.document_index];
597
+ if (!documentInfo) {
598
+ return null;
599
+ }
600
+ return {
601
+ type: "source",
602
+ sourceType: "document",
603
+ id: generateId3(),
604
+ mediaType: documentInfo.mediaType,
605
+ title: (_a = citation.document_title) != null ? _a : documentInfo.title,
606
+ filename: documentInfo.filename,
607
+ providerMetadata: {
608
+ anthropic: {
609
+ citedText: citation.cited_text,
610
+ startPageNumber: citation.start_page_number,
611
+ endPageNumber: citation.end_page_number
612
+ }
613
+ }
614
+ };
615
+ }
528
616
  var AnthropicMessagesLanguageModel = class {
529
617
  constructor(modelId, config) {
530
618
  this.specificationVersion = "v2";
@@ -722,9 +810,29 @@ var AnthropicMessagesLanguageModel = class {
722
810
  var _a, _b, _c;
723
811
  return (_c = (_b = (_a = this.config).transformRequestBody) == null ? void 0 : _b.call(_a, args)) != null ? _c : args;
724
812
  }
813
+ extractCitationDocuments(prompt) {
814
+ const isCitationEnabled = (part) => {
815
+ var _a, _b;
816
+ const anthropic2 = (_a = part.providerOptions) == null ? void 0 : _a.anthropic;
817
+ const citationsConfig = anthropic2 == null ? void 0 : anthropic2.citations;
818
+ return (_b = citationsConfig == null ? void 0 : citationsConfig.enabled) != null ? _b : false;
819
+ };
820
+ return prompt.filter((message) => message.role === "user").flatMap((message) => message.content).filter(
821
+ (part) => part.type === "file" && part.mediaType === "application/pdf" && isCitationEnabled(part)
822
+ ).map((part) => {
823
+ var _a;
824
+ const filePart = part;
825
+ return {
826
+ title: (_a = filePart.filename) != null ? _a : "Untitled Document",
827
+ filename: filePart.filename,
828
+ mediaType: filePart.mediaType
829
+ };
830
+ });
831
+ }
725
832
  async doGenerate(options) {
726
833
  var _a, _b, _c, _d, _e;
727
834
  const { args, warnings, betas, jsonResponseTool } = await this.getArgs(options);
835
+ const citationDocuments = this.extractCitationDocuments(options.prompt);
728
836
  const {
729
837
  responseHeaders,
730
838
  value: response,
@@ -746,6 +854,16 @@ var AnthropicMessagesLanguageModel = class {
746
854
  case "text": {
747
855
  if (jsonResponseTool == null) {
748
856
  content.push({ type: "text", text: part.text });
857
+ if (part.citations) {
858
+ for (const citation of part.citations) {
859
+ processPageLocationCitation(
860
+ citation,
861
+ citationDocuments,
862
+ this.generateId,
863
+ (source) => content.push(source)
864
+ );
865
+ }
866
+ }
749
867
  }
750
868
  break;
751
869
  }
@@ -852,6 +970,7 @@ var AnthropicMessagesLanguageModel = class {
852
970
  }
853
971
  async doStream(options) {
854
972
  const { args, warnings, betas, jsonResponseTool } = await this.getArgs(options);
973
+ const citationDocuments = this.extractCitationDocuments(options.prompt);
855
974
  const body = { ...args, stream: true };
856
975
  const { responseHeaders, value: response } = await (0, import_provider_utils3.postJsonToApi)({
857
976
  url: this.buildRequestUrl(true),
@@ -1036,6 +1155,13 @@ var AnthropicMessagesLanguageModel = class {
1036
1155
  return;
1037
1156
  }
1038
1157
  case "citations_delta": {
1158
+ const citation = value.delta.citation;
1159
+ processPageLocationCitation(
1160
+ citation,
1161
+ citationDocuments,
1162
+ generateId3,
1163
+ (source) => controller.enqueue(source)
1164
+ );
1039
1165
  return;
1040
1166
  }
1041
1167
  default: {
@@ -1104,7 +1230,26 @@ var anthropicMessagesResponseSchema = import_zod3.z.object({
1104
1230
  import_zod3.z.discriminatedUnion("type", [
1105
1231
  import_zod3.z.object({
1106
1232
  type: import_zod3.z.literal("text"),
1107
- text: import_zod3.z.string()
1233
+ text: import_zod3.z.string(),
1234
+ citations: import_zod3.z.array(
1235
+ import_zod3.z.discriminatedUnion("type", [
1236
+ import_zod3.z.object({
1237
+ type: import_zod3.z.literal("web_search_result_location"),
1238
+ cited_text: import_zod3.z.string(),
1239
+ url: import_zod3.z.string(),
1240
+ title: import_zod3.z.string(),
1241
+ encrypted_index: import_zod3.z.string()
1242
+ }),
1243
+ import_zod3.z.object({
1244
+ type: import_zod3.z.literal("page_location"),
1245
+ cited_text: import_zod3.z.string(),
1246
+ document_index: import_zod3.z.number(),
1247
+ document_title: import_zod3.z.string().nullable(),
1248
+ start_page_number: import_zod3.z.number(),
1249
+ end_page_number: import_zod3.z.number()
1250
+ })
1251
+ ])
1252
+ ).optional()
1108
1253
  }),
1109
1254
  import_zod3.z.object({
1110
1255
  type: import_zod3.z.literal("thinking"),
@@ -1243,13 +1388,23 @@ var anthropicMessagesChunkSchema = import_zod3.z.discriminatedUnion("type", [
1243
1388
  }),
1244
1389
  import_zod3.z.object({
1245
1390
  type: import_zod3.z.literal("citations_delta"),
1246
- citation: import_zod3.z.object({
1247
- type: import_zod3.z.literal("web_search_result_location"),
1248
- cited_text: import_zod3.z.string(),
1249
- url: import_zod3.z.string(),
1250
- title: import_zod3.z.string(),
1251
- encrypted_index: import_zod3.z.string()
1252
- })
1391
+ citation: import_zod3.z.discriminatedUnion("type", [
1392
+ import_zod3.z.object({
1393
+ type: import_zod3.z.literal("web_search_result_location"),
1394
+ cited_text: import_zod3.z.string(),
1395
+ url: import_zod3.z.string(),
1396
+ title: import_zod3.z.string(),
1397
+ encrypted_index: import_zod3.z.string()
1398
+ }),
1399
+ import_zod3.z.object({
1400
+ type: import_zod3.z.literal("page_location"),
1401
+ cited_text: import_zod3.z.string(),
1402
+ document_index: import_zod3.z.number(),
1403
+ document_title: import_zod3.z.string().nullable(),
1404
+ start_page_number: import_zod3.z.number(),
1405
+ end_page_number: import_zod3.z.number()
1406
+ })
1407
+ ])
1253
1408
  })
1254
1409
  ])
1255
1410
  }),