@langchain/langgraph 1.3.7 → 1.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.
Files changed (199) hide show
  1. package/dist/channels/base.cjs +78 -2
  2. package/dist/channels/base.cjs.map +1 -1
  3. package/dist/channels/base.d.cts +35 -2
  4. package/dist/channels/base.d.cts.map +1 -1
  5. package/dist/channels/base.d.ts +35 -2
  6. package/dist/channels/base.d.ts.map +1 -1
  7. package/dist/channels/base.js +77 -4
  8. package/dist/channels/base.js.map +1 -1
  9. package/dist/channels/delta.cjs +136 -0
  10. package/dist/channels/delta.cjs.map +1 -0
  11. package/dist/channels/delta.d.cts +99 -0
  12. package/dist/channels/delta.d.cts.map +1 -0
  13. package/dist/channels/delta.d.ts +99 -0
  14. package/dist/channels/delta.d.ts.map +1 -0
  15. package/dist/channels/delta.js +136 -0
  16. package/dist/channels/delta.js.map +1 -0
  17. package/dist/channels/index.cjs +5 -0
  18. package/dist/channels/index.d.cts +3 -2
  19. package/dist/channels/index.d.ts +3 -2
  20. package/dist/channels/index.js +3 -2
  21. package/dist/constants.cjs +62 -4
  22. package/dist/constants.cjs.map +1 -1
  23. package/dist/constants.d.cts +33 -2
  24. package/dist/constants.d.cts.map +1 -1
  25. package/dist/constants.d.ts +33 -2
  26. package/dist/constants.d.ts.map +1 -1
  27. package/dist/constants.js +59 -5
  28. package/dist/constants.js.map +1 -1
  29. package/dist/errors.cjs +128 -0
  30. package/dist/errors.cjs.map +1 -1
  31. package/dist/errors.d.cts +86 -1
  32. package/dist/errors.d.cts.map +1 -1
  33. package/dist/errors.d.ts +86 -1
  34. package/dist/errors.d.ts.map +1 -1
  35. package/dist/errors.js +123 -1
  36. package/dist/errors.js.map +1 -1
  37. package/dist/func/index.cjs +9 -2
  38. package/dist/func/index.cjs.map +1 -1
  39. package/dist/func/index.d.cts +14 -0
  40. package/dist/func/index.d.cts.map +1 -1
  41. package/dist/func/index.d.ts +14 -0
  42. package/dist/func/index.d.ts.map +1 -1
  43. package/dist/func/index.js +9 -2
  44. package/dist/func/index.js.map +1 -1
  45. package/dist/graph/graph.cjs +44 -7
  46. package/dist/graph/graph.cjs.map +1 -1
  47. package/dist/graph/graph.d.cts +24 -2
  48. package/dist/graph/graph.d.cts.map +1 -1
  49. package/dist/graph/graph.d.ts +24 -2
  50. package/dist/graph/graph.d.ts.map +1 -1
  51. package/dist/graph/graph.js +44 -7
  52. package/dist/graph/graph.js.map +1 -1
  53. package/dist/graph/index.d.ts +3 -3
  54. package/dist/graph/messages_reducer.cjs +55 -0
  55. package/dist/graph/messages_reducer.cjs.map +1 -1
  56. package/dist/graph/messages_reducer.d.cts +28 -1
  57. package/dist/graph/messages_reducer.d.cts.map +1 -1
  58. package/dist/graph/messages_reducer.d.ts +28 -1
  59. package/dist/graph/messages_reducer.d.ts.map +1 -1
  60. package/dist/graph/messages_reducer.js +56 -2
  61. package/dist/graph/messages_reducer.js.map +1 -1
  62. package/dist/graph/state.cjs +174 -7
  63. package/dist/graph/state.cjs.map +1 -1
  64. package/dist/graph/state.d.cts +193 -17
  65. package/dist/graph/state.d.cts.map +1 -1
  66. package/dist/graph/state.d.ts +193 -17
  67. package/dist/graph/state.d.ts.map +1 -1
  68. package/dist/graph/state.js +175 -8
  69. package/dist/graph/state.js.map +1 -1
  70. package/dist/graph/zod/schema.cjs +5 -0
  71. package/dist/graph/zod/schema.cjs.map +1 -1
  72. package/dist/graph/zod/schema.d.cts.map +1 -1
  73. package/dist/graph/zod/schema.d.ts.map +1 -1
  74. package/dist/graph/zod/schema.js +5 -0
  75. package/dist/graph/zod/schema.js.map +1 -1
  76. package/dist/index.cjs +11 -0
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.d.cts +11 -8
  79. package/dist/index.d.ts +11 -8
  80. package/dist/index.js +5 -3
  81. package/dist/index.js.map +1 -1
  82. package/dist/prebuilt/react_agent_executor.d.cts +1 -1
  83. package/dist/pregel/algo.cjs +182 -21
  84. package/dist/pregel/algo.cjs.map +1 -1
  85. package/dist/pregel/algo.d.cts +1 -1
  86. package/dist/pregel/algo.d.cts.map +1 -1
  87. package/dist/pregel/algo.d.ts +1 -1
  88. package/dist/pregel/algo.d.ts.map +1 -1
  89. package/dist/pregel/algo.js +185 -25
  90. package/dist/pregel/algo.js.map +1 -1
  91. package/dist/pregel/call.cjs +2 -1
  92. package/dist/pregel/call.cjs.map +1 -1
  93. package/dist/pregel/call.js +2 -1
  94. package/dist/pregel/call.js.map +1 -1
  95. package/dist/pregel/index.cjs +15 -3
  96. package/dist/pregel/index.cjs.map +1 -1
  97. package/dist/pregel/index.d.cts.map +1 -1
  98. package/dist/pregel/index.d.ts.map +1 -1
  99. package/dist/pregel/index.js +17 -5
  100. package/dist/pregel/index.js.map +1 -1
  101. package/dist/pregel/loop.cjs +362 -41
  102. package/dist/pregel/loop.cjs.map +1 -1
  103. package/dist/pregel/loop.js +365 -44
  104. package/dist/pregel/loop.js.map +1 -1
  105. package/dist/pregel/messages-v2.cjs +1 -1
  106. package/dist/pregel/messages-v2.js +1 -1
  107. package/dist/pregel/messages.cjs +1 -1
  108. package/dist/pregel/messages.js +1 -1
  109. package/dist/pregel/read.cjs +15 -5
  110. package/dist/pregel/read.cjs.map +1 -1
  111. package/dist/pregel/read.d.cts +9 -0
  112. package/dist/pregel/read.d.cts.map +1 -1
  113. package/dist/pregel/read.d.ts +9 -0
  114. package/dist/pregel/read.d.ts.map +1 -1
  115. package/dist/pregel/read.js +15 -5
  116. package/dist/pregel/read.js.map +1 -1
  117. package/dist/pregel/remote-run-stream.cjs +107 -0
  118. package/dist/pregel/remote-run-stream.cjs.map +1 -0
  119. package/dist/pregel/remote-run-stream.d.cts +33 -0
  120. package/dist/pregel/remote-run-stream.d.cts.map +1 -0
  121. package/dist/pregel/remote-run-stream.d.ts +33 -0
  122. package/dist/pregel/remote-run-stream.d.ts.map +1 -0
  123. package/dist/pregel/remote-run-stream.js +107 -0
  124. package/dist/pregel/remote-run-stream.js.map +1 -0
  125. package/dist/pregel/remote.cjs +61 -1
  126. package/dist/pregel/remote.cjs.map +1 -1
  127. package/dist/pregel/remote.d.cts +17 -0
  128. package/dist/pregel/remote.d.cts.map +1 -1
  129. package/dist/pregel/remote.d.ts +17 -0
  130. package/dist/pregel/remote.d.ts.map +1 -1
  131. package/dist/pregel/remote.js +61 -1
  132. package/dist/pregel/remote.js.map +1 -1
  133. package/dist/pregel/replay.cjs +62 -0
  134. package/dist/pregel/replay.cjs.map +1 -0
  135. package/dist/pregel/replay.js +62 -0
  136. package/dist/pregel/replay.js.map +1 -0
  137. package/dist/pregel/retry.cjs +8 -6
  138. package/dist/pregel/retry.cjs.map +1 -1
  139. package/dist/pregel/retry.js +8 -6
  140. package/dist/pregel/retry.js.map +1 -1
  141. package/dist/pregel/runnable_types.d.cts +20 -0
  142. package/dist/pregel/runnable_types.d.cts.map +1 -1
  143. package/dist/pregel/runnable_types.d.ts +20 -0
  144. package/dist/pregel/runnable_types.d.ts.map +1 -1
  145. package/dist/pregel/runner.cjs +48 -7
  146. package/dist/pregel/runner.cjs.map +1 -1
  147. package/dist/pregel/runner.js +50 -9
  148. package/dist/pregel/runner.js.map +1 -1
  149. package/dist/pregel/runtime.cjs +64 -0
  150. package/dist/pregel/runtime.cjs.map +1 -0
  151. package/dist/pregel/runtime.d.cts +57 -0
  152. package/dist/pregel/runtime.d.cts.map +1 -0
  153. package/dist/pregel/runtime.d.ts +57 -0
  154. package/dist/pregel/runtime.d.ts.map +1 -0
  155. package/dist/pregel/runtime.js +64 -0
  156. package/dist/pregel/runtime.js.map +1 -0
  157. package/dist/pregel/stream.cjs +2 -0
  158. package/dist/pregel/stream.cjs.map +1 -1
  159. package/dist/pregel/stream.js +2 -0
  160. package/dist/pregel/stream.js.map +1 -1
  161. package/dist/pregel/timeout.cjs +216 -0
  162. package/dist/pregel/timeout.cjs.map +1 -0
  163. package/dist/pregel/timeout.js +216 -0
  164. package/dist/pregel/timeout.js.map +1 -0
  165. package/dist/pregel/types.cjs +3 -1
  166. package/dist/pregel/types.cjs.map +1 -1
  167. package/dist/pregel/types.d.cts +13 -0
  168. package/dist/pregel/types.d.cts.map +1 -1
  169. package/dist/pregel/types.d.ts +14 -1
  170. package/dist/pregel/types.d.ts.map +1 -1
  171. package/dist/pregel/types.js +3 -1
  172. package/dist/pregel/types.js.map +1 -1
  173. package/dist/pregel/utils/config.cjs +3 -1
  174. package/dist/pregel/utils/config.cjs.map +1 -1
  175. package/dist/pregel/utils/config.d.cts.map +1 -1
  176. package/dist/pregel/utils/config.d.ts.map +1 -1
  177. package/dist/pregel/utils/config.js +3 -1
  178. package/dist/pregel/utils/config.js.map +1 -1
  179. package/dist/pregel/utils/index.cjs +1 -0
  180. package/dist/pregel/utils/index.cjs.map +1 -1
  181. package/dist/pregel/utils/index.d.cts +6 -1
  182. package/dist/pregel/utils/index.d.cts.map +1 -1
  183. package/dist/pregel/utils/index.d.ts +6 -1
  184. package/dist/pregel/utils/index.d.ts.map +1 -1
  185. package/dist/pregel/utils/index.js +1 -0
  186. package/dist/pregel/utils/index.js.map +1 -1
  187. package/dist/pregel/utils/timeout.cjs +34 -0
  188. package/dist/pregel/utils/timeout.cjs.map +1 -0
  189. package/dist/pregel/utils/timeout.d.cts +45 -0
  190. package/dist/pregel/utils/timeout.d.cts.map +1 -0
  191. package/dist/pregel/utils/timeout.d.ts +45 -0
  192. package/dist/pregel/utils/timeout.d.ts.map +1 -0
  193. package/dist/pregel/utils/timeout.js +34 -0
  194. package/dist/pregel/utils/timeout.js.map +1 -0
  195. package/dist/web.cjs +11 -0
  196. package/dist/web.d.cts +11 -8
  197. package/dist/web.d.ts +11 -8
  198. package/dist/web.js +5 -3
  199. package/package.json +5 -5
@@ -1,5 +1,5 @@
1
- import { CONFIG_KEY_ABORT_SIGNALS, CONFIG_KEY_CALL, CONFIG_KEY_SCRATCHPAD, ERROR, INTERRUPT, NO_WRITES, RESUME, RETURN } from "../constants.js";
2
- import { isGraphBubbleUp, isGraphInterrupt } from "../errors.js";
1
+ import { CONFIG_KEY_ABORT_SIGNALS, CONFIG_KEY_CALL, CONFIG_KEY_SCRATCHPAD, ERROR, ERROR_SOURCE_NODE, INTERRUPT, NO_WRITES, RESUME, RETURN } from "../constants.js";
2
+ import { isGraphBubbleUp, isGraphDrained, isGraphInterrupt } from "../errors.js";
3
3
  import { Call } from "./types.js";
4
4
  import { combineAbortSignals, patchConfigurable } from "./utils/index.js";
5
5
  import { _runWithRetry } from "./retry.js";
@@ -26,6 +26,11 @@ var PregelRunner = class {
26
26
  nodeFinished;
27
27
  loop;
28
28
  /**
29
+ * Exceptions already routed to a node-level error handler. Consulted when
30
+ * deciding whether a failed task should abort the run.
31
+ */
32
+ handledExceptions = /* @__PURE__ */ new WeakSet();
33
+ /**
29
34
  * Construct a new PregelRunner, which executes tasks from the provided PregelLoop.
30
35
  * @param loop - The PregelLoop that produces tasks for this runner to execute.
31
36
  */
@@ -46,7 +51,8 @@ var PregelRunner = class {
46
51
  const exceptionSignalController = new AbortController();
47
52
  const exceptionSignal = exceptionSignalController.signal;
48
53
  const stepTimeoutSignal = timeout ? AbortSignal.timeout(timeout) : void 0;
49
- const pendingTasks = Object.values(this.loop.tasks).filter((t) => t.writes.length === 0);
54
+ const allTasks = Object.values(this.loop.tasks);
55
+ const pendingTasks = allTasks.filter((t) => t.writes.length === 0);
50
56
  const { signals, disposeCombinedSignal } = this._initializeAbortSignals({
51
57
  exceptionSignal,
52
58
  stepTimeoutSignal,
@@ -59,6 +65,7 @@ var PregelRunner = class {
59
65
  });
60
66
  for await (const { task, error, signalAborted } of taskStream) {
61
67
  this._commit(task, error);
68
+ if (error !== void 0 && this.handledExceptions.has(error)) continue;
62
69
  if (isGraphInterrupt(error)) graphBubbleUp = error;
63
70
  else if (isGraphBubbleUp(error) && !isGraphInterrupt(graphBubbleUp)) graphBubbleUp = error;
64
71
  else if (error && (nodeErrors.size === 0 || !signalAborted)) {
@@ -67,10 +74,11 @@ var PregelRunner = class {
67
74
  }
68
75
  }
69
76
  disposeCombinedSignal?.();
70
- onStepWrite?.(this.loop.step, Object.values(this.loop.tasks).map((task) => task.writes).flat());
77
+ onStepWrite?.(this.loop.step, allTasks.map((task) => task.writes).flat());
71
78
  if (nodeErrors.size === 1) throw Array.from(nodeErrors)[0];
72
79
  else if (nodeErrors.size > 1) throw new AggregateError(Array.from(nodeErrors), `Multiple errors occurred during superstep ${this.loop.step}. See the "errors" field of this exception for more details.`);
73
80
  if (isGraphInterrupt(graphBubbleUp)) throw graphBubbleUp;
81
+ if (isGraphDrained(graphBubbleUp)) throw graphBubbleUp;
74
82
  if (isGraphBubbleUp(graphBubbleUp) && this.loop.isNested) throw graphBubbleUp;
75
83
  }
76
84
  /**
@@ -142,7 +150,22 @@ var PregelRunner = class {
142
150
  barrier.wait
143
151
  ]);
144
152
  if (settledTask === PROMISE_ADDED_SYMBOL) continue;
145
- yield settledTask;
153
+ const settled = settledTask;
154
+ const { task: settledPregelTask, error: settledError } = settled;
155
+ if (settledError !== void 0 && !isGraphBubbleUp(settledError) && !this.loop.isErrorHandlerNode(String(settledPregelTask.name)) && this.loop.getErrorHandlerNode(String(settledPregelTask.name)) !== void 0) {
156
+ const handlerTask = this.loop.scheduleErrorHandler(settledPregelTask, settledError);
157
+ if (handlerTask !== void 0) {
158
+ executingTasksMap[handlerTask.id] = _runWithRetry(handlerTask, retryPolicy, { [CONFIG_KEY_CALL]: call?.bind(thisCall, this, handlerTask) }, signals?.composedAbortSignal).catch((error) => {
159
+ return {
160
+ task: handlerTask,
161
+ error,
162
+ signalAborted: signals?.composedAbortSignal?.aborted
163
+ };
164
+ });
165
+ barrier.next();
166
+ }
167
+ }
168
+ yield settled;
146
169
  if (listener != null) {
147
170
  timeoutOrCancelSignal.signal?.removeEventListener("abort", listener);
148
171
  timeoutOrCancelSignal.dispose?.();
@@ -151,6 +174,14 @@ var PregelRunner = class {
151
174
  }
152
175
  }
153
176
  /**
177
+ * Whether a failed task should record {@link ERROR_SOURCE_NODE} provenance.
178
+ */
179
+ _shouldRouteToErrorHandler(task) {
180
+ const name = String(task.name);
181
+ if (this.loop.isErrorHandlerNode(name)) return false;
182
+ return this.loop.getErrorHandlerNode(name) !== void 0;
183
+ }
184
+ /**
154
185
  * Determines what writes to apply based on whether the task completed successfully, and what type of error occurred.
155
186
  *
156
187
  * Throws an error if the error is a {@link GraphBubbleUp} error and {@link PregelLoop}#isNested is true.
@@ -166,11 +197,20 @@ var PregelRunner = class {
166
197
  if (resumes.length) interrupts.push(...resumes);
167
198
  this.loop.putWrites(task.id, interrupts);
168
199
  }
200
+ } else if (isGraphDrained(error)) {
201
+ if (task.writes.length) this.loop.putWrites(task.id, task.writes);
169
202
  } else if (isGraphBubbleUp(error) && task.writes.length) this.loop.putWrites(task.id, task.writes);
170
- else this.loop.putWrites(task.id, [[ERROR, {
171
- message: error.message,
172
- name: error.name
173
- }]]);
203
+ else {
204
+ task.writes.push([ERROR, {
205
+ message: error.message,
206
+ name: error.name
207
+ }]);
208
+ if (this._shouldRouteToErrorHandler(task)) {
209
+ task.writes.push([ERROR_SOURCE_NODE, String(task.name)]);
210
+ this.handledExceptions.add(error);
211
+ }
212
+ this.loop.putWrites(task.id, task.writes);
213
+ }
174
214
  else {
175
215
  if (this.nodeFinished && (task.config?.tags == null || !task.config.tags.includes("langsmith:hidden"))) this.nodeFinished(String(task.name));
176
216
  if (task.writes.length === 0) task.writes.push([NO_WRITES, null]);
@@ -189,6 +229,7 @@ async function call(runner, task, func, name, input, options = {}) {
189
229
  input,
190
230
  cache: options.cache,
191
231
  retry: options.retry,
232
+ timeout: options.timeout,
192
233
  callbacks: options.callbacks
193
234
  });
194
235
  const nextTask = await this.scheduleTask(task, cnt, wcall);
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","names":[],"sources":["../../src/pregel/runner.ts"],"sourcesContent":["import { PendingWrite } from \"@langchain/langgraph-checkpoint\";\nimport {\n Call,\n PregelAbortSignals,\n PregelExecutableTask,\n PregelScratchpad,\n} from \"./types.js\";\nimport {\n CachePolicy,\n combineAbortSignals,\n patchConfigurable,\n RetryPolicy,\n} from \"./utils/index.js\";\nimport {\n CONFIG_KEY_SCRATCHPAD,\n ERROR,\n INTERRUPT,\n RESUME,\n NO_WRITES,\n TAG_HIDDEN,\n RETURN,\n CONFIG_KEY_CALL,\n CONFIG_KEY_ABORT_SIGNALS,\n} from \"../constants.js\";\nimport { GraphBubbleUp, isGraphBubbleUp, isGraphInterrupt } from \"../errors.js\";\nimport { _runWithRetry, SettledPregelTask } from \"./retry.js\";\nimport { PregelLoop } from \"./loop.js\";\n\nconst PROMISE_ADDED_SYMBOL = Symbol.for(\"promiseAdded\");\n\nfunction createPromiseBarrier() {\n const barrier: {\n next: () => void;\n wait: Promise<unknown>;\n } = {\n next: () => void 0,\n wait: Promise.resolve(PROMISE_ADDED_SYMBOL),\n };\n\n function waitHandler(resolve: (value: typeof PROMISE_ADDED_SYMBOL) => void) {\n barrier.next = () => {\n barrier.wait = new Promise(waitHandler);\n resolve(PROMISE_ADDED_SYMBOL);\n };\n }\n barrier.wait = new Promise(waitHandler);\n return barrier;\n}\n\n/**\n * Options for the {@link PregelRunner#tick} method.\n */\nexport type TickOptions = {\n /**\n * The deadline before which all tasks must be completed.\n */\n timeout?: number;\n\n /**\n * An optional {@link AbortSignal} to cancel processing of tasks.\n */\n signal?: AbortSignal;\n\n /**\n * The {@link RetryPolicy} to use for the tick.\n */\n retryPolicy?: RetryPolicy;\n\n /**\n * An optional callback to be called after all task writes are completed.\n */\n onStepWrite?: (step: number, writes: PendingWrite[]) => void;\n\n /**\n * The maximum number of tasks to execute concurrently.\n */\n maxConcurrency?: number;\n};\n\n/**\n * Responsible for handling task execution on each tick of the {@link PregelLoop}.\n */\nexport class PregelRunner {\n private nodeFinished?: (id: string) => void;\n\n private loop: PregelLoop;\n\n /**\n * Construct a new PregelRunner, which executes tasks from the provided PregelLoop.\n * @param loop - The PregelLoop that produces tasks for this runner to execute.\n */\n constructor({\n loop,\n nodeFinished,\n }: {\n loop: PregelLoop;\n nodeFinished?: (id: string) => void;\n }) {\n this.loop = loop;\n this.nodeFinished = nodeFinished;\n }\n\n /**\n * Execute tasks from the current step of the PregelLoop.\n *\n * Note: this method does NOT call {@link PregelLoop}#tick. That must be handled externally.\n * @param options - Options for the execution.\n */\n async tick(options: TickOptions = {}) {\n const { timeout, retryPolicy, onStepWrite, maxConcurrency } = options;\n\n const nodeErrors: Set<Error> = new Set();\n let graphBubbleUp: GraphBubbleUp | undefined;\n\n const exceptionSignalController = new AbortController();\n const exceptionSignal = exceptionSignalController.signal;\n const stepTimeoutSignal = timeout\n ? AbortSignal.timeout(timeout)\n : undefined;\n\n // Start task execution\n const pendingTasks = Object.values(this.loop.tasks).filter(\n (t) => t.writes.length === 0\n );\n\n const { signals, disposeCombinedSignal } = this._initializeAbortSignals({\n exceptionSignal,\n stepTimeoutSignal,\n signal: options.signal,\n });\n\n const taskStream = this._executeTasksWithRetry(pendingTasks, {\n signals,\n retryPolicy,\n maxConcurrency,\n });\n\n for await (const { task, error, signalAborted } of taskStream) {\n this._commit(task, error);\n if (isGraphInterrupt(error)) {\n graphBubbleUp = error;\n } else if (isGraphBubbleUp(error) && !isGraphInterrupt(graphBubbleUp)) {\n graphBubbleUp = error;\n } else if (error && (nodeErrors.size === 0 || !signalAborted)) {\n /*\n * The goal here is to capture the exception that causes the graph to terminate early. In\n * theory it's possible for multiple nodes to throw, so this also handles the edge case of\n * capturing concurrent exceptions thrown before the node saw an abort. This is checked via\n * the signalAborted flag, which records the state of the abort signal at the time the node\n * execution finished.\n *\n * There is a case however where one node throws some error causing us to trigger an abort,\n * which then causes other concurrently executing nodes to throw their own AbortErrors. In\n * this case we don't care about reporting the abort errors thrown by the other nodes,\n * because they don't tell the user anything about what caused the graph execution to\n * terminate early, so we ignore them (and any other errors that occur after the node sees\n * an abort signal).\n */\n exceptionSignalController.abort();\n nodeErrors.add(error);\n }\n }\n\n disposeCombinedSignal?.();\n\n onStepWrite?.(\n this.loop.step,\n Object.values(this.loop.tasks)\n .map((task) => task.writes)\n .flat()\n );\n\n if (nodeErrors.size === 1) {\n throw Array.from(nodeErrors)[0];\n } else if (nodeErrors.size > 1) {\n throw new AggregateError(\n Array.from(nodeErrors),\n `Multiple errors occurred during superstep ${this.loop.step}. See the \"errors\" field of this exception for more details.`\n );\n }\n\n if (isGraphInterrupt(graphBubbleUp)) {\n throw graphBubbleUp;\n }\n\n if (isGraphBubbleUp(graphBubbleUp) && this.loop.isNested) {\n throw graphBubbleUp;\n }\n }\n\n /**\n * Initializes the current AbortSignals for the PregelRunner, handling the various ways that\n * AbortSignals must be chained together so that the PregelLoop can be interrupted if necessary\n * while still allowing nodes to gracefully exit.\n *\n * This method must only be called once per PregelRunner#tick. It has the side effect of updating\n * the PregelLoop#config with the new AbortSignals so they may be propagated correctly to future\n * ticks and subgraph calls.\n *\n * @param options - Options for the initialization.\n * @returns The current abort signals.\n * @internal\n */\n private _initializeAbortSignals({\n exceptionSignal,\n stepTimeoutSignal,\n signal,\n }: {\n exceptionSignal: AbortSignal;\n stepTimeoutSignal?: AbortSignal;\n signal?: AbortSignal;\n }): { signals: PregelAbortSignals; disposeCombinedSignal?: () => void } {\n const previousSignals = (this.loop.config.configurable?.[\n CONFIG_KEY_ABORT_SIGNALS\n ] ?? {}) as PregelAbortSignals;\n\n // We always inherit the external abort signal from AsyncLocalStorage,\n // since that's the only way the signal is inherited by the subgraph calls.\n const externalAbortSignal = previousSignals.externalAbortSignal ?? signal;\n\n // inherit the step timeout signal from parent graph\n const timeoutAbortSignal =\n stepTimeoutSignal ?? previousSignals.timeoutAbortSignal;\n\n const { signal: composedAbortSignal, dispose: disposeCombinedSignal } =\n combineAbortSignals(\n externalAbortSignal,\n timeoutAbortSignal,\n exceptionSignal\n );\n\n const signals: PregelAbortSignals = {\n externalAbortSignal,\n timeoutAbortSignal,\n composedAbortSignal,\n };\n\n this.loop.config = patchConfigurable(this.loop.config, {\n [CONFIG_KEY_ABORT_SIGNALS]: signals,\n });\n\n return { signals, disposeCombinedSignal };\n }\n\n /**\n * Concurrently executes tasks with the requested retry policy, yielding a {@link SettledPregelTask} for each task as it completes.\n * @param tasks - The tasks to execute.\n * @param options - Options for the execution.\n */\n private async *_executeTasksWithRetry(\n tasks: PregelExecutableTask<string, string>[],\n options?: {\n signals?: PregelAbortSignals;\n retryPolicy?: RetryPolicy;\n maxConcurrency?: number;\n }\n ): AsyncGenerator<SettledPregelTask> {\n const { retryPolicy, maxConcurrency, signals } = options ?? {};\n\n const barrier = createPromiseBarrier();\n const executingTasksMap: Record<\n string,\n Promise<{\n task: PregelExecutableTask<string, string>;\n result?: unknown;\n error?: Error;\n }>\n > = {};\n\n const thisCall = {\n executingTasksMap,\n barrier,\n retryPolicy,\n scheduleTask: async (\n task: PregelExecutableTask<string, string>,\n writeIdx: number,\n call?: Call\n ) => this.loop.acceptPush(task, writeIdx, call),\n };\n\n if (signals?.composedAbortSignal?.aborted) {\n // note: don't use throwIfAborted here because it throws a DOMException,\n // which isn't consistent with how we throw on abort below.\n throw new Error(\"Abort\");\n }\n\n let startedTasksCount = 0;\n\n let listener: (() => void) | undefined;\n const timeoutOrCancelSignal = combineAbortSignals(\n signals?.externalAbortSignal,\n signals?.timeoutAbortSignal\n );\n\n const abortPromise = timeoutOrCancelSignal.signal\n ? new Promise<never>((_resolve, reject) => {\n listener = () => reject(new Error(\"Abort\"));\n timeoutOrCancelSignal.signal?.addEventListener(\"abort\", listener, {\n once: true,\n });\n })\n : undefined;\n\n while (\n (startedTasksCount === 0 || Object.keys(executingTasksMap).length > 0) &&\n tasks.length\n ) {\n for (\n ;\n Object.values(executingTasksMap).length <\n (maxConcurrency ?? tasks.length) && startedTasksCount < tasks.length;\n startedTasksCount += 1\n ) {\n const task = tasks[startedTasksCount];\n\n executingTasksMap[task.id] = _runWithRetry(\n task,\n retryPolicy,\n { [CONFIG_KEY_CALL]: call?.bind(thisCall, this, task) },\n signals?.composedAbortSignal\n ).catch((error) => {\n return {\n task,\n error,\n signalAborted: signals?.composedAbortSignal?.aborted,\n };\n });\n }\n\n const settledTask = await Promise.race([\n ...Object.values(executingTasksMap),\n ...(abortPromise ? [abortPromise] : []),\n barrier.wait,\n ]);\n\n if (settledTask === PROMISE_ADDED_SYMBOL) {\n continue;\n }\n\n yield settledTask as SettledPregelTask;\n\n if (listener != null) {\n timeoutOrCancelSignal.signal?.removeEventListener(\"abort\", listener);\n timeoutOrCancelSignal.dispose?.();\n }\n\n delete executingTasksMap[(settledTask as SettledPregelTask).task.id];\n }\n }\n\n /**\n * Determines what writes to apply based on whether the task completed successfully, and what type of error occurred.\n *\n * Throws an error if the error is a {@link GraphBubbleUp} error and {@link PregelLoop}#isNested is true.\n *\n * @param task - The task to commit.\n * @param error - The error that occurred, if any.\n */\n private _commit(task: PregelExecutableTask<string, string>, error?: Error) {\n if (error !== undefined) {\n if (isGraphInterrupt(error)) {\n if (error.interrupts.length) {\n const interrupts: PendingWrite<string>[] = error.interrupts.map(\n (interrupt) => [INTERRUPT, interrupt]\n );\n const resumes = task.writes.filter((w) => w[0] === RESUME);\n if (resumes.length) {\n interrupts.push(...resumes);\n }\n this.loop.putWrites(task.id, interrupts);\n }\n } else if (isGraphBubbleUp(error) && task.writes.length) {\n this.loop.putWrites(task.id, task.writes);\n } else {\n this.loop.putWrites(task.id, [\n [ERROR, { message: error.message, name: error.name }],\n ]);\n }\n } else {\n if (\n this.nodeFinished &&\n (task.config?.tags == null || !task.config.tags.includes(TAG_HIDDEN))\n ) {\n this.nodeFinished(String(task.name));\n }\n\n if (task.writes.length === 0) {\n // Add no writes marker\n task.writes.push([NO_WRITES, null]);\n }\n\n // Save task writes to checkpointer\n this.loop.putWrites(task.id, task.writes);\n }\n }\n}\n\nasync function call(\n this: {\n executingTasksMap: Record<\n string,\n Promise<{\n task: PregelExecutableTask<string, string>;\n result?: unknown;\n error?: Error;\n }>\n >;\n\n barrier: {\n next: () => void;\n wait: Promise<unknown>;\n };\n\n retryPolicy?: RetryPolicy;\n\n scheduleTask: (\n task: PregelExecutableTask<string, string>,\n writeIdx: number,\n call?: Call\n ) => Promise<PregelExecutableTask<string, string> | void>;\n },\n runner: PregelRunner,\n task: PregelExecutableTask<string, string>,\n func: (...args: unknown[]) => unknown | Promise<unknown>,\n name: string,\n input: unknown,\n options: {\n retry?: RetryPolicy;\n cache?: CachePolicy;\n callbacks?: unknown;\n } = {}\n): Promise<unknown> {\n // Schedule PUSH tasks, collect promises\n const scratchpad = task.config?.configurable?.[CONFIG_KEY_SCRATCHPAD] as\n | PregelScratchpad<unknown>\n | undefined;\n\n if (!scratchpad) {\n throw new Error(\n `BUG: No scratchpad found on task ${task.name}__${task.id}`\n );\n }\n\n const cnt = scratchpad.callCounter;\n scratchpad.callCounter += 1;\n\n // schedule the next task, if the callback returns one\n const wcall = new Call({\n func,\n name,\n input,\n cache: options.cache,\n retry: options.retry,\n callbacks: options.callbacks,\n });\n const nextTask = await this.scheduleTask(task, cnt, wcall);\n if (!nextTask) return undefined;\n\n // Check if this task is already running\n const existingPromise = this.executingTasksMap[nextTask.id];\n\n if (existingPromise !== undefined) {\n // If the parent task was retried, the next task might already be running\n return existingPromise;\n }\n\n if (nextTask.writes.length > 0) {\n // If it already ran, return the result\n const returns = nextTask.writes.filter(([c]) => c === RETURN);\n const errors = nextTask.writes.filter(([c]) => c === ERROR);\n\n if (returns.length > 0) {\n // Task completed successfully\n if (returns.length === 1) return Promise.resolve(returns[0][1]);\n\n // should be unreachable\n throw new Error(\n `BUG: multiple returns found for task ${nextTask.name}__${nextTask.id}`\n );\n }\n\n if (errors.length > 0) {\n // Task failed\n if (errors.length === 1) {\n const errorValue = errors[0][1];\n const error =\n // eslint-disable-next-line no-instanceof/no-instanceof\n errorValue instanceof Error\n ? errorValue\n : new Error(String(errorValue));\n\n return Promise.reject(error);\n }\n\n // the only way this should happen is if the task executes multiple times and writes aren't cleared\n throw new Error(\n `BUG: multiple errors found for task ${nextTask.name}__${nextTask.id}`\n );\n }\n\n return undefined;\n } else {\n // Schedule the next task with retry\n const prom = _runWithRetry<string, string>(nextTask, options.retry, {\n [CONFIG_KEY_CALL]: call.bind(this, runner, nextTask),\n });\n\n this.executingTasksMap[nextTask.id] = prom;\n this.barrier.next();\n\n return prom.then(({ result, error }) => {\n if (error) return Promise.reject(error);\n return result;\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","names":[],"sources":["../../src/pregel/runner.ts"],"sourcesContent":["import { PendingWrite } from \"@langchain/langgraph-checkpoint\";\nimport {\n Call,\n PregelAbortSignals,\n PregelExecutableTask,\n PregelScratchpad,\n} from \"./types.js\";\nimport {\n CachePolicy,\n combineAbortSignals,\n patchConfigurable,\n RetryPolicy,\n TimeoutPolicy,\n} from \"./utils/index.js\";\nimport {\n CONFIG_KEY_SCRATCHPAD,\n ERROR,\n ERROR_SOURCE_NODE,\n INTERRUPT,\n RESUME,\n NO_WRITES,\n TAG_HIDDEN,\n RETURN,\n CONFIG_KEY_CALL,\n CONFIG_KEY_ABORT_SIGNALS,\n} from \"../constants.js\";\nimport {\n GraphBubbleUp,\n isGraphBubbleUp,\n isGraphDrained,\n isGraphInterrupt,\n} from \"../errors.js\";\nimport { _runWithRetry, SettledPregelTask } from \"./retry.js\";\nimport { PregelLoop } from \"./loop.js\";\n\nconst PROMISE_ADDED_SYMBOL = Symbol.for(\"promiseAdded\");\n\nfunction createPromiseBarrier() {\n const barrier: {\n next: () => void;\n wait: Promise<unknown>;\n } = {\n next: () => void 0,\n wait: Promise.resolve(PROMISE_ADDED_SYMBOL),\n };\n\n function waitHandler(resolve: (value: typeof PROMISE_ADDED_SYMBOL) => void) {\n barrier.next = () => {\n barrier.wait = new Promise(waitHandler);\n resolve(PROMISE_ADDED_SYMBOL);\n };\n }\n barrier.wait = new Promise(waitHandler);\n return barrier;\n}\n\n/**\n * Options for the {@link PregelRunner#tick} method.\n */\nexport type TickOptions = {\n /**\n * The deadline before which all tasks must be completed.\n */\n timeout?: number;\n\n /**\n * An optional {@link AbortSignal} to cancel processing of tasks.\n */\n signal?: AbortSignal;\n\n /**\n * The {@link RetryPolicy} to use for the tick.\n */\n retryPolicy?: RetryPolicy;\n\n /**\n * An optional callback to be called after all task writes are completed.\n */\n onStepWrite?: (step: number, writes: PendingWrite[]) => void;\n\n /**\n * The maximum number of tasks to execute concurrently.\n */\n maxConcurrency?: number;\n};\n\n/**\n * Responsible for handling task execution on each tick of the {@link PregelLoop}.\n */\nexport class PregelRunner {\n private nodeFinished?: (id: string) => void;\n\n private loop: PregelLoop;\n\n /**\n * Exceptions already routed to a node-level error handler. Consulted when\n * deciding whether a failed task should abort the run.\n */\n private handledExceptions = new WeakSet<Error>();\n\n /**\n * Construct a new PregelRunner, which executes tasks from the provided PregelLoop.\n * @param loop - The PregelLoop that produces tasks for this runner to execute.\n */\n constructor({\n loop,\n nodeFinished,\n }: {\n loop: PregelLoop;\n nodeFinished?: (id: string) => void;\n }) {\n this.loop = loop;\n this.nodeFinished = nodeFinished;\n }\n\n /**\n * Execute tasks from the current step of the PregelLoop.\n *\n * Note: this method does NOT call {@link PregelLoop}#tick. That must be handled externally.\n * @param options - Options for the execution.\n */\n async tick(options: TickOptions = {}) {\n const { timeout, retryPolicy, onStepWrite, maxConcurrency } = options;\n\n const nodeErrors: Set<Error> = new Set();\n let graphBubbleUp: GraphBubbleUp | undefined;\n\n const exceptionSignalController = new AbortController();\n const exceptionSignal = exceptionSignalController.signal;\n const stepTimeoutSignal = timeout\n ? AbortSignal.timeout(timeout)\n : undefined;\n\n const allTasks = Object.values(this.loop.tasks);\n const pendingTasks = allTasks.filter((t) => t.writes.length === 0);\n\n const { signals, disposeCombinedSignal } = this._initializeAbortSignals({\n exceptionSignal,\n stepTimeoutSignal,\n signal: options.signal,\n });\n\n const taskStream = this._executeTasksWithRetry(pendingTasks, {\n signals,\n retryPolicy,\n maxConcurrency,\n });\n\n for await (const { task, error, signalAborted } of taskStream) {\n this._commit(task, error);\n if (error !== undefined && this.handledExceptions.has(error)) {\n // Routed to a node-level error handler in this tick; provenance is\n // checkpointed and the error must not abort the run.\n continue;\n }\n if (isGraphInterrupt(error)) {\n graphBubbleUp = error;\n } else if (isGraphBubbleUp(error) && !isGraphInterrupt(graphBubbleUp)) {\n graphBubbleUp = error;\n } else if (error && (nodeErrors.size === 0 || !signalAborted)) {\n /*\n * The goal here is to capture the exception that causes the graph to terminate early. In\n * theory it's possible for multiple nodes to throw, so this also handles the edge case of\n * capturing concurrent exceptions thrown before the node saw an abort. This is checked via\n * the signalAborted flag, which records the state of the abort signal at the time the node\n * execution finished.\n *\n * There is a case however where one node throws some error causing us to trigger an abort,\n * which then causes other concurrently executing nodes to throw their own AbortErrors. In\n * this case we don't care about reporting the abort errors thrown by the other nodes,\n * because they don't tell the user anything about what caused the graph execution to\n * terminate early, so we ignore them (and any other errors that occur after the node sees\n * an abort signal).\n */\n exceptionSignalController.abort();\n nodeErrors.add(error);\n }\n }\n\n disposeCombinedSignal?.();\n\n onStepWrite?.(this.loop.step, allTasks.map((task) => task.writes).flat());\n\n if (nodeErrors.size === 1) {\n throw Array.from(nodeErrors)[0];\n } else if (nodeErrors.size > 1) {\n throw new AggregateError(\n Array.from(nodeErrors),\n `Multiple errors occurred during superstep ${this.loop.step}. See the \"errors\" field of this exception for more details.`\n );\n }\n\n if (isGraphInterrupt(graphBubbleUp)) {\n throw graphBubbleUp;\n }\n\n // A cooperative drain raised by a subgraph bubbles up through the parent\n // loop (even when the parent is the top graph) so the parent stops at this\n // boundary and its checkpoint can be resumed later.\n if (isGraphDrained(graphBubbleUp)) {\n throw graphBubbleUp;\n }\n\n if (isGraphBubbleUp(graphBubbleUp) && this.loop.isNested) {\n throw graphBubbleUp;\n }\n }\n\n /**\n * Initializes the current AbortSignals for the PregelRunner, handling the various ways that\n * AbortSignals must be chained together so that the PregelLoop can be interrupted if necessary\n * while still allowing nodes to gracefully exit.\n *\n * This method must only be called once per PregelRunner#tick. It has the side effect of updating\n * the PregelLoop#config with the new AbortSignals so they may be propagated correctly to future\n * ticks and subgraph calls.\n *\n * @param options - Options for the initialization.\n * @returns The current abort signals.\n * @internal\n */\n private _initializeAbortSignals({\n exceptionSignal,\n stepTimeoutSignal,\n signal,\n }: {\n exceptionSignal: AbortSignal;\n stepTimeoutSignal?: AbortSignal;\n signal?: AbortSignal;\n }): { signals: PregelAbortSignals; disposeCombinedSignal?: () => void } {\n const previousSignals = (this.loop.config.configurable?.[\n CONFIG_KEY_ABORT_SIGNALS\n ] ?? {}) as PregelAbortSignals;\n\n // We always inherit the external abort signal from AsyncLocalStorage,\n // since that's the only way the signal is inherited by the subgraph calls.\n const externalAbortSignal = previousSignals.externalAbortSignal ?? signal;\n\n // inherit the step timeout signal from parent graph\n const timeoutAbortSignal =\n stepTimeoutSignal ?? previousSignals.timeoutAbortSignal;\n\n const { signal: composedAbortSignal, dispose: disposeCombinedSignal } =\n combineAbortSignals(\n externalAbortSignal,\n timeoutAbortSignal,\n exceptionSignal\n );\n\n const signals: PregelAbortSignals = {\n externalAbortSignal,\n timeoutAbortSignal,\n composedAbortSignal,\n };\n\n this.loop.config = patchConfigurable(this.loop.config, {\n [CONFIG_KEY_ABORT_SIGNALS]: signals,\n });\n\n return { signals, disposeCombinedSignal };\n }\n\n /**\n * Concurrently executes tasks with the requested retry policy, yielding a {@link SettledPregelTask} for each task as it completes.\n * @param tasks - The tasks to execute.\n * @param options - Options for the execution.\n */\n private async *_executeTasksWithRetry(\n tasks: PregelExecutableTask<string, string>[],\n options?: {\n signals?: PregelAbortSignals;\n retryPolicy?: RetryPolicy;\n maxConcurrency?: number;\n }\n ): AsyncGenerator<SettledPregelTask> {\n const { retryPolicy, maxConcurrency, signals } = options ?? {};\n\n const barrier = createPromiseBarrier();\n const executingTasksMap: Record<\n string,\n Promise<{\n task: PregelExecutableTask<string, string>;\n result?: unknown;\n error?: Error;\n }>\n > = {};\n\n const thisCall = {\n executingTasksMap,\n barrier,\n retryPolicy,\n scheduleTask: async (\n task: PregelExecutableTask<string, string>,\n writeIdx: number,\n call?: Call\n ) => this.loop.acceptPush(task, writeIdx, call),\n };\n\n if (signals?.composedAbortSignal?.aborted) {\n // note: don't use throwIfAborted here because it throws a DOMException,\n // which isn't consistent with how we throw on abort below.\n throw new Error(\"Abort\");\n }\n\n let startedTasksCount = 0;\n\n let listener: (() => void) | undefined;\n const timeoutOrCancelSignal = combineAbortSignals(\n signals?.externalAbortSignal,\n signals?.timeoutAbortSignal\n );\n\n const abortPromise = timeoutOrCancelSignal.signal\n ? new Promise<never>((_resolve, reject) => {\n listener = () => reject(new Error(\"Abort\"));\n timeoutOrCancelSignal.signal?.addEventListener(\"abort\", listener, {\n once: true,\n });\n })\n : undefined;\n\n while (\n (startedTasksCount === 0 || Object.keys(executingTasksMap).length > 0) &&\n tasks.length\n ) {\n for (\n ;\n Object.values(executingTasksMap).length <\n (maxConcurrency ?? tasks.length) && startedTasksCount < tasks.length;\n startedTasksCount += 1\n ) {\n const task = tasks[startedTasksCount];\n\n executingTasksMap[task.id] = _runWithRetry(\n task,\n retryPolicy,\n { [CONFIG_KEY_CALL]: call?.bind(thisCall, this, task) },\n signals?.composedAbortSignal\n ).catch((error) => {\n return {\n task,\n error,\n signalAborted: signals?.composedAbortSignal?.aborted,\n };\n });\n }\n\n const settledTask = await Promise.race([\n ...Object.values(executingTasksMap),\n ...(abortPromise ? [abortPromise] : []),\n barrier.wait,\n ]);\n\n if (settledTask === PROMISE_ADDED_SYMBOL) {\n continue;\n }\n\n const settled = settledTask as SettledPregelTask;\n const { task: settledPregelTask, error: settledError } = settled;\n\n // If the task failed (after exhausting its retry policy) and the node has\n // a registered error handler, schedule that handler to run within this\n // same tick instead of aborting the run. GraphBubbleUp errors (e.g.\n // interrupts / parent commands) are never routed to error handlers.\n if (\n settledError !== undefined &&\n !isGraphBubbleUp(settledError) &&\n !this.loop.isErrorHandlerNode(String(settledPregelTask.name)) &&\n this.loop.getErrorHandlerNode(String(settledPregelTask.name)) !==\n undefined\n ) {\n const handlerTask = this.loop.scheduleErrorHandler(\n settledPregelTask,\n settledError\n );\n if (handlerTask !== undefined) {\n executingTasksMap[handlerTask.id] = _runWithRetry(\n handlerTask,\n retryPolicy,\n { [CONFIG_KEY_CALL]: call?.bind(thisCall, this, handlerTask) },\n signals?.composedAbortSignal\n ).catch((error) => {\n return {\n task: handlerTask,\n error,\n signalAborted: signals?.composedAbortSignal?.aborted,\n };\n });\n barrier.next();\n }\n }\n\n yield settled;\n\n if (listener != null) {\n timeoutOrCancelSignal.signal?.removeEventListener(\"abort\", listener);\n timeoutOrCancelSignal.dispose?.();\n }\n\n delete executingTasksMap[(settledTask as SettledPregelTask).task.id];\n }\n }\n\n /**\n * Whether a failed task should record {@link ERROR_SOURCE_NODE} provenance.\n */\n private _shouldRouteToErrorHandler(\n task: PregelExecutableTask<string, string>\n ): boolean {\n const name = String(task.name);\n if (this.loop.isErrorHandlerNode(name)) {\n return false;\n }\n return this.loop.getErrorHandlerNode(name) !== undefined;\n }\n\n /**\n * Determines what writes to apply based on whether the task completed successfully, and what type of error occurred.\n *\n * Throws an error if the error is a {@link GraphBubbleUp} error and {@link PregelLoop}#isNested is true.\n *\n * @param task - The task to commit.\n * @param error - The error that occurred, if any.\n */\n private _commit(task: PregelExecutableTask<string, string>, error?: Error) {\n if (error !== undefined) {\n if (isGraphInterrupt(error)) {\n if (error.interrupts.length) {\n const interrupts: PendingWrite<string>[] = error.interrupts.map(\n (interrupt) => [INTERRUPT, interrupt]\n );\n const resumes = task.writes.filter((w) => w[0] === RESUME);\n if (resumes.length) {\n interrupts.push(...resumes);\n }\n this.loop.putWrites(task.id, interrupts);\n }\n } else if (isGraphDrained(error)) {\n // Cooperative drain bubbled up from a subgraph. Leave the task\n // uncommitted (unless it already produced writes) so it is\n // re-executed when the parent run resumes.\n if (task.writes.length) {\n this.loop.putWrites(task.id, task.writes);\n }\n } else if (isGraphBubbleUp(error) && task.writes.length) {\n this.loop.putWrites(task.id, task.writes);\n } else {\n task.writes.push([ERROR, { message: error.message, name: error.name }]);\n if (this._shouldRouteToErrorHandler(task)) {\n task.writes.push([ERROR_SOURCE_NODE, String(task.name)]);\n this.handledExceptions.add(error);\n }\n this.loop.putWrites(task.id, task.writes);\n }\n } else {\n if (\n this.nodeFinished &&\n (task.config?.tags == null || !task.config.tags.includes(TAG_HIDDEN))\n ) {\n this.nodeFinished(String(task.name));\n }\n\n if (task.writes.length === 0) {\n // Add no writes marker\n task.writes.push([NO_WRITES, null]);\n }\n\n // Save task writes to checkpointer\n this.loop.putWrites(task.id, task.writes);\n }\n }\n}\n\nasync function call(\n this: {\n executingTasksMap: Record<\n string,\n Promise<{\n task: PregelExecutableTask<string, string>;\n result?: unknown;\n error?: Error;\n }>\n >;\n\n barrier: {\n next: () => void;\n wait: Promise<unknown>;\n };\n\n retryPolicy?: RetryPolicy;\n\n scheduleTask: (\n task: PregelExecutableTask<string, string>,\n writeIdx: number,\n call?: Call\n ) => Promise<PregelExecutableTask<string, string> | void>;\n },\n runner: PregelRunner,\n task: PregelExecutableTask<string, string>,\n func: (...args: unknown[]) => unknown | Promise<unknown>,\n name: string,\n input: unknown,\n options: {\n retry?: RetryPolicy;\n cache?: CachePolicy;\n timeout?: TimeoutPolicy;\n callbacks?: unknown;\n } = {}\n): Promise<unknown> {\n // Schedule PUSH tasks, collect promises\n const scratchpad = task.config?.configurable?.[CONFIG_KEY_SCRATCHPAD] as\n | PregelScratchpad<unknown>\n | undefined;\n\n if (!scratchpad) {\n throw new Error(\n `BUG: No scratchpad found on task ${task.name}__${task.id}`\n );\n }\n\n const cnt = scratchpad.callCounter;\n scratchpad.callCounter += 1;\n\n // schedule the next task, if the callback returns one\n const wcall = new Call({\n func,\n name,\n input,\n cache: options.cache,\n retry: options.retry,\n timeout: options.timeout,\n callbacks: options.callbacks,\n });\n const nextTask = await this.scheduleTask(task, cnt, wcall);\n if (!nextTask) return undefined;\n\n // Check if this task is already running\n const existingPromise = this.executingTasksMap[nextTask.id];\n\n if (existingPromise !== undefined) {\n // If the parent task was retried, the next task might already be running\n return existingPromise;\n }\n\n if (nextTask.writes.length > 0) {\n // If it already ran, return the result\n const returns = nextTask.writes.filter(([c]) => c === RETURN);\n const errors = nextTask.writes.filter(([c]) => c === ERROR);\n\n if (returns.length > 0) {\n // Task completed successfully\n if (returns.length === 1) return Promise.resolve(returns[0][1]);\n\n // should be unreachable\n throw new Error(\n `BUG: multiple returns found for task ${nextTask.name}__${nextTask.id}`\n );\n }\n\n if (errors.length > 0) {\n // Task failed\n if (errors.length === 1) {\n const errorValue = errors[0][1];\n const error =\n // eslint-disable-next-line no-instanceof/no-instanceof\n errorValue instanceof Error\n ? errorValue\n : new Error(String(errorValue));\n\n return Promise.reject(error);\n }\n\n // the only way this should happen is if the task executes multiple times and writes aren't cleared\n throw new Error(\n `BUG: multiple errors found for task ${nextTask.name}__${nextTask.id}`\n );\n }\n\n return undefined;\n } else {\n // Schedule the next task with retry\n const prom = _runWithRetry<string, string>(nextTask, options.retry, {\n [CONFIG_KEY_CALL]: call.bind(this, runner, nextTask),\n });\n\n this.executingTasksMap[nextTask.id] = prom;\n this.barrier.next();\n\n return prom.then(({ result, error }) => {\n if (error) return Promise.reject(error);\n return result;\n });\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ //#region src/pregel/runtime.ts
2
+ /**
3
+ * Run-scoped control surface for cooperative draining.
4
+ *
5
+ * Intended for a single graph run. Create a fresh {@link RunControl} per run;
6
+ * reusing a control after {@link RunControl#requestDrain} leaves it drained.
7
+ *
8
+ * Safe to use from any concurrent context: the drain request is represented
9
+ * by a single field write, so no synchronization is needed for this signal.
10
+ * If more mutable state is added here, add synchronization.
11
+ *
12
+ * The intended use is hooking SIGTERM (or any external supervisor signal) to
13
+ * {@link RunControl#requestDrain} so an in-flight graph run can stop cleanly
14
+ * at the next superstep boundary and be resumed later from the saved
15
+ * checkpoint.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { RunControl, GraphDrained } from "@langchain/langgraph";
20
+ *
21
+ * const control = new RunControl();
22
+ *
23
+ * // In a signal handler, supervisor, etc.:
24
+ * // control.requestDrain("sigterm");
25
+ *
26
+ * try {
27
+ * const result = await graph.invoke(input, { ...config, control });
28
+ * if (control.drainRequested) {
29
+ * // finished naturally on the same tick where drain was requested
30
+ * }
31
+ * } catch (e) {
32
+ * if (e instanceof GraphDrained) {
33
+ * // checkpoint saved; resume later with the same config
34
+ * } else {
35
+ * throw e;
36
+ * }
37
+ * }
38
+ * ```
39
+ */
40
+ var RunControl = class {
41
+ #drainReason = void 0;
42
+ /**
43
+ * Request that the current run drain cooperatively, stopping at the next
44
+ * superstep boundary. Does not cancel work that is already running.
45
+ *
46
+ * @param reason - A short description of why the drain was requested.
47
+ * Surfaced on the resulting {@link GraphDrained} error.
48
+ */
49
+ requestDrain(reason = "shutdown") {
50
+ this.#drainReason = reason;
51
+ }
52
+ /** Whether a drain has been requested for this run. */
53
+ get drainRequested() {
54
+ return this.#drainReason !== void 0;
55
+ }
56
+ /** The reason passed to {@link RunControl#requestDrain}, if any. */
57
+ get drainReason() {
58
+ return this.#drainReason;
59
+ }
60
+ };
61
+ //#endregion
62
+ exports.RunControl = RunControl;
63
+
64
+ //# sourceMappingURL=runtime.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.cjs","names":["#drainReason"],"sources":["../../src/pregel/runtime.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars - needed to resolve below link\nimport type { GraphDrained } from \"../errors.js\";\n\n/**\n * Run-scoped control surface for cooperative draining.\n *\n * Intended for a single graph run. Create a fresh {@link RunControl} per run;\n * reusing a control after {@link RunControl#requestDrain} leaves it drained.\n *\n * Safe to use from any concurrent context: the drain request is represented\n * by a single field write, so no synchronization is needed for this signal.\n * If more mutable state is added here, add synchronization.\n *\n * The intended use is hooking SIGTERM (or any external supervisor signal) to\n * {@link RunControl#requestDrain} so an in-flight graph run can stop cleanly\n * at the next superstep boundary and be resumed later from the saved\n * checkpoint.\n *\n * @example\n * ```typescript\n * import { RunControl, GraphDrained } from \"@langchain/langgraph\";\n *\n * const control = new RunControl();\n *\n * // In a signal handler, supervisor, etc.:\n * // control.requestDrain(\"sigterm\");\n *\n * try {\n * const result = await graph.invoke(input, { ...config, control });\n * if (control.drainRequested) {\n * // finished naturally on the same tick where drain was requested\n * }\n * } catch (e) {\n * if (e instanceof GraphDrained) {\n * // checkpoint saved; resume later with the same config\n * } else {\n * throw e;\n * }\n * }\n * ```\n */\nexport class RunControl {\n #drainReason: string | undefined = undefined;\n\n /**\n * Request that the current run drain cooperatively, stopping at the next\n * superstep boundary. Does not cancel work that is already running.\n *\n * @param reason - A short description of why the drain was requested.\n * Surfaced on the resulting {@link GraphDrained} error.\n */\n requestDrain(reason: string = \"shutdown\"): void {\n this.#drainReason = reason;\n }\n\n /** Whether a drain has been requested for this run. */\n get drainRequested(): boolean {\n return this.#drainReason !== undefined;\n }\n\n /** The reason passed to {@link RunControl#requestDrain}, if any. */\n get drainReason(): string | undefined {\n return this.#drainReason;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,aAAb,MAAwB;CACtB,eAAmC,KAAA;;;;;;;;CASnC,aAAa,SAAiB,YAAkB;AAC9C,QAAA,cAAoB;;;CAItB,IAAI,iBAA0B;AAC5B,SAAO,MAAA,gBAAsB,KAAA;;;CAI/B,IAAI,cAAkC;AACpC,SAAO,MAAA"}
@@ -0,0 +1,57 @@
1
+ //#region src/pregel/runtime.d.ts
2
+ /**
3
+ * Run-scoped control surface for cooperative draining.
4
+ *
5
+ * Intended for a single graph run. Create a fresh {@link RunControl} per run;
6
+ * reusing a control after {@link RunControl#requestDrain} leaves it drained.
7
+ *
8
+ * Safe to use from any concurrent context: the drain request is represented
9
+ * by a single field write, so no synchronization is needed for this signal.
10
+ * If more mutable state is added here, add synchronization.
11
+ *
12
+ * The intended use is hooking SIGTERM (or any external supervisor signal) to
13
+ * {@link RunControl#requestDrain} so an in-flight graph run can stop cleanly
14
+ * at the next superstep boundary and be resumed later from the saved
15
+ * checkpoint.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { RunControl, GraphDrained } from "@langchain/langgraph";
20
+ *
21
+ * const control = new RunControl();
22
+ *
23
+ * // In a signal handler, supervisor, etc.:
24
+ * // control.requestDrain("sigterm");
25
+ *
26
+ * try {
27
+ * const result = await graph.invoke(input, { ...config, control });
28
+ * if (control.drainRequested) {
29
+ * // finished naturally on the same tick where drain was requested
30
+ * }
31
+ * } catch (e) {
32
+ * if (e instanceof GraphDrained) {
33
+ * // checkpoint saved; resume later with the same config
34
+ * } else {
35
+ * throw e;
36
+ * }
37
+ * }
38
+ * ```
39
+ */
40
+ declare class RunControl {
41
+ #private;
42
+ /**
43
+ * Request that the current run drain cooperatively, stopping at the next
44
+ * superstep boundary. Does not cancel work that is already running.
45
+ *
46
+ * @param reason - A short description of why the drain was requested.
47
+ * Surfaced on the resulting {@link GraphDrained} error.
48
+ */
49
+ requestDrain(reason?: string): void;
50
+ /** Whether a drain has been requested for this run. */
51
+ get drainRequested(): boolean;
52
+ /** The reason passed to {@link RunControl#requestDrain}, if any. */
53
+ get drainReason(): string | undefined;
54
+ }
55
+ //#endregion
56
+ export { RunControl };
57
+ //# sourceMappingURL=runtime.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.cts","names":[],"sources":["../../src/pregel/runtime.ts"],"mappings":";;AAyCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,UAAA;EAAA;;;;;;;;EAUX,YAAA,CAAa,MAAA;;MAKT,cAAA,CAAA;;MAKA,WAAA,CAAA;AAAA"}
@@ -0,0 +1,57 @@
1
+ //#region src/pregel/runtime.d.ts
2
+ /**
3
+ * Run-scoped control surface for cooperative draining.
4
+ *
5
+ * Intended for a single graph run. Create a fresh {@link RunControl} per run;
6
+ * reusing a control after {@link RunControl#requestDrain} leaves it drained.
7
+ *
8
+ * Safe to use from any concurrent context: the drain request is represented
9
+ * by a single field write, so no synchronization is needed for this signal.
10
+ * If more mutable state is added here, add synchronization.
11
+ *
12
+ * The intended use is hooking SIGTERM (or any external supervisor signal) to
13
+ * {@link RunControl#requestDrain} so an in-flight graph run can stop cleanly
14
+ * at the next superstep boundary and be resumed later from the saved
15
+ * checkpoint.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { RunControl, GraphDrained } from "@langchain/langgraph";
20
+ *
21
+ * const control = new RunControl();
22
+ *
23
+ * // In a signal handler, supervisor, etc.:
24
+ * // control.requestDrain("sigterm");
25
+ *
26
+ * try {
27
+ * const result = await graph.invoke(input, { ...config, control });
28
+ * if (control.drainRequested) {
29
+ * // finished naturally on the same tick where drain was requested
30
+ * }
31
+ * } catch (e) {
32
+ * if (e instanceof GraphDrained) {
33
+ * // checkpoint saved; resume later with the same config
34
+ * } else {
35
+ * throw e;
36
+ * }
37
+ * }
38
+ * ```
39
+ */
40
+ declare class RunControl {
41
+ #private;
42
+ /**
43
+ * Request that the current run drain cooperatively, stopping at the next
44
+ * superstep boundary. Does not cancel work that is already running.
45
+ *
46
+ * @param reason - A short description of why the drain was requested.
47
+ * Surfaced on the resulting {@link GraphDrained} error.
48
+ */
49
+ requestDrain(reason?: string): void;
50
+ /** Whether a drain has been requested for this run. */
51
+ get drainRequested(): boolean;
52
+ /** The reason passed to {@link RunControl#requestDrain}, if any. */
53
+ get drainReason(): string | undefined;
54
+ }
55
+ //#endregion
56
+ export { RunControl };
57
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","names":[],"sources":["../../src/pregel/runtime.ts"],"mappings":";;AAyCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,UAAA;EAAA;;;;;;;;EAUX,YAAA,CAAa,MAAA;;MAKT,cAAA,CAAA;;MAKA,WAAA,CAAA;AAAA"}
@@ -0,0 +1,64 @@
1
+ //#region src/pregel/runtime.ts
2
+ /**
3
+ * Run-scoped control surface for cooperative draining.
4
+ *
5
+ * Intended for a single graph run. Create a fresh {@link RunControl} per run;
6
+ * reusing a control after {@link RunControl#requestDrain} leaves it drained.
7
+ *
8
+ * Safe to use from any concurrent context: the drain request is represented
9
+ * by a single field write, so no synchronization is needed for this signal.
10
+ * If more mutable state is added here, add synchronization.
11
+ *
12
+ * The intended use is hooking SIGTERM (or any external supervisor signal) to
13
+ * {@link RunControl#requestDrain} so an in-flight graph run can stop cleanly
14
+ * at the next superstep boundary and be resumed later from the saved
15
+ * checkpoint.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { RunControl, GraphDrained } from "@langchain/langgraph";
20
+ *
21
+ * const control = new RunControl();
22
+ *
23
+ * // In a signal handler, supervisor, etc.:
24
+ * // control.requestDrain("sigterm");
25
+ *
26
+ * try {
27
+ * const result = await graph.invoke(input, { ...config, control });
28
+ * if (control.drainRequested) {
29
+ * // finished naturally on the same tick where drain was requested
30
+ * }
31
+ * } catch (e) {
32
+ * if (e instanceof GraphDrained) {
33
+ * // checkpoint saved; resume later with the same config
34
+ * } else {
35
+ * throw e;
36
+ * }
37
+ * }
38
+ * ```
39
+ */
40
+ var RunControl = class {
41
+ #drainReason = void 0;
42
+ /**
43
+ * Request that the current run drain cooperatively, stopping at the next
44
+ * superstep boundary. Does not cancel work that is already running.
45
+ *
46
+ * @param reason - A short description of why the drain was requested.
47
+ * Surfaced on the resulting {@link GraphDrained} error.
48
+ */
49
+ requestDrain(reason = "shutdown") {
50
+ this.#drainReason = reason;
51
+ }
52
+ /** Whether a drain has been requested for this run. */
53
+ get drainRequested() {
54
+ return this.#drainReason !== void 0;
55
+ }
56
+ /** The reason passed to {@link RunControl#requestDrain}, if any. */
57
+ get drainReason() {
58
+ return this.#drainReason;
59
+ }
60
+ };
61
+ //#endregion
62
+ export { RunControl };
63
+
64
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","names":["#drainReason"],"sources":["../../src/pregel/runtime.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars - needed to resolve below link\nimport type { GraphDrained } from \"../errors.js\";\n\n/**\n * Run-scoped control surface for cooperative draining.\n *\n * Intended for a single graph run. Create a fresh {@link RunControl} per run;\n * reusing a control after {@link RunControl#requestDrain} leaves it drained.\n *\n * Safe to use from any concurrent context: the drain request is represented\n * by a single field write, so no synchronization is needed for this signal.\n * If more mutable state is added here, add synchronization.\n *\n * The intended use is hooking SIGTERM (or any external supervisor signal) to\n * {@link RunControl#requestDrain} so an in-flight graph run can stop cleanly\n * at the next superstep boundary and be resumed later from the saved\n * checkpoint.\n *\n * @example\n * ```typescript\n * import { RunControl, GraphDrained } from \"@langchain/langgraph\";\n *\n * const control = new RunControl();\n *\n * // In a signal handler, supervisor, etc.:\n * // control.requestDrain(\"sigterm\");\n *\n * try {\n * const result = await graph.invoke(input, { ...config, control });\n * if (control.drainRequested) {\n * // finished naturally on the same tick where drain was requested\n * }\n * } catch (e) {\n * if (e instanceof GraphDrained) {\n * // checkpoint saved; resume later with the same config\n * } else {\n * throw e;\n * }\n * }\n * ```\n */\nexport class RunControl {\n #drainReason: string | undefined = undefined;\n\n /**\n * Request that the current run drain cooperatively, stopping at the next\n * superstep boundary. Does not cancel work that is already running.\n *\n * @param reason - A short description of why the drain was requested.\n * Surfaced on the resulting {@link GraphDrained} error.\n */\n requestDrain(reason: string = \"shutdown\"): void {\n this.#drainReason = reason;\n }\n\n /** Whether a drain has been requested for this run. */\n get drainRequested(): boolean {\n return this.#drainReason !== undefined;\n }\n\n /** The reason passed to {@link RunControl#requestDrain}, if any. */\n get drainReason(): string | undefined {\n return this.#drainReason;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,aAAb,MAAwB;CACtB,eAAmC,KAAA;;;;;;;;CASnC,aAAa,SAAiB,YAAkB;AAC9C,QAAA,cAAoB;;;CAItB,IAAI,iBAA0B;AAC5B,SAAO,MAAA,gBAAsB,KAAA;;;CAI/B,IAAI,cAAkC;AACpC,SAAO,MAAA"}
@@ -97,6 +97,8 @@ var IterableReadableWritableStream = class extends _langchain_core_utils_stream.
97
97
  */
98
98
  var StreamToolsHandler = class extends _langchain_core_callbacks_base.BaseCallbackHandler {
99
99
  name = "StreamToolsHandler";
100
+ /** Ensure tool lifecycle callbacks run before tool.invoke returns/errors. */
101
+ awaitHandlers = true;
100
102
  streamFn;
101
103
  runs = {};
102
104
  constructor(streamFn) {
@@ -1 +1 @@
1
- {"version":3,"file":"stream.cjs","names":["IterableReadableStream","BaseCallbackHandler","isCheckpointEnvelope"],"sources":["../../src/pregel/stream.ts"],"sourcesContent":["import { IterableReadableStream } from \"@langchain/core/utils/stream\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { BaseCallbackHandler } from \"@langchain/core/callbacks/base\";\nimport { Serialized } from \"@langchain/core/load/serializable\";\nimport { isCheckpointEnvelope } from \"../stream/convert.js\";\nimport type { Checkpoint } from \"../stream/types.js\";\nimport type { StreamMode, StreamOutputMap } from \"./types.js\";\nimport { TAG_HIDDEN } from \"../constants.js\";\n\n/**\n * Optional chunk-level metadata carried alongside the payload. Used by\n * `streamEvents(..., { version: \"v3\" })` to emit a companion `checkpoints`\n * protocol event adjacent to the `values` event for the same superstep, so\n * clients can build branching / time-travel UIs without subscribing to a\n * full-state `checkpoints` stream.\n *\n * Companion checkpoint envelopes are emitted as separate\n * ``[namespace, \"checkpoints\", envelope]`` chunks (see\n * ``PregelLoop._emitValuesWithCheckpointMeta``).\n */\nexport interface StreamChunkMeta {\n /**\n * Lightweight checkpoint envelope for the superstep that produced the\n * paired `values` chunk. Shape matches the canonical {@link Checkpoint}\n * generated from `protocol.cddl`.\n */\n checkpoint?: Checkpoint;\n}\n\n// [namespace, streamMode, payload]\nexport type StreamChunk = [string[], StreamMode, unknown];\n\ntype StreamCheckpointsOutput<StreamValues> = StreamOutputMap<\n \"checkpoints\",\n false,\n StreamValues,\n unknown,\n string,\n unknown,\n unknown,\n undefined\n>;\n\ntype AnyStreamOutput = StreamOutputMap<\n StreamMode[],\n true,\n unknown,\n unknown,\n string,\n unknown,\n unknown,\n undefined\n>;\n\ntype ToolRunInfo = {\n ns: string[];\n toolCallId?: string;\n toolName: string;\n input: unknown;\n};\n\n/**\n * A wrapper around an IterableReadableStream that allows for aborting the stream when\n * {@link cancel} is called.\n */\nexport class IterableReadableStreamWithAbortSignal<\n T,\n> extends IterableReadableStream<T> {\n protected _abortController: AbortController;\n\n protected _innerReader: ReadableStreamDefaultReader<T>;\n\n /**\n * @param readableStream - The stream to wrap.\n * @param abortController - The abort controller to use. Optional. One will be created if not provided.\n */\n constructor(\n readableStream: ReadableStream<T>,\n abortController?: AbortController\n ) {\n const reader = readableStream.getReader();\n const ac = abortController ?? new AbortController();\n super({\n start(controller: ReadableStreamDefaultController<T>) {\n return pump();\n function pump(): Promise<T | undefined> {\n return reader.read().then(({ done, value }) => {\n // When no more data needs to be consumed, close the stream\n if (done) {\n controller.close();\n return;\n }\n // Enqueue the next data chunk into our target stream\n controller.enqueue(value);\n return pump();\n });\n }\n },\n });\n this._abortController = ac;\n this._innerReader = reader;\n }\n\n /**\n * Aborts the stream, abandoning any pending operations in progress. Calling this triggers an\n * {@link AbortSignal} that is propagated to the tasks that are producing the data for this stream.\n * @param reason - The reason for aborting the stream. Optional.\n */\n override async cancel(reason?: unknown) {\n this._abortController.abort(reason);\n this._innerReader.releaseLock();\n }\n\n /**\n * The {@link AbortSignal} for the stream. Aborted when {@link cancel} is called.\n */\n get signal() {\n return this._abortController.signal;\n }\n}\n\nexport class IterableReadableWritableStream extends IterableReadableStream<StreamChunk> {\n modes: Set<StreamMode>;\n\n private controller: ReadableStreamDefaultController;\n\n private passthroughFn?: (chunk: StreamChunk) => void;\n\n private _closed: boolean = false;\n\n get closed() {\n return this._closed;\n }\n\n constructor(params: {\n passthroughFn?: (chunk: StreamChunk) => void;\n modes: Set<StreamMode>;\n }) {\n let streamControllerPromiseResolver: (\n controller: ReadableStreamDefaultController\n ) => void;\n const streamControllerPromise: Promise<ReadableStreamDefaultController> =\n new Promise<ReadableStreamDefaultController>((resolve) => {\n streamControllerPromiseResolver = resolve;\n });\n\n super({\n start: (controller) => {\n streamControllerPromiseResolver!(controller);\n },\n });\n\n // .start() will always be called before the stream can be interacted\n // with anyway\n void streamControllerPromise.then((controller) => {\n this.controller = controller;\n });\n\n this.passthroughFn = params.passthroughFn;\n this.modes = params.modes;\n }\n\n push(chunk: StreamChunk) {\n // Prevent pushing to a closed stream to avoid race condition errors\n if (this._closed || !this.controller) {\n // Silently drop chunks when stream is closed - this is expected behavior\n // when async operations try to push after stream termination\n return;\n }\n\n // Forward chunk to passthrough function if provided\n this.passthroughFn?.(chunk);\n\n // Attempt to enqueue the chunk to the underlying stream\n this.controller.enqueue(chunk);\n }\n\n close() {\n try {\n this.controller.close();\n } catch {\n // pass\n } finally {\n this._closed = true;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error(e: any) {\n try {\n this.controller?.error(e);\n } finally {\n // Mark the stream as closed so any late `push()` calls from in-flight\n // parallel tasks are dropped instead of throwing on an errored controller.\n this._closed = true;\n }\n }\n}\n\n/**\n * A callback handler that implements stream_mode=tools.\n * Emits on_tool_start, on_tool_event, on_tool_end, on_tool_error events.\n */\nexport class StreamToolsHandler extends BaseCallbackHandler {\n name = \"StreamToolsHandler\";\n\n streamFn: (streamChunk: StreamChunk) => void;\n\n runs: Record<string, ToolRunInfo | undefined> = {};\n\n constructor(streamFn: (streamChunk: StreamChunk) => void) {\n super();\n this.streamFn = streamFn;\n }\n\n handleToolStart(\n _tool: Serialized,\n input: string,\n runId: string,\n _parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n runName?: string,\n toolCallId?: string\n ) {\n if (!metadata || (tags && tags.includes(TAG_HIDDEN))) return;\n\n const ns = (metadata.langgraph_checkpoint_ns as string)?.split(\"|\") ?? [];\n const info: ToolRunInfo = {\n ns,\n toolCallId,\n toolName: runName ?? \"unknown\",\n input,\n };\n this.runs[runId] = info;\n\n this.streamFn([\n ns,\n \"tools\",\n {\n event: \"on_tool_start\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n input,\n },\n ]);\n }\n\n handleToolEvent(chunk: unknown, runId: string) {\n const info = this.runs[runId];\n if (!info) return;\n\n this.streamFn([\n info.ns,\n \"tools\",\n {\n event: \"on_tool_event\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n data: chunk,\n },\n ]);\n }\n\n handleToolEnd(output: unknown, runId: string) {\n const info = this.runs[runId];\n delete this.runs[runId];\n if (!info) return;\n\n this.streamFn([\n info.ns,\n \"tools\",\n {\n event: \"on_tool_end\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n output,\n },\n ]);\n }\n\n handleToolError(err: unknown, runId: string) {\n const info = this.runs[runId];\n delete this.runs[runId];\n if (!info) return;\n\n this.streamFn([\n info.ns,\n \"tools\",\n {\n event: \"on_tool_error\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n error: err,\n },\n ]);\n }\n}\n\nfunction _stringifyAsDict(obj: unknown) {\n return JSON.stringify(obj, function (key: string | number, value: unknown) {\n const rawValue = this[key];\n if (\n rawValue != null &&\n typeof rawValue === \"object\" &&\n \"toDict\" in rawValue &&\n typeof rawValue.toDict === \"function\"\n ) {\n const { type, data } = rawValue.toDict();\n return { ...data, type };\n }\n\n return value;\n });\n}\n\nfunction _serializeError(error: unknown) {\n // eslint-disable-next-line no-instanceof/no-instanceof\n if (error instanceof Error) {\n return { error: error.name, message: error.message };\n }\n return { error: \"Error\", message: JSON.stringify(error) };\n}\n\nfunction _isRunnableConfig(\n config: unknown\n): config is RunnableConfig & { configurable: Record<string, unknown> } {\n if (typeof config !== \"object\" || config == null) return false;\n return (\n \"configurable\" in config &&\n typeof config.configurable === \"object\" &&\n config.configurable != null\n );\n}\n\nfunction _extractCheckpointFromConfig(\n config: RunnableConfig | null | undefined\n) {\n if (!_isRunnableConfig(config) || !config.configurable.thread_id) {\n return null;\n }\n\n return {\n thread_id: config.configurable.thread_id,\n checkpoint_ns: config.configurable.checkpoint_ns || \"\",\n checkpoint_id: config.configurable.checkpoint_id || null,\n checkpoint_map: config.configurable.checkpoint_map || null,\n };\n}\n\nfunction _serializeConfig(config: unknown) {\n if (_isRunnableConfig(config)) {\n const configurable = Object.fromEntries(\n Object.entries(config.configurable).filter(\n ([key]) => !key.startsWith(\"__\")\n )\n );\n\n const newConfig = { ...config, configurable };\n delete newConfig.callbacks;\n return newConfig;\n }\n\n return config;\n}\n\nfunction _serializeCheckpoint(payload: StreamCheckpointsOutput<unknown>) {\n const result: Record<string, unknown> = {\n ...payload,\n checkpoint: _extractCheckpointFromConfig(payload.config),\n parent_checkpoint: _extractCheckpointFromConfig(payload.parentConfig),\n\n config: _serializeConfig(payload.config),\n parent_config: _serializeConfig(payload.parentConfig),\n\n tasks: payload.tasks.map((task) => {\n if (_isRunnableConfig(task.state)) {\n const checkpoint = _extractCheckpointFromConfig(task.state);\n if (checkpoint != null) {\n const cloneTask: Record<string, unknown> = { ...task, checkpoint };\n delete cloneTask.state;\n return cloneTask;\n }\n }\n\n return task;\n }),\n };\n\n delete result.parentConfig;\n return result;\n}\n\nexport function toEventStream(stream: AsyncGenerator) {\n const encoder = new TextEncoder();\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueueChunk = (sse: {\n id?: string;\n event: string;\n data: unknown;\n }) => {\n controller.enqueue(\n encoder.encode(\n `event: ${sse.event}\\ndata: ${_stringifyAsDict(sse.data)}\\n\\n`\n )\n );\n };\n\n try {\n for await (const payload of stream) {\n const [ns, mode, chunk] = payload as AnyStreamOutput;\n\n let data: unknown = chunk;\n if (mode === \"debug\") {\n const debugChunk = chunk;\n\n if (debugChunk.type === \"checkpoint\") {\n data = {\n ...debugChunk,\n payload: _serializeCheckpoint(debugChunk.payload),\n };\n }\n }\n\n if (mode === \"checkpoints\") {\n data = _serializeCheckpoint(chunk);\n }\n\n const event = ns?.length ? `${mode}|${ns.join(\"|\")}` : mode;\n enqueueChunk({ event, data });\n }\n } catch (error) {\n enqueueChunk({ event: \"error\", data: _serializeError(error) });\n }\n\n controller.close();\n },\n });\n}\n\n/** Multiplex subgraph stream chunks into the parent pregel stream. */\nexport function createDuplexStream(\n ...streams: IterableReadableWritableStream[]\n) {\n return new IterableReadableWritableStream({\n passthroughFn: (value: StreamChunk) => {\n const isEnvelope =\n value[1] === \"checkpoints\" && isCheckpointEnvelope(value[2]);\n for (const stream of streams) {\n if (stream.modes.has(value[1]) || isEnvelope) {\n stream.push(value);\n }\n }\n },\n modes: new Set(streams.flatMap((s) => Array.from(s.modes))),\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stream.cjs","names":["IterableReadableStream","BaseCallbackHandler","isCheckpointEnvelope"],"sources":["../../src/pregel/stream.ts"],"sourcesContent":["import { IterableReadableStream } from \"@langchain/core/utils/stream\";\nimport type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { BaseCallbackHandler } from \"@langchain/core/callbacks/base\";\nimport { Serialized } from \"@langchain/core/load/serializable\";\nimport { isCheckpointEnvelope } from \"../stream/convert.js\";\nimport type { Checkpoint } from \"../stream/types.js\";\nimport type { StreamMode, StreamOutputMap } from \"./types.js\";\nimport { TAG_HIDDEN } from \"../constants.js\";\n\n/**\n * Optional chunk-level metadata carried alongside the payload. Used by\n * `streamEvents(..., { version: \"v3\" })` to emit a companion `checkpoints`\n * protocol event adjacent to the `values` event for the same superstep, so\n * clients can build branching / time-travel UIs without subscribing to a\n * full-state `checkpoints` stream.\n *\n * Companion checkpoint envelopes are emitted as separate\n * ``[namespace, \"checkpoints\", envelope]`` chunks (see\n * ``PregelLoop._emitValuesWithCheckpointMeta``).\n */\nexport interface StreamChunkMeta {\n /**\n * Lightweight checkpoint envelope for the superstep that produced the\n * paired `values` chunk. Shape matches the canonical {@link Checkpoint}\n * generated from `protocol.cddl`.\n */\n checkpoint?: Checkpoint;\n}\n\n// [namespace, streamMode, payload]\nexport type StreamChunk = [string[], StreamMode, unknown];\n\ntype StreamCheckpointsOutput<StreamValues> = StreamOutputMap<\n \"checkpoints\",\n false,\n StreamValues,\n unknown,\n string,\n unknown,\n unknown,\n undefined\n>;\n\ntype AnyStreamOutput = StreamOutputMap<\n StreamMode[],\n true,\n unknown,\n unknown,\n string,\n unknown,\n unknown,\n undefined\n>;\n\ntype ToolRunInfo = {\n ns: string[];\n toolCallId?: string;\n toolName: string;\n input: unknown;\n};\n\n/**\n * A wrapper around an IterableReadableStream that allows for aborting the stream when\n * {@link cancel} is called.\n */\nexport class IterableReadableStreamWithAbortSignal<\n T,\n> extends IterableReadableStream<T> {\n protected _abortController: AbortController;\n\n protected _innerReader: ReadableStreamDefaultReader<T>;\n\n /**\n * @param readableStream - The stream to wrap.\n * @param abortController - The abort controller to use. Optional. One will be created if not provided.\n */\n constructor(\n readableStream: ReadableStream<T>,\n abortController?: AbortController\n ) {\n const reader = readableStream.getReader();\n const ac = abortController ?? new AbortController();\n super({\n start(controller: ReadableStreamDefaultController<T>) {\n return pump();\n function pump(): Promise<T | undefined> {\n return reader.read().then(({ done, value }) => {\n // When no more data needs to be consumed, close the stream\n if (done) {\n controller.close();\n return;\n }\n // Enqueue the next data chunk into our target stream\n controller.enqueue(value);\n return pump();\n });\n }\n },\n });\n this._abortController = ac;\n this._innerReader = reader;\n }\n\n /**\n * Aborts the stream, abandoning any pending operations in progress. Calling this triggers an\n * {@link AbortSignal} that is propagated to the tasks that are producing the data for this stream.\n * @param reason - The reason for aborting the stream. Optional.\n */\n override async cancel(reason?: unknown) {\n this._abortController.abort(reason);\n this._innerReader.releaseLock();\n }\n\n /**\n * The {@link AbortSignal} for the stream. Aborted when {@link cancel} is called.\n */\n get signal() {\n return this._abortController.signal;\n }\n}\n\nexport class IterableReadableWritableStream extends IterableReadableStream<StreamChunk> {\n modes: Set<StreamMode>;\n\n private controller: ReadableStreamDefaultController;\n\n private passthroughFn?: (chunk: StreamChunk) => void;\n\n private _closed: boolean = false;\n\n get closed() {\n return this._closed;\n }\n\n constructor(params: {\n passthroughFn?: (chunk: StreamChunk) => void;\n modes: Set<StreamMode>;\n }) {\n let streamControllerPromiseResolver: (\n controller: ReadableStreamDefaultController\n ) => void;\n const streamControllerPromise: Promise<ReadableStreamDefaultController> =\n new Promise<ReadableStreamDefaultController>((resolve) => {\n streamControllerPromiseResolver = resolve;\n });\n\n super({\n start: (controller) => {\n streamControllerPromiseResolver!(controller);\n },\n });\n\n // .start() will always be called before the stream can be interacted\n // with anyway\n void streamControllerPromise.then((controller) => {\n this.controller = controller;\n });\n\n this.passthroughFn = params.passthroughFn;\n this.modes = params.modes;\n }\n\n push(chunk: StreamChunk) {\n // Prevent pushing to a closed stream to avoid race condition errors\n if (this._closed || !this.controller) {\n // Silently drop chunks when stream is closed - this is expected behavior\n // when async operations try to push after stream termination\n return;\n }\n\n // Forward chunk to passthrough function if provided\n this.passthroughFn?.(chunk);\n\n // Attempt to enqueue the chunk to the underlying stream\n this.controller.enqueue(chunk);\n }\n\n close() {\n try {\n this.controller.close();\n } catch {\n // pass\n } finally {\n this._closed = true;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error(e: any) {\n try {\n this.controller?.error(e);\n } finally {\n // Mark the stream as closed so any late `push()` calls from in-flight\n // parallel tasks are dropped instead of throwing on an errored controller.\n this._closed = true;\n }\n }\n}\n\n/**\n * A callback handler that implements stream_mode=tools.\n * Emits on_tool_start, on_tool_event, on_tool_end, on_tool_error events.\n */\nexport class StreamToolsHandler extends BaseCallbackHandler {\n name = \"StreamToolsHandler\";\n\n /** Ensure tool lifecycle callbacks run before tool.invoke returns/errors. */\n awaitHandlers = true;\n\n streamFn: (streamChunk: StreamChunk) => void;\n\n runs: Record<string, ToolRunInfo | undefined> = {};\n\n constructor(streamFn: (streamChunk: StreamChunk) => void) {\n super();\n this.streamFn = streamFn;\n }\n\n handleToolStart(\n _tool: Serialized,\n input: string,\n runId: string,\n _parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n runName?: string,\n toolCallId?: string\n ) {\n if (!metadata || (tags && tags.includes(TAG_HIDDEN))) return;\n\n const ns = (metadata.langgraph_checkpoint_ns as string)?.split(\"|\") ?? [];\n const info: ToolRunInfo = {\n ns,\n toolCallId,\n toolName: runName ?? \"unknown\",\n input,\n };\n this.runs[runId] = info;\n\n this.streamFn([\n ns,\n \"tools\",\n {\n event: \"on_tool_start\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n input,\n },\n ]);\n }\n\n handleToolEvent(chunk: unknown, runId: string) {\n const info = this.runs[runId];\n if (!info) return;\n\n this.streamFn([\n info.ns,\n \"tools\",\n {\n event: \"on_tool_event\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n data: chunk,\n },\n ]);\n }\n\n handleToolEnd(output: unknown, runId: string) {\n const info = this.runs[runId];\n delete this.runs[runId];\n if (!info) return;\n\n this.streamFn([\n info.ns,\n \"tools\",\n {\n event: \"on_tool_end\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n output,\n },\n ]);\n }\n\n handleToolError(err: unknown, runId: string) {\n const info = this.runs[runId];\n delete this.runs[runId];\n if (!info) return;\n\n this.streamFn([\n info.ns,\n \"tools\",\n {\n event: \"on_tool_error\",\n toolCallId: info.toolCallId,\n name: info.toolName,\n error: err,\n },\n ]);\n }\n}\n\nfunction _stringifyAsDict(obj: unknown) {\n return JSON.stringify(obj, function (key: string | number, value: unknown) {\n const rawValue = this[key];\n if (\n rawValue != null &&\n typeof rawValue === \"object\" &&\n \"toDict\" in rawValue &&\n typeof rawValue.toDict === \"function\"\n ) {\n const { type, data } = rawValue.toDict();\n return { ...data, type };\n }\n\n return value;\n });\n}\n\nfunction _serializeError(error: unknown) {\n // eslint-disable-next-line no-instanceof/no-instanceof\n if (error instanceof Error) {\n return { error: error.name, message: error.message };\n }\n return { error: \"Error\", message: JSON.stringify(error) };\n}\n\nfunction _isRunnableConfig(\n config: unknown\n): config is RunnableConfig & { configurable: Record<string, unknown> } {\n if (typeof config !== \"object\" || config == null) return false;\n return (\n \"configurable\" in config &&\n typeof config.configurable === \"object\" &&\n config.configurable != null\n );\n}\n\nfunction _extractCheckpointFromConfig(\n config: RunnableConfig | null | undefined\n) {\n if (!_isRunnableConfig(config) || !config.configurable.thread_id) {\n return null;\n }\n\n return {\n thread_id: config.configurable.thread_id,\n checkpoint_ns: config.configurable.checkpoint_ns || \"\",\n checkpoint_id: config.configurable.checkpoint_id || null,\n checkpoint_map: config.configurable.checkpoint_map || null,\n };\n}\n\nfunction _serializeConfig(config: unknown) {\n if (_isRunnableConfig(config)) {\n const configurable = Object.fromEntries(\n Object.entries(config.configurable).filter(\n ([key]) => !key.startsWith(\"__\")\n )\n );\n\n const newConfig = { ...config, configurable };\n delete newConfig.callbacks;\n return newConfig;\n }\n\n return config;\n}\n\nfunction _serializeCheckpoint(payload: StreamCheckpointsOutput<unknown>) {\n const result: Record<string, unknown> = {\n ...payload,\n checkpoint: _extractCheckpointFromConfig(payload.config),\n parent_checkpoint: _extractCheckpointFromConfig(payload.parentConfig),\n\n config: _serializeConfig(payload.config),\n parent_config: _serializeConfig(payload.parentConfig),\n\n tasks: payload.tasks.map((task) => {\n if (_isRunnableConfig(task.state)) {\n const checkpoint = _extractCheckpointFromConfig(task.state);\n if (checkpoint != null) {\n const cloneTask: Record<string, unknown> = { ...task, checkpoint };\n delete cloneTask.state;\n return cloneTask;\n }\n }\n\n return task;\n }),\n };\n\n delete result.parentConfig;\n return result;\n}\n\nexport function toEventStream(stream: AsyncGenerator) {\n const encoder = new TextEncoder();\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueueChunk = (sse: {\n id?: string;\n event: string;\n data: unknown;\n }) => {\n controller.enqueue(\n encoder.encode(\n `event: ${sse.event}\\ndata: ${_stringifyAsDict(sse.data)}\\n\\n`\n )\n );\n };\n\n try {\n for await (const payload of stream) {\n const [ns, mode, chunk] = payload as AnyStreamOutput;\n\n let data: unknown = chunk;\n if (mode === \"debug\") {\n const debugChunk = chunk;\n\n if (debugChunk.type === \"checkpoint\") {\n data = {\n ...debugChunk,\n payload: _serializeCheckpoint(debugChunk.payload),\n };\n }\n }\n\n if (mode === \"checkpoints\") {\n data = _serializeCheckpoint(chunk);\n }\n\n const event = ns?.length ? `${mode}|${ns.join(\"|\")}` : mode;\n enqueueChunk({ event, data });\n }\n } catch (error) {\n enqueueChunk({ event: \"error\", data: _serializeError(error) });\n }\n\n controller.close();\n },\n });\n}\n\n/** Multiplex subgraph stream chunks into the parent pregel stream. */\nexport function createDuplexStream(\n ...streams: IterableReadableWritableStream[]\n) {\n return new IterableReadableWritableStream({\n passthroughFn: (value: StreamChunk) => {\n const isEnvelope =\n value[1] === \"checkpoints\" && isCheckpointEnvelope(value[2]);\n for (const stream of streams) {\n if (stream.modes.has(value[1]) || isEnvelope) {\n stream.push(value);\n }\n }\n },\n modes: new Set(streams.flatMap((s) => Array.from(s.modes))),\n });\n}\n"],"mappings":"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"}
@@ -97,6 +97,8 @@ var IterableReadableWritableStream = class extends IterableReadableStream {
97
97
  */
98
98
  var StreamToolsHandler = class extends BaseCallbackHandler {
99
99
  name = "StreamToolsHandler";
100
+ /** Ensure tool lifecycle callbacks run before tool.invoke returns/errors. */
101
+ awaitHandlers = true;
100
102
  streamFn;
101
103
  runs = {};
102
104
  constructor(streamFn) {