@ai-sdk/langchain 3.0.66 → 3.0.68

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,18 @@
1
1
  # @ai-sdk/langchain
2
2
 
3
+ ## 3.0.68
4
+
5
+ ### Patch Changes
6
+
7
+ - ai@7.0.68
8
+
9
+ ## 3.0.67
10
+
11
+ ### Patch Changes
12
+
13
+ - 404a9d9: Preserve tool input lifecycles when LangGraph steps reuse a provider tool call ID.
14
+ - ai@7.0.67
15
+
3
16
  ## 3.0.66
4
17
 
5
18
  ### Patch Changes
package/dist/index.js CHANGED
@@ -636,6 +636,51 @@ function getOrCreateToolCallInfoByIndex(toolCallInfoByIndex, msgId) {
636
636
  function getLangGraphNamespaceKey(namespace) {
637
637
  return JSON.stringify(namespace != null ? namespace : []);
638
638
  }
639
+ function getOrCreateNamespaceSet(setsByNamespace, namespace) {
640
+ let values = setsByNamespace.get(namespace);
641
+ if (!values) {
642
+ values = /* @__PURE__ */ new Set();
643
+ setsByNamespace.set(namespace, values);
644
+ }
645
+ return values;
646
+ }
647
+ function hasEmittedToolCallInCurrentStep(state, toolCallId, namespace) {
648
+ var _a;
649
+ return !state.currentStepsByNamespace.has(namespace) ? state.emittedToolCalls.has(toolCallId) : ((_a = state.emittedToolCallsInCurrentStepByNamespace.get(namespace)) == null ? void 0 : _a.has(toolCallId)) === true;
650
+ }
651
+ function markToolCallEmitted(state, toolCallId, namespace) {
652
+ state.emittedToolCalls.add(toolCallId);
653
+ if (state.currentStepsByNamespace.has(namespace)) {
654
+ getOrCreateNamespaceSet(
655
+ state.emittedToolCallsInCurrentStepByNamespace,
656
+ namespace
657
+ ).add(toolCallId);
658
+ }
659
+ }
660
+ function hasEmittedToolInputInCurrentStep(state, toolCallId, namespace) {
661
+ var _a;
662
+ return !state.currentStepsByNamespace.has(namespace) ? state.emittedToolInputs.has(toolCallId) : ((_a = state.emittedToolInputsInCurrentStepByNamespace.get(namespace)) == null ? void 0 : _a.has(toolCallId)) === true;
663
+ }
664
+ function markToolInputEmitted(state, toolCallId, namespace) {
665
+ state.emittedToolInputs.add(toolCallId);
666
+ if (state.currentStepsByNamespace.has(namespace)) {
667
+ getOrCreateNamespaceSet(
668
+ state.emittedToolInputsInCurrentStepByNamespace,
669
+ namespace
670
+ ).add(toolCallId);
671
+ }
672
+ }
673
+ function findMessageCurrentStepNamespace(state, messageId) {
674
+ for (const [
675
+ namespace,
676
+ messageIds
677
+ ] of state.messageIdsInCurrentStepByNamespace) {
678
+ if (messageIds.has(messageId)) {
679
+ return namespace;
680
+ }
681
+ }
682
+ return void 0;
683
+ }
639
684
  function closeStepNamespaceMessages(state, stepNamespace, controller) {
640
685
  let hasConcurrentMessageParts = false;
641
686
  for (const [id, seen] of state.messageSeen) {
@@ -662,7 +707,7 @@ function closeStepNamespaceMessages(state, stepNamespace, controller) {
662
707
  return hasConcurrentMessageParts;
663
708
  }
664
709
  function processLangGraphEvent(event, state, controller) {
665
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
710
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
666
711
  const {
667
712
  messageSeen,
668
713
  messageConcat,
@@ -671,11 +716,11 @@ function processLangGraphEvent(event, state, controller) {
671
716
  emittedReasoningIds,
672
717
  messageReasoningIds,
673
718
  toolCallInfoByIndex,
674
- emittedToolCallsByKey,
675
- emittedToolInputs
719
+ emittedToolCallsByKey
676
720
  } = state;
677
721
  const [rawNamespace, type, data] = parseLangGraphEvent(event);
678
722
  const namespace = Array.isArray(rawNamespace) && rawNamespace.every((segment) => typeof segment === "string") ? rawNamespace : void 0;
723
+ const eventNamespace = getLangGraphNamespaceKey(namespace);
679
724
  controller = createLangGraphNamespaceController(controller, state, namespace);
680
725
  switch (type) {
681
726
  case "custom": {
@@ -707,25 +752,55 @@ function processLangGraphEvent(event, state, controller) {
707
752
  state.messageNamespaces.set(msgId, namespace);
708
753
  }
709
754
  const langgraphStep = typeof (metadata == null ? void 0 : metadata.langgraph_step) === "number" ? metadata.langgraph_step : null;
710
- const eventNamespace = getLangGraphNamespaceKey(namespace);
711
- if (langgraphStep !== null && state.stepNamespace === null) {
712
- state.stepNamespace = eventNamespace;
713
- }
714
- if (langgraphStep !== null && eventNamespace === state.stepNamespace && langgraphStep !== state.currentStep) {
715
- if (state.currentStep !== null) {
755
+ if (langgraphStep !== null) {
756
+ const currentStep = (_a = state.currentStepsByNamespace.get(eventNamespace)) != null ? _a : null;
757
+ if (currentStep === null) {
758
+ if (state.currentStepsByNamespace.size === 0) {
759
+ controller.enqueue({ type: "start-step" });
760
+ }
761
+ state.currentStepsByNamespace.set(eventNamespace, langgraphStep);
762
+ state.messageIdsInCurrentStepByNamespace.set(
763
+ eventNamespace,
764
+ /* @__PURE__ */ new Set()
765
+ );
766
+ state.emittedToolCallsInCurrentStepByNamespace.set(
767
+ eventNamespace,
768
+ /* @__PURE__ */ new Set()
769
+ );
770
+ state.emittedToolInputsInCurrentStepByNamespace.set(
771
+ eventNamespace,
772
+ /* @__PURE__ */ new Set()
773
+ );
774
+ } else if (langgraphStep !== currentStep) {
716
775
  const hasConcurrentMessageParts = closeStepNamespaceMessages(
717
776
  state,
718
- state.stepNamespace,
777
+ eventNamespace,
719
778
  controller
720
779
  );
721
780
  if (!hasConcurrentMessageParts) {
722
781
  controller.enqueue({ type: "finish-step" });
723
- controller.enqueue({ type: "start-step" });
724
782
  }
725
- } else {
726
783
  controller.enqueue({ type: "start-step" });
784
+ state.currentStepsByNamespace.set(eventNamespace, langgraphStep);
785
+ state.messageIdsInCurrentStepByNamespace.set(
786
+ eventNamespace,
787
+ /* @__PURE__ */ new Set()
788
+ );
789
+ state.emittedToolCallsInCurrentStepByNamespace.set(
790
+ eventNamespace,
791
+ /* @__PURE__ */ new Set()
792
+ );
793
+ state.emittedToolInputsInCurrentStepByNamespace.set(
794
+ eventNamespace,
795
+ /* @__PURE__ */ new Set()
796
+ );
727
797
  }
728
- state.currentStep = langgraphStep;
798
+ }
799
+ if (state.currentStepsByNamespace.has(eventNamespace)) {
800
+ getOrCreateNamespaceSet(
801
+ state.messageIdsInCurrentStepByNamespace,
802
+ eventNamespace
803
+ ).add(msgId);
729
804
  }
730
805
  if (isAIMessageChunkInstance(msg)) {
731
806
  const existingMessage = messageConcat.get(msgId);
@@ -758,29 +833,33 @@ function processLangGraphEvent(event, state, controller) {
758
833
  const toolCallChunks = dataSource.tool_call_chunks;
759
834
  if (toolCallChunks == null ? void 0 : toolCallChunks.length) {
760
835
  for (const toolCallChunk of toolCallChunks) {
761
- const toolCallIndex = (_a = toolCallChunk.index) != null ? _a : 0;
836
+ const toolCallIndex = (_b = toolCallChunk.index) != null ? _b : 0;
762
837
  if (toolCallChunk.id) {
763
838
  getOrCreateToolCallInfoByIndex(toolCallInfoByIndex, msgId).set(
764
839
  toolCallIndex,
765
840
  {
766
841
  id: toolCallChunk.id,
767
- name: toolCallChunk.name || ((_c = (_b = concatChunk == null ? void 0 : concatChunk.tool_call_chunks) == null ? void 0 : _b[toolCallIndex]) == null ? void 0 : _c.name) || "unknown"
842
+ name: toolCallChunk.name || ((_d = (_c = concatChunk == null ? void 0 : concatChunk.tool_call_chunks) == null ? void 0 : _c[toolCallIndex]) == null ? void 0 : _d.name) || "unknown"
768
843
  }
769
844
  );
770
845
  }
771
- const storedToolCallInfo = (_d = toolCallInfoByIndex.get(msgId)) == null ? void 0 : _d.get(toolCallIndex);
772
- const toolCallId = toolCallChunk.id || (storedToolCallInfo == null ? void 0 : storedToolCallInfo.id) || ((_f = (_e = concatChunk == null ? void 0 : concatChunk.tool_call_chunks) == null ? void 0 : _e[toolCallIndex]) == null ? void 0 : _f.id);
846
+ const storedToolCallInfo = (_e = toolCallInfoByIndex.get(msgId)) == null ? void 0 : _e.get(toolCallIndex);
847
+ const toolCallId = toolCallChunk.id || (storedToolCallInfo == null ? void 0 : storedToolCallInfo.id) || ((_g = (_f = concatChunk == null ? void 0 : concatChunk.tool_call_chunks) == null ? void 0 : _f[toolCallIndex]) == null ? void 0 : _g.id);
773
848
  if (!toolCallId) {
774
849
  continue;
775
850
  }
776
- const toolName = toolCallChunk.name || (storedToolCallInfo == null ? void 0 : storedToolCallInfo.name) || ((_h = (_g = concatChunk == null ? void 0 : concatChunk.tool_call_chunks) == null ? void 0 : _g[toolCallIndex]) == null ? void 0 : _h.name) || "unknown";
851
+ const toolName = toolCallChunk.name || (storedToolCallInfo == null ? void 0 : storedToolCallInfo.name) || ((_i = (_h = concatChunk == null ? void 0 : concatChunk.tool_call_chunks) == null ? void 0 : _h[toolCallIndex]) == null ? void 0 : _i.name) || "unknown";
777
852
  const seen = messageSeen.get(msgId);
778
- if (!((_i = seen == null ? void 0 : seen.tool) == null ? void 0 : _i.has(toolCallId))) {
853
+ if (!((_j = seen == null ? void 0 : seen.tool) == null ? void 0 : _j.has(toolCallId))) {
779
854
  const updatedSeen = getOrCreateMessageSeen(messageSeen, msgId);
780
- (_j = updatedSeen.tool) != null ? _j : updatedSeen.tool = /* @__PURE__ */ new Set();
855
+ (_k = updatedSeen.tool) != null ? _k : updatedSeen.tool = /* @__PURE__ */ new Set();
781
856
  updatedSeen.tool.add(toolCallId);
782
- if (!emittedToolCalls.has(toolCallId)) {
783
- emittedToolCalls.add(toolCallId);
857
+ if (!hasEmittedToolCallInCurrentStep(
858
+ state,
859
+ toolCallId,
860
+ eventNamespace
861
+ )) {
862
+ markToolCallEmitted(state, toolCallId, eventNamespace);
784
863
  controller.enqueue({
785
864
  type: "tool-input-start",
786
865
  toolCallId,
@@ -808,7 +887,7 @@ function processLangGraphEvent(event, state, controller) {
808
887
  }
809
888
  const reasoning = extractReasoningFromContentBlocks(msg);
810
889
  if (reasoning) {
811
- const reasoningId = (_l = (_k = messageReasoningIds.get(msgId)) != null ? _k : chunkReasoningId) != null ? _l : msgId;
890
+ const reasoningId = (_m = (_l = messageReasoningIds.get(msgId)) != null ? _l : chunkReasoningId) != null ? _m : msgId;
812
891
  const seen = messageSeen.get(msgId);
813
892
  if (!(seen == null ? void 0 : seen.reasoning)) {
814
893
  controller.enqueue({ type: "reasoning-start", id: msgId });
@@ -878,9 +957,14 @@ function processLangGraphEvent(event, state, controller) {
878
957
  const toolCallId = typeof payload.toolCallId === "string" ? payload.toolCallId : void 0;
879
958
  const toolName = typeof payload.name === "string" ? payload.name : "unknown";
880
959
  if (!toolCallId) return;
881
- const ensureToolInputLifecycle = () => {
882
- if (!emittedToolCalls.has(toolCallId)) {
883
- emittedToolCalls.add(toolCallId);
960
+ const ensureToolInputLifecycle = ({
961
+ allowPreviousStep
962
+ }) => {
963
+ if (!hasEmittedToolCallInCurrentStep(state, toolCallId, eventNamespace)) {
964
+ if (allowPreviousStep && emittedToolCalls.has(toolCallId)) {
965
+ return;
966
+ }
967
+ markToolCallEmitted(state, toolCallId, eventNamespace);
884
968
  controller.enqueue({
885
969
  type: "tool-input-start",
886
970
  toolCallId,
@@ -888,8 +972,8 @@ function processLangGraphEvent(event, state, controller) {
888
972
  dynamic: true
889
973
  });
890
974
  }
891
- if (!emittedToolInputs.has(toolCallId)) {
892
- emittedToolInputs.add(toolCallId);
975
+ if (!hasEmittedToolInputInCurrentStep(state, toolCallId, eventNamespace)) {
976
+ markToolInputEmitted(state, toolCallId, eventNamespace);
893
977
  controller.enqueue({
894
978
  type: "tool-input-available",
895
979
  toolCallId,
@@ -903,11 +987,11 @@ function processLangGraphEvent(event, state, controller) {
903
987
  case "on_tool_start": {
904
988
  const toolCallKey = `${toolName}:${JSON.stringify(payload.input)}`;
905
989
  emittedToolCallsByKey.set(toolCallKey, toolCallId);
906
- ensureToolInputLifecycle();
990
+ ensureToolInputLifecycle({ allowPreviousStep: false });
907
991
  break;
908
992
  }
909
993
  case "on_tool_event": {
910
- ensureToolInputLifecycle();
994
+ ensureToolInputLifecycle({ allowPreviousStep: true });
911
995
  controller.enqueue({
912
996
  type: "tool-output-available",
913
997
  toolCallId,
@@ -917,7 +1001,7 @@ function processLangGraphEvent(event, state, controller) {
917
1001
  break;
918
1002
  }
919
1003
  case "on_tool_end": {
920
- ensureToolInputLifecycle();
1004
+ ensureToolInputLifecycle({ allowPreviousStep: true });
921
1005
  controller.enqueue({
922
1006
  type: "tool-output-available",
923
1007
  toolCallId,
@@ -926,7 +1010,7 @@ function processLangGraphEvent(event, state, controller) {
926
1010
  break;
927
1011
  }
928
1012
  case "on_tool_error": {
929
- ensureToolInputLifecycle();
1013
+ ensureToolInputLifecycle({ allowPreviousStep: true });
930
1014
  controller.enqueue({
931
1015
  type: "tool-output-error",
932
1016
  toolCallId,
@@ -939,19 +1023,26 @@ function processLangGraphEvent(event, state, controller) {
939
1023
  }
940
1024
  case "values": {
941
1025
  for (const [id, seen] of messageSeen) {
1026
+ const messageNamespace = getLangGraphNamespaceKey(
1027
+ state.messageNamespaces.get(id)
1028
+ );
942
1029
  if (seen.text) controller.enqueue({ type: "text-end", id });
943
1030
  if (seen.tool) {
944
1031
  for (const toolCallId of seen.tool) {
945
1032
  const concatMsg = messageConcat.get(id);
946
- const toolCall = (_m = concatMsg == null ? void 0 : concatMsg.tool_calls) == null ? void 0 : _m.find(
1033
+ const toolCall = (_n = concatMsg == null ? void 0 : concatMsg.tool_calls) == null ? void 0 : _n.find(
947
1034
  (call) => call.id === toolCallId
948
1035
  );
949
1036
  if (toolCall) {
950
- emittedToolCalls.add(toolCallId);
1037
+ markToolCallEmitted(state, toolCallId, messageNamespace);
951
1038
  const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;
952
1039
  emittedToolCallsByKey.set(toolCallKey, toolCallId);
953
- if (!emittedToolInputs.has(toolCallId)) {
954
- emittedToolInputs.add(toolCallId);
1040
+ if (!hasEmittedToolInputInCurrentStep(
1041
+ state,
1042
+ toolCallId,
1043
+ messageNamespace
1044
+ )) {
1045
+ markToolInputEmitted(state, toolCallId, messageNamespace);
955
1046
  controller.enqueue({
956
1047
  type: "tool-input-available",
957
1048
  toolCallId,
@@ -1028,8 +1119,18 @@ function processLangGraphEvent(event, state, controller) {
1028
1119
  }
1029
1120
  if (toolCalls && toolCalls.length > 0) {
1030
1121
  for (const toolCall of toolCalls) {
1031
- if (toolCall.id && !emittedToolCalls.has(toolCall.id) && !completedToolCallIds.has(toolCall.id)) {
1032
- emittedToolCalls.add(toolCall.id);
1122
+ const messageNamespace = findMessageCurrentStepNamespace(
1123
+ state,
1124
+ msgId
1125
+ );
1126
+ const lifecycleNamespace = messageNamespace != null ? messageNamespace : eventNamespace;
1127
+ const wasObservedInCurrentStep = messageNamespace !== void 0;
1128
+ if (toolCall.id && !hasEmittedToolCallInCurrentStep(
1129
+ state,
1130
+ toolCall.id,
1131
+ lifecycleNamespace
1132
+ ) && (wasObservedInCurrentStep || !emittedToolCalls.has(toolCall.id) && !completedToolCallIds.has(toolCall.id))) {
1133
+ markToolCallEmitted(state, toolCall.id, lifecycleNamespace);
1033
1134
  const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;
1034
1135
  emittedToolCallsByKey.set(toolCallKey, toolCall.id);
1035
1136
  controller.enqueue({
@@ -1038,7 +1139,7 @@ function processLangGraphEvent(event, state, controller) {
1038
1139
  toolName: toolCall.name,
1039
1140
  dynamic: true
1040
1141
  });
1041
- emittedToolInputs.add(toolCall.id);
1142
+ markToolInputEmitted(state, toolCall.id, lifecycleNamespace);
1042
1143
  controller.enqueue({
1043
1144
  type: "tool-input-available",
1044
1145
  toolCallId: toolCall.id,
@@ -1095,7 +1196,7 @@ function processLangGraphEvent(event, state, controller) {
1095
1196
  const toolCallKey = `${toolName}:${JSON.stringify(input)}`;
1096
1197
  const toolCallId = emittedToolCallsByKey.get(toolCallKey) || actionRequest.id || `hitl-${toolName}-${Date.now()}`;
1097
1198
  if (!emittedToolCalls.has(toolCallId)) {
1098
- emittedToolCalls.add(toolCallId);
1199
+ markToolCallEmitted(state, toolCallId, eventNamespace);
1099
1200
  emittedToolCallsByKey.set(toolCallKey, toolCallId);
1100
1201
  controller.enqueue({
1101
1202
  type: "tool-input-start",
@@ -1103,7 +1204,7 @@ function processLangGraphEvent(event, state, controller) {
1103
1204
  toolName,
1104
1205
  dynamic: true
1105
1206
  });
1106
- emittedToolInputs.add(toolCallId);
1207
+ markToolInputEmitted(state, toolCallId, eventNamespace);
1107
1208
  controller.enqueue({
1108
1209
  type: "tool-input-available",
1109
1210
  toolCallId,
@@ -1308,14 +1409,16 @@ function toUIMessageStream(stream, options) {
1308
1409
  messageSeen: /* @__PURE__ */ new Map(),
1309
1410
  messageNamespaces: /* @__PURE__ */ new Map(),
1310
1411
  messageConcat: /* @__PURE__ */ new Map(),
1412
+ messageIdsInCurrentStepByNamespace: /* @__PURE__ */ new Map(),
1311
1413
  emittedToolCalls: /* @__PURE__ */ new Set(),
1414
+ emittedToolCallsInCurrentStepByNamespace: /* @__PURE__ */ new Map(),
1312
1415
  emittedToolInputs: /* @__PURE__ */ new Set(),
1416
+ emittedToolInputsInCurrentStepByNamespace: /* @__PURE__ */ new Map(),
1313
1417
  emittedImages: /* @__PURE__ */ new Set(),
1314
1418
  emittedReasoningIds: /* @__PURE__ */ new Set(),
1315
1419
  messageReasoningIds: /* @__PURE__ */ new Map(),
1316
1420
  toolCallInfoByIndex: /* @__PURE__ */ new Map(),
1317
- currentStep: null,
1318
- stepNamespace: null,
1421
+ currentStepsByNamespace: /* @__PURE__ */ new Map(),
1319
1422
  emittedToolCallsByKey: /* @__PURE__ */ new Map(),
1320
1423
  emittedSourceIds: /* @__PURE__ */ new Set()
1321
1424
  };
@@ -1435,7 +1538,7 @@ function toUIMessageStream(stream, options) {
1435
1538
  });
1436
1539
  }
1437
1540
  }
1438
- if (langGraphState.currentStep !== null) {
1541
+ if (langGraphState.currentStepsByNamespace.size > 0) {
1439
1542
  controller.enqueue({ type: "finish-step" });
1440
1543
  }
1441
1544
  if (sendFinish) {