@langchain/langgraph 0.2.40 → 0.2.42
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/README.md +237 -154
- package/dist/channels/any_value.cjs +10 -10
- package/dist/channels/any_value.d.ts +1 -1
- package/dist/channels/any_value.js +10 -10
- package/dist/channels/ephemeral_value.cjs +10 -9
- package/dist/channels/ephemeral_value.d.ts +1 -1
- package/dist/channels/ephemeral_value.js +10 -9
- package/dist/channels/last_value.cjs +8 -7
- package/dist/channels/last_value.d.ts +1 -1
- package/dist/channels/last_value.js +8 -7
- package/dist/constants.cjs +33 -6
- package/dist/constants.d.ts +17 -2
- package/dist/constants.js +32 -5
- package/dist/errors.d.ts +3 -3
- package/dist/func/index.cjs +272 -0
- package/dist/func/index.d.ts +310 -0
- package/dist/func/index.js +267 -0
- package/dist/func/types.cjs +15 -0
- package/dist/func/types.d.ts +59 -0
- package/dist/func/types.js +11 -0
- package/dist/graph/graph.cjs +31 -35
- package/dist/graph/graph.d.ts +1 -5
- package/dist/graph/graph.js +1 -5
- package/dist/graph/index.cjs +1 -3
- package/dist/graph/index.d.ts +1 -1
- package/dist/graph/index.js +1 -1
- package/dist/graph/message.d.ts +1 -1
- package/dist/graph/state.cjs +17 -17
- package/dist/graph/state.d.ts +2 -1
- package/dist/graph/state.js +2 -2
- package/dist/index.cjs +8 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/interrupt.cjs +21 -34
- package/dist/interrupt.d.ts +1 -1
- package/dist/interrupt.js +22 -35
- package/dist/prebuilt/agent_executor.cjs +3 -3
- package/dist/prebuilt/agent_executor.d.ts +1 -1
- package/dist/prebuilt/agent_executor.js +1 -1
- package/dist/prebuilt/chat_agent_executor.cjs +3 -3
- package/dist/prebuilt/chat_agent_executor.d.ts +1 -1
- package/dist/prebuilt/chat_agent_executor.js +1 -1
- package/dist/prebuilt/react_agent_executor.cjs +79 -12
- package/dist/prebuilt/react_agent_executor.d.ts +35 -4
- package/dist/prebuilt/react_agent_executor.js +79 -13
- package/dist/prebuilt/tool_node.cjs +1 -2
- package/dist/prebuilt/tool_node.d.ts +1 -1
- package/dist/prebuilt/tool_node.js +1 -2
- package/dist/pregel/algo.cjs +121 -12
- package/dist/pregel/algo.d.ts +8 -6
- package/dist/pregel/algo.js +122 -13
- package/dist/pregel/call.cjs +77 -0
- package/dist/pregel/call.d.ts +15 -0
- package/dist/pregel/call.js +71 -0
- package/dist/pregel/index.cjs +59 -96
- package/dist/pregel/index.d.ts +1 -10
- package/dist/pregel/index.js +61 -98
- package/dist/pregel/io.cjs +6 -1
- package/dist/pregel/io.js +7 -2
- package/dist/pregel/loop.cjs +109 -75
- package/dist/pregel/loop.d.ts +17 -23
- package/dist/pregel/loop.js +110 -75
- package/dist/pregel/messages.d.ts +1 -1
- package/dist/pregel/retry.cjs +22 -50
- package/dist/pregel/retry.d.ts +6 -6
- package/dist/pregel/retry.js +22 -50
- package/dist/pregel/runner.cjs +275 -0
- package/dist/pregel/runner.d.ts +64 -0
- package/dist/pregel/runner.js +271 -0
- package/dist/pregel/stream.cjs +71 -0
- package/dist/pregel/stream.d.ts +17 -0
- package/dist/pregel/stream.js +67 -0
- package/dist/pregel/types.cjs +54 -0
- package/dist/pregel/types.d.ts +78 -6
- package/dist/pregel/types.js +51 -1
- package/dist/pregel/utils/config.cjs +26 -1
- package/dist/pregel/utils/config.d.ts +14 -0
- package/dist/pregel/utils/config.js +22 -0
- package/dist/pregel/write.d.ts +1 -1
- package/dist/utils.cjs +15 -1
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +12 -0
- package/dist/web.cjs +7 -5
- package/dist/web.d.ts +4 -4
- package/dist/web.js +3 -3
- package/package.json +8 -8
package/dist/pregel/loop.cjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PregelLoop =
|
|
4
|
-
const stream_1 = require("@langchain/core/utils/stream");
|
|
3
|
+
exports.PregelLoop = void 0;
|
|
5
4
|
const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
|
|
6
5
|
const base_js_1 = require("../channels/base.cjs");
|
|
7
6
|
const constants_js_1 = require("../constants.cjs");
|
|
@@ -11,66 +10,12 @@ const io_js_1 = require("./io.cjs");
|
|
|
11
10
|
const errors_js_1 = require("../errors.cjs");
|
|
12
11
|
const index_js_1 = require("./utils/index.cjs");
|
|
13
12
|
const debug_js_1 = require("./debug.cjs");
|
|
13
|
+
const stream_js_1 = require("./stream.cjs");
|
|
14
14
|
const INPUT_DONE = Symbol.for("INPUT_DONE");
|
|
15
15
|
const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
|
|
16
16
|
const DEFAULT_LOOP_LIMIT = 25;
|
|
17
|
-
class IterableReadableWritableStream extends stream_1.IterableReadableStream {
|
|
18
|
-
constructor(params) {
|
|
19
|
-
let streamControllerPromiseResolver;
|
|
20
|
-
const streamControllerPromise = new Promise((resolve) => {
|
|
21
|
-
streamControllerPromiseResolver = resolve;
|
|
22
|
-
});
|
|
23
|
-
super({
|
|
24
|
-
start: (controller) => {
|
|
25
|
-
streamControllerPromiseResolver(controller);
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(this, "modes", {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
configurable: true,
|
|
31
|
-
writable: true,
|
|
32
|
-
value: void 0
|
|
33
|
-
});
|
|
34
|
-
Object.defineProperty(this, "controller", {
|
|
35
|
-
enumerable: true,
|
|
36
|
-
configurable: true,
|
|
37
|
-
writable: true,
|
|
38
|
-
value: void 0
|
|
39
|
-
});
|
|
40
|
-
Object.defineProperty(this, "passthroughFn", {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
configurable: true,
|
|
43
|
-
writable: true,
|
|
44
|
-
value: void 0
|
|
45
|
-
});
|
|
46
|
-
// .start() will always be called before the stream can be interacted
|
|
47
|
-
// with anyway
|
|
48
|
-
void streamControllerPromise.then((controller) => {
|
|
49
|
-
this.controller = controller;
|
|
50
|
-
});
|
|
51
|
-
this.passthroughFn = params.passthroughFn;
|
|
52
|
-
this.modes = params.modes;
|
|
53
|
-
}
|
|
54
|
-
push(chunk) {
|
|
55
|
-
this.passthroughFn?.(chunk);
|
|
56
|
-
this.controller.enqueue(chunk);
|
|
57
|
-
}
|
|
58
|
-
close() {
|
|
59
|
-
try {
|
|
60
|
-
this.controller.close();
|
|
61
|
-
}
|
|
62
|
-
catch (e) {
|
|
63
|
-
// pass
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
-
error(e) {
|
|
68
|
-
this.controller.error(e);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
exports.IterableReadableWritableStream = IterableReadableWritableStream;
|
|
72
17
|
function createDuplexStream(...streams) {
|
|
73
|
-
return new IterableReadableWritableStream({
|
|
18
|
+
return new stream_js_1.IterableReadableWritableStream({
|
|
74
19
|
passthroughFn: (value) => {
|
|
75
20
|
for (const stream of streams) {
|
|
76
21
|
if (stream.modes.has(value[1])) {
|
|
@@ -249,6 +194,36 @@ class PregelLoop {
|
|
|
249
194
|
writable: true,
|
|
250
195
|
value: void 0
|
|
251
196
|
});
|
|
197
|
+
Object.defineProperty(this, "manager", {
|
|
198
|
+
enumerable: true,
|
|
199
|
+
configurable: true,
|
|
200
|
+
writable: true,
|
|
201
|
+
value: void 0
|
|
202
|
+
});
|
|
203
|
+
Object.defineProperty(this, "interruptAfter", {
|
|
204
|
+
enumerable: true,
|
|
205
|
+
configurable: true,
|
|
206
|
+
writable: true,
|
|
207
|
+
value: void 0
|
|
208
|
+
});
|
|
209
|
+
Object.defineProperty(this, "interruptBefore", {
|
|
210
|
+
enumerable: true,
|
|
211
|
+
configurable: true,
|
|
212
|
+
writable: true,
|
|
213
|
+
value: void 0
|
|
214
|
+
});
|
|
215
|
+
Object.defineProperty(this, "toInterrupt", {
|
|
216
|
+
enumerable: true,
|
|
217
|
+
configurable: true,
|
|
218
|
+
writable: true,
|
|
219
|
+
value: []
|
|
220
|
+
});
|
|
221
|
+
Object.defineProperty(this, "debug", {
|
|
222
|
+
enumerable: true,
|
|
223
|
+
configurable: true,
|
|
224
|
+
writable: true,
|
|
225
|
+
value: false
|
|
226
|
+
});
|
|
252
227
|
this.input = params.input;
|
|
253
228
|
this.checkpointer = params.checkpointer;
|
|
254
229
|
// TODO: if managed values no longer needs graph we can replace with
|
|
@@ -270,6 +245,7 @@ class PregelLoop {
|
|
|
270
245
|
this.config = params.config;
|
|
271
246
|
this.checkpointConfig = params.checkpointConfig;
|
|
272
247
|
this.isNested = params.isNested;
|
|
248
|
+
this.manager = params.manager;
|
|
273
249
|
this.outputKeys = params.outputKeys;
|
|
274
250
|
this.streamKeys = params.streamKeys;
|
|
275
251
|
this.nodes = params.nodes;
|
|
@@ -278,6 +254,9 @@ class PregelLoop {
|
|
|
278
254
|
this.stream = params.stream;
|
|
279
255
|
this.checkpointNamespace = params.checkpointNamespace;
|
|
280
256
|
this.prevCheckpointConfig = params.prevCheckpointConfig;
|
|
257
|
+
this.interruptAfter = params.interruptAfter;
|
|
258
|
+
this.interruptBefore = params.interruptBefore;
|
|
259
|
+
this.debug = params.debug;
|
|
281
260
|
}
|
|
282
261
|
static async initialize(params) {
|
|
283
262
|
let { config, stream } = params;
|
|
@@ -368,6 +347,7 @@ class PregelLoop {
|
|
|
368
347
|
channels,
|
|
369
348
|
managed: params.managed,
|
|
370
349
|
isNested,
|
|
350
|
+
manager: params.manager,
|
|
371
351
|
skipDoneTasks,
|
|
372
352
|
step,
|
|
373
353
|
stop,
|
|
@@ -378,6 +358,9 @@ class PregelLoop {
|
|
|
378
358
|
nodes: params.nodes,
|
|
379
359
|
stream,
|
|
380
360
|
store,
|
|
361
|
+
interruptAfter: params.interruptAfter,
|
|
362
|
+
interruptBefore: params.interruptBefore,
|
|
363
|
+
debug: params.debug,
|
|
381
364
|
});
|
|
382
365
|
}
|
|
383
366
|
_checkpointerPutAfterPrevious(input) {
|
|
@@ -458,7 +441,7 @@ class PregelLoop {
|
|
|
458
441
|
if (this.store && !this.store.isRunning) {
|
|
459
442
|
this.store?.start();
|
|
460
443
|
}
|
|
461
|
-
const { inputKeys = []
|
|
444
|
+
const { inputKeys = [] } = params;
|
|
462
445
|
if (this.status !== "pending") {
|
|
463
446
|
throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
|
|
464
447
|
}
|
|
@@ -482,7 +465,7 @@ class PregelLoop {
|
|
|
482
465
|
writes: (0, io_js_1.mapOutputUpdates)(this.outputKeys, Object.values(this.tasks).map((task) => [task, task.writes])).next().value ?? null,
|
|
483
466
|
});
|
|
484
467
|
// after execution, check if we should interrupt
|
|
485
|
-
if ((0, algo_js_1.shouldInterrupt)(this.checkpoint, interruptAfter, Object.values(this.tasks))) {
|
|
468
|
+
if ((0, algo_js_1.shouldInterrupt)(this.checkpoint, this.interruptAfter, Object.values(this.tasks))) {
|
|
486
469
|
this.status = "interrupt_after";
|
|
487
470
|
throw new errors_js_1.GraphInterrupt();
|
|
488
471
|
}
|
|
@@ -498,8 +481,9 @@ class PregelLoop {
|
|
|
498
481
|
step: this.step,
|
|
499
482
|
checkpointer: this.checkpointer,
|
|
500
483
|
isResuming: this.input === INPUT_RESUMING,
|
|
501
|
-
manager,
|
|
484
|
+
manager: this.manager,
|
|
502
485
|
store: this.store,
|
|
486
|
+
stream: this.stream,
|
|
503
487
|
});
|
|
504
488
|
this.tasks = nextTasks;
|
|
505
489
|
// Produce debug output
|
|
@@ -530,15 +514,10 @@ class PregelLoop {
|
|
|
530
514
|
}
|
|
531
515
|
// if all tasks have finished, re-tick
|
|
532
516
|
if (Object.values(this.tasks).every((task) => task.writes.length > 0)) {
|
|
533
|
-
return this.tick({
|
|
534
|
-
inputKeys,
|
|
535
|
-
interruptAfter,
|
|
536
|
-
interruptBefore,
|
|
537
|
-
manager,
|
|
538
|
-
});
|
|
517
|
+
return this.tick({ inputKeys });
|
|
539
518
|
}
|
|
540
519
|
// Before execution, check if we should interrupt
|
|
541
|
-
if ((0, algo_js_1.shouldInterrupt)(this.checkpoint, interruptBefore, Object.values(this.tasks))) {
|
|
520
|
+
if ((0, algo_js_1.shouldInterrupt)(this.checkpoint, this.interruptBefore, Object.values(this.tasks))) {
|
|
542
521
|
this.status = "interrupt_before";
|
|
543
522
|
throw new errors_js_1.GraphInterrupt();
|
|
544
523
|
}
|
|
@@ -575,20 +554,59 @@ class PregelLoop {
|
|
|
575
554
|
}
|
|
576
555
|
return suppress;
|
|
577
556
|
}
|
|
557
|
+
acceptPush(task, writeIdx, call) {
|
|
558
|
+
if (this.interruptAfter?.length > 0 &&
|
|
559
|
+
(0, algo_js_1.shouldInterrupt)(this.checkpoint, this.interruptAfter, [task])) {
|
|
560
|
+
this.toInterrupt.push(task);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const pushed = (0, algo_js_1._prepareSingleTask)([constants_js_1.PUSH, task.path ?? [], writeIdx, task.id, call], this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.managed, this.config, true, {
|
|
564
|
+
step: this.step,
|
|
565
|
+
checkpointer: this.checkpointer,
|
|
566
|
+
manager: this.manager,
|
|
567
|
+
store: this.store,
|
|
568
|
+
stream: this.stream,
|
|
569
|
+
});
|
|
570
|
+
if (pushed) {
|
|
571
|
+
if (this.interruptBefore?.length > 0 &&
|
|
572
|
+
(0, algo_js_1.shouldInterrupt)(this.checkpoint, this.interruptBefore, [pushed])) {
|
|
573
|
+
this.toInterrupt.push(pushed);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
this._emit((0, utils_js_1.gatherIteratorSync)((0, utils_js_1.prefixGenerator)((0, debug_js_1.mapDebugTasks)(this.step, [pushed]), "debug")));
|
|
577
|
+
if (this.debug) {
|
|
578
|
+
(0, debug_js_1.printStepTasks)(this.step, [pushed]);
|
|
579
|
+
}
|
|
580
|
+
this.tasks[pushed.id] = pushed;
|
|
581
|
+
if (this.skipDoneTasks) {
|
|
582
|
+
this._matchWrites({ [pushed.id]: pushed });
|
|
583
|
+
}
|
|
584
|
+
return pushed;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
578
587
|
_suppressInterrupt(e) {
|
|
579
588
|
return (0, errors_js_1.isGraphInterrupt)(e) && !this.isNested;
|
|
580
589
|
}
|
|
581
|
-
/**
|
|
582
|
-
* Resuming from previous checkpoint requires
|
|
583
|
-
* - finding a previous checkpoint
|
|
584
|
-
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
585
|
-
*/
|
|
586
590
|
async _first(inputKeys) {
|
|
591
|
+
/*
|
|
592
|
+
* Resuming from previous checkpoint requires
|
|
593
|
+
* - finding a previous checkpoint
|
|
594
|
+
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
595
|
+
*/
|
|
596
|
+
const { configurable } = this.config;
|
|
587
597
|
const isResuming = Object.keys(this.checkpoint.channel_versions).length !== 0 &&
|
|
588
598
|
(this.config.configurable?.[constants_js_1.CONFIG_KEY_RESUMING] !== undefined ||
|
|
589
599
|
this.input === null ||
|
|
590
600
|
(0, constants_js_1.isCommand)(this.input));
|
|
601
|
+
// take resume value from parent
|
|
602
|
+
const scratchpad = configurable?.[constants_js_1.CONFIG_KEY_SCRATCHPAD];
|
|
603
|
+
if (scratchpad && scratchpad.nullResume !== undefined) {
|
|
604
|
+
this.putWrites(constants_js_1.NULL_TASK_ID, [[constants_js_1.RESUME, scratchpad.nullResume]]);
|
|
605
|
+
}
|
|
591
606
|
if ((0, constants_js_1.isCommand)(this.input)) {
|
|
607
|
+
if (this.input.resume != null && this.checkpointer == null) {
|
|
608
|
+
throw new Error("Cannot use Command(resume=...) without checkpointer");
|
|
609
|
+
}
|
|
592
610
|
const writes = {};
|
|
593
611
|
// group writes by task id
|
|
594
612
|
for (const [tid, key, value] of (0, io_js_1.mapCommand)(this.input, this.checkpointPendingWrites)) {
|
|
@@ -653,10 +671,10 @@ class PregelLoop {
|
|
|
653
671
|
});
|
|
654
672
|
}
|
|
655
673
|
// done with input
|
|
656
|
-
this.input =
|
|
674
|
+
this.input = this.input === INPUT_RESUMING ? INPUT_RESUMING : INPUT_DONE;
|
|
657
675
|
if (!this.isNested) {
|
|
658
676
|
this.config = (0, index_js_1.patchConfigurable)(this.config, {
|
|
659
|
-
[constants_js_1.CONFIG_KEY_RESUMING]:
|
|
677
|
+
[constants_js_1.CONFIG_KEY_RESUMING]: this.input === INPUT_RESUMING,
|
|
660
678
|
});
|
|
661
679
|
}
|
|
662
680
|
}
|
|
@@ -717,5 +735,21 @@ class PregelLoop {
|
|
|
717
735
|
}
|
|
718
736
|
this.step += 1;
|
|
719
737
|
}
|
|
738
|
+
_matchWrites(tasks) {
|
|
739
|
+
for (const [tid, k, v] of this.checkpointPendingWrites) {
|
|
740
|
+
if (k === constants_js_1.ERROR || k === constants_js_1.INTERRUPT || k === constants_js_1.RESUME) {
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
const task = Object.values(tasks).find((t) => t.id === tid);
|
|
744
|
+
if (task) {
|
|
745
|
+
task.writes.push([k, v]);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
for (const task of Object.values(tasks)) {
|
|
749
|
+
if (task.writes.length > 0) {
|
|
750
|
+
this._outputWrites(task.id, task.writes, true);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
720
754
|
}
|
|
721
755
|
exports.PregelLoop = PregelLoop;
|
package/dist/pregel/loop.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
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";
|
|
4
3
|
import { BaseCheckpointSaver, Checkpoint, PendingWrite, CheckpointPendingWrite, CheckpointMetadata, All, BaseStore, AsyncBatchedStore } from "@langchain/langgraph-checkpoint";
|
|
5
4
|
import { BaseChannel } from "../channels/base.js";
|
|
6
|
-
import { PregelExecutableTask, StreamMode } from "./types.js";
|
|
5
|
+
import { Call, PregelExecutableTask, StreamMode } from "./types.js";
|
|
7
6
|
import { Command } from "../constants.js";
|
|
8
7
|
import { PregelNode } from "./read.js";
|
|
9
8
|
import { ManagedValueMapping } from "../managed/base.js";
|
|
10
9
|
import { LangGraphRunnableConfig } from "./runnable_types.js";
|
|
11
|
-
|
|
10
|
+
import { IterableReadableWritableStream } from "./stream.js";
|
|
12
11
|
export type PregelLoopInitializeParams = {
|
|
13
12
|
input?: any | Command;
|
|
14
13
|
config: RunnableConfig;
|
|
@@ -21,6 +20,10 @@ export type PregelLoopInitializeParams = {
|
|
|
21
20
|
stream: IterableReadableWritableStream;
|
|
22
21
|
store?: BaseStore;
|
|
23
22
|
checkSubgraphs?: boolean;
|
|
23
|
+
interruptAfter: string[] | All;
|
|
24
|
+
interruptBefore: string[] | All;
|
|
25
|
+
manager?: CallbackManagerForChainRun;
|
|
26
|
+
debug: boolean;
|
|
24
27
|
};
|
|
25
28
|
type PregelLoopParams = {
|
|
26
29
|
input?: any | Command;
|
|
@@ -41,22 +44,14 @@ type PregelLoopParams = {
|
|
|
41
44
|
checkpointNamespace: string[];
|
|
42
45
|
skipDoneTasks: boolean;
|
|
43
46
|
isNested: boolean;
|
|
47
|
+
manager?: CallbackManagerForChainRun;
|
|
44
48
|
stream: IterableReadableWritableStream;
|
|
45
49
|
store?: AsyncBatchedStore;
|
|
46
50
|
prevCheckpointConfig: RunnableConfig | undefined;
|
|
51
|
+
interruptAfter: string[] | All;
|
|
52
|
+
interruptBefore: string[] | All;
|
|
53
|
+
debug: boolean;
|
|
47
54
|
};
|
|
48
|
-
export declare class IterableReadableWritableStream extends IterableReadableStream<StreamChunk> {
|
|
49
|
-
modes: Set<StreamMode>;
|
|
50
|
-
private controller;
|
|
51
|
-
private passthroughFn?;
|
|
52
|
-
constructor(params: {
|
|
53
|
-
passthroughFn?: (chunk: StreamChunk) => void;
|
|
54
|
-
modes: Set<StreamMode>;
|
|
55
|
-
});
|
|
56
|
-
push(chunk: StreamChunk): void;
|
|
57
|
-
close(): void;
|
|
58
|
-
error(e: any): void;
|
|
59
|
-
}
|
|
60
55
|
export declare class PregelLoop {
|
|
61
56
|
protected input?: any | Command;
|
|
62
57
|
output: any;
|
|
@@ -85,6 +80,11 @@ export declare class PregelLoop {
|
|
|
85
80
|
isNested: boolean;
|
|
86
81
|
protected _checkpointerChainedPromise: Promise<unknown>;
|
|
87
82
|
store?: AsyncBatchedStore;
|
|
83
|
+
manager?: CallbackManagerForChainRun;
|
|
84
|
+
interruptAfter: string[] | All;
|
|
85
|
+
interruptBefore: string[] | All;
|
|
86
|
+
toInterrupt: PregelExecutableTask<string, string>[];
|
|
87
|
+
debug: boolean;
|
|
88
88
|
constructor(params: PregelLoopParams);
|
|
89
89
|
static initialize(params: PregelLoopInitializeParams): Promise<PregelLoop>;
|
|
90
90
|
protected _checkpointerPutAfterPrevious(input: {
|
|
@@ -108,19 +108,13 @@ export declare class PregelLoop {
|
|
|
108
108
|
*/
|
|
109
109
|
tick(params: {
|
|
110
110
|
inputKeys?: string | string[];
|
|
111
|
-
interruptAfter: string[] | All;
|
|
112
|
-
interruptBefore: string[] | All;
|
|
113
|
-
manager?: CallbackManagerForChainRun;
|
|
114
111
|
}): Promise<boolean>;
|
|
115
112
|
finishAndHandleError(error?: Error): Promise<boolean>;
|
|
113
|
+
acceptPush(task: PregelExecutableTask<string, string>, writeIdx: number, call?: Call): PregelExecutableTask<string, string> | void;
|
|
116
114
|
protected _suppressInterrupt(e?: Error): boolean;
|
|
117
|
-
/**
|
|
118
|
-
* Resuming from previous checkpoint requires
|
|
119
|
-
* - finding a previous checkpoint
|
|
120
|
-
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
121
|
-
*/
|
|
122
115
|
protected _first(inputKeys: string | string[]): Promise<void>;
|
|
123
116
|
protected _emit(values: [StreamMode, unknown][]): void;
|
|
124
117
|
protected _putCheckpoint(inputMetadata: Omit<CheckpointMetadata, "step" | "parents">): Promise<void>;
|
|
118
|
+
protected _matchWrites(tasks: Record<string, PregelExecutableTask<string, string>>): void;
|
|
125
119
|
}
|
|
126
120
|
export {};
|
package/dist/pregel/loop.js
CHANGED
|
@@ -1,70 +1,16 @@
|
|
|
1
|
-
import { IterableReadableStream } from "@langchain/core/utils/stream";
|
|
2
1
|
import { copyCheckpoint, emptyCheckpoint, AsyncBatchedStore, WRITES_IDX_MAP, } from "@langchain/langgraph-checkpoint";
|
|
3
2
|
import { createCheckpoint, emptyChannels, } from "../channels/base.js";
|
|
4
|
-
import { isCommand, CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, NULL_TASK_ID, RESUME, TAG_HIDDEN, } from "../constants.js";
|
|
5
|
-
import { _applyWrites, _prepareNextTasks, increment, shouldInterrupt, } from "./algo.js";
|
|
3
|
+
import { isCommand, CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, NULL_TASK_ID, RESUME, TAG_HIDDEN, PUSH, CONFIG_KEY_SCRATCHPAD, } from "../constants.js";
|
|
4
|
+
import { _applyWrites, _prepareNextTasks, _prepareSingleTask, increment, shouldInterrupt, } from "./algo.js";
|
|
6
5
|
import { gatherIterator, gatherIteratorSync, prefixGenerator, } from "../utils.js";
|
|
7
6
|
import { mapCommand, mapInput, mapOutputUpdates, mapOutputValues, readChannels, } from "./io.js";
|
|
8
7
|
import { getSubgraphsSeenSet, EmptyInputError, GraphInterrupt, isGraphInterrupt, MultipleSubgraphsError, } from "../errors.js";
|
|
9
8
|
import { getNewChannelVersions, patchConfigurable } from "./utils/index.js";
|
|
10
|
-
import { mapDebugTasks, mapDebugCheckpoint, mapDebugTaskResults, } from "./debug.js";
|
|
9
|
+
import { mapDebugTasks, mapDebugCheckpoint, mapDebugTaskResults, printStepTasks, } from "./debug.js";
|
|
10
|
+
import { IterableReadableWritableStream } from "./stream.js";
|
|
11
11
|
const INPUT_DONE = Symbol.for("INPUT_DONE");
|
|
12
12
|
const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
|
|
13
13
|
const DEFAULT_LOOP_LIMIT = 25;
|
|
14
|
-
export class IterableReadableWritableStream extends IterableReadableStream {
|
|
15
|
-
constructor(params) {
|
|
16
|
-
let streamControllerPromiseResolver;
|
|
17
|
-
const streamControllerPromise = new Promise((resolve) => {
|
|
18
|
-
streamControllerPromiseResolver = resolve;
|
|
19
|
-
});
|
|
20
|
-
super({
|
|
21
|
-
start: (controller) => {
|
|
22
|
-
streamControllerPromiseResolver(controller);
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
Object.defineProperty(this, "modes", {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
configurable: true,
|
|
28
|
-
writable: true,
|
|
29
|
-
value: void 0
|
|
30
|
-
});
|
|
31
|
-
Object.defineProperty(this, "controller", {
|
|
32
|
-
enumerable: true,
|
|
33
|
-
configurable: true,
|
|
34
|
-
writable: true,
|
|
35
|
-
value: void 0
|
|
36
|
-
});
|
|
37
|
-
Object.defineProperty(this, "passthroughFn", {
|
|
38
|
-
enumerable: true,
|
|
39
|
-
configurable: true,
|
|
40
|
-
writable: true,
|
|
41
|
-
value: void 0
|
|
42
|
-
});
|
|
43
|
-
// .start() will always be called before the stream can be interacted
|
|
44
|
-
// with anyway
|
|
45
|
-
void streamControllerPromise.then((controller) => {
|
|
46
|
-
this.controller = controller;
|
|
47
|
-
});
|
|
48
|
-
this.passthroughFn = params.passthroughFn;
|
|
49
|
-
this.modes = params.modes;
|
|
50
|
-
}
|
|
51
|
-
push(chunk) {
|
|
52
|
-
this.passthroughFn?.(chunk);
|
|
53
|
-
this.controller.enqueue(chunk);
|
|
54
|
-
}
|
|
55
|
-
close() {
|
|
56
|
-
try {
|
|
57
|
-
this.controller.close();
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
// pass
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
-
error(e) {
|
|
65
|
-
this.controller.error(e);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
14
|
function createDuplexStream(...streams) {
|
|
69
15
|
return new IterableReadableWritableStream({
|
|
70
16
|
passthroughFn: (value) => {
|
|
@@ -245,6 +191,36 @@ export class PregelLoop {
|
|
|
245
191
|
writable: true,
|
|
246
192
|
value: void 0
|
|
247
193
|
});
|
|
194
|
+
Object.defineProperty(this, "manager", {
|
|
195
|
+
enumerable: true,
|
|
196
|
+
configurable: true,
|
|
197
|
+
writable: true,
|
|
198
|
+
value: void 0
|
|
199
|
+
});
|
|
200
|
+
Object.defineProperty(this, "interruptAfter", {
|
|
201
|
+
enumerable: true,
|
|
202
|
+
configurable: true,
|
|
203
|
+
writable: true,
|
|
204
|
+
value: void 0
|
|
205
|
+
});
|
|
206
|
+
Object.defineProperty(this, "interruptBefore", {
|
|
207
|
+
enumerable: true,
|
|
208
|
+
configurable: true,
|
|
209
|
+
writable: true,
|
|
210
|
+
value: void 0
|
|
211
|
+
});
|
|
212
|
+
Object.defineProperty(this, "toInterrupt", {
|
|
213
|
+
enumerable: true,
|
|
214
|
+
configurable: true,
|
|
215
|
+
writable: true,
|
|
216
|
+
value: []
|
|
217
|
+
});
|
|
218
|
+
Object.defineProperty(this, "debug", {
|
|
219
|
+
enumerable: true,
|
|
220
|
+
configurable: true,
|
|
221
|
+
writable: true,
|
|
222
|
+
value: false
|
|
223
|
+
});
|
|
248
224
|
this.input = params.input;
|
|
249
225
|
this.checkpointer = params.checkpointer;
|
|
250
226
|
// TODO: if managed values no longer needs graph we can replace with
|
|
@@ -266,6 +242,7 @@ export class PregelLoop {
|
|
|
266
242
|
this.config = params.config;
|
|
267
243
|
this.checkpointConfig = params.checkpointConfig;
|
|
268
244
|
this.isNested = params.isNested;
|
|
245
|
+
this.manager = params.manager;
|
|
269
246
|
this.outputKeys = params.outputKeys;
|
|
270
247
|
this.streamKeys = params.streamKeys;
|
|
271
248
|
this.nodes = params.nodes;
|
|
@@ -274,6 +251,9 @@ export class PregelLoop {
|
|
|
274
251
|
this.stream = params.stream;
|
|
275
252
|
this.checkpointNamespace = params.checkpointNamespace;
|
|
276
253
|
this.prevCheckpointConfig = params.prevCheckpointConfig;
|
|
254
|
+
this.interruptAfter = params.interruptAfter;
|
|
255
|
+
this.interruptBefore = params.interruptBefore;
|
|
256
|
+
this.debug = params.debug;
|
|
277
257
|
}
|
|
278
258
|
static async initialize(params) {
|
|
279
259
|
let { config, stream } = params;
|
|
@@ -364,6 +344,7 @@ export class PregelLoop {
|
|
|
364
344
|
channels,
|
|
365
345
|
managed: params.managed,
|
|
366
346
|
isNested,
|
|
347
|
+
manager: params.manager,
|
|
367
348
|
skipDoneTasks,
|
|
368
349
|
step,
|
|
369
350
|
stop,
|
|
@@ -374,6 +355,9 @@ export class PregelLoop {
|
|
|
374
355
|
nodes: params.nodes,
|
|
375
356
|
stream,
|
|
376
357
|
store,
|
|
358
|
+
interruptAfter: params.interruptAfter,
|
|
359
|
+
interruptBefore: params.interruptBefore,
|
|
360
|
+
debug: params.debug,
|
|
377
361
|
});
|
|
378
362
|
}
|
|
379
363
|
_checkpointerPutAfterPrevious(input) {
|
|
@@ -454,7 +438,7 @@ export class PregelLoop {
|
|
|
454
438
|
if (this.store && !this.store.isRunning) {
|
|
455
439
|
this.store?.start();
|
|
456
440
|
}
|
|
457
|
-
const { inputKeys = []
|
|
441
|
+
const { inputKeys = [] } = params;
|
|
458
442
|
if (this.status !== "pending") {
|
|
459
443
|
throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
|
|
460
444
|
}
|
|
@@ -478,7 +462,7 @@ export class PregelLoop {
|
|
|
478
462
|
writes: mapOutputUpdates(this.outputKeys, Object.values(this.tasks).map((task) => [task, task.writes])).next().value ?? null,
|
|
479
463
|
});
|
|
480
464
|
// after execution, check if we should interrupt
|
|
481
|
-
if (shouldInterrupt(this.checkpoint, interruptAfter, Object.values(this.tasks))) {
|
|
465
|
+
if (shouldInterrupt(this.checkpoint, this.interruptAfter, Object.values(this.tasks))) {
|
|
482
466
|
this.status = "interrupt_after";
|
|
483
467
|
throw new GraphInterrupt();
|
|
484
468
|
}
|
|
@@ -494,8 +478,9 @@ export class PregelLoop {
|
|
|
494
478
|
step: this.step,
|
|
495
479
|
checkpointer: this.checkpointer,
|
|
496
480
|
isResuming: this.input === INPUT_RESUMING,
|
|
497
|
-
manager,
|
|
481
|
+
manager: this.manager,
|
|
498
482
|
store: this.store,
|
|
483
|
+
stream: this.stream,
|
|
499
484
|
});
|
|
500
485
|
this.tasks = nextTasks;
|
|
501
486
|
// Produce debug output
|
|
@@ -526,15 +511,10 @@ export class PregelLoop {
|
|
|
526
511
|
}
|
|
527
512
|
// if all tasks have finished, re-tick
|
|
528
513
|
if (Object.values(this.tasks).every((task) => task.writes.length > 0)) {
|
|
529
|
-
return this.tick({
|
|
530
|
-
inputKeys,
|
|
531
|
-
interruptAfter,
|
|
532
|
-
interruptBefore,
|
|
533
|
-
manager,
|
|
534
|
-
});
|
|
514
|
+
return this.tick({ inputKeys });
|
|
535
515
|
}
|
|
536
516
|
// Before execution, check if we should interrupt
|
|
537
|
-
if (shouldInterrupt(this.checkpoint, interruptBefore, Object.values(this.tasks))) {
|
|
517
|
+
if (shouldInterrupt(this.checkpoint, this.interruptBefore, Object.values(this.tasks))) {
|
|
538
518
|
this.status = "interrupt_before";
|
|
539
519
|
throw new GraphInterrupt();
|
|
540
520
|
}
|
|
@@ -571,20 +551,59 @@ export class PregelLoop {
|
|
|
571
551
|
}
|
|
572
552
|
return suppress;
|
|
573
553
|
}
|
|
554
|
+
acceptPush(task, writeIdx, call) {
|
|
555
|
+
if (this.interruptAfter?.length > 0 &&
|
|
556
|
+
shouldInterrupt(this.checkpoint, this.interruptAfter, [task])) {
|
|
557
|
+
this.toInterrupt.push(task);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const pushed = _prepareSingleTask([PUSH, task.path ?? [], writeIdx, task.id, call], this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.managed, this.config, true, {
|
|
561
|
+
step: this.step,
|
|
562
|
+
checkpointer: this.checkpointer,
|
|
563
|
+
manager: this.manager,
|
|
564
|
+
store: this.store,
|
|
565
|
+
stream: this.stream,
|
|
566
|
+
});
|
|
567
|
+
if (pushed) {
|
|
568
|
+
if (this.interruptBefore?.length > 0 &&
|
|
569
|
+
shouldInterrupt(this.checkpoint, this.interruptBefore, [pushed])) {
|
|
570
|
+
this.toInterrupt.push(pushed);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
this._emit(gatherIteratorSync(prefixGenerator(mapDebugTasks(this.step, [pushed]), "debug")));
|
|
574
|
+
if (this.debug) {
|
|
575
|
+
printStepTasks(this.step, [pushed]);
|
|
576
|
+
}
|
|
577
|
+
this.tasks[pushed.id] = pushed;
|
|
578
|
+
if (this.skipDoneTasks) {
|
|
579
|
+
this._matchWrites({ [pushed.id]: pushed });
|
|
580
|
+
}
|
|
581
|
+
return pushed;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
574
584
|
_suppressInterrupt(e) {
|
|
575
585
|
return isGraphInterrupt(e) && !this.isNested;
|
|
576
586
|
}
|
|
577
|
-
/**
|
|
578
|
-
* Resuming from previous checkpoint requires
|
|
579
|
-
* - finding a previous checkpoint
|
|
580
|
-
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
581
|
-
*/
|
|
582
587
|
async _first(inputKeys) {
|
|
588
|
+
/*
|
|
589
|
+
* Resuming from previous checkpoint requires
|
|
590
|
+
* - finding a previous checkpoint
|
|
591
|
+
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
592
|
+
*/
|
|
593
|
+
const { configurable } = this.config;
|
|
583
594
|
const isResuming = Object.keys(this.checkpoint.channel_versions).length !== 0 &&
|
|
584
595
|
(this.config.configurable?.[CONFIG_KEY_RESUMING] !== undefined ||
|
|
585
596
|
this.input === null ||
|
|
586
597
|
isCommand(this.input));
|
|
598
|
+
// take resume value from parent
|
|
599
|
+
const scratchpad = configurable?.[CONFIG_KEY_SCRATCHPAD];
|
|
600
|
+
if (scratchpad && scratchpad.nullResume !== undefined) {
|
|
601
|
+
this.putWrites(NULL_TASK_ID, [[RESUME, scratchpad.nullResume]]);
|
|
602
|
+
}
|
|
587
603
|
if (isCommand(this.input)) {
|
|
604
|
+
if (this.input.resume != null && this.checkpointer == null) {
|
|
605
|
+
throw new Error("Cannot use Command(resume=...) without checkpointer");
|
|
606
|
+
}
|
|
588
607
|
const writes = {};
|
|
589
608
|
// group writes by task id
|
|
590
609
|
for (const [tid, key, value] of mapCommand(this.input, this.checkpointPendingWrites)) {
|
|
@@ -649,10 +668,10 @@ export class PregelLoop {
|
|
|
649
668
|
});
|
|
650
669
|
}
|
|
651
670
|
// done with input
|
|
652
|
-
this.input =
|
|
671
|
+
this.input = this.input === INPUT_RESUMING ? INPUT_RESUMING : INPUT_DONE;
|
|
653
672
|
if (!this.isNested) {
|
|
654
673
|
this.config = patchConfigurable(this.config, {
|
|
655
|
-
[CONFIG_KEY_RESUMING]:
|
|
674
|
+
[CONFIG_KEY_RESUMING]: this.input === INPUT_RESUMING,
|
|
656
675
|
});
|
|
657
676
|
}
|
|
658
677
|
}
|
|
@@ -713,4 +732,20 @@ export class PregelLoop {
|
|
|
713
732
|
}
|
|
714
733
|
this.step += 1;
|
|
715
734
|
}
|
|
735
|
+
_matchWrites(tasks) {
|
|
736
|
+
for (const [tid, k, v] of this.checkpointPendingWrites) {
|
|
737
|
+
if (k === ERROR || k === INTERRUPT || k === RESUME) {
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
const task = Object.values(tasks).find((t) => t.id === tid);
|
|
741
|
+
if (task) {
|
|
742
|
+
task.writes.push([k, v]);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
for (const task of Object.values(tasks)) {
|
|
746
|
+
if (task.writes.length > 0) {
|
|
747
|
+
this._outputWrites(task.id, task.writes, true);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
716
751
|
}
|
|
@@ -3,7 +3,7 @@ import { BaseMessage } from "@langchain/core/messages";
|
|
|
3
3
|
import { Serialized } from "@langchain/core/load/serializable";
|
|
4
4
|
import { LLMResult } from "@langchain/core/outputs";
|
|
5
5
|
import { ChainValues } from "@langchain/core/utils/types";
|
|
6
|
-
import { StreamChunk } from "./
|
|
6
|
+
import { StreamChunk } from "./stream.js";
|
|
7
7
|
type Meta = [string[], Record<string, any>];
|
|
8
8
|
/**
|
|
9
9
|
* A callback handler that implements stream_mode=messages.
|