@ai-sdk/langchain 2.0.214 → 2.0.216

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,19 @@
1
1
  # @ai-sdk/langchain
2
2
 
3
+ ## 2.0.216
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [8261640]
8
+ - Updated dependencies [f994df3]
9
+ - ai@6.0.208
10
+
11
+ ## 2.0.215
12
+
13
+ ### Patch Changes
14
+
15
+ - dff49ee: Surface LangChain citation annotations as spec-compliant `source-url` / `source-document` UI message parts. Previously, citations attached to text content blocks (e.g. from web search or RAG) were dropped entirely instead of being emitted as AI SDK source parts. Citation metadata (`citedText`, `startIndex`, `endIndex`, `source`) is preserved under `providerMetadata.langchain`.
16
+
3
17
  ## 2.0.214
4
18
 
5
19
  ### Patch Changes
package/dist/index.js CHANGED
@@ -229,6 +229,9 @@ function processModelChunk(chunk, state, controller) {
229
229
  if (!state.emittedImages) {
230
230
  state.emittedImages = /* @__PURE__ */ new Set();
231
231
  }
232
+ if (!state.emittedSourceIds) {
233
+ state.emittedSourceIds = /* @__PURE__ */ new Set();
234
+ }
232
235
  if (chunk.id) {
233
236
  state.messageId = chunk.id;
234
237
  }
@@ -284,6 +287,15 @@ function processModelChunk(chunk, state, controller) {
284
287
  id: (_c = state.textMessageId) != null ? _c : state.messageId
285
288
  });
286
289
  }
290
+ const citations = extractCitationsFromContentBlocks(chunk);
291
+ if (citations.length > 0) {
292
+ emitSourceChunks(
293
+ citations,
294
+ state.messageId,
295
+ state.emittedSourceIds,
296
+ controller
297
+ );
298
+ }
287
299
  }
288
300
  function isPlainMessageObject(msg) {
289
301
  if (msg == null || typeof msg !== "object") return false;
@@ -446,6 +458,85 @@ function extractReasoningFromValuesMessage(msg) {
446
458
  }
447
459
  return void 0;
448
460
  }
461
+ function isCitationContentBlock(obj) {
462
+ return obj != null && typeof obj === "object" && "type" in obj && obj.type === "citation";
463
+ }
464
+ function extractCitationsFromContentBlocks(msg) {
465
+ if (msg == null || typeof msg !== "object") return [];
466
+ const msgObj = msg;
467
+ const kwargs = msgObj.kwargs && typeof msgObj.kwargs === "object" ? msgObj.kwargs : msgObj;
468
+ const contentBlocks = kwargs.contentBlocks;
469
+ const content = kwargs.content;
470
+ const blockSources = Array.isArray(contentBlocks) ? contentBlocks : Array.isArray(content) ? content : [];
471
+ const citations = [];
472
+ for (const block of blockSources) {
473
+ if (block == null || typeof block !== "object") continue;
474
+ const annotations = block.annotations;
475
+ if (!Array.isArray(annotations)) continue;
476
+ for (const annotation of annotations) {
477
+ if (!isCitationContentBlock(annotation)) continue;
478
+ citations.push({
479
+ url: annotation.url,
480
+ title: annotation.title,
481
+ source: annotation.source,
482
+ citedText: annotation.citedText,
483
+ startIndex: annotation.startIndex,
484
+ endIndex: annotation.endIndex
485
+ });
486
+ }
487
+ }
488
+ return citations;
489
+ }
490
+ function buildSourceProviderMetadata(citation) {
491
+ const langchain = {};
492
+ if (typeof citation.citedText === "string") {
493
+ langchain.citedText = citation.citedText;
494
+ }
495
+ if (typeof citation.startIndex === "number") {
496
+ langchain.startIndex = citation.startIndex;
497
+ }
498
+ if (typeof citation.endIndex === "number") {
499
+ langchain.endIndex = citation.endIndex;
500
+ }
501
+ if (typeof citation.source === "string") {
502
+ langchain.source = citation.source;
503
+ }
504
+ if (Object.keys(langchain).length === 0) {
505
+ return void 0;
506
+ }
507
+ return { langchain };
508
+ }
509
+ function emitSourceChunks(citations, messageId, emittedSourceIds, controller) {
510
+ var _a, _b, _c, _d;
511
+ for (const citation of citations) {
512
+ if (citation.url) {
513
+ if (emittedSourceIds.has(citation.url)) continue;
514
+ emittedSourceIds.add(citation.url);
515
+ const providerMetadata2 = buildSourceProviderMetadata(citation);
516
+ controller.enqueue({
517
+ type: "source-url",
518
+ sourceId: citation.url,
519
+ url: citation.url,
520
+ ...citation.title ? { title: citation.title } : {},
521
+ ...providerMetadata2 ? { providerMetadata: providerMetadata2 } : {}
522
+ });
523
+ continue;
524
+ }
525
+ const title = (_a = citation.title) != null ? _a : citation.source;
526
+ if (!title) continue;
527
+ const sourceId = `${messageId}:${title}:${(_b = citation.citedText) != null ? _b : ""}:${(_c = citation.startIndex) != null ? _c : ""}:${(_d = citation.endIndex) != null ? _d : ""}`;
528
+ if (emittedSourceIds.has(sourceId)) continue;
529
+ emittedSourceIds.add(sourceId);
530
+ const providerMetadata = buildSourceProviderMetadata(citation);
531
+ controller.enqueue({
532
+ type: "source-document",
533
+ sourceId,
534
+ mediaType: "text/plain",
535
+ title,
536
+ ...providerMetadata ? { providerMetadata } : {}
537
+ });
538
+ }
539
+ }
449
540
  function isImageGenerationOutput(obj) {
450
541
  return obj != null && typeof obj === "object" && "type" in obj && obj.type === "image_generation_call";
451
542
  }
@@ -636,6 +727,15 @@ function processLangGraphEvent(event, state, controller) {
636
727
  id: msgId
637
728
  });
638
729
  }
730
+ const citations = extractCitationsFromContentBlocks(msg);
731
+ if (citations.length > 0) {
732
+ emitSourceChunks(
733
+ citations,
734
+ msgId,
735
+ state.emittedSourceIds,
736
+ controller
737
+ );
738
+ }
639
739
  } else if (isToolMessageType(msg)) {
640
740
  const msgObj = msg;
641
741
  const dataSource = msgObj.type === "constructor" && msgObj.kwargs && typeof msgObj.kwargs === "object" ? msgObj.kwargs : msgObj;
@@ -783,6 +883,15 @@ function processLangGraphEvent(event, state, controller) {
783
883
  emittedReasoningIds.add(reasoningId);
784
884
  }
785
885
  }
886
+ const valuesCitations = extractCitationsFromContentBlocks(msg);
887
+ if (valuesCitations.length > 0) {
888
+ emitSourceChunks(
889
+ valuesCitations,
890
+ msgId,
891
+ state.emittedSourceIds,
892
+ controller
893
+ );
894
+ }
786
895
  }
787
896
  }
788
897
  }
@@ -932,6 +1041,15 @@ function processStreamEventsEvent(event, state, controller) {
932
1041
  id: (_c = state.textMessageId) != null ? _c : state.messageId
933
1042
  });
934
1043
  }
1044
+ const citations = extractCitationsFromContentBlocks(chunk);
1045
+ if (citations.length > 0) {
1046
+ emitSourceChunks(
1047
+ citations,
1048
+ state.messageId,
1049
+ state.emittedSourceIds,
1050
+ controller
1051
+ );
1052
+ }
935
1053
  }
936
1054
  break;
937
1055
  }
@@ -979,7 +1097,8 @@ function toUIMessageStream(stream, callbacks) {
979
1097
  /** Track the ID used for text-start to ensure text-end uses the same ID */
980
1098
  textMessageId: null,
981
1099
  /** Track the ID used for reasoning-start to ensure reasoning-end uses the same ID */
982
- reasoningMessageId: null
1100
+ reasoningMessageId: null,
1101
+ emittedSourceIds: /* @__PURE__ */ new Set()
983
1102
  };
984
1103
  const langGraphState = {
985
1104
  messageSeen: /* @__PURE__ */ new Map(),
@@ -990,7 +1109,8 @@ function toUIMessageStream(stream, callbacks) {
990
1109
  messageReasoningIds: /* @__PURE__ */ new Map(),
991
1110
  toolCallInfoByIndex: /* @__PURE__ */ new Map(),
992
1111
  currentStep: null,
993
- emittedToolCallsByKey: /* @__PURE__ */ new Map()
1112
+ emittedToolCallsByKey: /* @__PURE__ */ new Map(),
1113
+ emittedSourceIds: /* @__PURE__ */ new Set()
994
1114
  };
995
1115
  let streamType = null;
996
1116
  const getAsyncIterator = () => {