@langchain/langgraph 0.0.15 → 0.0.17
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/checkpoint/base.cjs +9 -1
- package/dist/checkpoint/base.d.ts +6 -4
- package/dist/checkpoint/base.js +6 -0
- package/dist/pregel/index.cjs +12 -10
- package/dist/pregel/index.js +13 -11
- package/dist/pregel/io.cjs +2 -3
- package/dist/pregel/io.js +2 -3
- package/dist/tests/pregel.test.js +27 -0
- package/package.json +1 -1
package/dist/checkpoint/base.cjs
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
|
|
3
|
+
exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = exports.getVersionSeen = exports.getChannelVersion = void 0;
|
|
4
4
|
const base_js_1 = require("../serde/base.cjs");
|
|
5
5
|
const id_js_1 = require("./id.cjs");
|
|
6
|
+
function getChannelVersion(checkpoint, channel) {
|
|
7
|
+
return checkpoint.channel_versions[channel] ?? 0;
|
|
8
|
+
}
|
|
9
|
+
exports.getChannelVersion = getChannelVersion;
|
|
10
|
+
function getVersionSeen(checkpoint, node, channel) {
|
|
11
|
+
return checkpoint.versions_seen[node]?.[channel] ?? 0;
|
|
12
|
+
}
|
|
13
|
+
exports.getVersionSeen = getVersionSeen;
|
|
6
14
|
function deepCopy(obj) {
|
|
7
15
|
if (typeof obj !== "object" || obj === null) {
|
|
8
16
|
return obj;
|
|
@@ -15,7 +15,7 @@ export interface CheckpointMetadata {
|
|
|
15
15
|
* ... for the nth checkpoint afterwards. */
|
|
16
16
|
writes?: Record<string, unknown>;
|
|
17
17
|
}
|
|
18
|
-
export interface Checkpoint {
|
|
18
|
+
export interface Checkpoint<N extends string = string, C extends string = string> {
|
|
19
19
|
/**
|
|
20
20
|
* Version number
|
|
21
21
|
*/
|
|
@@ -31,21 +31,23 @@ export interface Checkpoint {
|
|
|
31
31
|
/**
|
|
32
32
|
* @default {}
|
|
33
33
|
*/
|
|
34
|
-
channel_values: Record<
|
|
34
|
+
channel_values: Record<C, unknown>;
|
|
35
35
|
/**
|
|
36
36
|
* @default {}
|
|
37
37
|
*/
|
|
38
|
-
channel_versions: Record<
|
|
38
|
+
channel_versions: Record<C, number>;
|
|
39
39
|
/**
|
|
40
40
|
* @default {}
|
|
41
41
|
*/
|
|
42
|
-
versions_seen: Record<
|
|
42
|
+
versions_seen: Record<N, Record<C, number>>;
|
|
43
43
|
}
|
|
44
44
|
export interface ReadonlyCheckpoint extends Readonly<Checkpoint> {
|
|
45
45
|
readonly channel_values: Readonly<Record<string, unknown>>;
|
|
46
46
|
readonly channel_versions: Readonly<Record<string, number>>;
|
|
47
47
|
readonly versions_seen: Readonly<Record<string, Readonly<Record<string, number>>>>;
|
|
48
48
|
}
|
|
49
|
+
export declare function getChannelVersion(checkpoint: ReadonlyCheckpoint, channel: string): number;
|
|
50
|
+
export declare function getVersionSeen(checkpoint: ReadonlyCheckpoint, node: string, channel: string): number;
|
|
49
51
|
export declare function deepCopy<T>(obj: T): T;
|
|
50
52
|
export declare function emptyCheckpoint(): Checkpoint;
|
|
51
53
|
export declare function copyCheckpoint(checkpoint: ReadonlyCheckpoint): Checkpoint;
|
package/dist/checkpoint/base.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { DefaultSerializer } from "../serde/base.js";
|
|
2
2
|
import { uuid6 } from "./id.js";
|
|
3
|
+
export function getChannelVersion(checkpoint, channel) {
|
|
4
|
+
return checkpoint.channel_versions[channel] ?? 0;
|
|
5
|
+
}
|
|
6
|
+
export function getVersionSeen(checkpoint, node, channel) {
|
|
7
|
+
return checkpoint.versions_seen[node]?.[channel] ?? 0;
|
|
8
|
+
}
|
|
3
9
|
export function deepCopy(obj) {
|
|
4
10
|
if (typeof obj !== "object" || obj === null) {
|
|
5
11
|
return obj;
|
package/dist/pregel/index.cjs
CHANGED
|
@@ -406,7 +406,10 @@ class Pregel extends runnables_1.Runnable {
|
|
|
406
406
|
else {
|
|
407
407
|
checkpoint = (0, base_js_2.copyCheckpoint)(checkpoint);
|
|
408
408
|
for (const k of this.streamChannelsList) {
|
|
409
|
-
const version = checkpoint.channel_versions[k];
|
|
409
|
+
const version = checkpoint.channel_versions[k] ?? 0;
|
|
410
|
+
if (!checkpoint.versions_seen[constants_js_1.INTERRUPT]) {
|
|
411
|
+
checkpoint.versions_seen[constants_js_1.INTERRUPT] = {};
|
|
412
|
+
}
|
|
410
413
|
checkpoint.versions_seen[constants_js_1.INTERRUPT][k] = version;
|
|
411
414
|
}
|
|
412
415
|
}
|
|
@@ -551,8 +554,8 @@ async function executeTasks(tasks, stepTimeout) {
|
|
|
551
554
|
}
|
|
552
555
|
}
|
|
553
556
|
function _shouldInterrupt(checkpoint, interruptNodes, snapshotChannels, tasks) {
|
|
554
|
-
const
|
|
555
|
-
|
|
557
|
+
const anySnapshotChannelUpdated = snapshotChannels.some((chan) => (0, base_js_2.getChannelVersion)(checkpoint, chan) >
|
|
558
|
+
(0, base_js_2.getVersionSeen)(checkpoint, constants_js_1.INTERRUPT, chan));
|
|
556
559
|
const anyTaskNodeInInterruptNodes = tasks.some((task) => interruptNodes === "*"
|
|
557
560
|
? !task.config?.tags?.includes(constants_js_1.TAG_HIDDEN)
|
|
558
561
|
: interruptNodes.includes(task.name));
|
|
@@ -627,11 +630,6 @@ function _prepareNextTasks(checkpoint, processes, channels, forExecution) {
|
|
|
627
630
|
// Check if any processes should be run in next step
|
|
628
631
|
// If so, prepare the values to be passed to them
|
|
629
632
|
for (const [name, proc] of Object.entries(processes)) {
|
|
630
|
-
let seen = newCheckpoint.versions_seen[name];
|
|
631
|
-
if (!seen) {
|
|
632
|
-
newCheckpoint.versions_seen[name] = {};
|
|
633
|
-
seen = newCheckpoint.versions_seen[name];
|
|
634
|
-
}
|
|
635
633
|
// If any of the channels read by this process were updated
|
|
636
634
|
if (proc.triggers
|
|
637
635
|
.filter((chan) => {
|
|
@@ -643,7 +641,8 @@ function _prepareNextTasks(checkpoint, processes, channels, forExecution) {
|
|
|
643
641
|
return false;
|
|
644
642
|
}
|
|
645
643
|
})
|
|
646
|
-
.some((chan) => newCheckpoint
|
|
644
|
+
.some((chan) => (0, base_js_2.getChannelVersion)(newCheckpoint, chan) >
|
|
645
|
+
(0, base_js_2.getVersionSeen)(newCheckpoint, name, chan))) {
|
|
647
646
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
648
647
|
let val;
|
|
649
648
|
// If all trigger channels subscribed by this process are not empty
|
|
@@ -696,11 +695,14 @@ function _prepareNextTasks(checkpoint, processes, channels, forExecution) {
|
|
|
696
695
|
}
|
|
697
696
|
if (forExecution) {
|
|
698
697
|
// Update seen versions
|
|
698
|
+
if (!newCheckpoint.versions_seen[name]) {
|
|
699
|
+
newCheckpoint.versions_seen[name] = {};
|
|
700
|
+
}
|
|
699
701
|
proc.triggers.forEach((chan) => {
|
|
700
702
|
const version = newCheckpoint.channel_versions[chan];
|
|
701
703
|
if (version !== undefined) {
|
|
702
704
|
// side effect: updates newCheckpoint
|
|
703
|
-
|
|
705
|
+
newCheckpoint.versions_seen[name][chan] = version;
|
|
704
706
|
}
|
|
705
707
|
});
|
|
706
708
|
const node = proc.getNode();
|
package/dist/pregel/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Runnable, RunnableSequence, _coerceToRunnable, ensureConfig, patchConfig, } from "@langchain/core/runnables";
|
|
3
3
|
import { IterableReadableStream } from "@langchain/core/utils/stream";
|
|
4
4
|
import { createCheckpoint, emptyChannels, } from "../channels/base.js";
|
|
5
|
-
import { copyCheckpoint, emptyCheckpoint, } from "../checkpoint/base.js";
|
|
5
|
+
import { copyCheckpoint, emptyCheckpoint, getChannelVersion, getVersionSeen, } from "../checkpoint/base.js";
|
|
6
6
|
import { PregelNode } from "./read.js";
|
|
7
7
|
import { validateGraph, validateKeys } from "./validate.js";
|
|
8
8
|
import { mapInput, mapOutputUpdates, mapOutputValues, readChannel, readChannels, single, } from "./io.js";
|
|
@@ -402,7 +402,10 @@ export class Pregel extends Runnable {
|
|
|
402
402
|
else {
|
|
403
403
|
checkpoint = copyCheckpoint(checkpoint);
|
|
404
404
|
for (const k of this.streamChannelsList) {
|
|
405
|
-
const version = checkpoint.channel_versions[k];
|
|
405
|
+
const version = checkpoint.channel_versions[k] ?? 0;
|
|
406
|
+
if (!checkpoint.versions_seen[INTERRUPT]) {
|
|
407
|
+
checkpoint.versions_seen[INTERRUPT] = {};
|
|
408
|
+
}
|
|
406
409
|
checkpoint.versions_seen[INTERRUPT][k] = version;
|
|
407
410
|
}
|
|
408
411
|
}
|
|
@@ -546,8 +549,8 @@ async function executeTasks(tasks, stepTimeout) {
|
|
|
546
549
|
}
|
|
547
550
|
}
|
|
548
551
|
export function _shouldInterrupt(checkpoint, interruptNodes, snapshotChannels, tasks) {
|
|
549
|
-
const
|
|
550
|
-
|
|
552
|
+
const anySnapshotChannelUpdated = snapshotChannels.some((chan) => getChannelVersion(checkpoint, chan) >
|
|
553
|
+
getVersionSeen(checkpoint, INTERRUPT, chan));
|
|
551
554
|
const anyTaskNodeInInterruptNodes = tasks.some((task) => interruptNodes === "*"
|
|
552
555
|
? !task.config?.tags?.includes(TAG_HIDDEN)
|
|
553
556
|
: interruptNodes.includes(task.name));
|
|
@@ -619,11 +622,6 @@ export function _prepareNextTasks(checkpoint, processes, channels, forExecution)
|
|
|
619
622
|
// Check if any processes should be run in next step
|
|
620
623
|
// If so, prepare the values to be passed to them
|
|
621
624
|
for (const [name, proc] of Object.entries(processes)) {
|
|
622
|
-
let seen = newCheckpoint.versions_seen[name];
|
|
623
|
-
if (!seen) {
|
|
624
|
-
newCheckpoint.versions_seen[name] = {};
|
|
625
|
-
seen = newCheckpoint.versions_seen[name];
|
|
626
|
-
}
|
|
627
625
|
// If any of the channels read by this process were updated
|
|
628
626
|
if (proc.triggers
|
|
629
627
|
.filter((chan) => {
|
|
@@ -635,7 +633,8 @@ export function _prepareNextTasks(checkpoint, processes, channels, forExecution)
|
|
|
635
633
|
return false;
|
|
636
634
|
}
|
|
637
635
|
})
|
|
638
|
-
.some((chan) => newCheckpoint
|
|
636
|
+
.some((chan) => getChannelVersion(newCheckpoint, chan) >
|
|
637
|
+
getVersionSeen(newCheckpoint, name, chan))) {
|
|
639
638
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
640
639
|
let val;
|
|
641
640
|
// If all trigger channels subscribed by this process are not empty
|
|
@@ -688,11 +687,14 @@ export function _prepareNextTasks(checkpoint, processes, channels, forExecution)
|
|
|
688
687
|
}
|
|
689
688
|
if (forExecution) {
|
|
690
689
|
// Update seen versions
|
|
690
|
+
if (!newCheckpoint.versions_seen[name]) {
|
|
691
|
+
newCheckpoint.versions_seen[name] = {};
|
|
692
|
+
}
|
|
691
693
|
proc.triggers.forEach((chan) => {
|
|
692
694
|
const version = newCheckpoint.channel_versions[chan];
|
|
693
695
|
if (version !== undefined) {
|
|
694
696
|
// side effect: updates newCheckpoint
|
|
695
|
-
|
|
697
|
+
newCheckpoint.versions_seen[name][chan] = version;
|
|
696
698
|
}
|
|
697
699
|
});
|
|
698
700
|
const node = proc.getNode();
|
package/dist/pregel/io.cjs
CHANGED
|
@@ -53,11 +53,10 @@ function* mapInput(inputChannels,
|
|
|
53
53
|
chunk
|
|
54
54
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
55
|
) {
|
|
56
|
-
if (chunk) {
|
|
56
|
+
if (chunk !== undefined && chunk !== null) {
|
|
57
57
|
if (Array.isArray(inputChannels) &&
|
|
58
58
|
typeof chunk === "object" &&
|
|
59
|
-
!Array.isArray(chunk)
|
|
60
|
-
!!chunk) {
|
|
59
|
+
!Array.isArray(chunk)) {
|
|
61
60
|
for (const k in chunk) {
|
|
62
61
|
if (inputChannels.includes(k)) {
|
|
63
62
|
yield [k, chunk[k]];
|
package/dist/pregel/io.js
CHANGED
|
@@ -48,11 +48,10 @@ export function* mapInput(inputChannels,
|
|
|
48
48
|
chunk
|
|
49
49
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
50
|
) {
|
|
51
|
-
if (chunk) {
|
|
51
|
+
if (chunk !== undefined && chunk !== null) {
|
|
52
52
|
if (Array.isArray(inputChannels) &&
|
|
53
53
|
typeof chunk === "object" &&
|
|
54
|
-
!Array.isArray(chunk)
|
|
55
|
-
!!chunk) {
|
|
54
|
+
!Array.isArray(chunk)) {
|
|
56
55
|
for (const k in chunk) {
|
|
57
56
|
if (inputChannels.includes(k)) {
|
|
58
57
|
yield [k, chunk[k]];
|
|
@@ -209,6 +209,33 @@ describe("_shouldInterrupt", () => {
|
|
|
209
209
|
},
|
|
210
210
|
])).toBe(true);
|
|
211
211
|
});
|
|
212
|
+
it("should return true if any snapshot channel has been updated since last interrupt and any channel written to is in interrupt nodes list", () => {
|
|
213
|
+
// set up test
|
|
214
|
+
const checkpoint = {
|
|
215
|
+
v: 1,
|
|
216
|
+
id: uuid6(-1),
|
|
217
|
+
ts: "2024-04-19T17:19:07.952Z",
|
|
218
|
+
channel_values: {
|
|
219
|
+
channel1: "channel1value",
|
|
220
|
+
},
|
|
221
|
+
channel_versions: {
|
|
222
|
+
channel1: 2, // current channel version is greater than last version seen
|
|
223
|
+
},
|
|
224
|
+
versions_seen: {},
|
|
225
|
+
};
|
|
226
|
+
const interruptNodes = ["node1"];
|
|
227
|
+
const snapshotChannels = ["channel1"];
|
|
228
|
+
// call method / assertions
|
|
229
|
+
expect(_shouldInterrupt(checkpoint, interruptNodes, snapshotChannels, [
|
|
230
|
+
{
|
|
231
|
+
name: "node1",
|
|
232
|
+
input: undefined,
|
|
233
|
+
proc: new RunnablePassthrough(),
|
|
234
|
+
writes: [],
|
|
235
|
+
config: undefined,
|
|
236
|
+
},
|
|
237
|
+
])).toBe(true);
|
|
238
|
+
});
|
|
212
239
|
it("should return false if all snapshot channels have not been updated", () => {
|
|
213
240
|
// set up test
|
|
214
241
|
const checkpoint = {
|