@langchain/langgraph 0.2.8 → 0.2.10-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.cjs +11 -2
- package/dist/constants.d.ts +6 -1
- package/dist/constants.js +10 -1
- package/dist/errors.cjs +5 -4
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +5 -4
- package/dist/graph/graph.cjs +7 -2
- package/dist/graph/graph.js +8 -3
- package/dist/graph/message.cjs +2 -0
- package/dist/graph/message.js +2 -0
- package/dist/graph/state.cjs +8 -3
- package/dist/graph/state.d.ts +2 -3
- package/dist/graph/state.js +9 -4
- package/dist/managed/shared_value.cjs +12 -10
- package/dist/managed/shared_value.d.ts +6 -5
- package/dist/managed/shared_value.js +12 -10
- package/dist/pregel/algo.cjs +124 -54
- package/dist/pregel/algo.d.ts +13 -3
- package/dist/pregel/algo.js +122 -53
- package/dist/pregel/debug.cjs +15 -18
- package/dist/pregel/debug.d.ts +3 -2
- package/dist/pregel/debug.js +16 -19
- package/dist/pregel/index.cjs +307 -116
- package/dist/pregel/index.d.ts +21 -6
- package/dist/pregel/index.js +305 -117
- package/dist/pregel/io.cjs +15 -8
- package/dist/pregel/io.d.ts +2 -2
- package/dist/pregel/io.js +15 -8
- package/dist/pregel/loop.cjs +258 -113
- package/dist/pregel/loop.d.ts +24 -9
- package/dist/pregel/loop.js +258 -111
- package/dist/pregel/read.cjs +9 -2
- package/dist/pregel/read.d.ts +3 -2
- package/dist/pregel/read.js +9 -2
- package/dist/pregel/retry.d.ts +1 -1
- package/dist/pregel/runnable_types.cjs +2 -0
- package/dist/pregel/runnable_types.d.ts +5 -0
- package/dist/pregel/runnable_types.js +1 -0
- package/dist/pregel/types.d.ts +8 -4
- package/dist/pregel/utils/config.cjs +73 -0
- package/dist/pregel/utils/config.d.ts +3 -0
- package/dist/pregel/utils/config.js +69 -0
- package/dist/pregel/{utils.cjs → utils/index.cjs} +33 -10
- package/dist/pregel/{utils.d.ts → utils/index.d.ts} +4 -7
- package/dist/pregel/{utils.js → utils/index.js} +30 -8
- package/dist/utils.cjs +5 -3
- package/dist/utils.js +5 -3
- package/dist/web.cjs +4 -2
- package/dist/web.d.ts +4 -3
- package/dist/web.js +1 -2
- package/package.json +1 -1
- package/dist/store/base.cjs +0 -12
- package/dist/store/base.d.ts +0 -7
- package/dist/store/base.js +0 -8
- package/dist/store/batch.cjs +0 -126
- package/dist/store/batch.d.ts +0 -55
- package/dist/store/batch.js +0 -122
- package/dist/store/index.cjs +0 -19
- package/dist/store/index.d.ts +0 -3
- package/dist/store/index.js +0 -3
- package/dist/store/memory.cjs +0 -43
- package/dist/store/memory.d.ts +0 -6
- package/dist/store/memory.js +0 -39
package/dist/pregel/loop.js
CHANGED
|
@@ -1,17 +1,43 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { copyCheckpoint, emptyCheckpoint, } from "@langchain/langgraph-checkpoint";
|
|
1
|
+
import { copyCheckpoint, emptyCheckpoint, AsyncBatchedStore, } from "@langchain/langgraph-checkpoint";
|
|
3
2
|
import { createCheckpoint, emptyChannels, } from "../channels/base.js";
|
|
4
|
-
import { CONFIG_KEY_READ, CONFIG_KEY_RESUMING, ERROR, INPUT, INTERRUPT, } from "../constants.js";
|
|
3
|
+
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";
|
|
5
4
|
import { _applyWrites, _prepareNextTasks, increment, shouldInterrupt, } from "./algo.js";
|
|
6
5
|
import { gatherIterator, gatherIteratorSync, prefixGenerator, } from "../utils.js";
|
|
7
|
-
import { mapInput, mapOutputUpdates, mapOutputValues } from "./io.js";
|
|
8
|
-
import { EmptyInputError, GraphInterrupt } from "../errors.js";
|
|
9
|
-
import { getNewChannelVersions } from "./utils.js";
|
|
6
|
+
import { mapInput, mapOutputUpdates, mapOutputValues, readChannels, } from "./io.js";
|
|
7
|
+
import { EmptyInputError, GraphInterrupt, isGraphInterrupt, } from "../errors.js";
|
|
8
|
+
import { getNewChannelVersions, patchConfigurable } from "./utils/index.js";
|
|
10
9
|
import { mapDebugTasks, mapDebugCheckpoint, mapDebugTaskResults, } from "./debug.js";
|
|
11
|
-
import { AsyncBatchedStore } from "../store/batch.js";
|
|
12
10
|
const INPUT_DONE = Symbol.for("INPUT_DONE");
|
|
13
11
|
const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
|
|
14
12
|
const DEFAULT_LOOP_LIMIT = 25;
|
|
13
|
+
const SPECIAL_CHANNELS = [ERROR, INTERRUPT];
|
|
14
|
+
export class StreamProtocol {
|
|
15
|
+
constructor(pushFn, modes) {
|
|
16
|
+
Object.defineProperty(this, "push", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: void 0
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "modes", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: void 0
|
|
27
|
+
});
|
|
28
|
+
this.push = pushFn;
|
|
29
|
+
this.modes = modes;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function createDuplexStream(...streams) {
|
|
33
|
+
return new StreamProtocol((value) => {
|
|
34
|
+
for (const stream of streams) {
|
|
35
|
+
if (stream.modes.has(value[1])) {
|
|
36
|
+
stream.push(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, new Set(streams.flatMap((s) => Array.from(s.modes))));
|
|
40
|
+
}
|
|
15
41
|
export class PregelLoop {
|
|
16
42
|
constructor(params) {
|
|
17
43
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -21,6 +47,13 @@ export class PregelLoop {
|
|
|
21
47
|
writable: true,
|
|
22
48
|
value: void 0
|
|
23
49
|
});
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
Object.defineProperty(this, "output", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
value: void 0
|
|
56
|
+
});
|
|
24
57
|
Object.defineProperty(this, "config", {
|
|
25
58
|
enumerable: true,
|
|
26
59
|
configurable: true,
|
|
@@ -69,6 +102,12 @@ export class PregelLoop {
|
|
|
69
102
|
writable: true,
|
|
70
103
|
value: void 0
|
|
71
104
|
});
|
|
105
|
+
Object.defineProperty(this, "checkpointNamespace", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
configurable: true,
|
|
108
|
+
writable: true,
|
|
109
|
+
value: void 0
|
|
110
|
+
});
|
|
72
111
|
Object.defineProperty(this, "checkpointPendingWrites", {
|
|
73
112
|
enumerable: true,
|
|
74
113
|
configurable: true,
|
|
@@ -117,6 +156,12 @@ export class PregelLoop {
|
|
|
117
156
|
writable: true,
|
|
118
157
|
value: void 0
|
|
119
158
|
});
|
|
159
|
+
Object.defineProperty(this, "taskWritesLeft", {
|
|
160
|
+
enumerable: true,
|
|
161
|
+
configurable: true,
|
|
162
|
+
writable: true,
|
|
163
|
+
value: 0
|
|
164
|
+
});
|
|
120
165
|
Object.defineProperty(this, "status", {
|
|
121
166
|
enumerable: true,
|
|
122
167
|
configurable: true,
|
|
@@ -128,14 +173,14 @@ export class PregelLoop {
|
|
|
128
173
|
enumerable: true,
|
|
129
174
|
configurable: true,
|
|
130
175
|
writable: true,
|
|
131
|
-
value:
|
|
176
|
+
value: {}
|
|
132
177
|
});
|
|
133
178
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
134
179
|
Object.defineProperty(this, "stream", {
|
|
135
180
|
enumerable: true,
|
|
136
181
|
configurable: true,
|
|
137
182
|
writable: true,
|
|
138
|
-
value:
|
|
183
|
+
value: void 0
|
|
139
184
|
});
|
|
140
185
|
Object.defineProperty(this, "checkpointerPromises", {
|
|
141
186
|
enumerable: true,
|
|
@@ -162,7 +207,6 @@ export class PregelLoop {
|
|
|
162
207
|
value: void 0
|
|
163
208
|
});
|
|
164
209
|
this.input = params.input;
|
|
165
|
-
this.config = params.config;
|
|
166
210
|
this.checkpointer = params.checkpointer;
|
|
167
211
|
// TODO: if managed values no longer needs graph we can replace with
|
|
168
212
|
// managed_specs, channel_specs
|
|
@@ -173,7 +217,6 @@ export class PregelLoop {
|
|
|
173
217
|
this.checkpointerGetNextVersion = increment;
|
|
174
218
|
}
|
|
175
219
|
this.checkpoint = params.checkpoint;
|
|
176
|
-
this.checkpointConfig = params.checkpointConfig;
|
|
177
220
|
this.checkpointMetadata = params.checkpointMetadata;
|
|
178
221
|
this.checkpointPreviousVersions = params.checkpointPreviousVersions;
|
|
179
222
|
this.channels = params.channels;
|
|
@@ -181,29 +224,58 @@ export class PregelLoop {
|
|
|
181
224
|
this.checkpointPendingWrites = params.checkpointPendingWrites;
|
|
182
225
|
this.step = params.step;
|
|
183
226
|
this.stop = params.stop;
|
|
184
|
-
this.
|
|
227
|
+
this.config = params.config;
|
|
228
|
+
this.checkpointConfig = params.checkpointConfig;
|
|
229
|
+
this.isNested = params.isNested;
|
|
185
230
|
this.outputKeys = params.outputKeys;
|
|
186
231
|
this.streamKeys = params.streamKeys;
|
|
187
232
|
this.nodes = params.nodes;
|
|
188
|
-
this.skipDoneTasks =
|
|
233
|
+
this.skipDoneTasks = params.skipDoneTasks;
|
|
189
234
|
this.store = params.store;
|
|
235
|
+
this.stream = params.stream;
|
|
236
|
+
this.checkpointNamespace = params.checkpointNamespace;
|
|
190
237
|
}
|
|
191
238
|
static async initialize(params) {
|
|
192
|
-
|
|
193
|
-
|
|
239
|
+
let { config, stream } = params;
|
|
240
|
+
if (stream !== undefined &&
|
|
241
|
+
config.configurable?.[CONFIG_KEY_STREAM] !== undefined) {
|
|
242
|
+
stream = createDuplexStream(stream, config.configurable[CONFIG_KEY_STREAM]);
|
|
243
|
+
}
|
|
244
|
+
const skipDoneTasks = config.configurable?.checkpoint_id === undefined;
|
|
245
|
+
const isNested = CONFIG_KEY_READ in (config.configurable ?? {});
|
|
246
|
+
if (!isNested &&
|
|
247
|
+
config.configurable?.checkpoint_ns !== undefined &&
|
|
248
|
+
config.configurable?.checkpoint_ns !== "") {
|
|
249
|
+
config = patchConfigurable(config, {
|
|
250
|
+
checkpoint_ns: "",
|
|
251
|
+
checkpoint_id: undefined,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
let checkpointConfig = config;
|
|
255
|
+
if (config.configurable?.[CONFIG_KEY_CHECKPOINT_MAP] !== undefined &&
|
|
256
|
+
config.configurable?.[CONFIG_KEY_CHECKPOINT_MAP]?.[config.configurable?.checkpoint_ns]) {
|
|
257
|
+
checkpointConfig = patchConfigurable(config, {
|
|
258
|
+
checkpoint_id: config.configurable[CONFIG_KEY_CHECKPOINT_MAP][config.configurable?.checkpoint_ns],
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns?.split(CHECKPOINT_NAMESPACE_SEPARATOR) ?? [];
|
|
262
|
+
const saved = (await params.checkpointer?.getTuple(checkpointConfig)) ?? {
|
|
263
|
+
config,
|
|
194
264
|
checkpoint: emptyCheckpoint(),
|
|
195
265
|
metadata: {
|
|
196
266
|
source: "input",
|
|
197
267
|
step: -2,
|
|
198
268
|
writes: null,
|
|
269
|
+
parents: {},
|
|
199
270
|
},
|
|
200
271
|
pendingWrites: [],
|
|
201
272
|
};
|
|
202
|
-
|
|
203
|
-
...
|
|
273
|
+
checkpointConfig = {
|
|
274
|
+
...config,
|
|
204
275
|
...saved.config,
|
|
205
276
|
configurable: {
|
|
206
|
-
|
|
277
|
+
checkpoint_ns: "",
|
|
278
|
+
...config.configurable,
|
|
207
279
|
...saved.config.configurable,
|
|
208
280
|
},
|
|
209
281
|
};
|
|
@@ -212,7 +284,7 @@ export class PregelLoop {
|
|
|
212
284
|
const checkpointPendingWrites = saved.pendingWrites ?? [];
|
|
213
285
|
const channels = emptyChannels(params.channelSpecs, checkpoint);
|
|
214
286
|
const step = (checkpointMetadata.step ?? 0) + 1;
|
|
215
|
-
const stop = step + (
|
|
287
|
+
const stop = step + (config.recursionLimit ?? DEFAULT_LOOP_LIMIT) + 1;
|
|
216
288
|
const checkpointPreviousVersions = { ...checkpoint.channel_versions };
|
|
217
289
|
const store = params.store
|
|
218
290
|
? new AsyncBatchedStore(params.store)
|
|
@@ -223,13 +295,16 @@ export class PregelLoop {
|
|
|
223
295
|
}
|
|
224
296
|
return new PregelLoop({
|
|
225
297
|
input: params.input,
|
|
226
|
-
config
|
|
298
|
+
config,
|
|
227
299
|
checkpointer: params.checkpointer,
|
|
228
300
|
checkpoint,
|
|
229
301
|
checkpointMetadata,
|
|
230
302
|
checkpointConfig,
|
|
303
|
+
checkpointNamespace,
|
|
231
304
|
channels,
|
|
232
305
|
managed: params.managed,
|
|
306
|
+
isNested,
|
|
307
|
+
skipDoneTasks,
|
|
233
308
|
step,
|
|
234
309
|
stop,
|
|
235
310
|
checkpointPreviousVersions,
|
|
@@ -237,6 +312,7 @@ export class PregelLoop {
|
|
|
237
312
|
outputKeys: params.outputKeys ?? [],
|
|
238
313
|
streamKeys: params.streamKeys ?? [],
|
|
239
314
|
nodes: params.nodes,
|
|
315
|
+
stream,
|
|
240
316
|
store,
|
|
241
317
|
});
|
|
242
318
|
}
|
|
@@ -259,6 +335,22 @@ export class PregelLoop {
|
|
|
259
335
|
* @param writes
|
|
260
336
|
*/
|
|
261
337
|
putWrites(taskId, writes) {
|
|
338
|
+
if (writes.length === 0) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// adjust taskWritesLeft
|
|
342
|
+
const firstChannel = writes[0][0];
|
|
343
|
+
const anyChannelIsSend = writes.find(([channel]) => channel === TASKS);
|
|
344
|
+
const alwaysSave = anyChannelIsSend || SPECIAL_CHANNELS.includes(firstChannel);
|
|
345
|
+
if (!alwaysSave && !this.taskWritesLeft) {
|
|
346
|
+
return this._outputWrites(taskId, writes);
|
|
347
|
+
}
|
|
348
|
+
else if (firstChannel !== INTERRUPT) {
|
|
349
|
+
// INTERRUPT makes us want to save the last task's writes
|
|
350
|
+
// so we don't decrement tasksWritesLeft in that case
|
|
351
|
+
this.taskWritesLeft -= 1;
|
|
352
|
+
}
|
|
353
|
+
// save writes
|
|
262
354
|
const pendingWrites = writes.map(([key, value]) => {
|
|
263
355
|
return [taskId, key, value];
|
|
264
356
|
});
|
|
@@ -274,10 +366,23 @@ export class PregelLoop {
|
|
|
274
366
|
if (putWritePromise !== undefined) {
|
|
275
367
|
this.checkpointerPromises.push(putWritePromise);
|
|
276
368
|
}
|
|
277
|
-
|
|
369
|
+
this._outputWrites(taskId, writes);
|
|
370
|
+
}
|
|
371
|
+
_outputWrites(taskId, writes, cached = false) {
|
|
372
|
+
const task = this.tasks[taskId];
|
|
278
373
|
if (task !== undefined) {
|
|
279
|
-
|
|
280
|
-
|
|
374
|
+
if (task.config !== undefined &&
|
|
375
|
+
(task.config.tags ?? []).includes(TAG_HIDDEN)) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (writes.length > 0 &&
|
|
379
|
+
writes[0][0] !== ERROR &&
|
|
380
|
+
writes[0][0] !== INTERRUPT) {
|
|
381
|
+
this._emit(gatherIteratorSync(prefixGenerator(mapOutputUpdates(this.outputKeys, [[task, writes]], cached), "updates")));
|
|
382
|
+
}
|
|
383
|
+
if (!cached) {
|
|
384
|
+
this._emit(gatherIteratorSync(prefixGenerator(mapDebugTaskResults(this.step, [[task, writes]], this.streamKeys), "debug")));
|
|
385
|
+
}
|
|
281
386
|
}
|
|
282
387
|
}
|
|
283
388
|
/**
|
|
@@ -286,35 +391,99 @@ export class PregelLoop {
|
|
|
286
391
|
* @param params
|
|
287
392
|
*/
|
|
288
393
|
async tick(params) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
if (this.status !== "pending") {
|
|
294
|
-
throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
|
|
295
|
-
}
|
|
296
|
-
if (![INPUT_DONE, INPUT_RESUMING].includes(this.input)) {
|
|
297
|
-
await this._first(inputKeys);
|
|
298
|
-
}
|
|
299
|
-
else if (this.tasks.every((task) => task.writes.length > 0)) {
|
|
300
|
-
const writes = this.tasks.flatMap((t) => t.writes);
|
|
301
|
-
// All tasks have finished
|
|
302
|
-
const myWrites = _applyWrites(this.checkpoint, this.channels, this.tasks, this.checkpointerGetNextVersion);
|
|
303
|
-
for (const [key, values] of Object.entries(myWrites)) {
|
|
304
|
-
await this.updateManagedValues(key, values);
|
|
394
|
+
let tickError;
|
|
395
|
+
try {
|
|
396
|
+
if (this.store && !this.store.isRunning) {
|
|
397
|
+
this.store?.start();
|
|
305
398
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
this.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
399
|
+
const { inputKeys = [], interruptAfter = [], interruptBefore = [], manager, } = params;
|
|
400
|
+
if (this.status !== "pending") {
|
|
401
|
+
throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
|
|
402
|
+
}
|
|
403
|
+
if (![INPUT_DONE, INPUT_RESUMING].includes(this.input)) {
|
|
404
|
+
await this._first(inputKeys);
|
|
405
|
+
}
|
|
406
|
+
else if (Object.values(this.tasks).every((task) => task.writes.length > 0)) {
|
|
407
|
+
const writes = Object.values(this.tasks).flatMap((t) => t.writes);
|
|
408
|
+
// All tasks have finished
|
|
409
|
+
const managedValueWrites = _applyWrites(this.checkpoint, this.channels, Object.values(this.tasks), this.checkpointerGetNextVersion);
|
|
410
|
+
for (const [key, values] of Object.entries(managedValueWrites)) {
|
|
411
|
+
await this.updateManagedValues(key, values);
|
|
412
|
+
}
|
|
413
|
+
// produce values output
|
|
414
|
+
const valuesOutput = await gatherIterator(prefixGenerator(mapOutputValues(this.outputKeys, writes, this.channels), "values"));
|
|
415
|
+
this._emit(valuesOutput);
|
|
416
|
+
// clear pending writes
|
|
417
|
+
this.checkpointPendingWrites = [];
|
|
418
|
+
await this._putCheckpoint({
|
|
419
|
+
source: "loop",
|
|
420
|
+
writes: mapOutputUpdates(this.outputKeys, Object.values(this.tasks).map((task) => [task, task.writes])).next().value ?? null,
|
|
421
|
+
});
|
|
422
|
+
// after execution, check if we should interrupt
|
|
423
|
+
if (shouldInterrupt(this.checkpoint, interruptAfter, Object.values(this.tasks))) {
|
|
424
|
+
this.status = "interrupt_after";
|
|
425
|
+
if (this.isNested) {
|
|
426
|
+
throw new GraphInterrupt();
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
if (this.step > this.stop) {
|
|
437
|
+
this.status = "out_of_steps";
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
const nextTasks = _prepareNextTasks(this.checkpoint, this.nodes, this.channels, this.managed, this.config, true, {
|
|
441
|
+
step: this.step,
|
|
442
|
+
checkpointer: this.checkpointer,
|
|
443
|
+
isResuming: this.input === INPUT_RESUMING,
|
|
444
|
+
manager,
|
|
445
|
+
store: this.store,
|
|
314
446
|
});
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
447
|
+
this.tasks = nextTasks;
|
|
448
|
+
this.taskWritesLeft = Object.values(this.tasks).length - 1;
|
|
449
|
+
// Produce debug output
|
|
450
|
+
if (this.checkpointer) {
|
|
451
|
+
this._emit(await gatherIterator(prefixGenerator(mapDebugCheckpoint(this.step - 1, // printing checkpoint for previous step
|
|
452
|
+
this.checkpointConfig, this.channels, this.streamKeys, this.checkpointMetadata, Object.values(this.tasks), this.checkpointPendingWrites), "debug")));
|
|
453
|
+
}
|
|
454
|
+
if (Object.values(this.tasks).length === 0) {
|
|
455
|
+
this.status = "done";
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
// if there are pending writes from a previous loop, apply them
|
|
459
|
+
if (this.skipDoneTasks && this.checkpointPendingWrites.length > 0) {
|
|
460
|
+
for (const [tid, k, v] of this.checkpointPendingWrites) {
|
|
461
|
+
if (k === ERROR || k === INTERRUPT) {
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const task = Object.values(this.tasks).find((t) => t.id === tid);
|
|
465
|
+
if (task) {
|
|
466
|
+
task.writes.push([k, v]);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
for (const task of Object.values(this.tasks)) {
|
|
470
|
+
if (task.writes.length > 0) {
|
|
471
|
+
this._outputWrites(task.id, task.writes, true);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// if all tasks have finished, re-tick
|
|
476
|
+
if (Object.values(this.tasks).every((task) => task.writes.length > 0)) {
|
|
477
|
+
return this.tick({
|
|
478
|
+
inputKeys,
|
|
479
|
+
interruptAfter,
|
|
480
|
+
interruptBefore,
|
|
481
|
+
manager,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
// Before execution, check if we should interrupt
|
|
485
|
+
if (shouldInterrupt(this.checkpoint, interruptBefore, Object.values(this.tasks))) {
|
|
486
|
+
this.status = "interrupt_before";
|
|
318
487
|
if (this.isNested) {
|
|
319
488
|
throw new GraphInterrupt();
|
|
320
489
|
}
|
|
@@ -322,65 +491,29 @@ export class PregelLoop {
|
|
|
322
491
|
return false;
|
|
323
492
|
}
|
|
324
493
|
}
|
|
494
|
+
// Produce debug output
|
|
495
|
+
const debugOutput = await gatherIterator(prefixGenerator(mapDebugTasks(this.step, Object.values(this.tasks)), "debug"));
|
|
496
|
+
this._emit(debugOutput);
|
|
497
|
+
return true;
|
|
325
498
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
this.status = "out_of_steps";
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
const nextTasks = _prepareNextTasks(this.checkpoint, this.nodes, this.channels, this.managed, this.config, true, {
|
|
334
|
-
step: this.step,
|
|
335
|
-
checkpointer: this.checkpointer,
|
|
336
|
-
isResuming: this.input === INPUT_RESUMING,
|
|
337
|
-
manager,
|
|
338
|
-
});
|
|
339
|
-
this.tasks = nextTasks;
|
|
340
|
-
// Produce debug output
|
|
341
|
-
if (this.checkpointer) {
|
|
342
|
-
this.stream.push(...(await gatherIterator(prefixGenerator(mapDebugCheckpoint(this.step - 1, // printing checkpoint for previous step
|
|
343
|
-
this.checkpointConfig, this.channels, this.streamKeys, this.checkpointMetadata, this.tasks, this.checkpointPendingWrites), "debug"))));
|
|
344
|
-
}
|
|
345
|
-
if (this.tasks.length === 0) {
|
|
346
|
-
this.status = "done";
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
// if there are pending writes from a previous loop, apply them
|
|
350
|
-
if (this.checkpointPendingWrites.length > 0 && this.skipDoneTasks) {
|
|
351
|
-
for (const [tid, k, v] of this.checkpointPendingWrites) {
|
|
352
|
-
if (k === ERROR || k === INTERRUPT) {
|
|
353
|
-
continue;
|
|
354
|
-
}
|
|
355
|
-
const task = this.tasks.find((t) => t.id === tid);
|
|
356
|
-
if (task) {
|
|
357
|
-
task.writes.push([k, v]);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
// if all tasks have finished, re-tick
|
|
362
|
-
if (this.tasks.every((task) => task.writes.length > 0)) {
|
|
363
|
-
return this.tick({
|
|
364
|
-
inputKeys,
|
|
365
|
-
interruptAfter,
|
|
366
|
-
interruptBefore,
|
|
367
|
-
manager,
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
// Before execution, check if we should interrupt
|
|
371
|
-
if (shouldInterrupt(this.checkpoint, interruptBefore, this.tasks)) {
|
|
372
|
-
this.status = "interrupt_before";
|
|
373
|
-
if (this.isNested) {
|
|
374
|
-
throw new GraphInterrupt();
|
|
499
|
+
catch (e) {
|
|
500
|
+
tickError = e;
|
|
501
|
+
if (!this._suppressInterrupt(tickError)) {
|
|
502
|
+
throw tickError;
|
|
375
503
|
}
|
|
376
504
|
else {
|
|
377
|
-
|
|
505
|
+
this.output = readChannels(this.channels, this.outputKeys);
|
|
506
|
+
}
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
finally {
|
|
510
|
+
if (tickError === undefined) {
|
|
511
|
+
this.output = readChannels(this.channels, this.outputKeys);
|
|
378
512
|
}
|
|
379
513
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
this.
|
|
383
|
-
return true;
|
|
514
|
+
}
|
|
515
|
+
_suppressInterrupt(e) {
|
|
516
|
+
return isGraphInterrupt(e) && !this.isNested;
|
|
384
517
|
}
|
|
385
518
|
/**
|
|
386
519
|
* Resuming from previous checkpoint requires
|
|
@@ -388,9 +521,9 @@ export class PregelLoop {
|
|
|
388
521
|
* - receiving None input (outer graph) or RESUMING flag (subgraph)
|
|
389
522
|
*/
|
|
390
523
|
async _first(inputKeys) {
|
|
391
|
-
const isResuming =
|
|
392
|
-
this.config.configurable?.[CONFIG_KEY_RESUMING] !== undefined
|
|
393
|
-
|
|
524
|
+
const isResuming = Object.keys(this.checkpoint.channel_versions).length !== 0 &&
|
|
525
|
+
(this.config.configurable?.[CONFIG_KEY_RESUMING] !== undefined ||
|
|
526
|
+
this.input === null);
|
|
394
527
|
if (isResuming) {
|
|
395
528
|
for (const channelName of Object.keys(this.channels)) {
|
|
396
529
|
if (this.checkpoint.channel_versions[channelName] !== undefined) {
|
|
@@ -401,6 +534,9 @@ export class PregelLoop {
|
|
|
401
534
|
};
|
|
402
535
|
}
|
|
403
536
|
}
|
|
537
|
+
// produce values output
|
|
538
|
+
const valuesOutput = await gatherIterator(prefixGenerator(mapOutputValues(this.outputKeys, true, this.channels), "values"));
|
|
539
|
+
this._emit(valuesOutput);
|
|
404
540
|
// map inputs to channel updates
|
|
405
541
|
}
|
|
406
542
|
else {
|
|
@@ -409,7 +545,7 @@ export class PregelLoop {
|
|
|
409
545
|
throw new EmptyInputError(`Received no input writes for ${JSON.stringify(inputKeys, null, 2)}`);
|
|
410
546
|
}
|
|
411
547
|
const discardTasks = _prepareNextTasks(this.checkpoint, this.nodes, this.channels, this.managed, this.config, true, { step: this.step });
|
|
412
|
-
_applyWrites(this.checkpoint, this.channels, discardTasks.concat([
|
|
548
|
+
_applyWrites(this.checkpoint, this.channels, Object.values(discardTasks).concat([
|
|
413
549
|
{
|
|
414
550
|
name: INPUT,
|
|
415
551
|
writes: inputWrites,
|
|
@@ -424,12 +560,25 @@ export class PregelLoop {
|
|
|
424
560
|
}
|
|
425
561
|
// done with input
|
|
426
562
|
this.input = isResuming ? INPUT_RESUMING : INPUT_DONE;
|
|
563
|
+
if (!this.isNested) {
|
|
564
|
+
this.config = patchConfigurable(this.config, {
|
|
565
|
+
[CONFIG_KEY_RESUMING]: isResuming,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
_emit(values) {
|
|
570
|
+
for (const chunk of values) {
|
|
571
|
+
if (this.stream.modes.has(chunk[0])) {
|
|
572
|
+
this.stream.push([this.checkpointNamespace, ...chunk]);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
427
575
|
}
|
|
428
576
|
async _putCheckpoint(inputMetadata) {
|
|
429
577
|
// Assign step
|
|
430
578
|
const metadata = {
|
|
431
579
|
...inputMetadata,
|
|
432
580
|
step: this.step,
|
|
581
|
+
parents: this.config.configurable?.[CONFIG_KEY_CHECKPOINT_MAP] ?? {},
|
|
433
582
|
};
|
|
434
583
|
// Bail if no checkpointer
|
|
435
584
|
if (this.checkpointer !== undefined) {
|
|
@@ -439,9 +588,7 @@ export class PregelLoop {
|
|
|
439
588
|
// this is achieved by writing child checkpoints as progress is made
|
|
440
589
|
// (so that error recovery / resuming from interrupt don't lose work)
|
|
441
590
|
// but doing so always with an id equal to that of the parent checkpoint
|
|
442
|
-
this.checkpoint = createCheckpoint(this.checkpoint, this.channels, this.step
|
|
443
|
-
// id: this.isNested ? this.config.configurable?.checkpoint_id : undefined,
|
|
444
|
-
);
|
|
591
|
+
this.checkpoint = createCheckpoint(this.checkpoint, this.channels, this.step);
|
|
445
592
|
this.checkpointConfig = {
|
|
446
593
|
...this.checkpointConfig,
|
|
447
594
|
configurable: {
|
package/dist/pregel/read.cjs
CHANGED
|
@@ -63,10 +63,10 @@ const defaultRunnableBound =
|
|
|
63
63
|
/* #__PURE__ */ new runnables_1.RunnablePassthrough();
|
|
64
64
|
class PregelNode extends runnables_1.RunnableBinding {
|
|
65
65
|
constructor(fields) {
|
|
66
|
-
const { channels, triggers, mapper, writers, bound, kwargs, metadata, retryPolicy, } = fields;
|
|
66
|
+
const { channels, triggers, mapper, writers, bound, kwargs, metadata, retryPolicy, tags, } = fields;
|
|
67
67
|
const mergedTags = [
|
|
68
68
|
...(fields.config?.tags ? fields.config.tags : []),
|
|
69
|
-
...(
|
|
69
|
+
...(tags ?? []),
|
|
70
70
|
];
|
|
71
71
|
super({
|
|
72
72
|
...fields,
|
|
@@ -127,6 +127,12 @@ class PregelNode extends runnables_1.RunnableBinding {
|
|
|
127
127
|
writable: true,
|
|
128
128
|
value: {}
|
|
129
129
|
});
|
|
130
|
+
Object.defineProperty(this, "tags", {
|
|
131
|
+
enumerable: true,
|
|
132
|
+
configurable: true,
|
|
133
|
+
writable: true,
|
|
134
|
+
value: []
|
|
135
|
+
});
|
|
130
136
|
Object.defineProperty(this, "retryPolicy", {
|
|
131
137
|
enumerable: true,
|
|
132
138
|
configurable: true,
|
|
@@ -140,6 +146,7 @@ class PregelNode extends runnables_1.RunnableBinding {
|
|
|
140
146
|
this.bound = bound ?? this.bound;
|
|
141
147
|
this.kwargs = kwargs ?? this.kwargs;
|
|
142
148
|
this.metadata = metadata ?? this.metadata;
|
|
149
|
+
this.tags = mergedTags;
|
|
143
150
|
this.retryPolicy = retryPolicy;
|
|
144
151
|
}
|
|
145
152
|
getWriters() {
|
package/dist/pregel/read.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Runnable, RunnableBinding, RunnableBindingArgs, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
|
|
1
|
+
import { Runnable, RunnableBinding, RunnableBindingArgs, RunnableConfig, type RunnableLike } from "@langchain/core/runnables";
|
|
2
2
|
import { RunnableCallable } from "../utils.js";
|
|
3
|
-
import type { RetryPolicy } from "./utils.js";
|
|
3
|
+
import type { RetryPolicy } from "./utils/index.js";
|
|
4
4
|
export declare class ChannelRead<RunInput = any> extends RunnableCallable {
|
|
5
5
|
lc_graph_name: string;
|
|
6
6
|
channel: string | Array<string>;
|
|
@@ -32,6 +32,7 @@ export declare class PregelNode<RunInput = PregelNodeInputType, RunOutput = Preg
|
|
|
32
32
|
bound: Runnable<RunInput, RunOutput>;
|
|
33
33
|
kwargs: Record<string, any>;
|
|
34
34
|
metadata: Record<string, unknown>;
|
|
35
|
+
tags: string[];
|
|
35
36
|
retryPolicy?: RetryPolicy;
|
|
36
37
|
constructor(fields: PregelNodeArgs<RunInput, RunOutput>);
|
|
37
38
|
getWriters(): Array<Runnable>;
|
package/dist/pregel/read.js
CHANGED
|
@@ -59,10 +59,10 @@ const defaultRunnableBound =
|
|
|
59
59
|
/* #__PURE__ */ new RunnablePassthrough();
|
|
60
60
|
export class PregelNode extends RunnableBinding {
|
|
61
61
|
constructor(fields) {
|
|
62
|
-
const { channels, triggers, mapper, writers, bound, kwargs, metadata, retryPolicy, } = fields;
|
|
62
|
+
const { channels, triggers, mapper, writers, bound, kwargs, metadata, retryPolicy, tags, } = fields;
|
|
63
63
|
const mergedTags = [
|
|
64
64
|
...(fields.config?.tags ? fields.config.tags : []),
|
|
65
|
-
...(
|
|
65
|
+
...(tags ?? []),
|
|
66
66
|
];
|
|
67
67
|
super({
|
|
68
68
|
...fields,
|
|
@@ -123,6 +123,12 @@ export class PregelNode extends RunnableBinding {
|
|
|
123
123
|
writable: true,
|
|
124
124
|
value: {}
|
|
125
125
|
});
|
|
126
|
+
Object.defineProperty(this, "tags", {
|
|
127
|
+
enumerable: true,
|
|
128
|
+
configurable: true,
|
|
129
|
+
writable: true,
|
|
130
|
+
value: []
|
|
131
|
+
});
|
|
126
132
|
Object.defineProperty(this, "retryPolicy", {
|
|
127
133
|
enumerable: true,
|
|
128
134
|
configurable: true,
|
|
@@ -136,6 +142,7 @@ export class PregelNode extends RunnableBinding {
|
|
|
136
142
|
this.bound = bound ?? this.bound;
|
|
137
143
|
this.kwargs = kwargs ?? this.kwargs;
|
|
138
144
|
this.metadata = metadata ?? this.metadata;
|
|
145
|
+
this.tags = mergedTags;
|
|
139
146
|
this.retryPolicy = retryPolicy;
|
|
140
147
|
}
|
|
141
148
|
getWriters() {
|
package/dist/pregel/retry.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PregelExecutableTask } from "./types.js";
|
|
2
|
-
import type { RetryPolicy } from "./utils.js";
|
|
2
|
+
import type { RetryPolicy } from "./utils/index.js";
|
|
3
3
|
export declare const DEFAULT_INITIAL_INTERVAL = 500;
|
|
4
4
|
export declare const DEFAULT_BACKOFF_FACTOR = 2;
|
|
5
5
|
export declare const DEFAULT_MAX_INTERVAL = 128000;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|