@langchain/langgraph 0.1.0 → 0.1.2

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 (44) hide show
  1. package/README.md +3 -3
  2. package/dist/constants.cjs +1 -0
  3. package/dist/constants.d.ts +1 -0
  4. package/dist/constants.js +1 -0
  5. package/dist/graph/annotation.cjs +78 -4
  6. package/dist/graph/annotation.d.ts +82 -5
  7. package/dist/graph/annotation.js +77 -2
  8. package/dist/graph/graph.cjs +14 -8
  9. package/dist/graph/graph.d.ts +14 -5
  10. package/dist/graph/graph.js +14 -8
  11. package/dist/graph/message.cjs +6 -0
  12. package/dist/graph/message.d.ts +6 -0
  13. package/dist/graph/message.js +6 -0
  14. package/dist/graph/messages_annotation.cjs +5 -0
  15. package/dist/graph/messages_annotation.d.ts +5 -0
  16. package/dist/graph/messages_annotation.js +5 -0
  17. package/dist/graph/state.cjs +84 -3
  18. package/dist/graph/state.d.ts +75 -5
  19. package/dist/graph/state.js +86 -5
  20. package/dist/prebuilt/agent_executor.cjs +1 -0
  21. package/dist/prebuilt/agent_executor.d.ts +2 -0
  22. package/dist/prebuilt/agent_executor.js +1 -0
  23. package/dist/prebuilt/chat_agent_executor.cjs +1 -0
  24. package/dist/prebuilt/chat_agent_executor.d.ts +2 -0
  25. package/dist/prebuilt/chat_agent_executor.js +1 -0
  26. package/dist/pregel/algo.cjs +3 -41
  27. package/dist/pregel/algo.d.ts +0 -5
  28. package/dist/pregel/algo.js +2 -39
  29. package/dist/pregel/debug.d.ts +1 -1
  30. package/dist/pregel/index.cjs +17 -30
  31. package/dist/pregel/index.d.ts +2 -0
  32. package/dist/pregel/index.js +18 -31
  33. package/dist/pregel/loop.cjs +5 -2
  34. package/dist/pregel/loop.js +5 -2
  35. package/dist/pregel/read.cjs +19 -1
  36. package/dist/pregel/read.d.ts +5 -0
  37. package/dist/pregel/read.js +19 -1
  38. package/dist/pregel/retry.cjs +147 -0
  39. package/dist/pregel/retry.d.ts +11 -0
  40. package/dist/pregel/retry.js +143 -0
  41. package/dist/pregel/types.d.ts +4 -2
  42. package/dist/pregel/utils.d.ts +26 -0
  43. package/dist/web.d.ts +1 -0
  44. package/package.json +6 -5
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CompiledStateGraph = exports.StateGraph = void 0;
4
+ /* eslint-disable @typescript-eslint/no-use-before-define */
5
+ const runnables_1 = require("@langchain/core/runnables");
4
6
  const graph_js_1 = require("./graph.cjs");
5
7
  const write_js_1 = require("../pregel/write.cjs");
6
8
  const read_js_1 = require("../pregel/read.cjs");
@@ -11,6 +13,68 @@ const constants_js_1 = require("../constants.cjs");
11
13
  const errors_js_1 = require("../errors.cjs");
12
14
  const annotation_js_1 = require("./annotation.cjs");
13
15
  const ROOT = "__root__";
16
+ /**
17
+ * A graph whose nodes communicate by reading and writing to a shared state.
18
+ * Each node takes a defined `State` as input and returns a `Partial<State>`.
19
+ *
20
+ * Each state key can optionally be annotated with a reducer function that
21
+ * will be used to aggregate the values of that key received from multiple nodes.
22
+ * The signature of a reducer function is (left: Value, right: UpdateValue) => Value.
23
+ *
24
+ * See {@link Annotation} for more on defining state.
25
+ *
26
+ * After adding nodes and edges to your graph, you must call `.compile()` on it before
27
+ * you can use it.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import {
32
+ * type BaseMessage,
33
+ * AIMessage,
34
+ * HumanMessage,
35
+ * } from "@langchain/core/messages";
36
+ * import { StateGraph, Annotation } from "@langchain/langgraph";
37
+ *
38
+ * // Define a state with a single key named "messages" that will
39
+ * // combine a returned BaseMessage or arrays of BaseMessages
40
+ * const StateAnnotation = Annotation.Root({
41
+ * sentiment: Annotation<string>,
42
+ * messages: Annotation<BaseMessage[]>({
43
+ * reducer: (left: BaseMessage[], right: BaseMessage | BaseMessage[]) => {
44
+ * if (Array.isArray(right)) {
45
+ * return left.concat(right);
46
+ * }
47
+ * return left.concat([right]);
48
+ * },
49
+ * default: () => [],
50
+ * }),
51
+ * });
52
+ *
53
+ * const graphBuilder = new StateGraph(StateAnnotation);
54
+ *
55
+ * // A node in the graph that returns an object with a "messages" key
56
+ * // will update the state by combining the existing value with the returned one.
57
+ * const myNode = (state: typeof StateAnnotation.State) => {
58
+ * return {
59
+ * messages: [new AIMessage("Some new response")],
60
+ * sentiment: "positive",
61
+ * };
62
+ * };
63
+ *
64
+ * const graph = graphBuilder
65
+ * .addNode("myNode", myNode)
66
+ * .addEdge("__start__", "myNode")
67
+ * .addEdge("myNode", "__end__")
68
+ * .compile();
69
+ *
70
+ * await graph.invoke({ messages: [new HumanMessage("how are you?")] });
71
+ *
72
+ * // {
73
+ * // messages: [HumanMessage("how are you?"), AIMessage("Some new response")],
74
+ * // sentiment: "positive",
75
+ * // }
76
+ * ```
77
+ */
14
78
  class StateGraph extends graph_js_1.Graph {
15
79
  constructor(fields) {
16
80
  super();
@@ -55,11 +119,27 @@ class StateGraph extends graph_js_1.Graph {
55
119
  ...Array.from(this.waitingEdges).flatMap(([starts, end]) => starts.map((start) => [start, end])),
56
120
  ]);
57
121
  }
58
- addNode(key, action) {
122
+ addNode(key, action, options) {
59
123
  if (key in this.channels) {
60
124
  throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
61
125
  }
62
- return super.addNode(key, action);
126
+ if (key.includes(constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR)) {
127
+ throw new Error(`"${constants_js_1.CHECKPOINT_NAMESPACE_SEPARATOR}" is a reserved character and is not allowed in node names.`);
128
+ }
129
+ this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
130
+ if (key in this.nodes) {
131
+ throw new Error(`Node \`${key}\` already present.`);
132
+ }
133
+ if (key === graph_js_1.END || key === graph_js_1.START) {
134
+ throw new Error(`Node \`${key}\` is reserved.`);
135
+ }
136
+ const nodeSpec = {
137
+ runnable: (0, runnables_1._coerceToRunnable)(action),
138
+ retryPolicy: options?.retryPolicy,
139
+ metadata: options?.metadata,
140
+ };
141
+ this.nodes[key] = nodeSpec;
142
+ return this;
63
143
  }
64
144
  addEdge(startKey, endKey) {
65
145
  if (typeof startKey === "string") {
@@ -198,7 +278,8 @@ class CompiledStateGraph extends graph_js_1.CompiledGraph {
198
278
  writers: [
199
279
  new write_js_1.ChannelWrite(stateWriteEntries.concat({ channel: key, value: key }), [constants_js_1.TAG_HIDDEN]),
200
280
  ],
201
- bound: node,
281
+ bound: node?.runnable,
282
+ retryPolicy: node?.retryPolicy,
202
283
  });
203
284
  }
204
285
  }
@@ -1,9 +1,10 @@
1
- import { Runnable, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
1
+ import { RunnableLike } from "@langchain/core/runnables";
2
2
  import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
3
3
  import { BaseChannel } from "../channels/base.js";
4
- import { END, CompiledGraph, Graph, START, Branch } from "./graph.js";
4
+ import { END, CompiledGraph, Graph, START, Branch, AddNodeOptions, NodeSpec } from "./graph.js";
5
5
  import { All } from "../pregel/types.js";
6
6
  import { AnnotationRoot, SingleReducer, StateDefinition, StateType, UpdateType } from "./annotation.js";
7
+ import type { RetryPolicy } from "../pregel/utils.js";
7
8
  export type ChannelReducers<Channels extends object> = {
8
9
  [K in keyof Channels]: SingleReducer<Channels[K], any>;
9
10
  };
@@ -14,12 +15,81 @@ export interface StateGraphArgs<Channels extends object | unknown> {
14
15
  __root__: Channels;
15
16
  }>;
16
17
  }
17
- export declare class StateGraph<SD extends StateDefinition | unknown, S = SD extends StateDefinition ? StateType<SD> : SD, U = SD extends StateDefinition ? UpdateType<SD> : Partial<S>, N extends string = typeof START> extends Graph<N, S, U> {
18
+ export type StateGraphNodeSpec<RunInput, RunOutput> = NodeSpec<RunInput, RunOutput> & {
19
+ input?: any;
20
+ retryPolicy?: RetryPolicy;
21
+ };
22
+ export type StateGraphAddNodeOptions = {
23
+ retryPolicy?: RetryPolicy;
24
+ } & AddNodeOptions;
25
+ /**
26
+ * A graph whose nodes communicate by reading and writing to a shared state.
27
+ * Each node takes a defined `State` as input and returns a `Partial<State>`.
28
+ *
29
+ * Each state key can optionally be annotated with a reducer function that
30
+ * will be used to aggregate the values of that key received from multiple nodes.
31
+ * The signature of a reducer function is (left: Value, right: UpdateValue) => Value.
32
+ *
33
+ * See {@link Annotation} for more on defining state.
34
+ *
35
+ * After adding nodes and edges to your graph, you must call `.compile()` on it before
36
+ * you can use it.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import {
41
+ * type BaseMessage,
42
+ * AIMessage,
43
+ * HumanMessage,
44
+ * } from "@langchain/core/messages";
45
+ * import { StateGraph, Annotation } from "@langchain/langgraph";
46
+ *
47
+ * // Define a state with a single key named "messages" that will
48
+ * // combine a returned BaseMessage or arrays of BaseMessages
49
+ * const StateAnnotation = Annotation.Root({
50
+ * sentiment: Annotation<string>,
51
+ * messages: Annotation<BaseMessage[]>({
52
+ * reducer: (left: BaseMessage[], right: BaseMessage | BaseMessage[]) => {
53
+ * if (Array.isArray(right)) {
54
+ * return left.concat(right);
55
+ * }
56
+ * return left.concat([right]);
57
+ * },
58
+ * default: () => [],
59
+ * }),
60
+ * });
61
+ *
62
+ * const graphBuilder = new StateGraph(StateAnnotation);
63
+ *
64
+ * // A node in the graph that returns an object with a "messages" key
65
+ * // will update the state by combining the existing value with the returned one.
66
+ * const myNode = (state: typeof StateAnnotation.State) => {
67
+ * return {
68
+ * messages: [new AIMessage("Some new response")],
69
+ * sentiment: "positive",
70
+ * };
71
+ * };
72
+ *
73
+ * const graph = graphBuilder
74
+ * .addNode("myNode", myNode)
75
+ * .addEdge("__start__", "myNode")
76
+ * .addEdge("myNode", "__end__")
77
+ * .compile();
78
+ *
79
+ * await graph.invoke({ messages: [new HumanMessage("how are you?")] });
80
+ *
81
+ * // {
82
+ * // messages: [HumanMessage("how are you?"), AIMessage("Some new response")],
83
+ * // sentiment: "positive",
84
+ * // }
85
+ * ```
86
+ */
87
+ export declare class StateGraph<SD extends StateDefinition | unknown, S = SD extends StateDefinition ? StateType<SD> : SD, U = SD extends StateDefinition ? UpdateType<SD> : Partial<S>, N extends string = typeof START> extends Graph<N, S, U, StateGraphNodeSpec<S, U>> {
18
88
  channels: Record<string, BaseChannel>;
19
89
  waitingEdges: Set<[N[], N]>;
20
90
  constructor(fields: SD extends StateDefinition ? SD | AnnotationRoot<SD> | StateGraphArgs<S> : StateGraphArgs<S>);
21
91
  get allEdges(): Set<[string, string]>;
22
- addNode<K extends string, NodeInput = S>(key: K, action: RunnableLike<NodeInput, U>): StateGraph<SD, S, U, N | K>;
92
+ addNode<K extends string, NodeInput = S>(key: K, action: RunnableLike<NodeInput, U>, options?: StateGraphAddNodeOptions): StateGraph<SD, S, U, N | K>;
23
93
  addEdge(startKey: typeof START | N | N[], endKey: N | typeof END): this;
24
94
  compile({ checkpointer, interruptBefore, interruptAfter, }?: {
25
95
  checkpointer?: BaseCheckpointSaver;
@@ -30,7 +100,7 @@ export declare class StateGraph<SD extends StateDefinition | unknown, S = SD ext
30
100
  export declare class CompiledStateGraph<S, U, N extends string = typeof START> extends CompiledGraph<N, S, U> {
31
101
  builder: StateGraph<unknown, S, U, N>;
32
102
  attachNode(key: typeof START, node?: never): void;
33
- attachNode(key: N, node: Runnable<S, U, RunnableConfig>): void;
103
+ attachNode(key: N, node: StateGraphNodeSpec<S, U>): void;
34
104
  attachEdge(start: N | N[] | "__start__", end: N | "__end__"): void;
35
105
  attachBranch(start: N | typeof START, name: string, branch: Branch<S, N>): void;
36
106
  }
@@ -1,13 +1,77 @@
1
- import { END, CompiledGraph, Graph, START } from "./graph.js";
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
2
+ import { _coerceToRunnable, } from "@langchain/core/runnables";
3
+ import { END, CompiledGraph, Graph, START, } from "./graph.js";
2
4
  import { ChannelWrite, PASSTHROUGH, SKIP_WRITE, } from "../pregel/write.js";
3
5
  import { ChannelRead, PregelNode } from "../pregel/read.js";
4
6
  import { NamedBarrierValue } from "../channels/named_barrier_value.js";
5
7
  import { EphemeralValue } from "../channels/ephemeral_value.js";
6
8
  import { RunnableCallable } from "../utils.js";
7
- import { _isSend, TAG_HIDDEN } from "../constants.js";
9
+ import { _isSend, CHECKPOINT_NAMESPACE_SEPARATOR, TAG_HIDDEN, } from "../constants.js";
8
10
  import { InvalidUpdateError } from "../errors.js";
9
11
  import { getChannel, } from "./annotation.js";
10
12
  const ROOT = "__root__";
13
+ /**
14
+ * A graph whose nodes communicate by reading and writing to a shared state.
15
+ * Each node takes a defined `State` as input and returns a `Partial<State>`.
16
+ *
17
+ * Each state key can optionally be annotated with a reducer function that
18
+ * will be used to aggregate the values of that key received from multiple nodes.
19
+ * The signature of a reducer function is (left: Value, right: UpdateValue) => Value.
20
+ *
21
+ * See {@link Annotation} for more on defining state.
22
+ *
23
+ * After adding nodes and edges to your graph, you must call `.compile()` on it before
24
+ * you can use it.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import {
29
+ * type BaseMessage,
30
+ * AIMessage,
31
+ * HumanMessage,
32
+ * } from "@langchain/core/messages";
33
+ * import { StateGraph, Annotation } from "@langchain/langgraph";
34
+ *
35
+ * // Define a state with a single key named "messages" that will
36
+ * // combine a returned BaseMessage or arrays of BaseMessages
37
+ * const StateAnnotation = Annotation.Root({
38
+ * sentiment: Annotation<string>,
39
+ * messages: Annotation<BaseMessage[]>({
40
+ * reducer: (left: BaseMessage[], right: BaseMessage | BaseMessage[]) => {
41
+ * if (Array.isArray(right)) {
42
+ * return left.concat(right);
43
+ * }
44
+ * return left.concat([right]);
45
+ * },
46
+ * default: () => [],
47
+ * }),
48
+ * });
49
+ *
50
+ * const graphBuilder = new StateGraph(StateAnnotation);
51
+ *
52
+ * // A node in the graph that returns an object with a "messages" key
53
+ * // will update the state by combining the existing value with the returned one.
54
+ * const myNode = (state: typeof StateAnnotation.State) => {
55
+ * return {
56
+ * messages: [new AIMessage("Some new response")],
57
+ * sentiment: "positive",
58
+ * };
59
+ * };
60
+ *
61
+ * const graph = graphBuilder
62
+ * .addNode("myNode", myNode)
63
+ * .addEdge("__start__", "myNode")
64
+ * .addEdge("myNode", "__end__")
65
+ * .compile();
66
+ *
67
+ * await graph.invoke({ messages: [new HumanMessage("how are you?")] });
68
+ *
69
+ * // {
70
+ * // messages: [HumanMessage("how are you?"), AIMessage("Some new response")],
71
+ * // sentiment: "positive",
72
+ * // }
73
+ * ```
74
+ */
11
75
  export class StateGraph extends Graph {
12
76
  constructor(fields) {
13
77
  super();
@@ -52,11 +116,27 @@ export class StateGraph extends Graph {
52
116
  ...Array.from(this.waitingEdges).flatMap(([starts, end]) => starts.map((start) => [start, end])),
53
117
  ]);
54
118
  }
55
- addNode(key, action) {
119
+ addNode(key, action, options) {
56
120
  if (key in this.channels) {
57
121
  throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
58
122
  }
59
- return super.addNode(key, action);
123
+ if (key.includes(CHECKPOINT_NAMESPACE_SEPARATOR)) {
124
+ throw new Error(`"${CHECKPOINT_NAMESPACE_SEPARATOR}" is a reserved character and is not allowed in node names.`);
125
+ }
126
+ this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
127
+ if (key in this.nodes) {
128
+ throw new Error(`Node \`${key}\` already present.`);
129
+ }
130
+ if (key === END || key === START) {
131
+ throw new Error(`Node \`${key}\` is reserved.`);
132
+ }
133
+ const nodeSpec = {
134
+ runnable: _coerceToRunnable(action),
135
+ retryPolicy: options?.retryPolicy,
136
+ metadata: options?.metadata,
137
+ };
138
+ this.nodes[key] = nodeSpec;
139
+ return this;
60
140
  }
61
141
  addEdge(startKey, endKey) {
62
142
  if (typeof startKey === "string") {
@@ -194,7 +274,8 @@ export class CompiledStateGraph extends CompiledGraph {
194
274
  writers: [
195
275
  new ChannelWrite(stateWriteEntries.concat({ channel: key, value: key }), [TAG_HIDDEN]),
196
276
  ],
197
- bound: node,
277
+ bound: node?.runnable,
278
+ retryPolicy: node?.retryPolicy,
198
279
  });
199
280
  }
200
281
  }
@@ -4,6 +4,7 @@ exports.createAgentExecutor = void 0;
4
4
  const tool_executor_js_1 = require("./tool_executor.cjs");
5
5
  const state_js_1 = require("../graph/state.cjs");
6
6
  const index_js_1 = require("../graph/index.cjs");
7
+ /** @ignore */
7
8
  function createAgentExecutor({ agentRunnable, tools, }) {
8
9
  let toolExecutor;
9
10
  if (!Array.isArray(tools)) {
@@ -7,12 +7,14 @@ interface Step {
7
7
  action: AgentAction | AgentFinish;
8
8
  observation: unknown;
9
9
  }
10
+ /** @ignore */
10
11
  export interface AgentExecutorState {
11
12
  agentOutcome?: AgentAction | AgentFinish;
12
13
  steps: Array<Step>;
13
14
  input: string;
14
15
  chatHistory?: BaseMessage[];
15
16
  }
17
+ /** @ignore */
16
18
  export declare function createAgentExecutor({ agentRunnable, tools, }: {
17
19
  agentRunnable: Runnable;
18
20
  tools: Array<Tool> | ToolExecutor;
@@ -1,6 +1,7 @@
1
1
  import { ToolExecutor } from "./tool_executor.js";
2
2
  import { StateGraph } from "../graph/state.js";
3
3
  import { END, START } from "../graph/index.js";
4
+ /** @ignore */
4
5
  export function createAgentExecutor({ agentRunnable, tools, }) {
5
6
  let toolExecutor;
6
7
  if (!Array.isArray(tools)) {
@@ -7,6 +7,7 @@ const runnables_1 = require("@langchain/core/runnables");
7
7
  const tool_executor_js_1 = require("./tool_executor.cjs");
8
8
  const state_js_1 = require("../graph/state.cjs");
9
9
  const index_js_1 = require("../graph/index.cjs");
10
+ /** @ignore */
10
11
  function createFunctionCallingExecutor({ model, tools, }) {
11
12
  let toolExecutor;
12
13
  let toolClasses;
@@ -4,9 +4,11 @@ import { RunnableToolLike } from "@langchain/core/runnables";
4
4
  import { ToolExecutor } from "./tool_executor.js";
5
5
  import { CompiledStateGraph } from "../graph/state.js";
6
6
  import { START } from "../graph/index.js";
7
+ /** @ignore */
7
8
  export type FunctionCallingExecutorState = {
8
9
  messages: Array<BaseMessage>;
9
10
  };
11
+ /** @ignore */
10
12
  export declare function createFunctionCallingExecutor<Model extends object>({ model, tools, }: {
11
13
  model: Model;
12
14
  tools: Array<StructuredToolInterface | RunnableToolLike> | ToolExecutor;
@@ -4,6 +4,7 @@ import { RunnableLambda, } from "@langchain/core/runnables";
4
4
  import { ToolExecutor } from "./tool_executor.js";
5
5
  import { StateGraph, } from "../graph/state.js";
6
6
  import { END, START } from "../graph/index.js";
7
+ /** @ignore */
7
8
  export function createFunctionCallingExecutor({ model, tools, }) {
8
9
  let toolExecutor;
9
10
  let toolClasses;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._prepareNextTasks = exports._applyWrites = exports._localWrite = exports._localRead = exports.shouldInterrupt = exports.executeTasks = exports.increment = void 0;
3
+ exports._prepareNextTasks = exports._applyWrites = exports._localWrite = exports._localRead = exports.shouldInterrupt = exports.increment = void 0;
4
4
  /* eslint-disable no-param-reassign */
5
5
  const runnables_1 = require("@langchain/core/runnables");
6
6
  const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
@@ -13,46 +13,6 @@ const increment = (current) => {
13
13
  return current !== undefined ? current + 1 : 1;
14
14
  };
15
15
  exports.increment = increment;
16
- async function* executeTasks(tasks, stepTimeout, signal
17
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
- ) {
19
- if (stepTimeout && signal) {
20
- if ("any" in AbortSignal) {
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- signal = AbortSignal.any([
23
- signal,
24
- AbortSignal.timeout(stepTimeout),
25
- ]);
26
- }
27
- }
28
- else if (stepTimeout) {
29
- signal = AbortSignal.timeout(stepTimeout);
30
- }
31
- // Abort if signal is aborted
32
- signal?.throwIfAborted();
33
- // Start all tasks
34
- const executingTasks = Object.fromEntries(Object.entries(tasks).map(([taskId, task]) => {
35
- return [taskId, task()];
36
- }));
37
- let listener;
38
- const signalPromise = new Promise((_resolve, reject) => {
39
- listener = () => reject(new Error("Abort"));
40
- signal?.addEventListener("abort", listener);
41
- }).finally(() => signal?.removeEventListener("abort", listener));
42
- while (Object.keys(executingTasks).length > 0) {
43
- const { task, error } = await Promise.race([
44
- ...Object.values(executingTasks),
45
- signalPromise,
46
- ]);
47
- if (error !== undefined) {
48
- // TODO: don't stop others if exception is interrupt
49
- throw error;
50
- }
51
- yield task;
52
- delete executingTasks[task.id];
53
- }
54
- }
55
- exports.executeTasks = executeTasks;
56
16
  function shouldInterrupt(checkpoint, interruptNodes, tasks) {
57
17
  const versionValues = Object.values(checkpoint.channel_versions);
58
18
  const versionType = versionValues.length > 0 ? typeof versionValues[0] : undefined;
@@ -253,6 +213,7 @@ function _prepareNextTasks(checkpoint, processes, channels, config, forExecution
253
213
  },
254
214
  }),
255
215
  id: taskId,
216
+ retry_policy: proc.retryPolicy,
256
217
  });
257
218
  }
258
219
  }
@@ -325,6 +286,7 @@ function _prepareNextTasks(checkpoint, processes, channels, config, forExecution
325
286
  },
326
287
  }),
327
288
  id: taskId,
289
+ retry_policy: proc.retryPolicy,
328
290
  });
329
291
  }
330
292
  }
@@ -16,11 +16,6 @@ export type WritesProtocol<C = string> = {
16
16
  triggers: string[];
17
17
  };
18
18
  export declare const increment: (current?: number) => number;
19
- export declare function executeTasks(tasks: Record<string, () => Promise<{
20
- task: PregelExecutableTask<any, any>;
21
- result: any;
22
- error: Error;
23
- }>>, stepTimeout?: number, signal?: AbortSignal): AsyncGenerator<PregelExecutableTask<any, any>>;
24
19
  export declare function shouldInterrupt<N extends PropertyKey, C extends PropertyKey>(checkpoint: Checkpoint, interruptNodes: All | N[], tasks: PregelExecutableTask<N, C>[]): boolean;
25
20
  export declare function _localRead<Cc extends StrRecord<string, BaseChannel>>(checkpoint: ReadonlyCheckpoint, channels: Cc, task: WritesProtocol<keyof Cc>, select: Array<keyof Cc> | keyof Cc, fresh?: boolean): Record<string, unknown> | unknown;
26
21
  export declare function _localWrite(commit: (writes: [string, any][]) => void, processes: Record<string, PregelNode>, channels: Record<string, BaseChannel>, writes: [string, any][]): void;
@@ -9,45 +9,6 @@ import { _getIdMetadata, getNullChannelVersion } from "./utils.js";
9
9
  export const increment = (current) => {
10
10
  return current !== undefined ? current + 1 : 1;
11
11
  };
12
- export async function* executeTasks(tasks, stepTimeout, signal
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- ) {
15
- if (stepTimeout && signal) {
16
- if ("any" in AbortSignal) {
17
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
- signal = AbortSignal.any([
19
- signal,
20
- AbortSignal.timeout(stepTimeout),
21
- ]);
22
- }
23
- }
24
- else if (stepTimeout) {
25
- signal = AbortSignal.timeout(stepTimeout);
26
- }
27
- // Abort if signal is aborted
28
- signal?.throwIfAborted();
29
- // Start all tasks
30
- const executingTasks = Object.fromEntries(Object.entries(tasks).map(([taskId, task]) => {
31
- return [taskId, task()];
32
- }));
33
- let listener;
34
- const signalPromise = new Promise((_resolve, reject) => {
35
- listener = () => reject(new Error("Abort"));
36
- signal?.addEventListener("abort", listener);
37
- }).finally(() => signal?.removeEventListener("abort", listener));
38
- while (Object.keys(executingTasks).length > 0) {
39
- const { task, error } = await Promise.race([
40
- ...Object.values(executingTasks),
41
- signalPromise,
42
- ]);
43
- if (error !== undefined) {
44
- // TODO: don't stop others if exception is interrupt
45
- throw error;
46
- }
47
- yield task;
48
- delete executingTasks[task.id];
49
- }
50
- }
51
12
  export function shouldInterrupt(checkpoint, interruptNodes, tasks) {
52
13
  const versionValues = Object.values(checkpoint.channel_versions);
53
14
  const versionType = versionValues.length > 0 ? typeof versionValues[0] : undefined;
@@ -244,6 +205,7 @@ export function _prepareNextTasks(checkpoint, processes, channels, config, forEx
244
205
  },
245
206
  }),
246
207
  id: taskId,
208
+ retry_policy: proc.retryPolicy,
247
209
  });
248
210
  }
249
211
  }
@@ -316,6 +278,7 @@ export function _prepareNextTasks(checkpoint, processes, channels, config, forEx
316
278
  },
317
279
  }),
318
280
  id: taskId,
281
+ retry_policy: proc.retryPolicy,
319
282
  });
320
283
  }
321
284
  }
@@ -29,7 +29,7 @@ export declare function mapDebugCheckpoint<N extends PropertyKey, C extends Prop
29
29
  timestamp: string;
30
30
  step: number;
31
31
  payload: {
32
- config: Partial<Record<"tags" | "configurable" | "timeout" | "signal" | "metadata" | "callbacks" | "recursion_limit" | "max_concurrency" | "run_name" | "run_id", unknown>>;
32
+ config: Partial<Record<"configurable" | "timeout" | "signal" | "tags" | "metadata" | "callbacks" | "recursion_limit" | "max_concurrency" | "run_name" | "run_id", unknown>>;
33
33
  values: any;
34
34
  metadata: CheckpointMetadata;
35
35
  next: N[];
@@ -16,6 +16,7 @@ const algo_js_1 = require("./algo.cjs");
16
16
  const utils_js_1 = require("../utils.cjs");
17
17
  const utils_js_2 = require("./utils.cjs");
18
18
  const loop_js_1 = require("./loop.cjs");
19
+ const retry_js_1 = require("./retry.cjs");
19
20
  function isString(value) {
20
21
  return typeof value === "string";
21
22
  }
@@ -159,6 +160,12 @@ class Pregel extends runnables_1.Runnable {
159
160
  writable: true,
160
161
  value: void 0
161
162
  });
163
+ Object.defineProperty(this, "retryPolicy", {
164
+ enumerable: true,
165
+ configurable: true,
166
+ writable: true,
167
+ value: void 0
168
+ });
162
169
  let { streamMode } = fields;
163
170
  if (streamMode != null && !Array.isArray(streamMode)) {
164
171
  streamMode = [streamMode];
@@ -175,6 +182,7 @@ class Pregel extends runnables_1.Runnable {
175
182
  this.stepTimeout = fields.stepTimeout ?? this.stepTimeout;
176
183
  this.debug = fields.debug ?? this.debug;
177
184
  this.checkpointer = fields.checkpointer;
185
+ this.retryPolicy = fields.retryPolicy;
178
186
  if (this.autoValidate) {
179
187
  this.validate();
180
188
  }
@@ -344,12 +352,11 @@ class Pregel extends runnables_1.Runnable {
344
352
  writers.length > 1 ? runnables_1.RunnableSequence.from(writers) : writers[0],
345
353
  writes: [],
346
354
  triggers: [constants_js_1.INTERRUPT],
347
- config: undefined,
348
355
  id: (0, langgraph_checkpoint_1.uuid5)(constants_js_1.INTERRUPT, checkpoint.id),
349
356
  };
350
357
  // execute task
351
358
  await task.proc.invoke(task.input, (0, runnables_1.patchConfig)(config, {
352
- runName: `${this.name}UpdateState`,
359
+ runName: config.runName ?? `${this.getName()}UpdateState`,
353
360
  configurable: {
354
361
  [constants_js_1.CONFIG_KEY_SEND]: (items) => task.writes.push(...items),
355
362
  [constants_js_1.CONFIG_KEY_READ]: algo_js_1._localRead.bind(undefined, checkpoint, channels,
@@ -490,35 +497,15 @@ class Pregel extends runnables_1.Runnable {
490
497
  if (debug) {
491
498
  (0, debug_js_1.printStepTasks)(loop.step, loop.tasks);
492
499
  }
493
- // execute tasks, and wait for one to fail or all to finish.
494
- // each task is independent from all other concurrent tasks
495
- // yield updates/debug output as each task finishes
496
- const tasks = Object.fromEntries(loop.tasks
497
- .filter((task) => task.writes.length === 0)
498
- .map((pregelTask) => {
499
- return [
500
- pregelTask.id,
501
- async () => {
502
- let error;
503
- let result;
504
- try {
505
- result = await pregelTask.proc.invoke(pregelTask.input, pregelTask.config);
506
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
507
- }
508
- catch (e) {
509
- error = e;
510
- error.pregelTaskId = pregelTask.id;
511
- }
512
- return {
513
- task: pregelTask,
514
- result,
515
- error,
516
- };
517
- },
518
- ];
519
- }));
520
500
  try {
521
- for await (const task of (0, algo_js_1.executeTasks)(tasks, this.stepTimeout, config.signal)) {
501
+ // execute tasks, and wait for one to fail or all to finish.
502
+ // each task is independent from all other concurrent tasks
503
+ // yield updates/debug output as each task finishes
504
+ for await (const task of (0, retry_js_1.executeTasksWithRetry)(loop.tasks.filter((task) => task.writes.length === 0), {
505
+ stepTimeout: this.stepTimeout,
506
+ signal: config.signal,
507
+ retryPolicy: this.retryPolicy,
508
+ })) {
522
509
  loop.putWrites(task.id, task.writes);
523
510
  if (streamMode.includes("updates")) {
524
511
  yield* (0, utils_js_1.prefixGenerator)((0, io_js_1.mapOutputUpdates)(outputKeys, [task]), streamMode.length > 1 ? "updates" : undefined);
@@ -6,6 +6,7 @@ import { PregelNode } from "./read.js";
6
6
  import { ChannelWrite } from "./write.js";
7
7
  import { All, PregelInterface, PregelParams, StateSnapshot, StreamMode } from "./types.js";
8
8
  import { StrRecord } from "./algo.js";
9
+ import { RetryPolicy } from "./utils.js";
9
10
  type WriteValue = Runnable | RunnableFunc<unknown, unknown> | unknown;
10
11
  export declare class Channel {
11
12
  static subscribeTo(channels: string, options?: {
@@ -50,6 +51,7 @@ export declare class Pregel<Nn extends StrRecord<string, PregelNode>, Cc extends
50
51
  stepTimeout?: number;
51
52
  debug: boolean;
52
53
  checkpointer?: BaseCheckpointSaver;
54
+ retryPolicy?: RetryPolicy;
53
55
  constructor(fields: PregelParams<Nn, Cc>);
54
56
  validate(): this;
55
57
  get streamChannelsList(): Array<keyof Cc>;