@ai-sdk/langchain 2.0.213 → 2.0.215
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.js +122 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +122 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/adapter.ts +15 -0
- package/src/types.ts +14 -0
- package/src/utils.ts +191 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @ai-sdk/langchain
|
|
2
2
|
|
|
3
|
+
## 2.0.215
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 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`.
|
|
8
|
+
|
|
9
|
+
## 2.0.214
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [779f5cd]
|
|
14
|
+
- ai@6.0.207
|
|
15
|
+
|
|
3
16
|
## 2.0.213
|
|
4
17
|
|
|
5
18
|
### 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 = () => {
|