@langchain/langgraph 0.1.7 → 0.1.9

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.
@@ -68,3 +68,7 @@ export declare class Send implements SendInterface {
68
68
  constructor(node: string, args: any);
69
69
  }
70
70
  export declare function _isSend(x: unknown): x is Send;
71
+ export type Interrupt = {
72
+ value: any;
73
+ when: "during";
74
+ };
package/dist/errors.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InvalidUpdateError = exports.EmptyChannelError = exports.EmptyInputError = exports.GraphInterrupt = exports.GraphValueError = exports.GraphRecursionError = void 0;
3
+ exports.InvalidUpdateError = exports.EmptyChannelError = exports.EmptyInputError = exports.isGraphInterrupt = exports.NodeInterrupt = exports.GraphInterrupt = exports.GraphValueError = exports.GraphRecursionError = void 0;
4
4
  class GraphRecursionError extends Error {
5
5
  constructor(message) {
6
6
  super(message);
@@ -22,15 +22,45 @@ class GraphValueError extends Error {
22
22
  }
23
23
  exports.GraphValueError = GraphValueError;
24
24
  class GraphInterrupt extends Error {
25
- constructor(message) {
26
- super(message);
25
+ constructor(interrupts = []) {
26
+ super(JSON.stringify(interrupts, null, 2));
27
+ Object.defineProperty(this, "interrupts", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: void 0
32
+ });
27
33
  this.name = "GraphInterrupt";
34
+ this.interrupts = interrupts;
28
35
  }
29
36
  static get unminifiable_name() {
30
37
  return "GraphInterrupt";
31
38
  }
32
39
  }
33
40
  exports.GraphInterrupt = GraphInterrupt;
41
+ /** Raised by a node to interrupt execution. */
42
+ class NodeInterrupt extends GraphInterrupt {
43
+ constructor(message) {
44
+ super([
45
+ {
46
+ value: message,
47
+ when: "during",
48
+ },
49
+ ]);
50
+ this.name = "NodeInterrupt";
51
+ }
52
+ static get unminifiable_name() {
53
+ return "NodeInterrupt";
54
+ }
55
+ }
56
+ exports.NodeInterrupt = NodeInterrupt;
57
+ function isGraphInterrupt(e) {
58
+ return [
59
+ GraphInterrupt.unminifiable_name,
60
+ NodeInterrupt.unminifiable_name,
61
+ ].includes(e.name);
62
+ }
63
+ exports.isGraphInterrupt = isGraphInterrupt;
34
64
  class EmptyInputError extends Error {
35
65
  constructor(message) {
36
66
  super(message);
package/dist/errors.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Interrupt } from "./constants.js";
1
2
  export declare class GraphRecursionError extends Error {
2
3
  constructor(message?: string);
3
4
  static get unminifiable_name(): string;
@@ -7,9 +8,16 @@ export declare class GraphValueError extends Error {
7
8
  static get unminifiable_name(): string;
8
9
  }
9
10
  export declare class GraphInterrupt extends Error {
10
- constructor(message?: string);
11
+ interrupts: Interrupt[];
12
+ constructor(interrupts?: Interrupt[]);
13
+ static get unminifiable_name(): string;
14
+ }
15
+ /** Raised by a node to interrupt execution. */
16
+ export declare class NodeInterrupt extends GraphInterrupt {
17
+ constructor(message: string);
11
18
  static get unminifiable_name(): string;
12
19
  }
20
+ export declare function isGraphInterrupt(e: GraphInterrupt | Error): e is GraphInterrupt;
13
21
  export declare class EmptyInputError extends Error {
14
22
  constructor(message?: string);
15
23
  static get unminifiable_name(): string;
package/dist/errors.js CHANGED
@@ -17,14 +17,42 @@ export class GraphValueError extends Error {
17
17
  }
18
18
  }
19
19
  export class GraphInterrupt extends Error {
20
- constructor(message) {
21
- super(message);
20
+ constructor(interrupts = []) {
21
+ super(JSON.stringify(interrupts, null, 2));
22
+ Object.defineProperty(this, "interrupts", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
22
28
  this.name = "GraphInterrupt";
29
+ this.interrupts = interrupts;
23
30
  }
24
31
  static get unminifiable_name() {
25
32
  return "GraphInterrupt";
26
33
  }
27
34
  }
35
+ /** Raised by a node to interrupt execution. */
36
+ export class NodeInterrupt extends GraphInterrupt {
37
+ constructor(message) {
38
+ super([
39
+ {
40
+ value: message,
41
+ when: "during",
42
+ },
43
+ ]);
44
+ this.name = "NodeInterrupt";
45
+ }
46
+ static get unminifiable_name() {
47
+ return "NodeInterrupt";
48
+ }
49
+ }
50
+ export function isGraphInterrupt(e) {
51
+ return [
52
+ GraphInterrupt.unminifiable_name,
53
+ NodeInterrupt.unminifiable_name,
54
+ ].includes(e.name);
55
+ }
28
56
  export class EmptyInputError extends Error {
29
57
  constructor(message) {
30
58
  super(message);
@@ -223,12 +223,6 @@ class Graph {
223
223
  for (const [start] of Object.entries(this.branches)) {
224
224
  allSources.add(start);
225
225
  }
226
- // validate sources
227
- for (const node of Object.keys(this.nodes)) {
228
- if (!allSources.has(node)) {
229
- throw new Error(`Node \`${node}\` is a dead-end`);
230
- }
231
- }
232
226
  for (const source of allSources) {
233
227
  if (source !== exports.START && !(source in this.nodes)) {
234
228
  throw new Error(`Found edge starting at unknown node \`${source}\``);
@@ -219,12 +219,6 @@ export class Graph {
219
219
  for (const [start] of Object.entries(this.branches)) {
220
220
  allSources.add(start);
221
221
  }
222
- // validate sources
223
- for (const node of Object.keys(this.nodes)) {
224
- if (!allSources.has(node)) {
225
- throw new Error(`Node \`${node}\` is a dead-end`);
226
- }
227
- }
228
222
  for (const source of allSources) {
229
223
  if (source !== START && !(source in this.nodes)) {
230
224
  throw new Error(`Found edge starting at unknown node \`${source}\``);
@@ -1,6 +1,6 @@
1
1
  import { BaseMessage, BaseMessageLike } from "@langchain/core/messages";
2
2
  import { StateGraph } from "./state.js";
3
- type Messages = Array<BaseMessage | BaseMessageLike> | BaseMessage | BaseMessageLike;
3
+ export type Messages = Array<BaseMessage | BaseMessageLike> | BaseMessage | BaseMessageLike;
4
4
  /**
5
5
  * Prebuilt reducer that combines returned messages.
6
6
  * Can handle standard messages and special modifiers like {@link RemoveMessage}
@@ -11,4 +11,3 @@ export declare function messagesStateReducer(left: BaseMessage[], right: Message
11
11
  export declare class MessageGraph extends StateGraph<BaseMessage[], BaseMessage[], Messages> {
12
12
  constructor();
13
13
  }
14
- export {};
@@ -1,9 +1,10 @@
1
1
  import { BaseMessage } from "@langchain/core/messages";
2
+ import { Messages } from "./message.js";
2
3
  /**
3
4
  * Prebuilt state annotation that combines returned messages.
4
5
  * Can handle standard messages and special modifiers like {@link RemoveMessage}
5
6
  * instances.
6
7
  */
7
8
  export declare const MessagesAnnotation: import("./annotation.js").AnnotationRoot<{
8
- messages: import("../web.js").BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
9
+ messages: import("../web.js").BinaryOperatorAggregate<BaseMessage[], Messages>;
9
10
  }>;
@@ -4,16 +4,17 @@ exports.toolsCondition = exports.ToolNode = void 0;
4
4
  const messages_1 = require("@langchain/core/messages");
5
5
  const utils_js_1 = require("../utils.cjs");
6
6
  const graph_js_1 = require("../graph/graph.cjs");
7
+ /**
8
+ * A node that runs the tools requested in the last AIMessage. It can be used
9
+ * either in StateGraph with a "messages" key or in MessageGraph. If multiple
10
+ * tool calls are requested, they will be run in parallel. The output will be
11
+ * a list of ToolMessages, one for each tool call.
12
+ */
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
14
  class ToolNode extends utils_js_1.RunnableCallable {
8
15
  constructor(tools, options) {
9
16
  const { name, tags, handleToolErrors } = options ?? {};
10
17
  super({ name, tags, func: (input, config) => this.run(input, config) });
11
- /**
12
- A node that runs the tools requested in the last AIMessage. It can be used
13
- either in StateGraph with a "messages" key or in MessageGraph. If multiple
14
- tool calls are requested, they will be run in parallel. The output will be
15
- a list of ToolMessages, one for each tool call.
16
- */
17
18
  Object.defineProperty(this, "tools", {
18
19
  enumerable: true,
19
20
  configurable: true,
@@ -29,11 +30,12 @@ class ToolNode extends utils_js_1.RunnableCallable {
29
30
  this.tools = tools;
30
31
  this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;
31
32
  }
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
34
  async run(input, config) {
33
35
  const message = Array.isArray(input)
34
36
  ? input[input.length - 1]
35
37
  : input.messages[input.messages.length - 1];
36
- if (message._getType() !== "ai") {
38
+ if (message?._getType() !== "ai") {
37
39
  throw new Error("ToolNode only accepts AIMessages as input.");
38
40
  }
39
41
  const outputs = await Promise.all(message.tool_calls?.map(async (call) => {
@@ -66,7 +68,7 @@ class ToolNode extends utils_js_1.RunnableCallable {
66
68
  });
67
69
  }
68
70
  }) ?? []);
69
- return Array.isArray(input) ? outputs : { messages: outputs };
71
+ return (Array.isArray(input) ? outputs : { messages: outputs });
70
72
  }
71
73
  }
72
74
  exports.ToolNode = ToolNode;
@@ -9,13 +9,13 @@ export type ToolNodeOptions = {
9
9
  tags?: string[];
10
10
  handleToolErrors?: boolean;
11
11
  };
12
- export declare class ToolNode<T extends BaseMessage[] | typeof MessagesAnnotation.State> extends RunnableCallable<T, T> {
13
- /**
14
- A node that runs the tools requested in the last AIMessage. It can be used
15
- either in StateGraph with a "messages" key or in MessageGraph. If multiple
16
- tool calls are requested, they will be run in parallel. The output will be
17
- a list of ToolMessages, one for each tool call.
18
- */
12
+ /**
13
+ * A node that runs the tools requested in the last AIMessage. It can be used
14
+ * either in StateGraph with a "messages" key or in MessageGraph. If multiple
15
+ * tool calls are requested, they will be run in parallel. The output will be
16
+ * a list of ToolMessages, one for each tool call.
17
+ */
18
+ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
19
19
  tools: (StructuredToolInterface | RunnableToolLike)[];
20
20
  handleToolErrors: boolean;
21
21
  constructor(tools: (StructuredToolInterface | RunnableToolLike)[], options?: ToolNodeOptions);
@@ -1,16 +1,17 @@
1
1
  import { ToolMessage, isBaseMessage, } from "@langchain/core/messages";
2
2
  import { RunnableCallable } from "../utils.js";
3
3
  import { END } from "../graph/graph.js";
4
+ /**
5
+ * A node that runs the tools requested in the last AIMessage. It can be used
6
+ * either in StateGraph with a "messages" key or in MessageGraph. If multiple
7
+ * tool calls are requested, they will be run in parallel. The output will be
8
+ * a list of ToolMessages, one for each tool call.
9
+ */
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
11
  export class ToolNode extends RunnableCallable {
5
12
  constructor(tools, options) {
6
13
  const { name, tags, handleToolErrors } = options ?? {};
7
14
  super({ name, tags, func: (input, config) => this.run(input, config) });
8
- /**
9
- A node that runs the tools requested in the last AIMessage. It can be used
10
- either in StateGraph with a "messages" key or in MessageGraph. If multiple
11
- tool calls are requested, they will be run in parallel. The output will be
12
- a list of ToolMessages, one for each tool call.
13
- */
14
15
  Object.defineProperty(this, "tools", {
15
16
  enumerable: true,
16
17
  configurable: true,
@@ -26,11 +27,12 @@ export class ToolNode extends RunnableCallable {
26
27
  this.tools = tools;
27
28
  this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;
28
29
  }
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
31
  async run(input, config) {
30
32
  const message = Array.isArray(input)
31
33
  ? input[input.length - 1]
32
34
  : input.messages[input.messages.length - 1];
33
- if (message._getType() !== "ai") {
35
+ if (message?._getType() !== "ai") {
34
36
  throw new Error("ToolNode only accepts AIMessages as input.");
35
37
  }
36
38
  const outputs = await Promise.all(message.tool_calls?.map(async (call) => {
@@ -63,7 +65,7 @@ export class ToolNode extends RunnableCallable {
63
65
  });
64
66
  }
65
67
  }) ?? []);
66
- return Array.isArray(input) ? outputs : { messages: outputs };
68
+ return (Array.isArray(input) ? outputs : { messages: outputs });
67
69
  }
68
70
  }
69
71
  export function toolsCondition(state) {
@@ -218,7 +218,7 @@ function _prepareNextTasks(checkpoint, processes, channels, config, forExecution
218
218
  }
219
219
  }
220
220
  else {
221
- taskDescriptions.push({ id: taskId, name: packet.node });
221
+ taskDescriptions.push({ id: taskId, name: packet.node, interrupts: [] });
222
222
  }
223
223
  }
224
224
  // Check if any processes should be run in next step
@@ -291,7 +291,7 @@ function _prepareNextTasks(checkpoint, processes, channels, config, forExecution
291
291
  }
292
292
  }
293
293
  else {
294
- taskDescriptions.push({ id: taskId, name });
294
+ taskDescriptions.push({ id: taskId, name, interrupts: [] });
295
295
  }
296
296
  }
297
297
  }
@@ -210,7 +210,7 @@ export function _prepareNextTasks(checkpoint, processes, channels, config, forEx
210
210
  }
211
211
  }
212
212
  else {
213
- taskDescriptions.push({ id: taskId, name: packet.node });
213
+ taskDescriptions.push({ id: taskId, name: packet.node, interrupts: [] });
214
214
  }
215
215
  }
216
216
  // Check if any processes should be run in next step
@@ -283,7 +283,7 @@ export function _prepareNextTasks(checkpoint, processes, channels, config, forEx
283
283
  }
284
284
  }
285
285
  else {
286
- taskDescriptions.push({ id: taskId, name });
286
+ taskDescriptions.push({ id: taskId, name, interrupts: [] });
287
287
  }
288
288
  }
289
289
  }
@@ -53,7 +53,7 @@ function* _readChannels(channels
53
53
  }
54
54
  function* mapDebugTasks(step, tasks) {
55
55
  const ts = new Date().toISOString();
56
- for (const { name, input, config, triggers } of tasks) {
56
+ for (const { id, name, input, config, triggers, writes } of tasks) {
57
57
  if (config?.tags?.includes(constants_js_1.TAG_HIDDEN))
58
58
  continue;
59
59
  const metadata = { ...config?.metadata };
@@ -63,6 +63,13 @@ function* mapDebugTasks(step, tasks) {
63
63
  langgraph_triggers: metadata.langgraph_triggers,
64
64
  langgraph_task_idx: metadata.langgraph_task_idx,
65
65
  });
66
+ const interrupts = writes
67
+ .filter(([writeId, n]) => {
68
+ return writeId === id && n === constants_js_1.INTERRUPT;
69
+ })
70
+ .map(([, v]) => {
71
+ return v;
72
+ });
66
73
  yield {
67
74
  type: "task",
68
75
  timestamp: ts,
@@ -72,14 +79,15 @@ function* mapDebugTasks(step, tasks) {
72
79
  name,
73
80
  input,
74
81
  triggers,
82
+ interrupts,
75
83
  },
76
84
  };
77
85
  }
78
86
  }
79
87
  exports.mapDebugTasks = mapDebugTasks;
80
- function* mapDebugTaskResults(step, tasks, streamChannelsList) {
88
+ function* mapDebugTaskResults(step, tasks, streamChannels) {
81
89
  const ts = new Date().toISOString();
82
- for (const { name, writes, config } of tasks) {
90
+ for (const [{ name, config }, writes] of tasks) {
83
91
  if (config?.tags?.includes(constants_js_1.TAG_HIDDEN))
84
92
  continue;
85
93
  const metadata = { ...config?.metadata };
@@ -91,7 +99,9 @@ function* mapDebugTaskResults(step, tasks, streamChannelsList) {
91
99
  payload: {
92
100
  id: (0, langgraph_checkpoint_1.uuid5)(JSON.stringify([name, step, idMetadata]), constants_js_1.TASK_NAMESPACE),
93
101
  name,
94
- result: writes.filter(([channel]) => streamChannelsList.includes(channel)),
102
+ result: writes.filter(([channel]) => Array.isArray(streamChannels)
103
+ ? streamChannels.includes(channel)
104
+ : channel === streamChannels),
95
105
  },
96
106
  };
97
107
  }
@@ -141,9 +151,26 @@ exports.mapDebugCheckpoint = mapDebugCheckpoint;
141
151
  function tasksWithWrites(tasks, pendingWrites) {
142
152
  return tasks.map((task) => {
143
153
  const error = pendingWrites.find(([id, n]) => id === task.id && n === constants_js_1.ERROR)?.[2];
144
- if (error)
145
- return { id: task.id, name: task.name, error };
146
- return { id: task.id, name: task.name };
154
+ const interrupts = pendingWrites
155
+ .filter(([id, n]) => {
156
+ return id === task.id && n === constants_js_1.INTERRUPT;
157
+ })
158
+ .map(([, , v]) => {
159
+ return v;
160
+ });
161
+ if (error) {
162
+ return {
163
+ id: task.id,
164
+ name: task.name,
165
+ error,
166
+ interrupts,
167
+ };
168
+ }
169
+ return {
170
+ id: task.id,
171
+ name: task.name,
172
+ interrupts,
173
+ };
147
174
  });
148
175
  }
149
176
  exports.tasksWithWrites = tasksWithWrites;
@@ -12,9 +12,10 @@ export declare function mapDebugTasks<N extends PropertyKey, C extends PropertyK
12
12
  name: N;
13
13
  input: unknown;
14
14
  triggers: string[];
15
+ interrupts: unknown[];
15
16
  };
16
17
  }, void, unknown>;
17
- export declare function mapDebugTaskResults<N extends PropertyKey, C extends PropertyKey>(step: number, tasks: readonly PregelExecutableTask<N, C>[], streamChannelsList: Array<PropertyKey>): Generator<{
18
+ export declare function mapDebugTaskResults<N extends PropertyKey, C extends PropertyKey>(step: number, tasks: readonly [PregelExecutableTask<N, C>, PendingWrite<C>[]][], streamChannels: PropertyKey | Array<PropertyKey>): Generator<{
18
19
  type: string;
19
20
  timestamp: string;
20
21
  step: number;
@@ -1,5 +1,5 @@
1
1
  import { uuid5, } from "@langchain/langgraph-checkpoint";
2
- import { ERROR, TAG_HIDDEN, TASK_NAMESPACE } from "../constants.js";
2
+ import { ERROR, INTERRUPT, TAG_HIDDEN, TASK_NAMESPACE, } from "../constants.js";
3
3
  import { EmptyChannelError } from "../errors.js";
4
4
  import { readChannels } from "./io.js";
5
5
  import { _getIdMetadata } from "./utils.js";
@@ -49,7 +49,7 @@ function* _readChannels(channels
49
49
  }
50
50
  export function* mapDebugTasks(step, tasks) {
51
51
  const ts = new Date().toISOString();
52
- for (const { name, input, config, triggers } of tasks) {
52
+ for (const { id, name, input, config, triggers, writes } of tasks) {
53
53
  if (config?.tags?.includes(TAG_HIDDEN))
54
54
  continue;
55
55
  const metadata = { ...config?.metadata };
@@ -59,6 +59,13 @@ export function* mapDebugTasks(step, tasks) {
59
59
  langgraph_triggers: metadata.langgraph_triggers,
60
60
  langgraph_task_idx: metadata.langgraph_task_idx,
61
61
  });
62
+ const interrupts = writes
63
+ .filter(([writeId, n]) => {
64
+ return writeId === id && n === INTERRUPT;
65
+ })
66
+ .map(([, v]) => {
67
+ return v;
68
+ });
62
69
  yield {
63
70
  type: "task",
64
71
  timestamp: ts,
@@ -68,13 +75,14 @@ export function* mapDebugTasks(step, tasks) {
68
75
  name,
69
76
  input,
70
77
  triggers,
78
+ interrupts,
71
79
  },
72
80
  };
73
81
  }
74
82
  }
75
- export function* mapDebugTaskResults(step, tasks, streamChannelsList) {
83
+ export function* mapDebugTaskResults(step, tasks, streamChannels) {
76
84
  const ts = new Date().toISOString();
77
- for (const { name, writes, config } of tasks) {
85
+ for (const [{ name, config }, writes] of tasks) {
78
86
  if (config?.tags?.includes(TAG_HIDDEN))
79
87
  continue;
80
88
  const metadata = { ...config?.metadata };
@@ -86,7 +94,9 @@ export function* mapDebugTaskResults(step, tasks, streamChannelsList) {
86
94
  payload: {
87
95
  id: uuid5(JSON.stringify([name, step, idMetadata]), TASK_NAMESPACE),
88
96
  name,
89
- result: writes.filter(([channel]) => streamChannelsList.includes(channel)),
97
+ result: writes.filter(([channel]) => Array.isArray(streamChannels)
98
+ ? streamChannels.includes(channel)
99
+ : channel === streamChannels),
90
100
  },
91
101
  };
92
102
  }
@@ -134,9 +144,26 @@ export function* mapDebugCheckpoint(step, config, channels, streamChannels, meta
134
144
  export function tasksWithWrites(tasks, pendingWrites) {
135
145
  return tasks.map((task) => {
136
146
  const error = pendingWrites.find(([id, n]) => id === task.id && n === ERROR)?.[2];
137
- if (error)
138
- return { id: task.id, name: task.name, error };
139
- return { id: task.id, name: task.name };
147
+ const interrupts = pendingWrites
148
+ .filter(([id, n]) => {
149
+ return id === task.id && n === INTERRUPT;
150
+ })
151
+ .map(([, , v]) => {
152
+ return v;
153
+ });
154
+ if (error) {
155
+ return {
156
+ id: task.id,
157
+ name: task.name,
158
+ error,
159
+ interrupts,
160
+ };
161
+ }
162
+ return {
163
+ id: task.id,
164
+ name: task.name,
165
+ interrupts,
166
+ };
140
167
  });
141
168
  }
142
169
  export function printStepCheckpoint(step, channels, whitelist) {
@@ -13,8 +13,7 @@ const write_js_1 = require("./write.cjs");
13
13
  const constants_js_1 = require("../constants.cjs");
14
14
  const errors_js_1 = require("../errors.cjs");
15
15
  const algo_js_1 = require("./algo.cjs");
16
- const utils_js_1 = require("../utils.cjs");
17
- const utils_js_2 = require("./utils.cjs");
16
+ const utils_js_1 = require("./utils.cjs");
18
17
  const loop_js_1 = require("./loop.cjs");
19
18
  const retry_js_1 = require("./retry.cjs");
20
19
  function isString(value) {
@@ -365,7 +364,7 @@ class Pregel extends runnables_1.Runnable {
365
364
  // apply to checkpoint and save
366
365
  // TODO: Why does keyof StrRecord allow number and symbol?
367
366
  (0, algo_js_1._applyWrites)(checkpoint, channels, [task], this.checkpointer.getNextVersion.bind(this.checkpointer));
368
- const newVersions = (0, utils_js_2.getNewChannelVersions)(checkpointPreviousVersions, checkpoint.channel_versions);
367
+ const newVersions = (0, utils_js_1.getNewChannelVersions)(checkpointPreviousVersions, checkpoint.channel_versions);
369
368
  return await this.checkpointer.put(checkpointConfig, (0, base_js_1.createCheckpoint)(checkpoint, channels, step + 1), {
370
369
  source: "update",
371
370
  step: step + 1,
@@ -451,7 +450,7 @@ class Pregel extends runnables_1.Runnable {
451
450
  throw new Error(`Checkpointer requires one or more of the following "configurable" keys: "thread_id", "checkpoint_ns", "checkpoint_id"`);
452
451
  }
453
452
  const callbackManager = await (0, runnables_1.getCallbackManagerForConfig)(inputConfig);
454
- const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, utils_js_2._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
453
+ const runManager = await callbackManager?.handleChainStart(this.toJSON(), (0, utils_js_1._coerceToDict)(input, "input"), inputConfig.runId, undefined, undefined, undefined, inputConfig?.runName ?? this.getName());
455
454
  delete inputConfig.runId;
456
455
  // assign defaults
457
456
  const [debug, streamMode, , outputKeys, config, interruptBefore, interruptAfter, checkpointer,] = this._defaults(inputConfig);
@@ -467,10 +466,11 @@ class Pregel extends runnables_1.Runnable {
467
466
  checkpointer,
468
467
  graph: this,
469
468
  onBackgroundError,
469
+ outputKeys,
470
+ streamKeys: this.streamChannelsAsIs,
470
471
  });
471
472
  while (backgroundError === undefined &&
472
473
  (await loop.tick({
473
- outputKeys,
474
474
  interruptAfter,
475
475
  interruptBefore,
476
476
  manager: runManager,
@@ -495,35 +495,52 @@ class Pregel extends runnables_1.Runnable {
495
495
  if (debug) {
496
496
  (0, debug_js_1.printStepTasks)(loop.step, loop.tasks);
497
497
  }
498
- try {
499
- // execute tasks, and wait for one to fail or all to finish.
500
- // each task is independent from all other concurrent tasks
501
- // yield updates/debug output as each task finishes
502
- for await (const task of (0, retry_js_1.executeTasksWithRetry)(loop.tasks.filter((task) => task.writes.length === 0), {
503
- stepTimeout: this.stepTimeout,
504
- signal: config.signal,
505
- retryPolicy: this.retryPolicy,
506
- })) {
498
+ // execute tasks, and wait for one to fail or all to finish.
499
+ // each task is independent from all other concurrent tasks
500
+ // yield updates/debug output as each task finishes
501
+ const taskStream = (0, retry_js_1.executeTasksWithRetry)(loop.tasks.filter((task) => task.writes.length === 0), {
502
+ stepTimeout: this.stepTimeout,
503
+ signal: config.signal,
504
+ retryPolicy: this.retryPolicy,
505
+ });
506
+ // Timeouts will be thrown
507
+ for await (const { task, error } of taskStream) {
508
+ if (error !== undefined) {
509
+ if ((0, errors_js_1.isGraphInterrupt)(error)) {
510
+ loop.putWrites(task.id, error.interrupts.map((interrupt) => [constants_js_1.INTERRUPT, interrupt]));
511
+ }
512
+ else {
513
+ loop.putWrites(task.id, [
514
+ [constants_js_1.ERROR, { message: error.message, name: error.name }],
515
+ ]);
516
+ }
517
+ }
518
+ else {
507
519
  loop.putWrites(task.id, task.writes);
508
- if (streamMode.includes("updates")) {
509
- yield* (0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputUpdates)(outputKeys, [task]), streamMode.length > 1 ? "updates" : undefined);
520
+ }
521
+ while (loop.stream.length > 0) {
522
+ const nextItem = loop.stream.shift();
523
+ if (nextItem === undefined) {
524
+ throw new Error("Data structure error.");
510
525
  }
511
- if (streamMode.includes("debug")) {
512
- yield* (0, utils_js_1.prefixGenerator)((0, debug_js_1.mapDebugTaskResults)(loop.step, [task], this.streamChannelsList), streamMode.length > 1 ? "debug" : undefined);
526
+ if (streamMode.includes(nextItem[0])) {
527
+ if (streamMode.length === 1) {
528
+ yield nextItem[1];
529
+ }
530
+ else {
531
+ yield nextItem;
532
+ }
513
533
  }
514
534
  }
515
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
516
- }
517
- catch (e) {
518
- if (e.pregelTaskId) {
519
- loop.putWrites(e.pregelTaskId, [[constants_js_1.ERROR, { message: e.message }]]);
535
+ if (error !== undefined && !(0, errors_js_1.isGraphInterrupt)(error)) {
536
+ throw error;
520
537
  }
521
- throw e;
522
538
  }
523
539
  if (debug) {
524
540
  (0, debug_js_1.printStepWrites)(loop.step, loop.tasks.map((task) => task.writes).flat(), this.streamChannelsList);
525
541
  }
526
542
  }
543
+ // Checkpointing failures
527
544
  if (backgroundError !== undefined) {
528
545
  throw backgroundError;
529
546
  }
@@ -4,13 +4,12 @@ import { compareChannelVersions, copyCheckpoint, emptyCheckpoint, uuid5, } from
4
4
  import { createCheckpoint, emptyChannels, } from "../channels/base.js";
5
5
  import { PregelNode } from "./read.js";
6
6
  import { validateGraph, validateKeys } from "./validate.js";
7
- import { mapOutputUpdates, readChannels } from "./io.js";
8
- import { mapDebugTaskResults, printStepCheckpoint, printStepTasks, printStepWrites, tasksWithWrites, } from "./debug.js";
7
+ import { readChannels } from "./io.js";
8
+ import { printStepCheckpoint, printStepTasks, printStepWrites, tasksWithWrites, } from "./debug.js";
9
9
  import { ChannelWrite, PASSTHROUGH } from "./write.js";
10
10
  import { CONFIG_KEY_CHECKPOINTER, CONFIG_KEY_READ, CONFIG_KEY_SEND, ERROR, INTERRUPT, } from "../constants.js";
11
- import { GraphRecursionError, GraphValueError, InvalidUpdateError, } from "../errors.js";
11
+ import { GraphRecursionError, GraphValueError, InvalidUpdateError, isGraphInterrupt, } from "../errors.js";
12
12
  import { _prepareNextTasks, _localRead, _applyWrites, } from "./algo.js";
13
- import { prefixGenerator } from "../utils.js";
14
13
  import { _coerceToDict, getNewChannelVersions } from "./utils.js";
15
14
  import { PregelLoop } from "./loop.js";
16
15
  import { executeTasksWithRetry } from "./retry.js";
@@ -463,10 +462,11 @@ export class Pregel extends Runnable {
463
462
  checkpointer,
464
463
  graph: this,
465
464
  onBackgroundError,
465
+ outputKeys,
466
+ streamKeys: this.streamChannelsAsIs,
466
467
  });
467
468
  while (backgroundError === undefined &&
468
469
  (await loop.tick({
469
- outputKeys,
470
470
  interruptAfter,
471
471
  interruptBefore,
472
472
  manager: runManager,
@@ -491,35 +491,52 @@ export class Pregel extends Runnable {
491
491
  if (debug) {
492
492
  printStepTasks(loop.step, loop.tasks);
493
493
  }
494
- try {
495
- // execute tasks, and wait for one to fail or all to finish.
496
- // each task is independent from all other concurrent tasks
497
- // yield updates/debug output as each task finishes
498
- for await (const task of executeTasksWithRetry(loop.tasks.filter((task) => task.writes.length === 0), {
499
- stepTimeout: this.stepTimeout,
500
- signal: config.signal,
501
- retryPolicy: this.retryPolicy,
502
- })) {
494
+ // execute tasks, and wait for one to fail or all to finish.
495
+ // each task is independent from all other concurrent tasks
496
+ // yield updates/debug output as each task finishes
497
+ const taskStream = executeTasksWithRetry(loop.tasks.filter((task) => task.writes.length === 0), {
498
+ stepTimeout: this.stepTimeout,
499
+ signal: config.signal,
500
+ retryPolicy: this.retryPolicy,
501
+ });
502
+ // Timeouts will be thrown
503
+ for await (const { task, error } of taskStream) {
504
+ if (error !== undefined) {
505
+ if (isGraphInterrupt(error)) {
506
+ loop.putWrites(task.id, error.interrupts.map((interrupt) => [INTERRUPT, interrupt]));
507
+ }
508
+ else {
509
+ loop.putWrites(task.id, [
510
+ [ERROR, { message: error.message, name: error.name }],
511
+ ]);
512
+ }
513
+ }
514
+ else {
503
515
  loop.putWrites(task.id, task.writes);
504
- if (streamMode.includes("updates")) {
505
- yield* prefixGenerator(mapOutputUpdates(outputKeys, [task]), streamMode.length > 1 ? "updates" : undefined);
516
+ }
517
+ while (loop.stream.length > 0) {
518
+ const nextItem = loop.stream.shift();
519
+ if (nextItem === undefined) {
520
+ throw new Error("Data structure error.");
506
521
  }
507
- if (streamMode.includes("debug")) {
508
- yield* prefixGenerator(mapDebugTaskResults(loop.step, [task], this.streamChannelsList), streamMode.length > 1 ? "debug" : undefined);
522
+ if (streamMode.includes(nextItem[0])) {
523
+ if (streamMode.length === 1) {
524
+ yield nextItem[1];
525
+ }
526
+ else {
527
+ yield nextItem;
528
+ }
509
529
  }
510
530
  }
511
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
512
- }
513
- catch (e) {
514
- if (e.pregelTaskId) {
515
- loop.putWrites(e.pregelTaskId, [[ERROR, { message: e.message }]]);
531
+ if (error !== undefined && !isGraphInterrupt(error)) {
532
+ throw error;
516
533
  }
517
- throw e;
518
534
  }
519
535
  if (debug) {
520
536
  printStepWrites(loop.step, loop.tasks.map((task) => task.writes).flat(), this.streamChannelsList);
521
537
  }
522
538
  }
539
+ // Checkpointing failures
523
540
  if (backgroundError !== undefined) {
524
541
  throw backgroundError;
525
542
  }
@@ -135,6 +135,18 @@ class PregelLoop {
135
135
  writable: true,
136
136
  value: Promise.resolve()
137
137
  });
138
+ Object.defineProperty(this, "outputKeys", {
139
+ enumerable: true,
140
+ configurable: true,
141
+ writable: true,
142
+ value: void 0
143
+ });
144
+ Object.defineProperty(this, "streamKeys", {
145
+ enumerable: true,
146
+ configurable: true,
147
+ writable: true,
148
+ value: void 0
149
+ });
138
150
  Object.defineProperty(this, "onBackgroundError", {
139
151
  enumerable: true,
140
152
  configurable: true,
@@ -162,6 +174,8 @@ class PregelLoop {
162
174
  this.step = params.step;
163
175
  this.stop = params.stop;
164
176
  this.isNested = constants_js_1.CONFIG_KEY_READ in (this.config.configurable ?? {});
177
+ this.outputKeys = params.outputKeys;
178
+ this.streamKeys = params.streamKeys;
165
179
  this.onBackgroundError = params.onBackgroundError;
166
180
  }
167
181
  static async initialize(params) {
@@ -203,6 +217,8 @@ class PregelLoop {
203
217
  stop,
204
218
  checkpointPreviousVersions,
205
219
  checkpointPendingWrites,
220
+ outputKeys: params.outputKeys,
221
+ streamKeys: params.streamKeys,
206
222
  onBackgroundError: params.onBackgroundError,
207
223
  });
208
224
  }
@@ -239,6 +255,11 @@ class PregelLoop {
239
255
  }, writes, taskId)
240
256
  .catch(this.onBackgroundError);
241
257
  }
258
+ const task = this.tasks.find((task) => task.id === taskId);
259
+ if (task !== undefined) {
260
+ this.stream.push(...(0, utils_js_1.gatherIteratorSync)((0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputUpdates)(this.outputKeys, [task]), "updates")));
261
+ this.stream.push(...(0, utils_js_1.gatherIteratorSync)((0, utils_js_1.prefixGenerator)((0, debug_js_1.mapDebugTaskResults)(this.step, [[task, writes]], this.streamKeys), "debug")));
262
+ }
242
263
  }
243
264
  /**
244
265
  * Execute a single iteration of the Pregel loop.
@@ -246,7 +267,7 @@ class PregelLoop {
246
267
  * @param params
247
268
  */
248
269
  async tick(params) {
249
- const { outputKeys = [], interruptAfter = [], interruptBefore = [], manager, } = params;
270
+ const { interruptAfter = [], interruptBefore = [], manager } = params;
250
271
  if (this.status !== "pending") {
251
272
  throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
252
273
  }
@@ -258,15 +279,11 @@ class PregelLoop {
258
279
  // All tasks have finished
259
280
  (0, algo_js_1._applyWrites)(this.checkpoint, this.channels, this.tasks, this.checkpointerGetNextVersion);
260
281
  // produce values output
261
- const valuesOutput = await (0, utils_js_1.gatherIterator)((0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputValues)(outputKeys, writes, this.channels), "values"));
282
+ const valuesOutput = await (0, utils_js_1.gatherIterator)((0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputValues)(this.outputKeys, writes, this.channels), "values"));
262
283
  this.stream.push(...valuesOutput);
263
284
  // clear pending writes
264
285
  this.checkpointPendingWrites = [];
265
- const updatesOnly = this.graph.streamMode?.length === 1 &&
266
- this.graph.streamMode?.includes("updates");
267
- const metadataWrites = updatesOnly
268
- ? (0, io_js_1.mapOutputUpdates)(outputKeys, this.tasks).next().value
269
- : (0, io_js_1.mapOutputValues)(outputKeys, writes, this.channels).next().value;
286
+ const metadataWrites = (0, io_js_1.mapOutputUpdates)(this.outputKeys, this.tasks).next().value;
270
287
  await this._putCheckpoint({
271
288
  source: "loop",
272
289
  writes: metadataWrites ?? null,
@@ -308,8 +325,7 @@ class PregelLoop {
308
325
  // if there are pending writes from a previous loop, apply them
309
326
  if (this.checkpointPendingWrites.length > 0) {
310
327
  for (const [tid, k, v] of this.checkpointPendingWrites) {
311
- // TODO: Do the same for INTERRUPT
312
- if (k === constants_js_1.ERROR) {
328
+ if (k === constants_js_1.ERROR || k === constants_js_1.INTERRUPT) {
313
329
  continue;
314
330
  }
315
331
  const task = this.tasks.find((t) => t.id === tid);
@@ -321,7 +337,6 @@ class PregelLoop {
321
337
  // if all tasks have finished, re-tick
322
338
  if (this.tasks.every((task) => task.writes.length > 0)) {
323
339
  return this.tick({
324
- outputKeys,
325
340
  interruptAfter,
326
341
  interruptBefore,
327
342
  manager,
@@ -9,6 +9,8 @@ export type PregelLoopInitializeParams = {
9
9
  config: RunnableConfig;
10
10
  checkpointer?: BaseCheckpointSaver;
11
11
  graph: PregelInterface<any, any>;
12
+ outputKeys: string | string[];
13
+ streamKeys: string | string[];
12
14
  onBackgroundError: (e: Error) => void;
13
15
  };
14
16
  type PregelLoopParams = {
@@ -24,6 +26,8 @@ type PregelLoopParams = {
24
26
  channels: Record<string, BaseChannel>;
25
27
  step: number;
26
28
  stop: number;
29
+ outputKeys: string | string[];
30
+ streamKeys: string | string[];
27
31
  onBackgroundError: (e: Error) => void;
28
32
  };
29
33
  export declare class PregelLoop {
@@ -45,6 +49,8 @@ export declare class PregelLoop {
45
49
  stream: Deque<[StreamMode, any]>;
46
50
  protected isNested: boolean;
47
51
  protected _putCheckpointPromise: Promise<unknown>;
52
+ outputKeys: string | string[];
53
+ streamKeys: string | string[];
48
54
  onBackgroundError: (e: Error) => void;
49
55
  get backgroundTasksPromise(): Promise<unknown>;
50
56
  constructor(params: PregelLoopParams);
@@ -67,7 +73,6 @@ export declare class PregelLoop {
67
73
  * @param params
68
74
  */
69
75
  tick(params: {
70
- outputKeys: string | string[];
71
76
  interruptAfter: string[] | All;
72
77
  interruptBefore: string[] | All;
73
78
  manager?: CallbackManagerForChainRun;
@@ -3,11 +3,11 @@ import { copyCheckpoint, emptyCheckpoint, } from "@langchain/langgraph-checkpoin
3
3
  import { createCheckpoint, emptyChannels, } from "../channels/base.js";
4
4
  import { CONFIG_KEY_READ, CONFIG_KEY_RESUMING, ERROR, INPUT, INTERRUPT, } from "../constants.js";
5
5
  import { _applyWrites, _prepareNextTasks, increment, shouldInterrupt, } from "./algo.js";
6
- import { gatherIterator, prefixGenerator } from "../utils.js";
6
+ import { gatherIterator, gatherIteratorSync, prefixGenerator, } from "../utils.js";
7
7
  import { mapInput, mapOutputUpdates, mapOutputValues } from "./io.js";
8
8
  import { EmptyInputError, GraphInterrupt } from "../errors.js";
9
9
  import { getNewChannelVersions } from "./utils.js";
10
- import { mapDebugTasks, mapDebugCheckpoint } from "./debug.js";
10
+ import { mapDebugTasks, mapDebugCheckpoint, mapDebugTaskResults, } from "./debug.js";
11
11
  const INPUT_DONE = Symbol.for("INPUT_DONE");
12
12
  const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
13
13
  const DEFAULT_LOOP_LIMIT = 25;
@@ -129,6 +129,18 @@ export class PregelLoop {
129
129
  writable: true,
130
130
  value: Promise.resolve()
131
131
  });
132
+ Object.defineProperty(this, "outputKeys", {
133
+ enumerable: true,
134
+ configurable: true,
135
+ writable: true,
136
+ value: void 0
137
+ });
138
+ Object.defineProperty(this, "streamKeys", {
139
+ enumerable: true,
140
+ configurable: true,
141
+ writable: true,
142
+ value: void 0
143
+ });
132
144
  Object.defineProperty(this, "onBackgroundError", {
133
145
  enumerable: true,
134
146
  configurable: true,
@@ -156,6 +168,8 @@ export class PregelLoop {
156
168
  this.step = params.step;
157
169
  this.stop = params.stop;
158
170
  this.isNested = CONFIG_KEY_READ in (this.config.configurable ?? {});
171
+ this.outputKeys = params.outputKeys;
172
+ this.streamKeys = params.streamKeys;
159
173
  this.onBackgroundError = params.onBackgroundError;
160
174
  }
161
175
  static async initialize(params) {
@@ -197,6 +211,8 @@ export class PregelLoop {
197
211
  stop,
198
212
  checkpointPreviousVersions,
199
213
  checkpointPendingWrites,
214
+ outputKeys: params.outputKeys,
215
+ streamKeys: params.streamKeys,
200
216
  onBackgroundError: params.onBackgroundError,
201
217
  });
202
218
  }
@@ -233,6 +249,11 @@ export class PregelLoop {
233
249
  }, writes, taskId)
234
250
  .catch(this.onBackgroundError);
235
251
  }
252
+ const task = this.tasks.find((task) => task.id === taskId);
253
+ if (task !== undefined) {
254
+ this.stream.push(...gatherIteratorSync(prefixGenerator(mapOutputUpdates(this.outputKeys, [task]), "updates")));
255
+ this.stream.push(...gatherIteratorSync(prefixGenerator(mapDebugTaskResults(this.step, [[task, writes]], this.streamKeys), "debug")));
256
+ }
236
257
  }
237
258
  /**
238
259
  * Execute a single iteration of the Pregel loop.
@@ -240,7 +261,7 @@ export class PregelLoop {
240
261
  * @param params
241
262
  */
242
263
  async tick(params) {
243
- const { outputKeys = [], interruptAfter = [], interruptBefore = [], manager, } = params;
264
+ const { interruptAfter = [], interruptBefore = [], manager } = params;
244
265
  if (this.status !== "pending") {
245
266
  throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
246
267
  }
@@ -252,15 +273,11 @@ export class PregelLoop {
252
273
  // All tasks have finished
253
274
  _applyWrites(this.checkpoint, this.channels, this.tasks, this.checkpointerGetNextVersion);
254
275
  // produce values output
255
- const valuesOutput = await gatherIterator(prefixGenerator(mapOutputValues(outputKeys, writes, this.channels), "values"));
276
+ const valuesOutput = await gatherIterator(prefixGenerator(mapOutputValues(this.outputKeys, writes, this.channels), "values"));
256
277
  this.stream.push(...valuesOutput);
257
278
  // clear pending writes
258
279
  this.checkpointPendingWrites = [];
259
- const updatesOnly = this.graph.streamMode?.length === 1 &&
260
- this.graph.streamMode?.includes("updates");
261
- const metadataWrites = updatesOnly
262
- ? mapOutputUpdates(outputKeys, this.tasks).next().value
263
- : mapOutputValues(outputKeys, writes, this.channels).next().value;
280
+ const metadataWrites = mapOutputUpdates(this.outputKeys, this.tasks).next().value;
264
281
  await this._putCheckpoint({
265
282
  source: "loop",
266
283
  writes: metadataWrites ?? null,
@@ -302,8 +319,7 @@ export class PregelLoop {
302
319
  // if there are pending writes from a previous loop, apply them
303
320
  if (this.checkpointPendingWrites.length > 0) {
304
321
  for (const [tid, k, v] of this.checkpointPendingWrites) {
305
- // TODO: Do the same for INTERRUPT
306
- if (k === ERROR) {
322
+ if (k === ERROR || k === INTERRUPT) {
307
323
  continue;
308
324
  }
309
325
  const task = this.tasks.find((t) => t.id === tid);
@@ -315,7 +331,6 @@ export class PregelLoop {
315
331
  // if all tasks have finished, re-tick
316
332
  if (this.tasks.every((task) => task.writes.length > 0)) {
317
333
  return this.tick({
318
- outputKeys,
319
334
  interruptAfter,
320
335
  interruptBefore,
321
336
  manager,
@@ -42,9 +42,7 @@ const DEFAULT_RETRY_ON_HANDLER = (error) => {
42
42
  };
43
43
  async function* executeTasksWithRetry(
44
44
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
- tasks, options
46
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
- ) {
45
+ tasks, options) {
48
46
  const { stepTimeout, retryPolicy } = options ?? {};
49
47
  let signal = options?.signal;
50
48
  // Start tasks
@@ -71,16 +69,12 @@ tasks, options
71
69
  signal?.addEventListener("abort", listener);
72
70
  }).finally(() => signal?.removeEventListener("abort", listener));
73
71
  while (Object.keys(executingTasksMap).length > 0) {
74
- const { task, error } = await Promise.race([
72
+ const settledTask = await Promise.race([
75
73
  ...Object.values(executingTasksMap),
76
74
  signalPromise,
77
75
  ]);
78
- if (error !== undefined) {
79
- // TODO: don't stop others if exception is interrupt
80
- throw error;
81
- }
82
- yield task;
83
- delete executingTasksMap[task.id];
76
+ yield settledTask;
77
+ delete executingTasksMap[settledTask.task.id];
84
78
  }
85
79
  }
86
80
  exports.executeTasksWithRetry = executeTasksWithRetry;
@@ -109,7 +103,7 @@ pregelTask, retryPolicy) {
109
103
  catch (e) {
110
104
  error = e;
111
105
  error.pregelTaskId = pregelTask.id;
112
- if (error.name === errors_js_1.GraphInterrupt.unminifiable_name) {
106
+ if ((0, errors_js_1.isGraphInterrupt)(error)) {
113
107
  break;
114
108
  }
115
109
  if (resolvedRetryPolicy === undefined) {
@@ -4,8 +4,12 @@ export declare const DEFAULT_INITIAL_INTERVAL = 500;
4
4
  export declare const DEFAULT_BACKOFF_FACTOR = 2;
5
5
  export declare const DEFAULT_MAX_INTERVAL = 128000;
6
6
  export declare const DEFAULT_MAX_RETRIES = 3;
7
+ export type SettledPregelTask = {
8
+ task: PregelExecutableTask<any, any>;
9
+ error: Error;
10
+ };
7
11
  export declare function executeTasksWithRetry(tasks: PregelExecutableTask<any, any>[], options?: {
8
12
  stepTimeout?: number;
9
13
  signal?: AbortSignal;
10
14
  retryPolicy?: RetryPolicy;
11
- }): AsyncGenerator<PregelExecutableTask<any, any>>;
15
+ }): AsyncGenerator<SettledPregelTask>;
@@ -1,4 +1,4 @@
1
- import { GraphInterrupt } from "../errors.js";
1
+ import { isGraphInterrupt } from "../errors.js";
2
2
  export const DEFAULT_INITIAL_INTERVAL = 500;
3
3
  export const DEFAULT_BACKOFF_FACTOR = 2;
4
4
  export const DEFAULT_MAX_INTERVAL = 128000;
@@ -39,9 +39,7 @@ const DEFAULT_RETRY_ON_HANDLER = (error) => {
39
39
  };
40
40
  export async function* executeTasksWithRetry(
41
41
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
- tasks, options
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- ) {
42
+ tasks, options) {
45
43
  const { stepTimeout, retryPolicy } = options ?? {};
46
44
  let signal = options?.signal;
47
45
  // Start tasks
@@ -68,16 +66,12 @@ tasks, options
68
66
  signal?.addEventListener("abort", listener);
69
67
  }).finally(() => signal?.removeEventListener("abort", listener));
70
68
  while (Object.keys(executingTasksMap).length > 0) {
71
- const { task, error } = await Promise.race([
69
+ const settledTask = await Promise.race([
72
70
  ...Object.values(executingTasksMap),
73
71
  signalPromise,
74
72
  ]);
75
- if (error !== undefined) {
76
- // TODO: don't stop others if exception is interrupt
77
- throw error;
78
- }
79
- yield task;
80
- delete executingTasksMap[task.id];
73
+ yield settledTask;
74
+ delete executingTasksMap[settledTask.task.id];
81
75
  }
82
76
  }
83
77
  async function _runWithRetry(
@@ -105,7 +99,7 @@ pregelTask, retryPolicy) {
105
99
  catch (e) {
106
100
  error = e;
107
101
  error.pregelTaskId = pregelTask.id;
108
- if (error.name === GraphInterrupt.unminifiable_name) {
102
+ if (isGraphInterrupt(error)) {
109
103
  break;
110
104
  }
111
105
  if (resolvedRetryPolicy === undefined) {
@@ -3,6 +3,7 @@ import type { PendingWrite, CheckpointMetadata, BaseCheckpointSaver } from "@lan
3
3
  import type { BaseChannel } from "../channels/base.js";
4
4
  import type { PregelNode } from "./read.js";
5
5
  import { RetryPolicy } from "./utils.js";
6
+ import { Interrupt } from "../constants.js";
6
7
  export type StreamMode = "values" | "updates" | "debug";
7
8
  /**
8
9
  * Construct a type with a set of properties K of type T
@@ -49,6 +50,7 @@ export interface PregelTaskDescription {
49
50
  readonly id: string;
50
51
  readonly name: string;
51
52
  readonly error?: unknown;
53
+ readonly interrupts: Interrupt[];
52
54
  }
53
55
  export interface PregelExecutableTask<N extends PropertyKey, C extends PropertyKey> {
54
56
  readonly name: N;
package/dist/utils.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.gatherIterator = exports.prefixGenerator = exports.RunnableCallable = void 0;
3
+ exports.gatherIteratorSync = exports.gatherIterator = exports.prefixGenerator = exports.RunnableCallable = void 0;
4
4
  const runnables_1 = require("@langchain/core/runnables");
5
5
  const singletons_1 = require("@langchain/core/singletons");
6
6
  class RunnableCallable extends runnables_1.Runnable {
@@ -105,3 +105,11 @@ async function gatherIterator(i) {
105
105
  return out;
106
106
  }
107
107
  exports.gatherIterator = gatherIterator;
108
+ function gatherIteratorSync(i) {
109
+ const out = [];
110
+ for (const item of i) {
111
+ out.push(item);
112
+ }
113
+ return out;
114
+ }
115
+ exports.gatherIteratorSync = gatherIteratorSync;
package/dist/utils.d.ts CHANGED
@@ -22,3 +22,4 @@ export declare function prefixGenerator<T, Prefix extends string>(generator: Gen
22
22
  export declare function prefixGenerator<T>(generator: Generator<T>, prefix?: undefined): Generator<T>;
23
23
  export declare function prefixGenerator<T, Prefix extends string | undefined = undefined>(generator: Generator<T>, prefix?: Prefix | undefined): Generator<Prefix extends string ? [Prefix, T] : T>;
24
24
  export declare function gatherIterator<T>(i: AsyncIterable<T> | Promise<AsyncIterable<T>> | Iterable<T> | Promise<Iterable<T>>): Promise<Array<T>>;
25
+ export declare function gatherIteratorSync<T>(i: Iterable<T>): Array<T>;
package/dist/utils.js CHANGED
@@ -99,3 +99,10 @@ export async function gatherIterator(i) {
99
99
  }
100
100
  return out;
101
101
  }
102
+ export function gatherIteratorSync(i) {
103
+ const out = [];
104
+ for (const item of i) {
105
+ out.push(item);
106
+ }
107
+ return out;
108
+ }
package/dist/web.cjs CHANGED
@@ -1,6 +1,20 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BaseCheckpointSaver = exports.emptyCheckpoint = exports.copyCheckpoint = exports.MemorySaver = exports.Send = exports.BinaryOperatorAggregate = exports.BaseChannel = exports.EmptyChannelError = exports.InvalidUpdateError = exports.GraphValueError = exports.GraphRecursionError = exports.AnnotationRoot = exports.Annotation = exports.messagesStateReducer = exports.MessageGraph = exports.StateGraph = exports.START = exports.Graph = exports.END = void 0;
17
+ exports.BaseCheckpointSaver = exports.emptyCheckpoint = exports.copyCheckpoint = exports.MemorySaver = exports.Send = exports.BinaryOperatorAggregate = exports.BaseChannel = exports.Annotation = exports.messagesStateReducer = exports.MessageGraph = exports.StateGraph = exports.START = exports.Graph = exports.END = void 0;
4
18
  var index_js_1 = require("./graph/index.cjs");
5
19
  Object.defineProperty(exports, "END", { enumerable: true, get: function () { return index_js_1.END; } });
6
20
  Object.defineProperty(exports, "Graph", { enumerable: true, get: function () { return index_js_1.Graph; } });
@@ -9,12 +23,7 @@ Object.defineProperty(exports, "StateGraph", { enumerable: true, get: function (
9
23
  Object.defineProperty(exports, "MessageGraph", { enumerable: true, get: function () { return index_js_1.MessageGraph; } });
10
24
  Object.defineProperty(exports, "messagesStateReducer", { enumerable: true, get: function () { return index_js_1.messagesStateReducer; } });
11
25
  Object.defineProperty(exports, "Annotation", { enumerable: true, get: function () { return index_js_1.Annotation; } });
12
- Object.defineProperty(exports, "AnnotationRoot", { enumerable: true, get: function () { return index_js_1.AnnotationRoot; } });
13
- var errors_js_1 = require("./errors.cjs");
14
- Object.defineProperty(exports, "GraphRecursionError", { enumerable: true, get: function () { return errors_js_1.GraphRecursionError; } });
15
- Object.defineProperty(exports, "GraphValueError", { enumerable: true, get: function () { return errors_js_1.GraphValueError; } });
16
- Object.defineProperty(exports, "InvalidUpdateError", { enumerable: true, get: function () { return errors_js_1.InvalidUpdateError; } });
17
- Object.defineProperty(exports, "EmptyChannelError", { enumerable: true, get: function () { return errors_js_1.EmptyChannelError; } });
26
+ __exportStar(require("./errors.cjs"), exports);
18
27
  var index_js_2 = require("./channels/index.cjs");
19
28
  Object.defineProperty(exports, "BaseChannel", { enumerable: true, get: function () { return index_js_2.BaseChannel; } });
20
29
  Object.defineProperty(exports, "BinaryOperatorAggregate", { enumerable: true, get: function () { return index_js_2.BinaryOperatorAggregate; } });
package/dist/web.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { END, Graph, type StateGraphArgs, START, StateGraph, type CompiledStateGraph, MessageGraph, messagesStateReducer, Annotation, AnnotationRoot, type StateDefinition, type SingleReducer, type StateType, type UpdateType, type NodeType, type CompiledGraph, } from "./graph/index.js";
2
- export { GraphRecursionError, GraphValueError, InvalidUpdateError, EmptyChannelError, } from "./errors.js";
1
+ export { END, Graph, type StateGraphArgs, START, StateGraph, type CompiledStateGraph, MessageGraph, messagesStateReducer, Annotation, type AnnotationRoot, type StateDefinition, type SingleReducer, type StateType, type UpdateType, type NodeType, type CompiledGraph, } from "./graph/index.js";
2
+ export * from "./errors.js";
3
3
  export { BaseChannel, type BinaryOperator, BinaryOperatorAggregate, type AnyValue, type WaitForNames, type DynamicBarrierValue, type LastValue, type NamedBarrierValue, type Topic, } from "./channels/index.js";
4
4
  export { type RetryPolicy } from "./pregel/utils.js";
5
5
  export { Send } from "./constants.js";
package/dist/web.js CHANGED
@@ -1,5 +1,5 @@
1
- export { END, Graph, START, StateGraph, MessageGraph, messagesStateReducer, Annotation, AnnotationRoot, } from "./graph/index.js";
2
- export { GraphRecursionError, GraphValueError, InvalidUpdateError, EmptyChannelError, } from "./errors.js";
1
+ export { END, Graph, START, StateGraph, MessageGraph, messagesStateReducer, Annotation, } from "./graph/index.js";
2
+ export * from "./errors.js";
3
3
  export { BaseChannel, BinaryOperatorAggregate, } from "./channels/index.js";
4
4
  export { Send } from "./constants.js";
5
5
  export { MemorySaver, copyCheckpoint, emptyCheckpoint, BaseCheckpointSaver, } from "@langchain/langgraph-checkpoint";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "LangGraph",
5
5
  "type": "module",
6
6
  "engines": {
@@ -31,7 +31,7 @@
31
31
  "author": "LangChain",
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@langchain/core": ">=0.2.20 <0.3.0",
34
+ "@langchain/core": ">=0.2.31 <0.3.0",
35
35
  "@langchain/langgraph-checkpoint": "~0.0.4",
36
36
  "@langchain/langgraph-checkpoint-sqlite": "~0.0.1",
37
37
  "double-ended-queue": "^2.1.0-0",