@langchain/langgraph 0.2.19 → 0.2.20
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/constants.cjs +2 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/pregel/algo.cjs +1 -1
- package/dist/pregel/algo.js +1 -1
- package/dist/pregel/index.cjs +155 -109
- package/dist/pregel/index.d.ts +3 -2
- package/dist/pregel/index.js +156 -107
- 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/messages.cjs +148 -0
- package/dist/pregel/messages.d.ts +28 -0
- package/dist/pregel/messages.js +144 -0
- package/dist/pregel/retry.cjs +1 -1
- package/dist/pregel/retry.js +1 -1
- package/dist/pregel/runnable_types.d.ts +1 -0
- package/dist/pregel/types.d.ts +2 -2
- package/dist/pregel/utils/config.cjs +1 -0
- package/dist/pregel/utils/config.js +1 -0
- package/package.json +2 -4
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,11 +12,12 @@ 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";
|
|
20
19
|
import { ensureLangGraphConfig } from "./utils/config.js";
|
|
20
|
+
import { StreamMessagesHandler } from "./messages.js";
|
|
21
21
|
function isString(value) {
|
|
22
22
|
return typeof value === "string";
|
|
23
23
|
}
|
|
@@ -572,6 +572,7 @@ export class Pregel extends Runnable {
|
|
|
572
572
|
}
|
|
573
573
|
_defaults(config) {
|
|
574
574
|
const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
|
|
575
|
+
let streamModeSingle = true;
|
|
575
576
|
const defaultDebug = debug !== undefined ? debug : this.debug;
|
|
576
577
|
let defaultOutputKeys = outputKeys;
|
|
577
578
|
if (defaultOutputKeys === undefined) {
|
|
@@ -592,9 +593,11 @@ export class Pregel extends Runnable {
|
|
|
592
593
|
let defaultStreamMode;
|
|
593
594
|
if (streamMode !== undefined) {
|
|
594
595
|
defaultStreamMode = Array.isArray(streamMode) ? streamMode : [streamMode];
|
|
596
|
+
streamModeSingle = typeof streamMode === "string";
|
|
595
597
|
}
|
|
596
598
|
else {
|
|
597
599
|
defaultStreamMode = this.streamMode;
|
|
600
|
+
streamModeSingle = true;
|
|
598
601
|
}
|
|
599
602
|
// if being called as a node in another graph, always use values mode
|
|
600
603
|
if (config.configurable?.[CONFIG_KEY_TASK_ID] !== undefined) {
|
|
@@ -622,6 +625,7 @@ export class Pregel extends Runnable {
|
|
|
622
625
|
defaultInterruptAfter,
|
|
623
626
|
defaultCheckpointer,
|
|
624
627
|
defaultStore,
|
|
628
|
+
streamModeSingle,
|
|
625
629
|
];
|
|
626
630
|
}
|
|
627
631
|
/**
|
|
@@ -698,135 +702,180 @@ export class Pregel extends Runnable {
|
|
|
698
702
|
inputConfig.configurable === undefined) {
|
|
699
703
|
throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`);
|
|
700
704
|
}
|
|
701
|
-
const
|
|
702
|
-
const runManager = await callbackManager?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
|
|
703
|
-
delete inputConfig.runId;
|
|
705
|
+
const { runId, ...restConfig } = inputConfig;
|
|
704
706
|
// assign defaults
|
|
705
|
-
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer, store,] = this._defaults(
|
|
707
|
+
const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer, store, streamModeSingle,] = this._defaults(restConfig);
|
|
708
|
+
const stream = new IterableReadableWritableStream({
|
|
709
|
+
modes: new Set(streamMode),
|
|
710
|
+
});
|
|
711
|
+
// set up messages stream mode
|
|
712
|
+
if (streamMode.includes("messages")) {
|
|
713
|
+
const messageStreamer = new StreamMessagesHandler((chunk) => stream.push(chunk));
|
|
714
|
+
const { callbacks } = config;
|
|
715
|
+
if (callbacks === undefined) {
|
|
716
|
+
config.callbacks = [messageStreamer];
|
|
717
|
+
}
|
|
718
|
+
else if (Array.isArray(callbacks)) {
|
|
719
|
+
config.callbacks = callbacks.concat(messageStreamer);
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
const copiedCallbacks = callbacks.copy();
|
|
723
|
+
copiedCallbacks.addHandler(messageStreamer, true);
|
|
724
|
+
config.callbacks = copiedCallbacks;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
// setup custom stream mode
|
|
728
|
+
if (streamMode.includes("custom")) {
|
|
729
|
+
config.writer = (chunk) => stream.push([[], "custom", chunk]);
|
|
730
|
+
}
|
|
731
|
+
const callbackManager = await getCallbackManagerForConfig(config);
|
|
732
|
+
const runManager = await callbackManager?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), runId, undefined, undefined, undefined, config?.runName ?? this.getName());
|
|
706
733
|
const { channelSpecs, managed } = await this.prepareSpecs(config);
|
|
707
734
|
let loop;
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
735
|
+
let loopError;
|
|
736
|
+
const runLoop = async () => {
|
|
737
|
+
try {
|
|
738
|
+
loop = await PregelLoop.initialize({
|
|
739
|
+
input,
|
|
740
|
+
config,
|
|
741
|
+
checkpointer,
|
|
742
|
+
nodes: this.nodes,
|
|
743
|
+
channelSpecs,
|
|
744
|
+
managed,
|
|
745
|
+
outputKeys,
|
|
746
|
+
streamKeys: this.streamChannelsAsIs,
|
|
747
|
+
store,
|
|
748
|
+
stream,
|
|
749
|
+
});
|
|
750
|
+
if (options?.subgraphs) {
|
|
751
|
+
loop.config.configurable = {
|
|
752
|
+
...loop.config.configurable,
|
|
753
|
+
[CONFIG_KEY_STREAM]: loop.stream,
|
|
754
|
+
};
|
|
714
755
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
else if (streamSubgraphs) {
|
|
724
|
-
yield [namespace, payload];
|
|
756
|
+
while (await loop.tick({
|
|
757
|
+
inputKeys: this.inputChannels,
|
|
758
|
+
interruptAfter,
|
|
759
|
+
interruptBefore,
|
|
760
|
+
manager: runManager,
|
|
761
|
+
})) {
|
|
762
|
+
if (debug) {
|
|
763
|
+
printStepCheckpoint(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
|
|
725
764
|
}
|
|
726
|
-
|
|
727
|
-
|
|
765
|
+
if (debug) {
|
|
766
|
+
printStepTasks(loop.step, Object.values(loop.tasks));
|
|
728
767
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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;
|
|
768
|
+
// execute tasks, and wait for one to fail or all to finish.
|
|
769
|
+
// each task is independent from all other concurrent tasks
|
|
770
|
+
// yield updates/debug output as each task finishes
|
|
771
|
+
const taskStream = executeTasksWithRetry(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
|
|
772
|
+
stepTimeout: this.stepTimeout,
|
|
773
|
+
signal: config.signal,
|
|
774
|
+
retryPolicy: this.retryPolicy,
|
|
775
|
+
});
|
|
776
|
+
// Timeouts will be thrown
|
|
777
|
+
for await (const { task, error } of taskStream) {
|
|
778
|
+
if (error !== undefined) {
|
|
779
|
+
if (isGraphInterrupt(error)) {
|
|
780
|
+
if (loop.isNested) {
|
|
781
|
+
throw error;
|
|
782
|
+
}
|
|
783
|
+
if (error.interrupts.length) {
|
|
784
|
+
loop.putWrites(task.id, error.interrupts.map((interrupt) => [INTERRUPT, interrupt]));
|
|
785
|
+
}
|
|
778
786
|
}
|
|
779
|
-
|
|
780
|
-
loop.putWrites(task.id,
|
|
787
|
+
else {
|
|
788
|
+
loop.putWrites(task.id, [
|
|
789
|
+
[ERROR, { message: error.message, name: error.name }],
|
|
790
|
+
]);
|
|
781
791
|
}
|
|
782
792
|
}
|
|
783
793
|
else {
|
|
784
|
-
loop.putWrites(task.id,
|
|
785
|
-
|
|
786
|
-
|
|
794
|
+
loop.putWrites(task.id, task.writes);
|
|
795
|
+
}
|
|
796
|
+
if (error !== undefined && !isGraphInterrupt(error)) {
|
|
797
|
+
throw error;
|
|
787
798
|
}
|
|
788
799
|
}
|
|
789
|
-
|
|
790
|
-
loop.
|
|
800
|
+
if (debug) {
|
|
801
|
+
printStepWrites(loop.step, Object.values(loop.tasks)
|
|
802
|
+
.map((task) => task.writes)
|
|
803
|
+
.flat(), this.streamChannelsList);
|
|
791
804
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
805
|
+
}
|
|
806
|
+
if (loop.status === "out_of_steps") {
|
|
807
|
+
throw new GraphRecursionError([
|
|
808
|
+
`Recursion limit of ${config.recursionLimit} reached`,
|
|
809
|
+
"without hitting a stop condition. You can increase the",
|
|
810
|
+
`limit by setting the "recursionLimit" config key.`,
|
|
811
|
+
].join(" "), {
|
|
812
|
+
lc_error_code: "GRAPH_RECURSION_LIMIT",
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
catch (e) {
|
|
817
|
+
loopError = e;
|
|
818
|
+
}
|
|
819
|
+
finally {
|
|
820
|
+
try {
|
|
821
|
+
// Call `.stop()` again incase it was not called in the loop, e.g due to an error.
|
|
822
|
+
if (loop) {
|
|
823
|
+
await loop.store?.stop();
|
|
795
824
|
}
|
|
825
|
+
await Promise.all([
|
|
826
|
+
...(loop?.checkpointerPromises ?? []),
|
|
827
|
+
...Array.from(managed.values()).map((mv) => mv.promises()),
|
|
828
|
+
]);
|
|
796
829
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
830
|
+
catch (e) {
|
|
831
|
+
loopError = loopError ?? e;
|
|
832
|
+
}
|
|
833
|
+
if (loopError) {
|
|
834
|
+
// "Causes any future interactions with the associated stream to error".
|
|
835
|
+
// Wraps ReadableStreamDefaultController#error:
|
|
836
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController/error
|
|
837
|
+
stream.error(loopError);
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
// Will end the iterator outside of this method,
|
|
841
|
+
// keeping previously enqueued chunks.
|
|
842
|
+
// Wraps ReadableStreamDefaultController#close:
|
|
843
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController/close
|
|
844
|
+
stream.close();
|
|
801
845
|
}
|
|
802
846
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
847
|
+
};
|
|
848
|
+
const runLoopPromise = runLoop();
|
|
849
|
+
try {
|
|
850
|
+
for await (const chunk of stream) {
|
|
851
|
+
if (chunk === undefined) {
|
|
852
|
+
throw new Error("Data structure error.");
|
|
853
|
+
}
|
|
854
|
+
const [namespace, mode, payload] = chunk;
|
|
855
|
+
if (streamMode.includes(mode)) {
|
|
856
|
+
if (streamSubgraphs && !streamModeSingle) {
|
|
857
|
+
yield [namespace, mode, payload];
|
|
858
|
+
}
|
|
859
|
+
else if (!streamModeSingle) {
|
|
860
|
+
yield [mode, payload];
|
|
861
|
+
}
|
|
862
|
+
else if (streamSubgraphs) {
|
|
863
|
+
yield [namespace, payload];
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
yield payload;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
812
869
|
}
|
|
813
|
-
await Promise.all(loop?.checkpointerPromises ?? []);
|
|
814
|
-
await runManager?.handleChainEnd(loop.output);
|
|
815
870
|
}
|
|
816
871
|
catch (e) {
|
|
817
|
-
await runManager?.handleChainError(
|
|
872
|
+
await runManager?.handleChainError(loopError);
|
|
818
873
|
throw e;
|
|
819
874
|
}
|
|
820
875
|
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
|
-
]);
|
|
876
|
+
await runLoopPromise;
|
|
829
877
|
}
|
|
878
|
+
await runManager?.handleChainEnd(loop?.output ?? {});
|
|
830
879
|
}
|
|
831
880
|
/**
|
|
832
881
|
* 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
|
+
const 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
|
+
void 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
|
+
const 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
|
+
void 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) {
|