@langchain/langgraph 0.2.19 → 0.2.20-rc.0
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/dist/pregel/index.cjs +119 -103
- package/dist/pregel/index.js +120 -101
- package/dist/pregel/loop.cjs +54 -14
- package/dist/pregel/loop.d.ts +14 -6
- package/dist/pregel/loop.js +52 -12
- package/dist/pregel/retry.cjs +1 -1
- package/dist/pregel/retry.js +1 -1
- package/package.json +2 -4
package/dist/pregel/index.cjs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.Pregel = exports.Channel = void 0;
|
|
7
4
|
/* eslint-disable no-param-reassign */
|
|
8
5
|
const runnables_1 = require("@langchain/core/runnables");
|
|
9
6
|
const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
|
|
10
|
-
const double_ended_queue_1 = __importDefault(require("double-ended-queue"));
|
|
11
7
|
const base_js_1 = require("../channels/base.cjs");
|
|
12
8
|
const read_js_1 = require("./read.cjs");
|
|
13
9
|
const validate_js_1 = require("./validate.cjs");
|
|
@@ -711,15 +707,125 @@ class Pregel extends runnables_1.Runnable {
|
|
|
711
707
|
// assign defaults
|
|
712
708
|
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer, store,] = this._defaults(inputConfig);
|
|
713
709
|
const { channelSpecs, managed } = await this.prepareSpecs(config);
|
|
710
|
+
const stream = new loop_js_1.IterableReadableWritableStream({
|
|
711
|
+
modes: new Set(streamMode),
|
|
712
|
+
});
|
|
714
713
|
let loop;
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
714
|
+
let loopError;
|
|
715
|
+
const runLoop = async () => {
|
|
716
|
+
try {
|
|
717
|
+
loop = await loop_js_1.PregelLoop.initialize({
|
|
718
|
+
input,
|
|
719
|
+
config,
|
|
720
|
+
checkpointer,
|
|
721
|
+
nodes: this.nodes,
|
|
722
|
+
channelSpecs,
|
|
723
|
+
managed,
|
|
724
|
+
outputKeys,
|
|
725
|
+
streamKeys: this.streamChannelsAsIs,
|
|
726
|
+
store,
|
|
727
|
+
stream,
|
|
728
|
+
});
|
|
729
|
+
if (options?.subgraphs) {
|
|
730
|
+
loop.config.configurable = {
|
|
731
|
+
...loop.config.configurable,
|
|
732
|
+
[constants_js_1.CONFIG_KEY_STREAM]: loop.stream,
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
while (await loop.tick({
|
|
736
|
+
inputKeys: this.inputChannels,
|
|
737
|
+
interruptAfter,
|
|
738
|
+
interruptBefore,
|
|
739
|
+
manager: runManager,
|
|
740
|
+
})) {
|
|
741
|
+
if (debug) {
|
|
742
|
+
(0, debug_js_1.printStepCheckpoint)(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
743
|
+
}
|
|
744
|
+
if (debug) {
|
|
745
|
+
(0, debug_js_1.printStepTasks)(loop.step, Object.values(loop.tasks));
|
|
746
|
+
}
|
|
747
|
+
// execute tasks, and wait for one to fail or all to finish.
|
|
748
|
+
// each task is independent from all other concurrent tasks
|
|
749
|
+
// yield updates/debug output as each task finishes
|
|
750
|
+
const taskStream = (0, retry_js_1.executeTasksWithRetry)(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
751
|
+
stepTimeout: this.stepTimeout,
|
|
752
|
+
signal: config.signal,
|
|
753
|
+
retryPolicy: this.retryPolicy,
|
|
754
|
+
});
|
|
755
|
+
// Timeouts will be thrown
|
|
756
|
+
for await (const { task, error } of taskStream) {
|
|
757
|
+
if (error !== undefined) {
|
|
758
|
+
if ((0, errors_js_1.isGraphInterrupt)(error)) {
|
|
759
|
+
if (loop.isNested) {
|
|
760
|
+
throw error;
|
|
761
|
+
}
|
|
762
|
+
if (error.interrupts.length) {
|
|
763
|
+
loop.putWrites(task.id, error.interrupts.map((interrupt) => [constants_js_1.INTERRUPT, interrupt]));
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
loop.putWrites(task.id, [
|
|
768
|
+
[constants_js_1.ERROR, { message: error.message, name: error.name }],
|
|
769
|
+
]);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
loop.putWrites(task.id, task.writes);
|
|
774
|
+
}
|
|
775
|
+
if (error !== undefined && !(0, errors_js_1.isGraphInterrupt)(error)) {
|
|
776
|
+
throw error;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (debug) {
|
|
780
|
+
(0, debug_js_1.printStepWrites)(loop.step, Object.values(loop.tasks)
|
|
781
|
+
.map((task) => task.writes)
|
|
782
|
+
.flat(), this.streamChannelsList);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
if (loop.status === "out_of_steps") {
|
|
786
|
+
throw new errors_js_1.GraphRecursionError([
|
|
787
|
+
`Recursion limit of ${config.recursionLimit} reached`,
|
|
788
|
+
"without hitting a stop condition. You can increase the",
|
|
789
|
+
`limit by setting the "recursionLimit" config key.`,
|
|
790
|
+
].join(" "), {
|
|
791
|
+
lc_error_code: "GRAPH_RECURSION_LIMIT",
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
catch (e) {
|
|
796
|
+
loopError = e;
|
|
797
|
+
}
|
|
798
|
+
finally {
|
|
799
|
+
try {
|
|
800
|
+
// Call `.stop()` again incase it was not called in the loop, e.g due to an error.
|
|
801
|
+
if (loop) {
|
|
802
|
+
await loop.store?.stop();
|
|
803
|
+
}
|
|
804
|
+
await Promise.all([
|
|
805
|
+
...(loop?.checkpointerPromises ?? []),
|
|
806
|
+
...Array.from(managed.values()).map((mv) => mv.promises()),
|
|
807
|
+
]);
|
|
808
|
+
}
|
|
809
|
+
catch (e) {
|
|
810
|
+
loopError = loopError ?? e;
|
|
811
|
+
}
|
|
812
|
+
if (loopError) {
|
|
813
|
+
// Will throw an error outside of this method
|
|
814
|
+
stream.error(loopError);
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
// Will end the iterator outside of this method
|
|
818
|
+
stream.close();
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
const runLoopPromise = runLoop();
|
|
823
|
+
try {
|
|
824
|
+
for await (const chunk of stream) {
|
|
825
|
+
if (chunk === undefined) {
|
|
720
826
|
throw new Error("Data structure error.");
|
|
721
827
|
}
|
|
722
|
-
const [namespace, mode, payload] =
|
|
828
|
+
const [namespace, mode, payload] = chunk;
|
|
723
829
|
if (streamMode.includes(mode)) {
|
|
724
830
|
if (streamSubgraphs && streamMode.length > 1) {
|
|
725
831
|
yield [namespace, mode, payload];
|
|
@@ -736,104 +842,14 @@ class Pregel extends runnables_1.Runnable {
|
|
|
736
842
|
}
|
|
737
843
|
}
|
|
738
844
|
}
|
|
739
|
-
try {
|
|
740
|
-
loop = await loop_js_1.PregelLoop.initialize({
|
|
741
|
-
input,
|
|
742
|
-
config,
|
|
743
|
-
checkpointer,
|
|
744
|
-
nodes: this.nodes,
|
|
745
|
-
channelSpecs,
|
|
746
|
-
managed,
|
|
747
|
-
outputKeys,
|
|
748
|
-
streamKeys: this.streamChannelsAsIs,
|
|
749
|
-
store,
|
|
750
|
-
stream: new loop_js_1.StreamProtocol((chunk) => stream.push(chunk), new Set(streamMode)),
|
|
751
|
-
});
|
|
752
|
-
if (options?.subgraphs) {
|
|
753
|
-
loop.config.configurable = {
|
|
754
|
-
...loop.config.configurable,
|
|
755
|
-
[constants_js_1.CONFIG_KEY_STREAM]: loop.stream,
|
|
756
|
-
};
|
|
757
|
-
}
|
|
758
|
-
while (await loop.tick({
|
|
759
|
-
inputKeys: this.inputChannels,
|
|
760
|
-
interruptAfter,
|
|
761
|
-
interruptBefore,
|
|
762
|
-
manager: runManager,
|
|
763
|
-
})) {
|
|
764
|
-
if (debug) {
|
|
765
|
-
(0, debug_js_1.printStepCheckpoint)(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
766
|
-
}
|
|
767
|
-
yield* emitCurrentLoopOutputs();
|
|
768
|
-
if (debug) {
|
|
769
|
-
(0, debug_js_1.printStepTasks)(loop.step, Object.values(loop.tasks));
|
|
770
|
-
}
|
|
771
|
-
// execute tasks, and wait for one to fail or all to finish.
|
|
772
|
-
// each task is independent from all other concurrent tasks
|
|
773
|
-
// yield updates/debug output as each task finishes
|
|
774
|
-
const taskStream = (0, retry_js_1.executeTasksWithRetry)(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
775
|
-
stepTimeout: this.stepTimeout,
|
|
776
|
-
signal: config.signal,
|
|
777
|
-
retryPolicy: this.retryPolicy,
|
|
778
|
-
});
|
|
779
|
-
// Timeouts will be thrown
|
|
780
|
-
for await (const { task, error } of taskStream) {
|
|
781
|
-
if (error !== undefined) {
|
|
782
|
-
if ((0, errors_js_1.isGraphInterrupt)(error)) {
|
|
783
|
-
if (loop.isNested) {
|
|
784
|
-
throw error;
|
|
785
|
-
}
|
|
786
|
-
if (error.interrupts.length) {
|
|
787
|
-
loop.putWrites(task.id, error.interrupts.map((interrupt) => [constants_js_1.INTERRUPT, interrupt]));
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
791
|
-
loop.putWrites(task.id, [
|
|
792
|
-
[constants_js_1.ERROR, { message: error.message, name: error.name }],
|
|
793
|
-
]);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
loop.putWrites(task.id, task.writes);
|
|
798
|
-
}
|
|
799
|
-
yield* emitCurrentLoopOutputs();
|
|
800
|
-
if (error !== undefined && !(0, errors_js_1.isGraphInterrupt)(error)) {
|
|
801
|
-
throw error;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (debug) {
|
|
805
|
-
(0, debug_js_1.printStepWrites)(loop.step, Object.values(loop.tasks)
|
|
806
|
-
.map((task) => task.writes)
|
|
807
|
-
.flat(), this.streamChannelsList);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
yield* emitCurrentLoopOutputs();
|
|
811
|
-
if (loop.status === "out_of_steps") {
|
|
812
|
-
throw new errors_js_1.GraphRecursionError([
|
|
813
|
-
`Recursion limit of ${config.recursionLimit} reached`,
|
|
814
|
-
"without hitting a stop condition. You can increase the",
|
|
815
|
-
`limit by setting the "recursionLimit" config key.`,
|
|
816
|
-
].join(" "), {
|
|
817
|
-
lc_error_code: "GRAPH_RECURSION_LIMIT",
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
await Promise.all(loop?.checkpointerPromises ?? []);
|
|
821
|
-
await runManager?.handleChainEnd(loop.output);
|
|
822
|
-
}
|
|
823
845
|
catch (e) {
|
|
824
|
-
await runManager?.handleChainError(
|
|
846
|
+
await runManager?.handleChainError(loopError);
|
|
825
847
|
throw e;
|
|
826
848
|
}
|
|
827
849
|
finally {
|
|
828
|
-
|
|
829
|
-
if (loop) {
|
|
830
|
-
await loop.store?.stop();
|
|
831
|
-
}
|
|
832
|
-
await Promise.all([
|
|
833
|
-
...(loop?.checkpointerPromises ?? []),
|
|
834
|
-
...Array.from(managed.values()).map((mv) => mv.promises()),
|
|
835
|
-
]);
|
|
850
|
+
await runLoopPromise;
|
|
836
851
|
}
|
|
852
|
+
await runManager?.handleChainEnd(loop?.output ?? {});
|
|
837
853
|
}
|
|
838
854
|
/**
|
|
839
855
|
* Run the graph with a single input and config.
|
package/dist/pregel/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
2
|
import { Runnable, RunnableSequence, getCallbackManagerForConfig, mergeConfigs, patchConfig, _coerceToRunnable, } from "@langchain/core/runnables";
|
|
3
3
|
import { compareChannelVersions, copyCheckpoint, emptyCheckpoint, uuid5, } from "@langchain/langgraph-checkpoint";
|
|
4
|
-
import Deque from "double-ended-queue";
|
|
5
4
|
import { createCheckpoint, emptyChannels, isBaseChannel, } from "../channels/base.js";
|
|
6
5
|
import { PregelNode } from "./read.js";
|
|
7
6
|
import { validateGraph, validateKeys } from "./validate.js";
|
|
@@ -13,7 +12,7 @@ import { GraphRecursionError, GraphValueError, InvalidUpdateError, isGraphInterr
|
|
|
13
12
|
import { _prepareNextTasks, _localRead, _applyWrites, } from "./algo.js";
|
|
14
13
|
import { _coerceToDict, getNewChannelVersions, patchCheckpointMap, } from "./utils/index.js";
|
|
15
14
|
import { findSubgraphPregel } from "./utils/subgraph.js";
|
|
16
|
-
import { PregelLoop,
|
|
15
|
+
import { PregelLoop, IterableReadableWritableStream } from "./loop.js";
|
|
17
16
|
import { executeTasksWithRetry } from "./retry.js";
|
|
18
17
|
import { ChannelKeyPlaceholder, isConfiguredManagedValue, ManagedValueMapping, NoopManagedValue, } from "../managed/base.js";
|
|
19
18
|
import { gatherIterator, patchConfigurable } from "../utils.js";
|
|
@@ -704,15 +703,125 @@ export class Pregel extends Runnable {
|
|
|
704
703
|
// assign defaults
|
|
705
704
|
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer, store,] = this._defaults(inputConfig);
|
|
706
705
|
const { channelSpecs, managed } = await this.prepareSpecs(config);
|
|
706
|
+
const stream = new IterableReadableWritableStream({
|
|
707
|
+
modes: new Set(streamMode),
|
|
708
|
+
});
|
|
707
709
|
let loop;
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
710
|
+
let loopError;
|
|
711
|
+
const runLoop = async () => {
|
|
712
|
+
try {
|
|
713
|
+
loop = await PregelLoop.initialize({
|
|
714
|
+
input,
|
|
715
|
+
config,
|
|
716
|
+
checkpointer,
|
|
717
|
+
nodes: this.nodes,
|
|
718
|
+
channelSpecs,
|
|
719
|
+
managed,
|
|
720
|
+
outputKeys,
|
|
721
|
+
streamKeys: this.streamChannelsAsIs,
|
|
722
|
+
store,
|
|
723
|
+
stream,
|
|
724
|
+
});
|
|
725
|
+
if (options?.subgraphs) {
|
|
726
|
+
loop.config.configurable = {
|
|
727
|
+
...loop.config.configurable,
|
|
728
|
+
[CONFIG_KEY_STREAM]: loop.stream,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
while (await loop.tick({
|
|
732
|
+
inputKeys: this.inputChannels,
|
|
733
|
+
interruptAfter,
|
|
734
|
+
interruptBefore,
|
|
735
|
+
manager: runManager,
|
|
736
|
+
})) {
|
|
737
|
+
if (debug) {
|
|
738
|
+
printStepCheckpoint(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
739
|
+
}
|
|
740
|
+
if (debug) {
|
|
741
|
+
printStepTasks(loop.step, Object.values(loop.tasks));
|
|
742
|
+
}
|
|
743
|
+
// execute tasks, and wait for one to fail or all to finish.
|
|
744
|
+
// each task is independent from all other concurrent tasks
|
|
745
|
+
// yield updates/debug output as each task finishes
|
|
746
|
+
const taskStream = executeTasksWithRetry(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
747
|
+
stepTimeout: this.stepTimeout,
|
|
748
|
+
signal: config.signal,
|
|
749
|
+
retryPolicy: this.retryPolicy,
|
|
750
|
+
});
|
|
751
|
+
// Timeouts will be thrown
|
|
752
|
+
for await (const { task, error } of taskStream) {
|
|
753
|
+
if (error !== undefined) {
|
|
754
|
+
if (isGraphInterrupt(error)) {
|
|
755
|
+
if (loop.isNested) {
|
|
756
|
+
throw error;
|
|
757
|
+
}
|
|
758
|
+
if (error.interrupts.length) {
|
|
759
|
+
loop.putWrites(task.id, error.interrupts.map((interrupt) => [INTERRUPT, interrupt]));
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
loop.putWrites(task.id, [
|
|
764
|
+
[ERROR, { message: error.message, name: error.name }],
|
|
765
|
+
]);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
loop.putWrites(task.id, task.writes);
|
|
770
|
+
}
|
|
771
|
+
if (error !== undefined && !isGraphInterrupt(error)) {
|
|
772
|
+
throw error;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (debug) {
|
|
776
|
+
printStepWrites(loop.step, Object.values(loop.tasks)
|
|
777
|
+
.map((task) => task.writes)
|
|
778
|
+
.flat(), this.streamChannelsList);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
if (loop.status === "out_of_steps") {
|
|
782
|
+
throw new GraphRecursionError([
|
|
783
|
+
`Recursion limit of ${config.recursionLimit} reached`,
|
|
784
|
+
"without hitting a stop condition. You can increase the",
|
|
785
|
+
`limit by setting the "recursionLimit" config key.`,
|
|
786
|
+
].join(" "), {
|
|
787
|
+
lc_error_code: "GRAPH_RECURSION_LIMIT",
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
catch (e) {
|
|
792
|
+
loopError = e;
|
|
793
|
+
}
|
|
794
|
+
finally {
|
|
795
|
+
try {
|
|
796
|
+
// Call `.stop()` again incase it was not called in the loop, e.g due to an error.
|
|
797
|
+
if (loop) {
|
|
798
|
+
await loop.store?.stop();
|
|
799
|
+
}
|
|
800
|
+
await Promise.all([
|
|
801
|
+
...(loop?.checkpointerPromises ?? []),
|
|
802
|
+
...Array.from(managed.values()).map((mv) => mv.promises()),
|
|
803
|
+
]);
|
|
804
|
+
}
|
|
805
|
+
catch (e) {
|
|
806
|
+
loopError = loopError ?? e;
|
|
807
|
+
}
|
|
808
|
+
if (loopError) {
|
|
809
|
+
// Will throw an error outside of this method
|
|
810
|
+
stream.error(loopError);
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
// Will end the iterator outside of this method
|
|
814
|
+
stream.close();
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
const runLoopPromise = runLoop();
|
|
819
|
+
try {
|
|
820
|
+
for await (const chunk of stream) {
|
|
821
|
+
if (chunk === undefined) {
|
|
713
822
|
throw new Error("Data structure error.");
|
|
714
823
|
}
|
|
715
|
-
const [namespace, mode, payload] =
|
|
824
|
+
const [namespace, mode, payload] = chunk;
|
|
716
825
|
if (streamMode.includes(mode)) {
|
|
717
826
|
if (streamSubgraphs && streamMode.length > 1) {
|
|
718
827
|
yield [namespace, mode, payload];
|
|
@@ -729,104 +838,14 @@ export class Pregel extends Runnable {
|
|
|
729
838
|
}
|
|
730
839
|
}
|
|
731
840
|
}
|
|
732
|
-
try {
|
|
733
|
-
loop = await PregelLoop.initialize({
|
|
734
|
-
input,
|
|
735
|
-
config,
|
|
736
|
-
checkpointer,
|
|
737
|
-
nodes: this.nodes,
|
|
738
|
-
channelSpecs,
|
|
739
|
-
managed,
|
|
740
|
-
outputKeys,
|
|
741
|
-
streamKeys: this.streamChannelsAsIs,
|
|
742
|
-
store,
|
|
743
|
-
stream: new StreamProtocol((chunk) => stream.push(chunk), new Set(streamMode)),
|
|
744
|
-
});
|
|
745
|
-
if (options?.subgraphs) {
|
|
746
|
-
loop.config.configurable = {
|
|
747
|
-
...loop.config.configurable,
|
|
748
|
-
[CONFIG_KEY_STREAM]: loop.stream,
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
while (await loop.tick({
|
|
752
|
-
inputKeys: this.inputChannels,
|
|
753
|
-
interruptAfter,
|
|
754
|
-
interruptBefore,
|
|
755
|
-
manager: runManager,
|
|
756
|
-
})) {
|
|
757
|
-
if (debug) {
|
|
758
|
-
printStepCheckpoint(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
759
|
-
}
|
|
760
|
-
yield* emitCurrentLoopOutputs();
|
|
761
|
-
if (debug) {
|
|
762
|
-
printStepTasks(loop.step, Object.values(loop.tasks));
|
|
763
|
-
}
|
|
764
|
-
// execute tasks, and wait for one to fail or all to finish.
|
|
765
|
-
// each task is independent from all other concurrent tasks
|
|
766
|
-
// yield updates/debug output as each task finishes
|
|
767
|
-
const taskStream = executeTasksWithRetry(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
768
|
-
stepTimeout: this.stepTimeout,
|
|
769
|
-
signal: config.signal,
|
|
770
|
-
retryPolicy: this.retryPolicy,
|
|
771
|
-
});
|
|
772
|
-
// Timeouts will be thrown
|
|
773
|
-
for await (const { task, error } of taskStream) {
|
|
774
|
-
if (error !== undefined) {
|
|
775
|
-
if (isGraphInterrupt(error)) {
|
|
776
|
-
if (loop.isNested) {
|
|
777
|
-
throw error;
|
|
778
|
-
}
|
|
779
|
-
if (error.interrupts.length) {
|
|
780
|
-
loop.putWrites(task.id, error.interrupts.map((interrupt) => [INTERRUPT, interrupt]));
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
else {
|
|
784
|
-
loop.putWrites(task.id, [
|
|
785
|
-
[ERROR, { message: error.message, name: error.name }],
|
|
786
|
-
]);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
else {
|
|
790
|
-
loop.putWrites(task.id, task.writes);
|
|
791
|
-
}
|
|
792
|
-
yield* emitCurrentLoopOutputs();
|
|
793
|
-
if (error !== undefined && !isGraphInterrupt(error)) {
|
|
794
|
-
throw error;
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
if (debug) {
|
|
798
|
-
printStepWrites(loop.step, Object.values(loop.tasks)
|
|
799
|
-
.map((task) => task.writes)
|
|
800
|
-
.flat(), this.streamChannelsList);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
yield* emitCurrentLoopOutputs();
|
|
804
|
-
if (loop.status === "out_of_steps") {
|
|
805
|
-
throw new GraphRecursionError([
|
|
806
|
-
`Recursion limit of ${config.recursionLimit} reached`,
|
|
807
|
-
"without hitting a stop condition. You can increase the",
|
|
808
|
-
`limit by setting the "recursionLimit" config key.`,
|
|
809
|
-
].join(" "), {
|
|
810
|
-
lc_error_code: "GRAPH_RECURSION_LIMIT",
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
await Promise.all(loop?.checkpointerPromises ?? []);
|
|
814
|
-
await runManager?.handleChainEnd(loop.output);
|
|
815
|
-
}
|
|
816
841
|
catch (e) {
|
|
817
|
-
await runManager?.handleChainError(
|
|
842
|
+
await runManager?.handleChainError(loopError);
|
|
818
843
|
throw e;
|
|
819
844
|
}
|
|
820
845
|
finally {
|
|
821
|
-
|
|
822
|
-
if (loop) {
|
|
823
|
-
await loop.store?.stop();
|
|
824
|
-
}
|
|
825
|
-
await Promise.all([
|
|
826
|
-
...(loop?.checkpointerPromises ?? []),
|
|
827
|
-
...Array.from(managed.values()).map((mv) => mv.promises()),
|
|
828
|
-
]);
|
|
846
|
+
await runLoopPromise;
|
|
829
847
|
}
|
|
848
|
+
await runManager?.handleChainEnd(loop?.output ?? {});
|
|
830
849
|
}
|
|
831
850
|
/**
|
|
832
851
|
* Run the graph with a single input and config.
|
package/dist/pregel/loop.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PregelLoop = exports.
|
|
3
|
+
exports.PregelLoop = exports.IterableReadableWritableStream = void 0;
|
|
4
|
+
const stream_1 = require("@langchain/core/utils/stream");
|
|
4
5
|
const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
|
|
5
6
|
const base_js_1 = require("../channels/base.cjs");
|
|
6
7
|
const constants_js_1 = require("../constants.cjs");
|
|
@@ -14,33 +15,72 @@ const INPUT_DONE = Symbol.for("INPUT_DONE");
|
|
|
14
15
|
const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
|
|
15
16
|
const DEFAULT_LOOP_LIMIT = 25;
|
|
16
17
|
const SPECIAL_CHANNELS = [constants_js_1.ERROR, constants_js_1.INTERRUPT];
|
|
17
|
-
class
|
|
18
|
-
constructor(
|
|
19
|
-
|
|
18
|
+
class IterableReadableWritableStream extends stream_1.IterableReadableStream {
|
|
19
|
+
constructor(params) {
|
|
20
|
+
let streamControllerPromiseResolver;
|
|
21
|
+
let streamControllerPromise = new Promise((resolve) => {
|
|
22
|
+
streamControllerPromiseResolver = resolve;
|
|
23
|
+
});
|
|
24
|
+
super({
|
|
25
|
+
start: (controller) => {
|
|
26
|
+
streamControllerPromiseResolver(controller);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
Object.defineProperty(this, "modes", {
|
|
20
30
|
enumerable: true,
|
|
21
31
|
configurable: true,
|
|
22
32
|
writable: true,
|
|
23
33
|
value: void 0
|
|
24
34
|
});
|
|
25
|
-
Object.defineProperty(this, "
|
|
35
|
+
Object.defineProperty(this, "controller", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
writable: true,
|
|
39
|
+
value: void 0
|
|
40
|
+
});
|
|
41
|
+
Object.defineProperty(this, "passthroughFn", {
|
|
26
42
|
enumerable: true,
|
|
27
43
|
configurable: true,
|
|
28
44
|
writable: true,
|
|
29
45
|
value: void 0
|
|
30
46
|
});
|
|
31
|
-
|
|
32
|
-
|
|
47
|
+
// .start() will always be called before the stream can be interacted
|
|
48
|
+
// with anyway
|
|
49
|
+
streamControllerPromise.then((controller) => {
|
|
50
|
+
this.controller = controller;
|
|
51
|
+
});
|
|
52
|
+
this.passthroughFn = params.passthroughFn;
|
|
53
|
+
this.modes = params.modes;
|
|
54
|
+
}
|
|
55
|
+
push(chunk) {
|
|
56
|
+
this.passthroughFn?.(chunk);
|
|
57
|
+
this.controller.enqueue(chunk);
|
|
58
|
+
}
|
|
59
|
+
close() {
|
|
60
|
+
try {
|
|
61
|
+
this.controller.close();
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
// pass
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
error(e) {
|
|
69
|
+
this.controller.error(e);
|
|
33
70
|
}
|
|
34
71
|
}
|
|
35
|
-
exports.
|
|
72
|
+
exports.IterableReadableWritableStream = IterableReadableWritableStream;
|
|
36
73
|
function createDuplexStream(...streams) {
|
|
37
|
-
return new
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
stream.
|
|
74
|
+
return new IterableReadableWritableStream({
|
|
75
|
+
passthroughFn: (value) => {
|
|
76
|
+
for (const stream of streams) {
|
|
77
|
+
if (stream.modes.has(value[1])) {
|
|
78
|
+
stream.push(value);
|
|
79
|
+
}
|
|
41
80
|
}
|
|
42
|
-
}
|
|
43
|
-
|
|
81
|
+
},
|
|
82
|
+
modes: new Set(streams.flatMap((s) => Array.from(s.modes))),
|
|
83
|
+
});
|
|
44
84
|
}
|
|
45
85
|
class PregelLoop {
|
|
46
86
|
constructor(params) {
|
package/dist/pregel/loop.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
2
2
|
import type { CallbackManagerForChainRun } from "@langchain/core/callbacks/manager";
|
|
3
|
+
import { IterableReadableStream } from "@langchain/core/utils/stream";
|
|
3
4
|
import { BaseCheckpointSaver, Checkpoint, PendingWrite, CheckpointPendingWrite, CheckpointMetadata, All, BaseStore, AsyncBatchedStore } from "@langchain/langgraph-checkpoint";
|
|
4
5
|
import { BaseChannel } from "../channels/base.js";
|
|
5
6
|
import { PregelExecutableTask, StreamMode } from "./types.js";
|
|
@@ -16,7 +17,7 @@ export type PregelLoopInitializeParams = {
|
|
|
16
17
|
nodes: Record<string, PregelNode>;
|
|
17
18
|
channelSpecs: Record<string, BaseChannel>;
|
|
18
19
|
managed: ManagedValueMapping;
|
|
19
|
-
stream:
|
|
20
|
+
stream: IterableReadableWritableStream;
|
|
20
21
|
store?: BaseStore;
|
|
21
22
|
checkSubgraphs?: boolean;
|
|
22
23
|
};
|
|
@@ -39,14 +40,21 @@ type PregelLoopParams = {
|
|
|
39
40
|
checkpointNamespace: string[];
|
|
40
41
|
skipDoneTasks: boolean;
|
|
41
42
|
isNested: boolean;
|
|
42
|
-
stream:
|
|
43
|
+
stream: IterableReadableWritableStream;
|
|
43
44
|
store?: AsyncBatchedStore;
|
|
44
45
|
prevCheckpointConfig: RunnableConfig | undefined;
|
|
45
46
|
};
|
|
46
|
-
export declare class
|
|
47
|
-
push: (chunk: StreamChunk) => void;
|
|
47
|
+
export declare class IterableReadableWritableStream extends IterableReadableStream<StreamChunk> {
|
|
48
48
|
modes: Set<StreamMode>;
|
|
49
|
-
|
|
49
|
+
private controller;
|
|
50
|
+
private passthroughFn?;
|
|
51
|
+
constructor(params: {
|
|
52
|
+
passthroughFn?: (chunk: StreamChunk) => void;
|
|
53
|
+
modes: Set<StreamMode>;
|
|
54
|
+
});
|
|
55
|
+
push(chunk: StreamChunk): void;
|
|
56
|
+
close(): void;
|
|
57
|
+
error(e: any): void;
|
|
50
58
|
}
|
|
51
59
|
export declare class PregelLoop {
|
|
52
60
|
protected input?: any;
|
|
@@ -72,7 +80,7 @@ export declare class PregelLoop {
|
|
|
72
80
|
protected prevCheckpointConfig: RunnableConfig | undefined;
|
|
73
81
|
status: "pending" | "done" | "interrupt_before" | "interrupt_after" | "out_of_steps";
|
|
74
82
|
tasks: Record<string, PregelExecutableTask<any, any>>;
|
|
75
|
-
stream:
|
|
83
|
+
stream: IterableReadableWritableStream;
|
|
76
84
|
checkpointerPromises: Promise<unknown>[];
|
|
77
85
|
isNested: boolean;
|
|
78
86
|
protected _checkpointerChainedPromise: Promise<unknown>;
|
package/dist/pregel/loop.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IterableReadableStream } from "@langchain/core/utils/stream";
|
|
1
2
|
import { copyCheckpoint, emptyCheckpoint, AsyncBatchedStore, } from "@langchain/langgraph-checkpoint";
|
|
2
3
|
import { createCheckpoint, emptyChannels, } from "../channels/base.js";
|
|
3
4
|
import { CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, TAG_HIDDEN, TASKS, } from "../constants.js";
|
|
@@ -11,32 +12,71 @@ const INPUT_DONE = Symbol.for("INPUT_DONE");
|
|
|
11
12
|
const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
|
|
12
13
|
const DEFAULT_LOOP_LIMIT = 25;
|
|
13
14
|
const SPECIAL_CHANNELS = [ERROR, INTERRUPT];
|
|
14
|
-
export class
|
|
15
|
-
constructor(
|
|
16
|
-
|
|
15
|
+
export class IterableReadableWritableStream extends IterableReadableStream {
|
|
16
|
+
constructor(params) {
|
|
17
|
+
let streamControllerPromiseResolver;
|
|
18
|
+
let streamControllerPromise = new Promise((resolve) => {
|
|
19
|
+
streamControllerPromiseResolver = resolve;
|
|
20
|
+
});
|
|
21
|
+
super({
|
|
22
|
+
start: (controller) => {
|
|
23
|
+
streamControllerPromiseResolver(controller);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(this, "modes", {
|
|
17
27
|
enumerable: true,
|
|
18
28
|
configurable: true,
|
|
19
29
|
writable: true,
|
|
20
30
|
value: void 0
|
|
21
31
|
});
|
|
22
|
-
Object.defineProperty(this, "
|
|
32
|
+
Object.defineProperty(this, "controller", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "passthroughFn", {
|
|
23
39
|
enumerable: true,
|
|
24
40
|
configurable: true,
|
|
25
41
|
writable: true,
|
|
26
42
|
value: void 0
|
|
27
43
|
});
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
// .start() will always be called before the stream can be interacted
|
|
45
|
+
// with anyway
|
|
46
|
+
streamControllerPromise.then((controller) => {
|
|
47
|
+
this.controller = controller;
|
|
48
|
+
});
|
|
49
|
+
this.passthroughFn = params.passthroughFn;
|
|
50
|
+
this.modes = params.modes;
|
|
51
|
+
}
|
|
52
|
+
push(chunk) {
|
|
53
|
+
this.passthroughFn?.(chunk);
|
|
54
|
+
this.controller.enqueue(chunk);
|
|
55
|
+
}
|
|
56
|
+
close() {
|
|
57
|
+
try {
|
|
58
|
+
this.controller.close();
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
// pass
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
error(e) {
|
|
66
|
+
this.controller.error(e);
|
|
30
67
|
}
|
|
31
68
|
}
|
|
32
69
|
function createDuplexStream(...streams) {
|
|
33
|
-
return new
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
stream.
|
|
70
|
+
return new IterableReadableWritableStream({
|
|
71
|
+
passthroughFn: (value) => {
|
|
72
|
+
for (const stream of streams) {
|
|
73
|
+
if (stream.modes.has(value[1])) {
|
|
74
|
+
stream.push(value);
|
|
75
|
+
}
|
|
37
76
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
77
|
+
},
|
|
78
|
+
modes: new Set(streams.flatMap((s) => Array.from(s.modes))),
|
|
79
|
+
});
|
|
40
80
|
}
|
|
41
81
|
export class PregelLoop {
|
|
42
82
|
constructor(params) {
|
package/dist/pregel/retry.cjs
CHANGED
|
@@ -130,7 +130,7 @@ pregelTask, retryPolicy) {
|
|
|
130
130
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
131
131
|
error.constructor.unminifiable_name ??
|
|
132
132
|
error.constructor.name;
|
|
133
|
-
console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)}
|
|
133
|
+
console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
|
|
134
134
|
}
|
|
135
135
|
finally {
|
|
136
136
|
// Clear checkpoint_ns seen (for subgraph detection)
|
package/dist/pregel/retry.js
CHANGED
|
@@ -126,7 +126,7 @@ pregelTask, retryPolicy) {
|
|
|
126
126
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
127
|
error.constructor.unminifiable_name ??
|
|
128
128
|
error.constructor.name;
|
|
129
|
-
console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)}
|
|
129
|
+
console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
|
|
130
130
|
}
|
|
131
131
|
finally {
|
|
132
132
|
// Clear checkpoint_ns seen (for subgraph detection)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20-rc.0",
|
|
4
4
|
"description": "LangGraph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@langchain/langgraph-checkpoint": "~0.0.10",
|
|
35
35
|
"@langchain/langgraph-sdk": "~0.0.20",
|
|
36
|
-
"double-ended-queue": "^2.1.0-0",
|
|
37
36
|
"uuid": "^10.0.0",
|
|
38
37
|
"zod": "^3.23.8"
|
|
39
38
|
},
|
|
@@ -44,7 +43,7 @@
|
|
|
44
43
|
"@jest/globals": "^29.5.0",
|
|
45
44
|
"@langchain/anthropic": "^0.3.5",
|
|
46
45
|
"@langchain/community": "^0.3.9",
|
|
47
|
-
"@langchain/core": "^0.3.
|
|
46
|
+
"@langchain/core": "^0.3.16",
|
|
48
47
|
"@langchain/langgraph-checkpoint-postgres": "workspace:*",
|
|
49
48
|
"@langchain/langgraph-checkpoint-sqlite": "workspace:*",
|
|
50
49
|
"@langchain/openai": "^0.3.11",
|
|
@@ -52,7 +51,6 @@
|
|
|
52
51
|
"@swc/core": "^1.3.90",
|
|
53
52
|
"@swc/jest": "^0.2.29",
|
|
54
53
|
"@tsconfig/recommended": "^1.0.3",
|
|
55
|
-
"@types/double-ended-queue": "^2",
|
|
56
54
|
"@types/pg": "^8",
|
|
57
55
|
"@types/uuid": "^10",
|
|
58
56
|
"@typescript-eslint/eslint-plugin": "^6.12.0",
|