@langchain/langgraph 0.2.41 → 0.2.43-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.
Files changed (86) hide show
  1. package/README.md +237 -154
  2. package/dist/channels/any_value.cjs +10 -10
  3. package/dist/channels/any_value.d.ts +1 -1
  4. package/dist/channels/any_value.js +10 -10
  5. package/dist/channels/ephemeral_value.cjs +10 -9
  6. package/dist/channels/ephemeral_value.d.ts +1 -1
  7. package/dist/channels/ephemeral_value.js +10 -9
  8. package/dist/channels/last_value.cjs +8 -7
  9. package/dist/channels/last_value.d.ts +1 -1
  10. package/dist/channels/last_value.js +8 -7
  11. package/dist/constants.cjs +33 -6
  12. package/dist/constants.d.ts +17 -2
  13. package/dist/constants.js +32 -5
  14. package/dist/errors.d.ts +3 -3
  15. package/dist/func/index.cjs +272 -0
  16. package/dist/func/index.d.ts +310 -0
  17. package/dist/func/index.js +267 -0
  18. package/dist/func/types.cjs +15 -0
  19. package/dist/func/types.d.ts +59 -0
  20. package/dist/func/types.js +11 -0
  21. package/dist/graph/graph.cjs +31 -35
  22. package/dist/graph/graph.d.ts +1 -5
  23. package/dist/graph/graph.js +1 -5
  24. package/dist/graph/index.cjs +1 -3
  25. package/dist/graph/index.d.ts +1 -1
  26. package/dist/graph/index.js +1 -1
  27. package/dist/graph/message.d.ts +1 -1
  28. package/dist/graph/state.cjs +17 -17
  29. package/dist/graph/state.d.ts +2 -1
  30. package/dist/graph/state.js +2 -2
  31. package/dist/index.cjs +8 -0
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.js +3 -0
  34. package/dist/interrupt.cjs +21 -34
  35. package/dist/interrupt.d.ts +1 -1
  36. package/dist/interrupt.js +22 -35
  37. package/dist/prebuilt/agent_executor.cjs +3 -3
  38. package/dist/prebuilt/agent_executor.d.ts +1 -1
  39. package/dist/prebuilt/agent_executor.js +1 -1
  40. package/dist/prebuilt/chat_agent_executor.cjs +3 -3
  41. package/dist/prebuilt/chat_agent_executor.d.ts +1 -1
  42. package/dist/prebuilt/chat_agent_executor.js +1 -1
  43. package/dist/prebuilt/react_agent_executor.cjs +33 -8
  44. package/dist/prebuilt/react_agent_executor.d.ts +4 -1
  45. package/dist/prebuilt/react_agent_executor.js +31 -6
  46. package/dist/prebuilt/tool_node.cjs +1 -2
  47. package/dist/prebuilt/tool_node.d.ts +1 -1
  48. package/dist/prebuilt/tool_node.js +1 -2
  49. package/dist/pregel/algo.cjs +121 -12
  50. package/dist/pregel/algo.d.ts +8 -6
  51. package/dist/pregel/algo.js +122 -13
  52. package/dist/pregel/call.cjs +77 -0
  53. package/dist/pregel/call.d.ts +15 -0
  54. package/dist/pregel/call.js +71 -0
  55. package/dist/pregel/index.cjs +59 -96
  56. package/dist/pregel/index.d.ts +1 -10
  57. package/dist/pregel/index.js +61 -98
  58. package/dist/pregel/io.cjs +6 -1
  59. package/dist/pregel/io.js +7 -2
  60. package/dist/pregel/loop.cjs +109 -75
  61. package/dist/pregel/loop.d.ts +17 -23
  62. package/dist/pregel/loop.js +110 -75
  63. package/dist/pregel/messages.d.ts +1 -1
  64. package/dist/pregel/retry.cjs +22 -50
  65. package/dist/pregel/retry.d.ts +6 -6
  66. package/dist/pregel/retry.js +22 -50
  67. package/dist/pregel/runner.cjs +275 -0
  68. package/dist/pregel/runner.d.ts +64 -0
  69. package/dist/pregel/runner.js +271 -0
  70. package/dist/pregel/stream.cjs +71 -0
  71. package/dist/pregel/stream.d.ts +17 -0
  72. package/dist/pregel/stream.js +67 -0
  73. package/dist/pregel/types.cjs +54 -0
  74. package/dist/pregel/types.d.ts +78 -6
  75. package/dist/pregel/types.js +51 -1
  76. package/dist/pregel/utils/config.cjs +26 -1
  77. package/dist/pregel/utils/config.d.ts +14 -0
  78. package/dist/pregel/utils/config.js +22 -0
  79. package/dist/pregel/write.d.ts +1 -1
  80. package/dist/utils.cjs +15 -1
  81. package/dist/utils.d.ts +3 -1
  82. package/dist/utils.js +12 -0
  83. package/dist/web.cjs +7 -5
  84. package/dist/web.d.ts +4 -4
  85. package/dist/web.js +3 -3
  86. package/package.json +8 -8
@@ -7,17 +7,18 @@ import { validateGraph, validateKeys } from "./validate.js";
7
7
  import { readChannels } from "./io.js";
8
8
  import { printStepCheckpoint, printStepTasks, printStepWrites, tasksWithWrites, } from "./debug.js";
9
9
  import { ChannelWrite, PASSTHROUGH } from "./write.js";
10
- import { CONFIG_KEY_CHECKPOINTER, CONFIG_KEY_READ, CONFIG_KEY_SEND, ERROR, INTERRUPT, CHECKPOINT_NAMESPACE_SEPARATOR, CHECKPOINT_NAMESPACE_END, CONFIG_KEY_STREAM, CONFIG_KEY_TASK_ID, NULL_TASK_ID, INPUT, RESUME, PUSH, } from "../constants.js";
11
- import { GraphRecursionError, GraphValueError, InvalidUpdateError, isGraphBubbleUp, isGraphInterrupt, } from "../errors.js";
10
+ import { CONFIG_KEY_CHECKPOINTER, CONFIG_KEY_READ, CONFIG_KEY_SEND, ERROR, INTERRUPT, CHECKPOINT_NAMESPACE_SEPARATOR, CHECKPOINT_NAMESPACE_END, CONFIG_KEY_STREAM, CONFIG_KEY_TASK_ID, NULL_TASK_ID, INPUT, PUSH, } from "../constants.js";
11
+ import { GraphRecursionError, GraphValueError, InvalidUpdateError, } from "../errors.js";
12
12
  import { _prepareNextTasks, _localRead, _applyWrites, } from "./algo.js";
13
13
  import { _coerceToDict, getNewChannelVersions, patchCheckpointMap, } from "./utils/index.js";
14
14
  import { findSubgraphPregel } from "./utils/subgraph.js";
15
- import { PregelLoop, IterableReadableWritableStream } from "./loop.js";
16
- import { executeTasksWithRetry } from "./retry.js";
15
+ import { PregelLoop } from "./loop.js";
17
16
  import { ChannelKeyPlaceholder, isConfiguredManagedValue, ManagedValueMapping, NoopManagedValue, } from "../managed/base.js";
18
17
  import { gatherIterator, patchConfigurable } from "../utils.js";
19
18
  import { ensureLangGraphConfig } from "./utils/config.js";
20
19
  import { StreamMessagesHandler } from "./messages.js";
20
+ import { PregelRunner } from "./runner.js";
21
+ import { IterableReadableWritableStream } from "./stream.js";
21
22
  function isString(value) {
22
23
  return typeof value === "string";
23
24
  }
@@ -820,92 +821,6 @@ export class Pregel extends Runnable {
820
821
  managed,
821
822
  };
822
823
  }
823
- async _runLoop(params) {
824
- const { loop, interruptAfter, interruptBefore, runManager, debug, config } = params;
825
- let tickError;
826
- try {
827
- while (await loop.tick({
828
- inputKeys: this.inputChannels,
829
- interruptAfter,
830
- interruptBefore,
831
- manager: runManager,
832
- })) {
833
- if (debug) {
834
- printStepCheckpoint(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
835
- }
836
- if (debug) {
837
- printStepTasks(loop.step, Object.values(loop.tasks));
838
- }
839
- // execute tasks, and wait for one to fail or all to finish.
840
- // each task is independent from all other concurrent tasks
841
- // yield updates/debug output as each task finishes
842
- const taskStream = executeTasksWithRetry(Object.values(loop.tasks).filter((task) => task.writes.length === 0), {
843
- stepTimeout: this.stepTimeout,
844
- signal: config.signal,
845
- retryPolicy: this.retryPolicy,
846
- });
847
- let graphInterrupt;
848
- for await (const { task, error } of taskStream) {
849
- if (error !== undefined) {
850
- if (isGraphBubbleUp(error)) {
851
- if (loop.isNested) {
852
- throw error;
853
- }
854
- if (isGraphInterrupt(error)) {
855
- graphInterrupt = error;
856
- if (error.interrupts.length) {
857
- const interrupts = error.interrupts.map((interrupt) => [INTERRUPT, interrupt]);
858
- const resumes = task.writes.filter((w) => w[0] === RESUME);
859
- if (resumes.length) {
860
- interrupts.push(...resumes);
861
- }
862
- loop.putWrites(task.id, interrupts);
863
- }
864
- }
865
- }
866
- else {
867
- loop.putWrites(task.id, [
868
- [ERROR, { message: error.message, name: error.name }],
869
- ]);
870
- throw error;
871
- }
872
- }
873
- else {
874
- loop.putWrites(task.id, task.writes);
875
- }
876
- }
877
- if (debug) {
878
- printStepWrites(loop.step, Object.values(loop.tasks)
879
- .map((task) => task.writes)
880
- .flat(), this.streamChannelsList);
881
- }
882
- if (graphInterrupt !== undefined) {
883
- throw graphInterrupt;
884
- }
885
- }
886
- if (loop.status === "out_of_steps") {
887
- throw new GraphRecursionError([
888
- `Recursion limit of ${config.recursionLimit} reached`,
889
- "without hitting a stop condition. You can increase the",
890
- `limit by setting the "recursionLimit" config key.`,
891
- ].join(" "), {
892
- lc_error_code: "GRAPH_RECURSION_LIMIT",
893
- });
894
- }
895
- }
896
- catch (e) {
897
- tickError = e;
898
- const suppress = await loop.finishAndHandleError(tickError);
899
- if (!suppress) {
900
- throw e;
901
- }
902
- }
903
- finally {
904
- if (tickError === undefined) {
905
- await loop.finishAndHandleError();
906
- }
907
- }
908
- }
909
824
  async *_streamIterator(input, options) {
910
825
  const streamSubgraphs = options?.subgraphs;
911
826
  const inputConfig = ensureLangGraphConfig(this.config, options);
@@ -970,6 +885,14 @@ export class Pregel extends Runnable {
970
885
  streamKeys: this.streamChannelsAsIs,
971
886
  store,
972
887
  stream,
888
+ interruptAfter,
889
+ interruptBefore,
890
+ manager: runManager,
891
+ debug: this.debug,
892
+ });
893
+ const runner = new PregelRunner({
894
+ loop,
895
+ nodeFinished: config.configurable?.nodeFinished,
973
896
  });
974
897
  if (options?.subgraphs) {
975
898
  loop.config.configurable = {
@@ -977,14 +900,7 @@ export class Pregel extends Runnable {
977
900
  [CONFIG_KEY_STREAM]: loop.stream,
978
901
  };
979
902
  }
980
- await this._runLoop({
981
- loop,
982
- interruptAfter,
983
- interruptBefore,
984
- runManager,
985
- debug,
986
- config,
987
- });
903
+ await this._runLoop({ loop, runner, debug, config });
988
904
  }
989
905
  catch (e) {
990
906
  loopError = e;
@@ -1082,4 +998,51 @@ export class Pregel extends Runnable {
1082
998
  }
1083
999
  return chunks;
1084
1000
  }
1001
+ async _runLoop(params) {
1002
+ const { loop, runner, debug, config } = params;
1003
+ let tickError;
1004
+ try {
1005
+ while (await loop.tick({
1006
+ inputKeys: this.inputChannels,
1007
+ })) {
1008
+ if (debug) {
1009
+ printStepCheckpoint(loop.checkpointMetadata.step, loop.channels, this.streamChannelsList);
1010
+ }
1011
+ if (debug) {
1012
+ printStepTasks(loop.step, Object.values(loop.tasks));
1013
+ }
1014
+ await runner.tick({
1015
+ timeout: this.stepTimeout,
1016
+ retryPolicy: this.retryPolicy,
1017
+ onStepWrite: (step, writes) => {
1018
+ if (debug) {
1019
+ printStepWrites(step, writes, this.streamChannelsList);
1020
+ }
1021
+ },
1022
+ signal: config.signal,
1023
+ });
1024
+ }
1025
+ if (loop.status === "out_of_steps") {
1026
+ throw new GraphRecursionError([
1027
+ `Recursion limit of ${config.recursionLimit} reached`,
1028
+ "without hitting a stop condition. You can increase the",
1029
+ `limit by setting the "recursionLimit" config key.`,
1030
+ ].join(" "), {
1031
+ lc_error_code: "GRAPH_RECURSION_LIMIT",
1032
+ });
1033
+ }
1034
+ }
1035
+ catch (e) {
1036
+ tickError = e;
1037
+ const suppress = await loop.finishAndHandleError(tickError);
1038
+ if (!suppress) {
1039
+ throw e;
1040
+ }
1041
+ }
1042
+ finally {
1043
+ if (tickError === undefined) {
1044
+ await loop.finishAndHandleError();
1045
+ }
1046
+ }
1047
+ }
1085
1048
  }
@@ -171,7 +171,12 @@ function* mapOutputUpdates(outputChannels, tasks, cached
171
171
  }
172
172
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
173
173
  let updated;
174
- if (!Array.isArray(outputChannels)) {
174
+ if (outputTasks.some(([task]) => task.writes.some(([chan, _]) => chan === constants_js_1.RETURN))) {
175
+ updated = outputTasks.flatMap(([task]) => task.writes
176
+ .filter(([chan, _]) => chan === constants_js_1.RETURN)
177
+ .map(([_, value]) => [task.name, value]));
178
+ }
179
+ else if (!Array.isArray(outputChannels)) {
175
180
  updated = outputTasks.flatMap(([task]) => task.writes
176
181
  .filter(([chan, _]) => chan === outputChannels)
177
182
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
package/dist/pregel/io.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { validate } from "uuid";
2
- import { _isSend, Command, ERROR, INTERRUPT, NULL_TASK_ID, RESUME, SELF, TAG_HIDDEN, TASKS, } from "../constants.js";
2
+ import { _isSend, Command, ERROR, INTERRUPT, NULL_TASK_ID, RESUME, RETURN, SELF, TAG_HIDDEN, TASKS, } from "../constants.js";
3
3
  import { EmptyChannelError, InvalidUpdateError } from "../errors.js";
4
4
  export function readChannel(channels, chan, catchErrors = true, returnException = false) {
5
5
  try {
@@ -163,7 +163,12 @@ export function* mapOutputUpdates(outputChannels, tasks, cached
163
163
  }
164
164
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
165
165
  let updated;
166
- if (!Array.isArray(outputChannels)) {
166
+ if (outputTasks.some(([task]) => task.writes.some(([chan, _]) => chan === RETURN))) {
167
+ updated = outputTasks.flatMap(([task]) => task.writes
168
+ .filter(([chan, _]) => chan === RETURN)
169
+ .map(([_, value]) => [task.name, value]));
170
+ }
171
+ else if (!Array.isArray(outputChannels)) {
167
172
  updated = outputTasks.flatMap(([task]) => task.writes
168
173
  .filter(([chan, _]) => chan === outputChannels)
169
174
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PregelLoop = exports.IterableReadableWritableStream = void 0;
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 = [], interruptAfter = [], interruptBefore = [], manager, } = params;
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 = isResuming ? INPUT_RESUMING : INPUT_DONE;
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]: isResuming,
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;
@@ -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
- export type StreamChunk = [string[], StreamMode, unknown];
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 {};