@langchain/langgraph 0.3.11 → 0.4.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/CHANGELOG.md +27 -0
- package/dist/channels/base.cjs +1 -2
- package/dist/channels/base.js +1 -2
- package/dist/channels/base.js.map +1 -1
- package/dist/channels/topic.cjs +5 -5
- package/dist/channels/topic.js +5 -5
- package/dist/channels/topic.js.map +1 -1
- package/dist/constants.cjs +3 -3
- package/dist/constants.d.ts +2 -5
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/graph/annotation.cjs +1 -5
- package/dist/graph/annotation.d.ts +4 -5
- package/dist/graph/annotation.js +1 -5
- package/dist/graph/annotation.js.map +1 -1
- package/dist/graph/graph.cjs +1 -3
- package/dist/graph/graph.d.ts +3 -3
- package/dist/graph/graph.js +1 -3
- package/dist/graph/graph.js.map +1 -1
- package/dist/graph/state.cjs +6 -10
- package/dist/graph/state.d.ts +8 -8
- package/dist/graph/state.js +7 -11
- package/dist/graph/state.js.map +1 -1
- package/dist/interrupt.cjs +2 -13
- package/dist/interrupt.js +2 -13
- package/dist/interrupt.js.map +1 -1
- package/dist/prebuilt/agent_executor.d.ts +22 -1
- package/dist/prebuilt/agent_executor.js.map +1 -1
- package/dist/pregel/algo.cjs +42 -71
- package/dist/pregel/algo.d.ts +9 -10
- package/dist/pregel/algo.js +42 -71
- package/dist/pregel/algo.js.map +1 -1
- package/dist/pregel/index.cjs +56 -92
- package/dist/pregel/index.d.ts +12 -30
- package/dist/pregel/index.js +57 -93
- package/dist/pregel/index.js.map +1 -1
- package/dist/pregel/loop.cjs +25 -86
- package/dist/pregel/loop.d.ts +5 -11
- package/dist/pregel/loop.js +25 -86
- package/dist/pregel/loop.js.map +1 -1
- package/dist/pregel/remote.cjs +5 -1
- package/dist/pregel/remote.d.ts +9 -12
- package/dist/pregel/remote.js +5 -1
- package/dist/pregel/remote.js.map +1 -1
- package/dist/pregel/runnable_types.d.ts +15 -2
- package/dist/pregel/types.d.ts +23 -10
- package/dist/pregel/types.js.map +1 -1
- package/dist/pregel/utils/config.cjs +2 -0
- package/dist/pregel/utils/config.js +2 -0
- package/dist/pregel/utils/config.js.map +1 -1
- package/dist/pregel/validate.d.ts +2 -3
- package/dist/pregel/validate.js.map +1 -1
- package/dist/web.cjs +0 -1
- package/dist/web.d.ts +1 -2
- package/dist/web.js +0 -1
- package/dist/web.js.map +1 -1
- package/package.json +7 -6
- package/dist/managed/base.cjs +0 -177
- package/dist/managed/base.d.ts +0 -38
- package/dist/managed/base.js +0 -168
- package/dist/managed/base.js.map +0 -1
- package/dist/managed/index.cjs +0 -20
- package/dist/managed/index.d.ts +0 -3
- package/dist/managed/index.js +0 -4
- package/dist/managed/index.js.map +0 -1
- package/dist/managed/is_last_step.cjs +0 -12
- package/dist/managed/is_last_step.d.ts +0 -4
- package/dist/managed/is_last_step.js +0 -8
- package/dist/managed/is_last_step.js.map +0 -1
- package/dist/managed/shared_value.cjs +0 -112
- package/dist/managed/shared_value.d.ts +0 -24
- package/dist/managed/shared_value.js +0 -108
- package/dist/managed/shared_value.js.map +0 -1
package/dist/pregel/loop.cjs
CHANGED
|
@@ -124,12 +124,6 @@ class PregelLoop {
|
|
|
124
124
|
writable: true,
|
|
125
125
|
value: void 0
|
|
126
126
|
});
|
|
127
|
-
Object.defineProperty(this, "managed", {
|
|
128
|
-
enumerable: true,
|
|
129
|
-
configurable: true,
|
|
130
|
-
writable: true,
|
|
131
|
-
value: void 0
|
|
132
|
-
});
|
|
133
127
|
Object.defineProperty(this, "checkpoint", {
|
|
134
128
|
enumerable: true,
|
|
135
129
|
configurable: true,
|
|
@@ -184,7 +178,7 @@ class PregelLoop {
|
|
|
184
178
|
writable: true,
|
|
185
179
|
value: void 0
|
|
186
180
|
});
|
|
187
|
-
Object.defineProperty(this, "
|
|
181
|
+
Object.defineProperty(this, "durability", {
|
|
188
182
|
enumerable: true,
|
|
189
183
|
configurable: true,
|
|
190
184
|
writable: true,
|
|
@@ -220,12 +214,6 @@ class PregelLoop {
|
|
|
220
214
|
writable: true,
|
|
221
215
|
value: void 0
|
|
222
216
|
});
|
|
223
|
-
Object.defineProperty(this, "prevCheckpoint", {
|
|
224
|
-
enumerable: true,
|
|
225
|
-
configurable: true,
|
|
226
|
-
writable: true,
|
|
227
|
-
value: void 0
|
|
228
|
-
});
|
|
229
217
|
Object.defineProperty(this, "status", {
|
|
230
218
|
enumerable: true,
|
|
231
219
|
configurable: true,
|
|
@@ -326,7 +314,6 @@ class PregelLoop {
|
|
|
326
314
|
this.checkpointMetadata = params.checkpointMetadata;
|
|
327
315
|
this.checkpointPreviousVersions = params.checkpointPreviousVersions;
|
|
328
316
|
this.channels = params.channels;
|
|
329
|
-
this.managed = params.managed;
|
|
330
317
|
this.checkpointPendingWrites = params.checkpointPendingWrites;
|
|
331
318
|
this.step = params.step;
|
|
332
319
|
this.stop = params.stop;
|
|
@@ -345,7 +332,7 @@ class PregelLoop {
|
|
|
345
332
|
this.prevCheckpointConfig = params.prevCheckpointConfig;
|
|
346
333
|
this.interruptAfter = params.interruptAfter;
|
|
347
334
|
this.interruptBefore = params.interruptBefore;
|
|
348
|
-
this.
|
|
335
|
+
this.durability = params.durability;
|
|
349
336
|
this.debug = params.debug;
|
|
350
337
|
this.triggerToNodes = params.triggerToNodes;
|
|
351
338
|
}
|
|
@@ -390,12 +377,7 @@ class PregelLoop {
|
|
|
390
377
|
const saved = (await params.checkpointer?.getTuple(checkpointConfig)) ?? {
|
|
391
378
|
config,
|
|
392
379
|
checkpoint: (0, langgraph_checkpoint_1.emptyCheckpoint)(),
|
|
393
|
-
metadata: {
|
|
394
|
-
source: "input",
|
|
395
|
-
step: -2,
|
|
396
|
-
writes: null,
|
|
397
|
-
parents: {},
|
|
398
|
-
},
|
|
380
|
+
metadata: { source: "input", step: -2, parents: {} },
|
|
399
381
|
pendingWrites: [],
|
|
400
382
|
};
|
|
401
383
|
checkpointConfig = {
|
|
@@ -420,7 +402,7 @@ class PregelLoop {
|
|
|
420
402
|
: undefined;
|
|
421
403
|
if (store) {
|
|
422
404
|
// Start the store. This is a batch store, so it will run continuously
|
|
423
|
-
store.start();
|
|
405
|
+
await store.start();
|
|
424
406
|
}
|
|
425
407
|
return new PregelLoop({
|
|
426
408
|
input: params.input,
|
|
@@ -432,7 +414,6 @@ class PregelLoop {
|
|
|
432
414
|
prevCheckpointConfig,
|
|
433
415
|
checkpointNamespace,
|
|
434
416
|
channels,
|
|
435
|
-
managed: params.managed,
|
|
436
417
|
isNested,
|
|
437
418
|
manager: params.manager,
|
|
438
419
|
skipDoneTasks,
|
|
@@ -448,7 +429,7 @@ class PregelLoop {
|
|
|
448
429
|
cache: params.cache,
|
|
449
430
|
interruptAfter: params.interruptAfter,
|
|
450
431
|
interruptBefore: params.interruptBefore,
|
|
451
|
-
|
|
432
|
+
durability: params.durability,
|
|
452
433
|
debug: params.debug,
|
|
453
434
|
triggerToNodes: params.triggerToNodes,
|
|
454
435
|
});
|
|
@@ -459,13 +440,6 @@ class PregelLoop {
|
|
|
459
440
|
});
|
|
460
441
|
this.checkpointerPromises.push(this._checkpointerChainedPromise);
|
|
461
442
|
}
|
|
462
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
463
|
-
async updateManagedValues(key, values) {
|
|
464
|
-
const mv = this.managed.get(key);
|
|
465
|
-
if (mv && "update" in mv && typeof mv.update === "function") {
|
|
466
|
-
await mv.update(values);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
443
|
/**
|
|
470
444
|
* Put writes for a task, to be read by the next tick.
|
|
471
445
|
* @param taskId
|
|
@@ -485,16 +459,12 @@ class PregelLoop {
|
|
|
485
459
|
for (const [c, v] of writesCopy) {
|
|
486
460
|
this.checkpointPendingWrites.push([taskId, c, v]);
|
|
487
461
|
}
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
},
|
|
495
|
-
}, writesCopy, taskId);
|
|
496
|
-
if (putWritePromise !== undefined) {
|
|
497
|
-
this.checkpointerPromises.push(putWritePromise);
|
|
462
|
+
const config = (0, index_js_1.patchConfigurable)(this.checkpointConfig, {
|
|
463
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINT_NS]: this.config.configurable?.checkpoint_ns ?? "",
|
|
464
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINT_ID]: this.checkpoint.id,
|
|
465
|
+
});
|
|
466
|
+
if (this.durability !== "exit" && this.checkpointer != null) {
|
|
467
|
+
this.checkpointerPromises.push(this.checkpointer.putWrites(config, writesCopy, taskId));
|
|
498
468
|
}
|
|
499
469
|
if (this.tasks) {
|
|
500
470
|
this._outputWrites(taskId, writesCopy);
|
|
@@ -585,7 +555,7 @@ class PregelLoop {
|
|
|
585
555
|
*/
|
|
586
556
|
async tick(params) {
|
|
587
557
|
if (this.store && !this.store.isRunning) {
|
|
588
|
-
this.store?.start();
|
|
558
|
+
await this.store?.start();
|
|
589
559
|
}
|
|
590
560
|
const { inputKeys = [] } = params;
|
|
591
561
|
if (this.status !== "pending") {
|
|
@@ -602,19 +572,13 @@ class PregelLoop {
|
|
|
602
572
|
// finish superstep
|
|
603
573
|
const writes = Object.values(this.tasks).flatMap((t) => t.writes);
|
|
604
574
|
// All tasks have finished
|
|
605
|
-
|
|
606
|
-
for (const [key, values] of Object.entries(managedValueWrites)) {
|
|
607
|
-
await this.updateManagedValues(key, values);
|
|
608
|
-
}
|
|
575
|
+
(0, algo_js_1._applyWrites)(this.checkpoint, this.channels, Object.values(this.tasks), this.checkpointerGetNextVersion, this.triggerToNodes);
|
|
609
576
|
// produce values output
|
|
610
577
|
const valuesOutput = await (0, utils_js_1.gatherIterator)((0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputValues)(this.outputKeys, writes, this.channels), "values"));
|
|
611
578
|
this._emit(valuesOutput);
|
|
612
579
|
// clear pending writes
|
|
613
580
|
this.checkpointPendingWrites = [];
|
|
614
|
-
await this._putCheckpoint({
|
|
615
|
-
source: "loop",
|
|
616
|
-
writes: (0, io_js_1.mapOutputUpdates)(this.outputKeys, Object.values(this.tasks).map((task) => [task, task.writes])).next().value ?? null,
|
|
617
|
-
});
|
|
581
|
+
await this._putCheckpoint({ source: "loop" });
|
|
618
582
|
// after execution, check if we should interrupt
|
|
619
583
|
if ((0, algo_js_1.shouldInterrupt)(this.checkpoint, this.interruptAfter, Object.values(this.tasks))) {
|
|
620
584
|
this.status = "interrupt_after";
|
|
@@ -632,7 +596,7 @@ class PregelLoop {
|
|
|
632
596
|
this.status = "out_of_steps";
|
|
633
597
|
return false;
|
|
634
598
|
}
|
|
635
|
-
const nextTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.
|
|
599
|
+
const nextTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.config, true, {
|
|
636
600
|
step: this.step,
|
|
637
601
|
checkpointer: this.checkpointer,
|
|
638
602
|
isResuming: this.isResuming,
|
|
@@ -682,7 +646,7 @@ class PregelLoop {
|
|
|
682
646
|
}
|
|
683
647
|
async finishAndHandleError(error) {
|
|
684
648
|
// persist current checkpoint and writes
|
|
685
|
-
if (
|
|
649
|
+
if (this.durability === "exit" &&
|
|
686
650
|
// if it's a top graph
|
|
687
651
|
(!this.isNested ||
|
|
688
652
|
// or a nested graph with error or interrupt
|
|
@@ -701,10 +665,7 @@ class PregelLoop {
|
|
|
701
665
|
if (this.tasks !== undefined &&
|
|
702
666
|
this.checkpointPendingWrites.length > 0 &&
|
|
703
667
|
Object.values(this.tasks).some((task) => task.writes.length > 0)) {
|
|
704
|
-
|
|
705
|
-
for (const [key, values] of Object.entries(managedValueWrites)) {
|
|
706
|
-
await this.updateManagedValues(key, values);
|
|
707
|
-
}
|
|
668
|
+
(0, algo_js_1._applyWrites)(this.checkpoint, this.channels, Object.values(this.tasks), this.checkpointerGetNextVersion, this.triggerToNodes);
|
|
708
669
|
this._emit((0, utils_js_1.gatherIteratorSync)((0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputValues)(this.outputKeys, Object.values(this.tasks).flatMap((t) => t.writes), this.channels), "values")));
|
|
709
670
|
}
|
|
710
671
|
// Emit INTERRUPT event
|
|
@@ -723,7 +684,7 @@ class PregelLoop {
|
|
|
723
684
|
this.toInterrupt.push(task);
|
|
724
685
|
return;
|
|
725
686
|
}
|
|
726
|
-
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,
|
|
687
|
+
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, task.config ?? {}, true, {
|
|
727
688
|
step: this.step,
|
|
728
689
|
checkpointer: this.checkpointer,
|
|
729
690
|
manager: this.manager,
|
|
@@ -825,14 +786,14 @@ class PregelLoop {
|
|
|
825
786
|
// we need to create a new checkpoint for Command(update=...) or Command(goto=...)
|
|
826
787
|
// in case the result of Command(goto=...) is an interrupt.
|
|
827
788
|
// If not done, the checkpoint containing the interrupt will be lost.
|
|
828
|
-
await this._putCheckpoint({ source: "input"
|
|
789
|
+
await this._putCheckpoint({ source: "input" });
|
|
829
790
|
this.input = INPUT_DONE;
|
|
830
791
|
}
|
|
831
792
|
else {
|
|
832
793
|
// map inputs to channel updates
|
|
833
794
|
const inputWrites = await (0, utils_js_1.gatherIterator)((0, io_js_1.mapInput)(inputKeys, this.input));
|
|
834
795
|
if (inputWrites.length > 0) {
|
|
835
|
-
const discardTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.
|
|
796
|
+
const discardTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.config, true, { step: this.step });
|
|
836
797
|
(0, algo_js_1._applyWrites)(this.checkpoint, this.channels, Object.values(discardTasks).concat([
|
|
837
798
|
{
|
|
838
799
|
name: constants_js_1.INPUT,
|
|
@@ -841,10 +802,7 @@ class PregelLoop {
|
|
|
841
802
|
},
|
|
842
803
|
]), this.checkpointerGetNextVersion, this.triggerToNodes);
|
|
843
804
|
// save input checkpoint
|
|
844
|
-
await this._putCheckpoint({
|
|
845
|
-
source: "input",
|
|
846
|
-
writes: Object.fromEntries(inputWrites),
|
|
847
|
-
});
|
|
805
|
+
await this._putCheckpoint({ source: "input" });
|
|
848
806
|
this.input = INPUT_DONE;
|
|
849
807
|
}
|
|
850
808
|
else if (!(constants_js_1.CONFIG_KEY_RESUMING in (this.config.configurable ?? {}))) {
|
|
@@ -895,7 +853,7 @@ class PregelLoop {
|
|
|
895
853
|
}
|
|
896
854
|
_putCheckpoint(inputMetadata) {
|
|
897
855
|
const exiting = this.checkpointMetadata === inputMetadata;
|
|
898
|
-
const doCheckpoint = this.checkpointer != null && (this.
|
|
856
|
+
const doCheckpoint = this.checkpointer != null && (this.durability !== "exit" || exiting);
|
|
899
857
|
const storeCheckpoint = (checkpoint) => {
|
|
900
858
|
// store the previous checkpoint config for debug events
|
|
901
859
|
this.prevCheckpointConfig = this.checkpointConfig?.configurable
|
|
@@ -906,13 +864,9 @@ class PregelLoop {
|
|
|
906
864
|
// this is achieved by writing child checkpoints as progress is made
|
|
907
865
|
// (so that error recovery / resuming from interrupt don't lose work)
|
|
908
866
|
// but doing so always with an id equal to that of the parent checkpoint
|
|
909
|
-
this.checkpointConfig = {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
...this.checkpointConfig.configurable,
|
|
913
|
-
checkpoint_ns: this.config.configurable?.checkpoint_ns ?? "",
|
|
914
|
-
},
|
|
915
|
-
};
|
|
867
|
+
this.checkpointConfig = (0, index_js_1.patchConfigurable)(this.checkpointConfig, {
|
|
868
|
+
[constants_js_1.CONFIG_KEY_CHECKPOINT_NS]: this.config.configurable?.checkpoint_ns ?? "",
|
|
869
|
+
});
|
|
916
870
|
const channelVersions = { ...this.checkpoint.channel_versions };
|
|
917
871
|
const newVersions = (0, index_js_1.getNewChannelVersions)(this.checkpointPreviousVersions, channelVersions);
|
|
918
872
|
this.checkpointPreviousVersions = channelVersions;
|
|
@@ -933,16 +887,6 @@ class PregelLoop {
|
|
|
933
887
|
},
|
|
934
888
|
};
|
|
935
889
|
};
|
|
936
|
-
// We need to retroactively store the previous checkpoint
|
|
937
|
-
// if it turns out that pending sends are scheduled.
|
|
938
|
-
// TODO: remove when `pending_sends` is removed from checkpoints
|
|
939
|
-
if (!exiting &&
|
|
940
|
-
!this.checkpointDuring &&
|
|
941
|
-
this.checkpointer != null &&
|
|
942
|
-
this.prevCheckpoint != null &&
|
|
943
|
-
this.checkpoint.pending_sends.length > 0) {
|
|
944
|
-
storeCheckpoint(this.prevCheckpoint);
|
|
945
|
-
}
|
|
946
890
|
if (!exiting) {
|
|
947
891
|
this.checkpointMetadata = {
|
|
948
892
|
...inputMetadata,
|
|
@@ -950,11 +894,6 @@ class PregelLoop {
|
|
|
950
894
|
parents: this.config.configurable?.[constants_js_1.CONFIG_KEY_CHECKPOINT_MAP] ?? {},
|
|
951
895
|
};
|
|
952
896
|
}
|
|
953
|
-
// Store previous checkpoint in case pending_sends are scheduled
|
|
954
|
-
// for next checkpoint.
|
|
955
|
-
if (!this.checkpointDuring) {
|
|
956
|
-
this.prevCheckpoint = this.checkpoint;
|
|
957
|
-
}
|
|
958
897
|
// create new checkpoint
|
|
959
898
|
this.checkpoint = (0, base_js_1.createCheckpoint)(this.checkpoint, doCheckpoint ? this.channels : undefined, this.step, exiting ? { id: this.checkpoint.id } : undefined);
|
|
960
899
|
// Bail if no checkpointer
|
package/dist/pregel/loop.d.ts
CHANGED
|
@@ -2,10 +2,9 @@ import type { RunnableConfig } from "@langchain/core/runnables";
|
|
|
2
2
|
import type { CallbackManagerForChainRun } from "@langchain/core/callbacks/manager";
|
|
3
3
|
import { BaseCheckpointSaver, Checkpoint, PendingWrite, CheckpointPendingWrite, CheckpointMetadata, All, BaseStore, AsyncBatchedStore, BaseCache, CacheFullKey, CacheNamespace } from "@langchain/langgraph-checkpoint";
|
|
4
4
|
import { BaseChannel } from "../channels/base.js";
|
|
5
|
-
import { Call, PregelExecutableTask, StreamMode } from "./types.js";
|
|
5
|
+
import type { Call, Durability, PregelExecutableTask, StreamMode } from "./types.js";
|
|
6
6
|
import { Command } from "../constants.js";
|
|
7
7
|
import { PregelNode } from "./read.js";
|
|
8
|
-
import { ManagedValueMapping } from "../managed/base.js";
|
|
9
8
|
import { LangGraphRunnableConfig } from "./runnable_types.js";
|
|
10
9
|
import { IterableReadableWritableStream } from "./stream.js";
|
|
11
10
|
export type PregelLoopInitializeParams = {
|
|
@@ -16,13 +15,12 @@ export type PregelLoopInitializeParams = {
|
|
|
16
15
|
streamKeys: string | string[];
|
|
17
16
|
nodes: Record<string, PregelNode>;
|
|
18
17
|
channelSpecs: Record<string, BaseChannel>;
|
|
19
|
-
managed: ManagedValueMapping;
|
|
20
18
|
stream: IterableReadableWritableStream;
|
|
21
19
|
store?: BaseStore;
|
|
22
20
|
cache?: BaseCache<PendingWrite<string>[]>;
|
|
23
21
|
interruptAfter: string[] | All;
|
|
24
22
|
interruptBefore: string[] | All;
|
|
25
|
-
|
|
23
|
+
durability: Durability;
|
|
26
24
|
manager?: CallbackManagerForChainRun;
|
|
27
25
|
debug: boolean;
|
|
28
26
|
triggerToNodes: Record<string, string[]>;
|
|
@@ -37,7 +35,6 @@ type PregelLoopParams = {
|
|
|
37
35
|
checkpointPendingWrites: CheckpointPendingWrite[];
|
|
38
36
|
checkpointConfig: RunnableConfig;
|
|
39
37
|
channels: Record<string, BaseChannel>;
|
|
40
|
-
managed: ManagedValueMapping;
|
|
41
38
|
step: number;
|
|
42
39
|
stop: number;
|
|
43
40
|
outputKeys: string | string[];
|
|
@@ -53,7 +50,7 @@ type PregelLoopParams = {
|
|
|
53
50
|
prevCheckpointConfig: RunnableConfig | undefined;
|
|
54
51
|
interruptAfter: string[] | All;
|
|
55
52
|
interruptBefore: string[] | All;
|
|
56
|
-
|
|
53
|
+
durability: Durability;
|
|
57
54
|
debug: boolean;
|
|
58
55
|
triggerToNodes: Record<string, string[]>;
|
|
59
56
|
};
|
|
@@ -79,9 +76,8 @@ export declare class PregelLoop {
|
|
|
79
76
|
output: any;
|
|
80
77
|
config: LangGraphRunnableConfig;
|
|
81
78
|
protected checkpointer?: BaseCheckpointSaver;
|
|
82
|
-
protected checkpointerGetNextVersion: (current: number | undefined
|
|
79
|
+
protected checkpointerGetNextVersion: (current: number | undefined) => number;
|
|
83
80
|
channels: Record<string, BaseChannel>;
|
|
84
|
-
managed: ManagedValueMapping;
|
|
85
81
|
protected checkpoint: Checkpoint;
|
|
86
82
|
protected checkpointIdSaved: string | undefined;
|
|
87
83
|
protected checkpointConfig: RunnableConfig;
|
|
@@ -91,13 +87,12 @@ export declare class PregelLoop {
|
|
|
91
87
|
protected checkpointPreviousVersions: Record<string, string | number>;
|
|
92
88
|
step: number;
|
|
93
89
|
protected stop: number;
|
|
94
|
-
protected
|
|
90
|
+
protected durability: Durability;
|
|
95
91
|
protected outputKeys: string | string[];
|
|
96
92
|
protected streamKeys: string | string[];
|
|
97
93
|
protected nodes: Record<string, PregelNode>;
|
|
98
94
|
protected skipDoneTasks: boolean;
|
|
99
95
|
protected prevCheckpointConfig: RunnableConfig | undefined;
|
|
100
|
-
protected prevCheckpoint: Checkpoint | undefined;
|
|
101
96
|
status: "pending" | "done" | "interrupt_before" | "interrupt_after" | "out_of_steps";
|
|
102
97
|
tasks: Record<string, PregelExecutableTask<any, any>>;
|
|
103
98
|
stream: IterableReadableWritableStream;
|
|
@@ -121,7 +116,6 @@ export declare class PregelLoop {
|
|
|
121
116
|
metadata: CheckpointMetadata;
|
|
122
117
|
newVersions: Record<string, string | number>;
|
|
123
118
|
}): void;
|
|
124
|
-
protected updateManagedValues(key: string, values: any[]): Promise<void>;
|
|
125
119
|
/**
|
|
126
120
|
* Put writes for a task, to be read by the next tick.
|
|
127
121
|
* @param taskId
|
package/dist/pregel/loop.js
CHANGED
|
@@ -121,12 +121,6 @@ export class PregelLoop {
|
|
|
121
121
|
writable: true,
|
|
122
122
|
value: void 0
|
|
123
123
|
});
|
|
124
|
-
Object.defineProperty(this, "managed", {
|
|
125
|
-
enumerable: true,
|
|
126
|
-
configurable: true,
|
|
127
|
-
writable: true,
|
|
128
|
-
value: void 0
|
|
129
|
-
});
|
|
130
124
|
Object.defineProperty(this, "checkpoint", {
|
|
131
125
|
enumerable: true,
|
|
132
126
|
configurable: true,
|
|
@@ -181,7 +175,7 @@ export class PregelLoop {
|
|
|
181
175
|
writable: true,
|
|
182
176
|
value: void 0
|
|
183
177
|
});
|
|
184
|
-
Object.defineProperty(this, "
|
|
178
|
+
Object.defineProperty(this, "durability", {
|
|
185
179
|
enumerable: true,
|
|
186
180
|
configurable: true,
|
|
187
181
|
writable: true,
|
|
@@ -217,12 +211,6 @@ export class PregelLoop {
|
|
|
217
211
|
writable: true,
|
|
218
212
|
value: void 0
|
|
219
213
|
});
|
|
220
|
-
Object.defineProperty(this, "prevCheckpoint", {
|
|
221
|
-
enumerable: true,
|
|
222
|
-
configurable: true,
|
|
223
|
-
writable: true,
|
|
224
|
-
value: void 0
|
|
225
|
-
});
|
|
226
214
|
Object.defineProperty(this, "status", {
|
|
227
215
|
enumerable: true,
|
|
228
216
|
configurable: true,
|
|
@@ -323,7 +311,6 @@ export class PregelLoop {
|
|
|
323
311
|
this.checkpointMetadata = params.checkpointMetadata;
|
|
324
312
|
this.checkpointPreviousVersions = params.checkpointPreviousVersions;
|
|
325
313
|
this.channels = params.channels;
|
|
326
|
-
this.managed = params.managed;
|
|
327
314
|
this.checkpointPendingWrites = params.checkpointPendingWrites;
|
|
328
315
|
this.step = params.step;
|
|
329
316
|
this.stop = params.stop;
|
|
@@ -342,7 +329,7 @@ export class PregelLoop {
|
|
|
342
329
|
this.prevCheckpointConfig = params.prevCheckpointConfig;
|
|
343
330
|
this.interruptAfter = params.interruptAfter;
|
|
344
331
|
this.interruptBefore = params.interruptBefore;
|
|
345
|
-
this.
|
|
332
|
+
this.durability = params.durability;
|
|
346
333
|
this.debug = params.debug;
|
|
347
334
|
this.triggerToNodes = params.triggerToNodes;
|
|
348
335
|
}
|
|
@@ -387,12 +374,7 @@ export class PregelLoop {
|
|
|
387
374
|
const saved = (await params.checkpointer?.getTuple(checkpointConfig)) ?? {
|
|
388
375
|
config,
|
|
389
376
|
checkpoint: emptyCheckpoint(),
|
|
390
|
-
metadata: {
|
|
391
|
-
source: "input",
|
|
392
|
-
step: -2,
|
|
393
|
-
writes: null,
|
|
394
|
-
parents: {},
|
|
395
|
-
},
|
|
377
|
+
metadata: { source: "input", step: -2, parents: {} },
|
|
396
378
|
pendingWrites: [],
|
|
397
379
|
};
|
|
398
380
|
checkpointConfig = {
|
|
@@ -417,7 +399,7 @@ export class PregelLoop {
|
|
|
417
399
|
: undefined;
|
|
418
400
|
if (store) {
|
|
419
401
|
// Start the store. This is a batch store, so it will run continuously
|
|
420
|
-
store.start();
|
|
402
|
+
await store.start();
|
|
421
403
|
}
|
|
422
404
|
return new PregelLoop({
|
|
423
405
|
input: params.input,
|
|
@@ -429,7 +411,6 @@ export class PregelLoop {
|
|
|
429
411
|
prevCheckpointConfig,
|
|
430
412
|
checkpointNamespace,
|
|
431
413
|
channels,
|
|
432
|
-
managed: params.managed,
|
|
433
414
|
isNested,
|
|
434
415
|
manager: params.manager,
|
|
435
416
|
skipDoneTasks,
|
|
@@ -445,7 +426,7 @@ export class PregelLoop {
|
|
|
445
426
|
cache: params.cache,
|
|
446
427
|
interruptAfter: params.interruptAfter,
|
|
447
428
|
interruptBefore: params.interruptBefore,
|
|
448
|
-
|
|
429
|
+
durability: params.durability,
|
|
449
430
|
debug: params.debug,
|
|
450
431
|
triggerToNodes: params.triggerToNodes,
|
|
451
432
|
});
|
|
@@ -456,13 +437,6 @@ export class PregelLoop {
|
|
|
456
437
|
});
|
|
457
438
|
this.checkpointerPromises.push(this._checkpointerChainedPromise);
|
|
458
439
|
}
|
|
459
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
460
|
-
async updateManagedValues(key, values) {
|
|
461
|
-
const mv = this.managed.get(key);
|
|
462
|
-
if (mv && "update" in mv && typeof mv.update === "function") {
|
|
463
|
-
await mv.update(values);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
440
|
/**
|
|
467
441
|
* Put writes for a task, to be read by the next tick.
|
|
468
442
|
* @param taskId
|
|
@@ -482,16 +456,12 @@ export class PregelLoop {
|
|
|
482
456
|
for (const [c, v] of writesCopy) {
|
|
483
457
|
this.checkpointPendingWrites.push([taskId, c, v]);
|
|
484
458
|
}
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
},
|
|
492
|
-
}, writesCopy, taskId);
|
|
493
|
-
if (putWritePromise !== undefined) {
|
|
494
|
-
this.checkpointerPromises.push(putWritePromise);
|
|
459
|
+
const config = patchConfigurable(this.checkpointConfig, {
|
|
460
|
+
[CONFIG_KEY_CHECKPOINT_NS]: this.config.configurable?.checkpoint_ns ?? "",
|
|
461
|
+
[CONFIG_KEY_CHECKPOINT_ID]: this.checkpoint.id,
|
|
462
|
+
});
|
|
463
|
+
if (this.durability !== "exit" && this.checkpointer != null) {
|
|
464
|
+
this.checkpointerPromises.push(this.checkpointer.putWrites(config, writesCopy, taskId));
|
|
495
465
|
}
|
|
496
466
|
if (this.tasks) {
|
|
497
467
|
this._outputWrites(taskId, writesCopy);
|
|
@@ -582,7 +552,7 @@ export class PregelLoop {
|
|
|
582
552
|
*/
|
|
583
553
|
async tick(params) {
|
|
584
554
|
if (this.store && !this.store.isRunning) {
|
|
585
|
-
this.store?.start();
|
|
555
|
+
await this.store?.start();
|
|
586
556
|
}
|
|
587
557
|
const { inputKeys = [] } = params;
|
|
588
558
|
if (this.status !== "pending") {
|
|
@@ -599,19 +569,13 @@ export class PregelLoop {
|
|
|
599
569
|
// finish superstep
|
|
600
570
|
const writes = Object.values(this.tasks).flatMap((t) => t.writes);
|
|
601
571
|
// All tasks have finished
|
|
602
|
-
|
|
603
|
-
for (const [key, values] of Object.entries(managedValueWrites)) {
|
|
604
|
-
await this.updateManagedValues(key, values);
|
|
605
|
-
}
|
|
572
|
+
_applyWrites(this.checkpoint, this.channels, Object.values(this.tasks), this.checkpointerGetNextVersion, this.triggerToNodes);
|
|
606
573
|
// produce values output
|
|
607
574
|
const valuesOutput = await gatherIterator(prefixGenerator(mapOutputValues(this.outputKeys, writes, this.channels), "values"));
|
|
608
575
|
this._emit(valuesOutput);
|
|
609
576
|
// clear pending writes
|
|
610
577
|
this.checkpointPendingWrites = [];
|
|
611
|
-
await this._putCheckpoint({
|
|
612
|
-
source: "loop",
|
|
613
|
-
writes: mapOutputUpdates(this.outputKeys, Object.values(this.tasks).map((task) => [task, task.writes])).next().value ?? null,
|
|
614
|
-
});
|
|
578
|
+
await this._putCheckpoint({ source: "loop" });
|
|
615
579
|
// after execution, check if we should interrupt
|
|
616
580
|
if (shouldInterrupt(this.checkpoint, this.interruptAfter, Object.values(this.tasks))) {
|
|
617
581
|
this.status = "interrupt_after";
|
|
@@ -629,7 +593,7 @@ export class PregelLoop {
|
|
|
629
593
|
this.status = "out_of_steps";
|
|
630
594
|
return false;
|
|
631
595
|
}
|
|
632
|
-
const nextTasks = _prepareNextTasks(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.
|
|
596
|
+
const nextTasks = _prepareNextTasks(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.config, true, {
|
|
633
597
|
step: this.step,
|
|
634
598
|
checkpointer: this.checkpointer,
|
|
635
599
|
isResuming: this.isResuming,
|
|
@@ -679,7 +643,7 @@ export class PregelLoop {
|
|
|
679
643
|
}
|
|
680
644
|
async finishAndHandleError(error) {
|
|
681
645
|
// persist current checkpoint and writes
|
|
682
|
-
if (
|
|
646
|
+
if (this.durability === "exit" &&
|
|
683
647
|
// if it's a top graph
|
|
684
648
|
(!this.isNested ||
|
|
685
649
|
// or a nested graph with error or interrupt
|
|
@@ -698,10 +662,7 @@ export class PregelLoop {
|
|
|
698
662
|
if (this.tasks !== undefined &&
|
|
699
663
|
this.checkpointPendingWrites.length > 0 &&
|
|
700
664
|
Object.values(this.tasks).some((task) => task.writes.length > 0)) {
|
|
701
|
-
|
|
702
|
-
for (const [key, values] of Object.entries(managedValueWrites)) {
|
|
703
|
-
await this.updateManagedValues(key, values);
|
|
704
|
-
}
|
|
665
|
+
_applyWrites(this.checkpoint, this.channels, Object.values(this.tasks), this.checkpointerGetNextVersion, this.triggerToNodes);
|
|
705
666
|
this._emit(gatherIteratorSync(prefixGenerator(mapOutputValues(this.outputKeys, Object.values(this.tasks).flatMap((t) => t.writes), this.channels), "values")));
|
|
706
667
|
}
|
|
707
668
|
// Emit INTERRUPT event
|
|
@@ -720,7 +681,7 @@ export class PregelLoop {
|
|
|
720
681
|
this.toInterrupt.push(task);
|
|
721
682
|
return;
|
|
722
683
|
}
|
|
723
|
-
const pushed = _prepareSingleTask([PUSH, task.path ?? [], writeIdx, task.id, call], this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels,
|
|
684
|
+
const pushed = _prepareSingleTask([PUSH, task.path ?? [], writeIdx, task.id, call], this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, task.config ?? {}, true, {
|
|
724
685
|
step: this.step,
|
|
725
686
|
checkpointer: this.checkpointer,
|
|
726
687
|
manager: this.manager,
|
|
@@ -822,14 +783,14 @@ export class PregelLoop {
|
|
|
822
783
|
// we need to create a new checkpoint for Command(update=...) or Command(goto=...)
|
|
823
784
|
// in case the result of Command(goto=...) is an interrupt.
|
|
824
785
|
// If not done, the checkpoint containing the interrupt will be lost.
|
|
825
|
-
await this._putCheckpoint({ source: "input"
|
|
786
|
+
await this._putCheckpoint({ source: "input" });
|
|
826
787
|
this.input = INPUT_DONE;
|
|
827
788
|
}
|
|
828
789
|
else {
|
|
829
790
|
// map inputs to channel updates
|
|
830
791
|
const inputWrites = await gatherIterator(mapInput(inputKeys, this.input));
|
|
831
792
|
if (inputWrites.length > 0) {
|
|
832
|
-
const discardTasks = _prepareNextTasks(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.
|
|
793
|
+
const discardTasks = _prepareNextTasks(this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.config, true, { step: this.step });
|
|
833
794
|
_applyWrites(this.checkpoint, this.channels, Object.values(discardTasks).concat([
|
|
834
795
|
{
|
|
835
796
|
name: INPUT,
|
|
@@ -838,10 +799,7 @@ export class PregelLoop {
|
|
|
838
799
|
},
|
|
839
800
|
]), this.checkpointerGetNextVersion, this.triggerToNodes);
|
|
840
801
|
// save input checkpoint
|
|
841
|
-
await this._putCheckpoint({
|
|
842
|
-
source: "input",
|
|
843
|
-
writes: Object.fromEntries(inputWrites),
|
|
844
|
-
});
|
|
802
|
+
await this._putCheckpoint({ source: "input" });
|
|
845
803
|
this.input = INPUT_DONE;
|
|
846
804
|
}
|
|
847
805
|
else if (!(CONFIG_KEY_RESUMING in (this.config.configurable ?? {}))) {
|
|
@@ -892,7 +850,7 @@ export class PregelLoop {
|
|
|
892
850
|
}
|
|
893
851
|
_putCheckpoint(inputMetadata) {
|
|
894
852
|
const exiting = this.checkpointMetadata === inputMetadata;
|
|
895
|
-
const doCheckpoint = this.checkpointer != null && (this.
|
|
853
|
+
const doCheckpoint = this.checkpointer != null && (this.durability !== "exit" || exiting);
|
|
896
854
|
const storeCheckpoint = (checkpoint) => {
|
|
897
855
|
// store the previous checkpoint config for debug events
|
|
898
856
|
this.prevCheckpointConfig = this.checkpointConfig?.configurable
|
|
@@ -903,13 +861,9 @@ export class PregelLoop {
|
|
|
903
861
|
// this is achieved by writing child checkpoints as progress is made
|
|
904
862
|
// (so that error recovery / resuming from interrupt don't lose work)
|
|
905
863
|
// but doing so always with an id equal to that of the parent checkpoint
|
|
906
|
-
this.checkpointConfig = {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
...this.checkpointConfig.configurable,
|
|
910
|
-
checkpoint_ns: this.config.configurable?.checkpoint_ns ?? "",
|
|
911
|
-
},
|
|
912
|
-
};
|
|
864
|
+
this.checkpointConfig = patchConfigurable(this.checkpointConfig, {
|
|
865
|
+
[CONFIG_KEY_CHECKPOINT_NS]: this.config.configurable?.checkpoint_ns ?? "",
|
|
866
|
+
});
|
|
913
867
|
const channelVersions = { ...this.checkpoint.channel_versions };
|
|
914
868
|
const newVersions = getNewChannelVersions(this.checkpointPreviousVersions, channelVersions);
|
|
915
869
|
this.checkpointPreviousVersions = channelVersions;
|
|
@@ -930,16 +884,6 @@ export class PregelLoop {
|
|
|
930
884
|
},
|
|
931
885
|
};
|
|
932
886
|
};
|
|
933
|
-
// We need to retroactively store the previous checkpoint
|
|
934
|
-
// if it turns out that pending sends are scheduled.
|
|
935
|
-
// TODO: remove when `pending_sends` is removed from checkpoints
|
|
936
|
-
if (!exiting &&
|
|
937
|
-
!this.checkpointDuring &&
|
|
938
|
-
this.checkpointer != null &&
|
|
939
|
-
this.prevCheckpoint != null &&
|
|
940
|
-
this.checkpoint.pending_sends.length > 0) {
|
|
941
|
-
storeCheckpoint(this.prevCheckpoint);
|
|
942
|
-
}
|
|
943
887
|
if (!exiting) {
|
|
944
888
|
this.checkpointMetadata = {
|
|
945
889
|
...inputMetadata,
|
|
@@ -947,11 +891,6 @@ export class PregelLoop {
|
|
|
947
891
|
parents: this.config.configurable?.[CONFIG_KEY_CHECKPOINT_MAP] ?? {},
|
|
948
892
|
};
|
|
949
893
|
}
|
|
950
|
-
// Store previous checkpoint in case pending_sends are scheduled
|
|
951
|
-
// for next checkpoint.
|
|
952
|
-
if (!this.checkpointDuring) {
|
|
953
|
-
this.prevCheckpoint = this.checkpoint;
|
|
954
|
-
}
|
|
955
894
|
// create new checkpoint
|
|
956
895
|
this.checkpoint = createCheckpoint(this.checkpoint, doCheckpoint ? this.channels : undefined, this.step, exiting ? { id: this.checkpoint.id } : undefined);
|
|
957
896
|
// Bail if no checkpointer
|