@langchain/langgraph 0.1.9 → 0.1.10-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,10 @@
1
1
  import { Runnable, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
2
2
  import { Graph as RunnableGraph } from "@langchain/core/runnables/graph";
3
- import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
3
+ import { All, BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
4
4
  import { PregelNode } from "../pregel/read.js";
5
5
  import { Pregel } from "../pregel/index.js";
6
6
  import type { PregelParams } from "../pregel/types.js";
7
7
  import { BaseChannel } from "../channels/base.js";
8
- import { All } from "../pregel/types.js";
9
8
  import { Send } from "../constants.js";
10
9
  import { RunnableCallable } from "../utils.js";
11
10
  /** Special reserved node name denoting the start of a graph. */
@@ -82,7 +82,7 @@ class StateGraph extends graph_js_1.Graph {
82
82
  enumerable: true,
83
83
  configurable: true,
84
84
  writable: true,
85
- value: void 0
85
+ value: {}
86
86
  });
87
87
  // TODO: this doesn't dedupe edges as in py, so worth fixing at some point
88
88
  Object.defineProperty(this, "waitingEdges", {
@@ -91,21 +91,50 @@ class StateGraph extends graph_js_1.Graph {
91
91
  writable: true,
92
92
  value: new Set()
93
93
  });
94
- if (isStateDefinition(fields) || isAnnotationRoot(fields)) {
94
+ Object.defineProperty(this, "schema", {
95
+ enumerable: true,
96
+ configurable: true,
97
+ writable: true,
98
+ value: void 0
99
+ });
100
+ Object.defineProperty(this, "input", {
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ value: void 0
105
+ });
106
+ Object.defineProperty(this, "output", {
107
+ enumerable: true,
108
+ configurable: true,
109
+ writable: true,
110
+ value: void 0
111
+ });
112
+ if (isStateGraphArgsWithInputOutputSchemas(fields)) {
113
+ this.schema = fields.input.spec;
114
+ this.input = fields.input.spec;
115
+ this.output = fields.output.spec;
116
+ }
117
+ else if (isStateGraphArgsWithStateSchema(fields)) {
118
+ this.schema = fields.stateSchema.spec;
119
+ this.input = (fields.input?.spec ?? this.schema);
120
+ this.output = (fields.output?.spec ?? this.schema);
121
+ }
122
+ else if (isStateDefinition(fields) || isAnnotationRoot(fields)) {
95
123
  const spec = isAnnotationRoot(fields) ? fields.spec : fields;
96
- this.channels = {};
97
- for (const [key, val] of Object.entries(spec)) {
98
- if (typeof val === "function") {
99
- this.channels[key] = val();
100
- }
101
- else {
102
- this.channels[key] = val;
103
- }
104
- }
124
+ this.schema = spec;
125
+ }
126
+ else if (isStateGraphArgs(fields)) {
127
+ const spec = _getChannels(fields.channels);
128
+ this.schema = spec;
105
129
  }
106
130
  else {
107
- this.channels = _getChannels(fields.channels);
131
+ throw new Error("Invalid StateGraph input.");
108
132
  }
133
+ this.input = this.input ?? this.schema;
134
+ this.output = this.output ?? this.schema;
135
+ this._addSchema(this.schema);
136
+ this._addSchema(this.input);
137
+ this._addSchema(this.output);
109
138
  for (const c of Object.values(this.channels)) {
110
139
  if (c.lc_graph_name === "BinaryOperatorAggregate") {
111
140
  this.supportMultipleEdges = true;
@@ -119,6 +148,27 @@ class StateGraph extends graph_js_1.Graph {
119
148
  ...Array.from(this.waitingEdges).flatMap(([starts, end]) => starts.map((start) => [start, end])),
120
149
  ]);
121
150
  }
151
+ _addSchema(stateDefinition) {
152
+ for (const [key, val] of Object.entries(stateDefinition)) {
153
+ let channel;
154
+ if (typeof val === "function") {
155
+ channel = val();
156
+ }
157
+ else {
158
+ channel = val;
159
+ }
160
+ if (this.channels[key] !== undefined) {
161
+ if (this.channels[key].lc_graph_name !== channel.lc_graph_name) {
162
+ if (channel.lc_graph_name !== "LastValue") {
163
+ throw new Error(`Channel "${key}" already exists with a different type.`);
164
+ }
165
+ }
166
+ }
167
+ else {
168
+ this.channels[key] = channel;
169
+ }
170
+ }
171
+ }
122
172
  addNode(key, action, options) {
123
173
  if (key in this.channels) {
124
174
  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.`);
@@ -173,10 +223,10 @@ class StateGraph extends graph_js_1.Graph {
173
223
  ...(Array.isArray(interruptAfter) ? interruptAfter : []),
174
224
  ]);
175
225
  // prepare output channels
176
- const stateKeys = Object.keys(this.channels);
177
- const outputChannels = stateKeys.length === 1 && stateKeys[0] === ROOT
178
- ? stateKeys[0]
179
- : stateKeys;
226
+ const stateKeys = Object.keys(this.schema);
227
+ const outputChannels = stateKeys.length === 1 && stateKeys[0] === ROOT ? ROOT : stateKeys;
228
+ const outputKeys = Object.keys(this.output);
229
+ const streamChannels = outputKeys.length === 1 && outputKeys[0] === ROOT ? ROOT : outputKeys;
180
230
  // create empty compiled graph
181
231
  const compiled = new CompiledStateGraph({
182
232
  builder: this,
@@ -191,7 +241,7 @@ class StateGraph extends graph_js_1.Graph {
191
241
  },
192
242
  inputChannels: graph_js_1.START,
193
243
  outputChannels,
194
- streamChannels: outputChannels,
244
+ streamChannels,
195
245
  streamMode: "updates",
196
246
  });
197
247
  // attach nodes, edges and branches
@@ -229,7 +279,7 @@ function _getChannels(schema) {
229
279
  }
230
280
  class CompiledStateGraph extends graph_js_1.CompiledGraph {
231
281
  attachNode(key, node) {
232
- const stateKeys = Object.keys(this.builder.channels);
282
+ const stateKeys = Object.keys(this.builder.input);
233
283
  function getStateKey(key, input) {
234
284
  if (!input) {
235
285
  return write_js_1.SKIP_WRITE;
@@ -367,3 +417,20 @@ function isAnnotationRoot(obj) {
367
417
  "lc_graph_name" in obj &&
368
418
  obj.lc_graph_name === "AnnotationRoot");
369
419
  }
420
+ function isStateGraphArgs(obj) {
421
+ return (typeof obj === "object" &&
422
+ obj !== null &&
423
+ obj.channels !== undefined);
424
+ }
425
+ function isStateGraphArgsWithStateSchema(obj) {
426
+ return (typeof obj === "object" &&
427
+ obj !== null &&
428
+ obj.stateSchema !== undefined);
429
+ }
430
+ function isStateGraphArgsWithInputOutputSchemas(obj) {
431
+ return (typeof obj === "object" &&
432
+ obj !== null &&
433
+ obj.stateSchema === undefined &&
434
+ obj.input !== undefined &&
435
+ obj.output !== undefined);
436
+ }
@@ -1,8 +1,7 @@
1
1
  import { RunnableLike } from "@langchain/core/runnables";
2
- import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
2
+ import { All, BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
3
3
  import { BaseChannel } from "../channels/base.js";
4
4
  import { END, CompiledGraph, Graph, START, Branch, AddNodeOptions, NodeSpec } from "./graph.js";
5
- import { All } from "../pregel/types.js";
6
5
  import { AnnotationRoot, SingleReducer, StateDefinition, StateType, UpdateType } from "./annotation.js";
7
6
  import type { RetryPolicy } from "../pregel/utils.js";
8
7
  export type ChannelReducers<Channels extends object> = {
@@ -22,6 +21,15 @@ export type StateGraphNodeSpec<RunInput, RunOutput> = NodeSpec<RunInput, RunOutp
22
21
  export type StateGraphAddNodeOptions = {
23
22
  retryPolicy?: RetryPolicy;
24
23
  } & AddNodeOptions;
24
+ export type StateGraphArgsWithStateSchema<SD extends StateDefinition, I extends StateDefinition, O extends StateDefinition> = {
25
+ stateSchema: AnnotationRoot<SD>;
26
+ input?: AnnotationRoot<I>;
27
+ output?: AnnotationRoot<O>;
28
+ };
29
+ export type StateGraphArgsWithInputOutputSchemas<SD extends StateDefinition, O extends StateDefinition = SD> = {
30
+ input: AnnotationRoot<SD>;
31
+ output: AnnotationRoot<O>;
32
+ };
25
33
  /**
26
34
  * A graph whose nodes communicate by reading and writing to a shared state.
27
35
  * Each node takes a defined `State` as input and returns a `Partial<State>`.
@@ -84,21 +92,25 @@ export type StateGraphAddNodeOptions = {
84
92
  * // }
85
93
  * ```
86
94
  */
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>> {
95
+ 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, I extends StateDefinition = SD extends StateDefinition ? SD : StateDefinition, O extends StateDefinition = SD extends StateDefinition ? SD : StateDefinition> extends Graph<N, S, U, StateGraphNodeSpec<S, U>> {
88
96
  channels: Record<string, BaseChannel>;
89
97
  waitingEdges: Set<[N[], N]>;
90
- constructor(fields: SD extends StateDefinition ? SD | AnnotationRoot<SD> | StateGraphArgs<S> : StateGraphArgs<S>);
98
+ schema: StateDefinition;
99
+ input: I;
100
+ output: O;
101
+ constructor(fields: SD extends StateDefinition ? SD | AnnotationRoot<SD> | StateGraphArgs<S> | StateGraphArgsWithStateSchema<SD, I, O> | StateGraphArgsWithInputOutputSchemas<SD, O> : StateGraphArgs<S>);
91
102
  get allEdges(): Set<[string, string]>;
92
- addNode<K extends string, NodeInput = S>(key: K, action: RunnableLike<NodeInput, U>, options?: StateGraphAddNodeOptions): StateGraph<SD, S, U, N | K>;
103
+ _addSchema(stateDefinition: StateDefinition): void;
104
+ addNode<K extends string, NodeInput = S>(key: K, action: RunnableLike<NodeInput, U>, options?: StateGraphAddNodeOptions): StateGraph<SD, S, U, N | K, I, O>;
93
105
  addEdge(startKey: typeof START | N | N[], endKey: N | typeof END): this;
94
106
  compile({ checkpointer, interruptBefore, interruptAfter, }?: {
95
107
  checkpointer?: BaseCheckpointSaver;
96
108
  interruptBefore?: N[] | All;
97
109
  interruptAfter?: N[] | All;
98
- }): CompiledStateGraph<S, U, N>;
110
+ }): CompiledStateGraph<S, U, N, I, O>;
99
111
  }
100
- export declare class CompiledStateGraph<S, U, N extends string = typeof START> extends CompiledGraph<N, S, U> {
101
- builder: StateGraph<unknown, S, U, N>;
112
+ export declare class CompiledStateGraph<S, U, N extends string = typeof START, I extends StateDefinition = StateDefinition, O extends StateDefinition = StateDefinition> extends CompiledGraph<N, S, U> {
113
+ builder: StateGraph<unknown, S, U, N, I, O>;
102
114
  attachNode(key: typeof START, node?: never): void;
103
115
  attachNode(key: N, node: StateGraphNodeSpec<S, U>): void;
104
116
  attachEdge(start: N | N[] | "__start__", end: N | "__end__"): void;
@@ -79,7 +79,7 @@ export class StateGraph extends Graph {
79
79
  enumerable: true,
80
80
  configurable: true,
81
81
  writable: true,
82
- value: void 0
82
+ value: {}
83
83
  });
84
84
  // TODO: this doesn't dedupe edges as in py, so worth fixing at some point
85
85
  Object.defineProperty(this, "waitingEdges", {
@@ -88,21 +88,50 @@ export class StateGraph extends Graph {
88
88
  writable: true,
89
89
  value: new Set()
90
90
  });
91
- if (isStateDefinition(fields) || isAnnotationRoot(fields)) {
91
+ Object.defineProperty(this, "schema", {
92
+ enumerable: true,
93
+ configurable: true,
94
+ writable: true,
95
+ value: void 0
96
+ });
97
+ Object.defineProperty(this, "input", {
98
+ enumerable: true,
99
+ configurable: true,
100
+ writable: true,
101
+ value: void 0
102
+ });
103
+ Object.defineProperty(this, "output", {
104
+ enumerable: true,
105
+ configurable: true,
106
+ writable: true,
107
+ value: void 0
108
+ });
109
+ if (isStateGraphArgsWithInputOutputSchemas(fields)) {
110
+ this.schema = fields.input.spec;
111
+ this.input = fields.input.spec;
112
+ this.output = fields.output.spec;
113
+ }
114
+ else if (isStateGraphArgsWithStateSchema(fields)) {
115
+ this.schema = fields.stateSchema.spec;
116
+ this.input = (fields.input?.spec ?? this.schema);
117
+ this.output = (fields.output?.spec ?? this.schema);
118
+ }
119
+ else if (isStateDefinition(fields) || isAnnotationRoot(fields)) {
92
120
  const spec = isAnnotationRoot(fields) ? fields.spec : fields;
93
- this.channels = {};
94
- for (const [key, val] of Object.entries(spec)) {
95
- if (typeof val === "function") {
96
- this.channels[key] = val();
97
- }
98
- else {
99
- this.channels[key] = val;
100
- }
101
- }
121
+ this.schema = spec;
122
+ }
123
+ else if (isStateGraphArgs(fields)) {
124
+ const spec = _getChannels(fields.channels);
125
+ this.schema = spec;
102
126
  }
103
127
  else {
104
- this.channels = _getChannels(fields.channels);
128
+ throw new Error("Invalid StateGraph input.");
105
129
  }
130
+ this.input = this.input ?? this.schema;
131
+ this.output = this.output ?? this.schema;
132
+ this._addSchema(this.schema);
133
+ this._addSchema(this.input);
134
+ this._addSchema(this.output);
106
135
  for (const c of Object.values(this.channels)) {
107
136
  if (c.lc_graph_name === "BinaryOperatorAggregate") {
108
137
  this.supportMultipleEdges = true;
@@ -116,6 +145,27 @@ export class StateGraph extends Graph {
116
145
  ...Array.from(this.waitingEdges).flatMap(([starts, end]) => starts.map((start) => [start, end])),
117
146
  ]);
118
147
  }
148
+ _addSchema(stateDefinition) {
149
+ for (const [key, val] of Object.entries(stateDefinition)) {
150
+ let channel;
151
+ if (typeof val === "function") {
152
+ channel = val();
153
+ }
154
+ else {
155
+ channel = val;
156
+ }
157
+ if (this.channels[key] !== undefined) {
158
+ if (this.channels[key].lc_graph_name !== channel.lc_graph_name) {
159
+ if (channel.lc_graph_name !== "LastValue") {
160
+ throw new Error(`Channel "${key}" already exists with a different type.`);
161
+ }
162
+ }
163
+ }
164
+ else {
165
+ this.channels[key] = channel;
166
+ }
167
+ }
168
+ }
119
169
  addNode(key, action, options) {
120
170
  if (key in this.channels) {
121
171
  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.`);
@@ -170,10 +220,10 @@ export class StateGraph extends Graph {
170
220
  ...(Array.isArray(interruptAfter) ? interruptAfter : []),
171
221
  ]);
172
222
  // prepare output channels
173
- const stateKeys = Object.keys(this.channels);
174
- const outputChannels = stateKeys.length === 1 && stateKeys[0] === ROOT
175
- ? stateKeys[0]
176
- : stateKeys;
223
+ const stateKeys = Object.keys(this.schema);
224
+ const outputChannels = stateKeys.length === 1 && stateKeys[0] === ROOT ? ROOT : stateKeys;
225
+ const outputKeys = Object.keys(this.output);
226
+ const streamChannels = outputKeys.length === 1 && outputKeys[0] === ROOT ? ROOT : outputKeys;
177
227
  // create empty compiled graph
178
228
  const compiled = new CompiledStateGraph({
179
229
  builder: this,
@@ -188,7 +238,7 @@ export class StateGraph extends Graph {
188
238
  },
189
239
  inputChannels: START,
190
240
  outputChannels,
191
- streamChannels: outputChannels,
241
+ streamChannels,
192
242
  streamMode: "updates",
193
243
  });
194
244
  // attach nodes, edges and branches
@@ -225,7 +275,7 @@ function _getChannels(schema) {
225
275
  }
226
276
  export class CompiledStateGraph extends CompiledGraph {
227
277
  attachNode(key, node) {
228
- const stateKeys = Object.keys(this.builder.channels);
278
+ const stateKeys = Object.keys(this.builder.input);
229
279
  function getStateKey(key, input) {
230
280
  if (!input) {
231
281
  return SKIP_WRITE;
@@ -362,3 +412,20 @@ function isAnnotationRoot(obj) {
362
412
  "lc_graph_name" in obj &&
363
413
  obj.lc_graph_name === "AnnotationRoot");
364
414
  }
415
+ function isStateGraphArgs(obj) {
416
+ return (typeof obj === "object" &&
417
+ obj !== null &&
418
+ obj.channels !== undefined);
419
+ }
420
+ function isStateGraphArgsWithStateSchema(obj) {
421
+ return (typeof obj === "object" &&
422
+ obj !== null &&
423
+ obj.stateSchema !== undefined);
424
+ }
425
+ function isStateGraphArgsWithInputOutputSchemas(obj) {
426
+ return (typeof obj === "object" &&
427
+ obj !== null &&
428
+ obj.stateSchema === undefined &&
429
+ obj.input !== undefined &&
430
+ obj.output !== undefined);
431
+ }
@@ -18,5 +18,5 @@ export interface AgentExecutorState {
18
18
  export declare function createAgentExecutor({ agentRunnable, tools, }: {
19
19
  agentRunnable: Runnable;
20
20
  tools: Array<Tool> | ToolExecutor;
21
- }): import("../graph/state.js").CompiledStateGraph<AgentExecutorState, Partial<AgentExecutorState>, "__start__" | "agent" | "action">;
21
+ }): import("../graph/state.js").CompiledStateGraph<AgentExecutorState, Partial<AgentExecutorState>, "__start__" | "agent" | "action", import("../graph/annotation.js").StateDefinition, import("../graph/annotation.js").StateDefinition>;
22
22
  export {};
@@ -2,11 +2,10 @@ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
2
2
  import { BaseMessage, SystemMessage } from "@langchain/core/messages";
3
3
  import { Runnable, RunnableToolLike } from "@langchain/core/runnables";
4
4
  import { StructuredToolInterface } from "@langchain/core/tools";
5
- import { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
5
+ import { All, BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
6
6
  import { START } from "../graph/index.js";
7
7
  import { MessagesAnnotation } from "../graph/messages_annotation.js";
8
8
  import { CompiledStateGraph } from "../graph/state.js";
9
- import { All } from "../pregel/types.js";
10
9
  import { ToolNode } from "./tool_node.js";
11
10
  export interface AgentState {
12
11
  messages: BaseMessage[];
@@ -1,9 +1,9 @@
1
1
  import { RunnableConfig } from "@langchain/core/runnables";
2
2
  import { CallbackManagerForChainRun } from "@langchain/core/callbacks/manager";
3
- import { BaseCheckpointSaver, Checkpoint, ReadonlyCheckpoint, type PendingWrite } from "@langchain/langgraph-checkpoint";
3
+ import { All, BaseCheckpointSaver, Checkpoint, ReadonlyCheckpoint, type PendingWrite } from "@langchain/langgraph-checkpoint";
4
4
  import { BaseChannel } from "../channels/base.js";
5
5
  import { PregelNode } from "./read.js";
6
- import { All, PregelExecutableTask, PregelTaskDescription } from "./types.js";
6
+ import { PregelExecutableTask, PregelTaskDescription } from "./types.js";
7
7
  /**
8
8
  * Construct a type with a set of properties K of type T
9
9
  */
@@ -464,13 +464,15 @@ class Pregel extends runnables_1.Runnable {
464
464
  input,
465
465
  config,
466
466
  checkpointer,
467
- graph: this,
467
+ nodes: this.nodes,
468
+ channelSpecs: this.channels,
468
469
  onBackgroundError,
469
470
  outputKeys,
470
471
  streamKeys: this.streamChannelsAsIs,
471
472
  });
472
473
  while (backgroundError === undefined &&
473
474
  (await loop.tick({
475
+ inputKeys: this.inputChannels,
474
476
  interruptAfter,
475
477
  interruptBefore,
476
478
  manager: runManager,
@@ -1,10 +1,10 @@
1
1
  import { Runnable, RunnableConfig, RunnableFunc } from "@langchain/core/runnables";
2
2
  import { IterableReadableStream } from "@langchain/core/utils/stream";
3
- import { BaseCheckpointSaver, CheckpointListOptions } from "@langchain/langgraph-checkpoint";
3
+ import { All, BaseCheckpointSaver, CheckpointListOptions } from "@langchain/langgraph-checkpoint";
4
4
  import { BaseChannel } from "../channels/base.js";
5
5
  import { PregelNode } from "./read.js";
6
6
  import { ChannelWrite } from "./write.js";
7
- import { All, PregelInterface, PregelParams, StateSnapshot, StreamMode } from "./types.js";
7
+ import { PregelInterface, PregelParams, StateSnapshot, StreamMode } from "./types.js";
8
8
  import { StrRecord } from "./algo.js";
9
9
  import { RetryPolicy } from "./utils.js";
10
10
  type WriteValue = Runnable | RunnableFunc<unknown, unknown> | unknown;
@@ -460,13 +460,15 @@ export class Pregel extends Runnable {
460
460
  input,
461
461
  config,
462
462
  checkpointer,
463
- graph: this,
463
+ nodes: this.nodes,
464
+ channelSpecs: this.channels,
464
465
  onBackgroundError,
465
466
  outputKeys,
466
467
  streamKeys: this.streamChannelsAsIs,
467
468
  });
468
469
  while (backgroundError === undefined &&
469
470
  (await loop.tick({
471
+ inputKeys: this.inputChannels,
470
472
  interruptAfter,
471
473
  interruptBefore,
472
474
  manager: runManager,
@@ -47,14 +47,6 @@ class PregelLoop {
47
47
  writable: true,
48
48
  value: void 0
49
49
  });
50
- // TODO: Fix typing
51
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
- Object.defineProperty(this, "graph", {
53
- enumerable: true,
54
- configurable: true,
55
- writable: true,
56
- value: void 0
57
- });
58
50
  Object.defineProperty(this, "channels", {
59
51
  enumerable: true,
60
52
  configurable: true,
@@ -103,6 +95,24 @@ class PregelLoop {
103
95
  writable: true,
104
96
  value: void 0
105
97
  });
98
+ Object.defineProperty(this, "outputKeys", {
99
+ enumerable: true,
100
+ configurable: true,
101
+ writable: true,
102
+ value: void 0
103
+ });
104
+ Object.defineProperty(this, "streamKeys", {
105
+ enumerable: true,
106
+ configurable: true,
107
+ writable: true,
108
+ value: void 0
109
+ });
110
+ Object.defineProperty(this, "nodes", {
111
+ enumerable: true,
112
+ configurable: true,
113
+ writable: true,
114
+ value: void 0
115
+ });
106
116
  Object.defineProperty(this, "status", {
107
117
  enumerable: true,
108
118
  configurable: true,
@@ -135,18 +145,6 @@ class PregelLoop {
135
145
  writable: true,
136
146
  value: Promise.resolve()
137
147
  });
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
- });
150
148
  Object.defineProperty(this, "onBackgroundError", {
151
149
  enumerable: true,
152
150
  configurable: true,
@@ -164,7 +162,6 @@ class PregelLoop {
164
162
  else {
165
163
  this.checkpointerGetNextVersion = algo_js_1.increment;
166
164
  }
167
- this.graph = params.graph;
168
165
  this.checkpoint = params.checkpoint;
169
166
  this.checkpointConfig = params.checkpointConfig;
170
167
  this.checkpointMetadata = params.checkpointMetadata;
@@ -176,6 +173,7 @@ class PregelLoop {
176
173
  this.isNested = constants_js_1.CONFIG_KEY_READ in (this.config.configurable ?? {});
177
174
  this.outputKeys = params.outputKeys;
178
175
  this.streamKeys = params.streamKeys;
176
+ this.nodes = params.nodes;
179
177
  this.onBackgroundError = params.onBackgroundError;
180
178
  }
181
179
  static async initialize(params) {
@@ -200,7 +198,7 @@ class PregelLoop {
200
198
  const checkpoint = (0, langgraph_checkpoint_1.copyCheckpoint)(saved.checkpoint);
201
199
  const checkpointMetadata = { ...saved.metadata };
202
200
  const checkpointPendingWrites = saved.pendingWrites ?? [];
203
- const channels = (0, base_js_1.emptyChannels)(params.graph.channels, checkpoint);
201
+ const channels = (0, base_js_1.emptyChannels)(params.channelSpecs, checkpoint);
204
202
  const step = (checkpointMetadata.step ?? 0) + 1;
205
203
  const stop = step + (params.config.recursionLimit ?? DEFAULT_LOOP_LIMIT) + 1;
206
204
  const checkpointPreviousVersions = { ...checkpoint.channel_versions };
@@ -208,7 +206,6 @@ class PregelLoop {
208
206
  input: params.input,
209
207
  config: params.config,
210
208
  checkpointer: params.checkpointer,
211
- graph: params.graph,
212
209
  checkpoint,
213
210
  checkpointMetadata,
214
211
  checkpointConfig,
@@ -217,8 +214,9 @@ class PregelLoop {
217
214
  stop,
218
215
  checkpointPreviousVersions,
219
216
  checkpointPendingWrites,
220
- outputKeys: params.outputKeys,
221
- streamKeys: params.streamKeys,
217
+ outputKeys: params.outputKeys ?? [],
218
+ streamKeys: params.streamKeys ?? [],
219
+ nodes: params.nodes,
222
220
  onBackgroundError: params.onBackgroundError,
223
221
  });
224
222
  }
@@ -267,12 +265,12 @@ class PregelLoop {
267
265
  * @param params
268
266
  */
269
267
  async tick(params) {
270
- const { interruptAfter = [], interruptBefore = [], manager } = params;
268
+ const { inputKeys = [], interruptAfter = [], interruptBefore = [], manager, } = params;
271
269
  if (this.status !== "pending") {
272
270
  throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
273
271
  }
274
272
  if (![INPUT_DONE, INPUT_RESUMING].includes(this.input)) {
275
- await this._first();
273
+ await this._first(inputKeys);
276
274
  }
277
275
  else if (this.tasks.every((task) => task.writes.length > 0)) {
278
276
  const writes = this.tasks.flatMap((t) => t.writes);
@@ -283,10 +281,9 @@ class PregelLoop {
283
281
  this.stream.push(...valuesOutput);
284
282
  // clear pending writes
285
283
  this.checkpointPendingWrites = [];
286
- const metadataWrites = (0, io_js_1.mapOutputUpdates)(this.outputKeys, this.tasks).next().value;
287
284
  await this._putCheckpoint({
288
285
  source: "loop",
289
- writes: metadataWrites ?? null,
286
+ writes: (0, io_js_1.mapOutputUpdates)(this.outputKeys, this.tasks).next().value ?? null,
290
287
  });
291
288
  // after execution, check if we should interrupt
292
289
  if ((0, algo_js_1.shouldInterrupt)(this.checkpoint, interruptAfter, this.tasks)) {
@@ -306,7 +303,7 @@ class PregelLoop {
306
303
  this.status = "out_of_steps";
307
304
  return false;
308
305
  }
309
- const nextTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.graph.nodes, this.channels, this.config, true, {
306
+ const nextTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.nodes, this.channels, this.config, true, {
310
307
  step: this.step,
311
308
  checkpointer: this.checkpointer,
312
309
  isResuming: this.input === INPUT_RESUMING,
@@ -316,7 +313,7 @@ class PregelLoop {
316
313
  // Produce debug output
317
314
  if (this.checkpointer) {
318
315
  this.stream.push(...(await (0, utils_js_1.gatherIterator)((0, utils_js_1.prefixGenerator)((0, debug_js_1.mapDebugCheckpoint)(this.step - 1, // printing checkpoint for previous step
319
- this.checkpointConfig, this.channels, this.graph.streamChannelsAsIs, this.checkpointMetadata, this.tasks, this.checkpointPendingWrites), "debug"))));
316
+ this.checkpointConfig, this.channels, this.streamKeys, this.checkpointMetadata, this.tasks, this.checkpointPendingWrites), "debug"))));
320
317
  }
321
318
  if (this.tasks.length === 0) {
322
319
  this.status = "done";
@@ -337,6 +334,7 @@ class PregelLoop {
337
334
  // if all tasks have finished, re-tick
338
335
  if (this.tasks.every((task) => task.writes.length > 0)) {
339
336
  return this.tick({
337
+ inputKeys,
340
338
  interruptAfter,
341
339
  interruptBefore,
342
340
  manager,
@@ -362,7 +360,7 @@ class PregelLoop {
362
360
  * - finding a previous checkpoint
363
361
  * - receiving None input (outer graph) or RESUMING flag (subgraph)
364
362
  */
365
- async _first() {
363
+ async _first(inputKeys) {
366
364
  const isResuming = (Object.keys(this.checkpoint.channel_versions).length !== 0 &&
367
365
  this.config.configurable?.[constants_js_1.CONFIG_KEY_RESUMING] !== undefined) ||
368
366
  this.input === null;
@@ -379,11 +377,11 @@ class PregelLoop {
379
377
  // map inputs to channel updates
380
378
  }
381
379
  else {
382
- const inputWrites = await (0, utils_js_1.gatherIterator)((0, io_js_1.mapInput)(this.graph.inputChannels, this.input));
380
+ const inputWrites = await (0, utils_js_1.gatherIterator)((0, io_js_1.mapInput)(inputKeys, this.input));
383
381
  if (inputWrites.length === 0) {
384
- throw new errors_js_1.EmptyInputError(`Received no input writes for ${JSON.stringify(this.graph.inputChannels, null, 2)}`);
382
+ throw new errors_js_1.EmptyInputError(`Received no input writes for ${JSON.stringify(inputKeys, null, 2)}`);
385
383
  }
386
- const discardTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.graph.nodes, this.channels, this.config, true, { step: this.step });
384
+ const discardTasks = (0, algo_js_1._prepareNextTasks)(this.checkpoint, this.nodes, this.channels, this.config, true, { step: this.step });
387
385
  (0, algo_js_1._applyWrites)(this.checkpoint, this.channels, discardTasks.concat([
388
386
  {
389
387
  name: constants_js_1.INPUT,
@@ -3,21 +3,22 @@ import type { RunnableConfig } from "@langchain/core/runnables";
3
3
  import type { CallbackManagerForChainRun } from "@langchain/core/callbacks/manager";
4
4
  import { BaseCheckpointSaver, Checkpoint, PendingWrite, CheckpointPendingWrite, CheckpointMetadata, All } from "@langchain/langgraph-checkpoint";
5
5
  import { BaseChannel } from "../channels/base.js";
6
- import { PregelExecutableTask, PregelInterface, StreamMode } from "./types.js";
6
+ import { PregelExecutableTask, StreamMode } from "./types.js";
7
+ import { PregelNode } from "./read.js";
7
8
  export type PregelLoopInitializeParams = {
8
9
  input?: any;
9
10
  config: RunnableConfig;
10
11
  checkpointer?: BaseCheckpointSaver;
11
- graph: PregelInterface<any, any>;
12
+ onBackgroundError: (e: Error) => void;
12
13
  outputKeys: string | string[];
13
14
  streamKeys: string | string[];
14
- onBackgroundError: (e: Error) => void;
15
+ nodes: Record<string, PregelNode>;
16
+ channelSpecs: Record<string, BaseChannel>;
15
17
  };
16
18
  type PregelLoopParams = {
17
19
  input?: any;
18
20
  config: RunnableConfig;
19
21
  checkpointer?: BaseCheckpointSaver;
20
- graph: PregelInterface<any, any>;
21
22
  checkpoint: Checkpoint;
22
23
  checkpointMetadata: CheckpointMetadata;
23
24
  checkpointPreviousVersions: Record<string, string | number>;
@@ -29,13 +30,13 @@ type PregelLoopParams = {
29
30
  outputKeys: string | string[];
30
31
  streamKeys: string | string[];
31
32
  onBackgroundError: (e: Error) => void;
33
+ nodes: Record<string, PregelNode>;
32
34
  };
33
35
  export declare class PregelLoop {
34
36
  protected input?: any;
35
37
  config: RunnableConfig;
36
38
  protected checkpointer?: BaseCheckpointSaver;
37
39
  protected checkpointerGetNextVersion: (current: number | undefined, channel: BaseChannel) => number;
38
- protected graph: PregelInterface<any, any>;
39
40
  channels: Record<string, BaseChannel>;
40
41
  protected checkpoint: Checkpoint;
41
42
  protected checkpointConfig: RunnableConfig;
@@ -44,13 +45,14 @@ export declare class PregelLoop {
44
45
  protected checkpointPreviousVersions: Record<string, string | number>;
45
46
  step: number;
46
47
  protected stop: number;
48
+ protected outputKeys: string | string[];
49
+ protected streamKeys: string | string[];
50
+ protected nodes: Record<string, PregelNode>;
47
51
  status: "pending" | "done" | "interrupt_before" | "interrupt_after" | "out_of_steps";
48
52
  tasks: PregelExecutableTask<any, any>[];
49
53
  stream: Deque<[StreamMode, any]>;
50
54
  protected isNested: boolean;
51
55
  protected _putCheckpointPromise: Promise<unknown>;
52
- outputKeys: string | string[];
53
- streamKeys: string | string[];
54
56
  onBackgroundError: (e: Error) => void;
55
57
  get backgroundTasksPromise(): Promise<unknown>;
56
58
  constructor(params: PregelLoopParams);
@@ -73,6 +75,7 @@ export declare class PregelLoop {
73
75
  * @param params
74
76
  */
75
77
  tick(params: {
78
+ inputKeys?: string | string[];
76
79
  interruptAfter: string[] | All;
77
80
  interruptBefore: string[] | All;
78
81
  manager?: CallbackManagerForChainRun;
@@ -82,7 +85,7 @@ export declare class PregelLoop {
82
85
  * - finding a previous checkpoint
83
86
  * - receiving None input (outer graph) or RESUMING flag (subgraph)
84
87
  */
85
- protected _first(): Promise<void>;
88
+ protected _first(inputKeys: string | string[]): Promise<void>;
86
89
  protected _putCheckpoint(inputMetadata: Omit<CheckpointMetadata, "step">): Promise<void>;
87
90
  }
88
91
  export {};
@@ -41,14 +41,6 @@ export class PregelLoop {
41
41
  writable: true,
42
42
  value: void 0
43
43
  });
44
- // TODO: Fix typing
45
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
- Object.defineProperty(this, "graph", {
47
- enumerable: true,
48
- configurable: true,
49
- writable: true,
50
- value: void 0
51
- });
52
44
  Object.defineProperty(this, "channels", {
53
45
  enumerable: true,
54
46
  configurable: true,
@@ -97,6 +89,24 @@ export class PregelLoop {
97
89
  writable: true,
98
90
  value: void 0
99
91
  });
92
+ Object.defineProperty(this, "outputKeys", {
93
+ enumerable: true,
94
+ configurable: true,
95
+ writable: true,
96
+ value: void 0
97
+ });
98
+ Object.defineProperty(this, "streamKeys", {
99
+ enumerable: true,
100
+ configurable: true,
101
+ writable: true,
102
+ value: void 0
103
+ });
104
+ Object.defineProperty(this, "nodes", {
105
+ enumerable: true,
106
+ configurable: true,
107
+ writable: true,
108
+ value: void 0
109
+ });
100
110
  Object.defineProperty(this, "status", {
101
111
  enumerable: true,
102
112
  configurable: true,
@@ -129,18 +139,6 @@ export class PregelLoop {
129
139
  writable: true,
130
140
  value: Promise.resolve()
131
141
  });
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
- });
144
142
  Object.defineProperty(this, "onBackgroundError", {
145
143
  enumerable: true,
146
144
  configurable: true,
@@ -158,7 +156,6 @@ export class PregelLoop {
158
156
  else {
159
157
  this.checkpointerGetNextVersion = increment;
160
158
  }
161
- this.graph = params.graph;
162
159
  this.checkpoint = params.checkpoint;
163
160
  this.checkpointConfig = params.checkpointConfig;
164
161
  this.checkpointMetadata = params.checkpointMetadata;
@@ -170,6 +167,7 @@ export class PregelLoop {
170
167
  this.isNested = CONFIG_KEY_READ in (this.config.configurable ?? {});
171
168
  this.outputKeys = params.outputKeys;
172
169
  this.streamKeys = params.streamKeys;
170
+ this.nodes = params.nodes;
173
171
  this.onBackgroundError = params.onBackgroundError;
174
172
  }
175
173
  static async initialize(params) {
@@ -194,7 +192,7 @@ export class PregelLoop {
194
192
  const checkpoint = copyCheckpoint(saved.checkpoint);
195
193
  const checkpointMetadata = { ...saved.metadata };
196
194
  const checkpointPendingWrites = saved.pendingWrites ?? [];
197
- const channels = emptyChannels(params.graph.channels, checkpoint);
195
+ const channels = emptyChannels(params.channelSpecs, checkpoint);
198
196
  const step = (checkpointMetadata.step ?? 0) + 1;
199
197
  const stop = step + (params.config.recursionLimit ?? DEFAULT_LOOP_LIMIT) + 1;
200
198
  const checkpointPreviousVersions = { ...checkpoint.channel_versions };
@@ -202,7 +200,6 @@ export class PregelLoop {
202
200
  input: params.input,
203
201
  config: params.config,
204
202
  checkpointer: params.checkpointer,
205
- graph: params.graph,
206
203
  checkpoint,
207
204
  checkpointMetadata,
208
205
  checkpointConfig,
@@ -211,8 +208,9 @@ export class PregelLoop {
211
208
  stop,
212
209
  checkpointPreviousVersions,
213
210
  checkpointPendingWrites,
214
- outputKeys: params.outputKeys,
215
- streamKeys: params.streamKeys,
211
+ outputKeys: params.outputKeys ?? [],
212
+ streamKeys: params.streamKeys ?? [],
213
+ nodes: params.nodes,
216
214
  onBackgroundError: params.onBackgroundError,
217
215
  });
218
216
  }
@@ -261,12 +259,12 @@ export class PregelLoop {
261
259
  * @param params
262
260
  */
263
261
  async tick(params) {
264
- const { interruptAfter = [], interruptBefore = [], manager } = params;
262
+ const { inputKeys = [], interruptAfter = [], interruptBefore = [], manager, } = params;
265
263
  if (this.status !== "pending") {
266
264
  throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
267
265
  }
268
266
  if (![INPUT_DONE, INPUT_RESUMING].includes(this.input)) {
269
- await this._first();
267
+ await this._first(inputKeys);
270
268
  }
271
269
  else if (this.tasks.every((task) => task.writes.length > 0)) {
272
270
  const writes = this.tasks.flatMap((t) => t.writes);
@@ -277,10 +275,9 @@ export class PregelLoop {
277
275
  this.stream.push(...valuesOutput);
278
276
  // clear pending writes
279
277
  this.checkpointPendingWrites = [];
280
- const metadataWrites = mapOutputUpdates(this.outputKeys, this.tasks).next().value;
281
278
  await this._putCheckpoint({
282
279
  source: "loop",
283
- writes: metadataWrites ?? null,
280
+ writes: mapOutputUpdates(this.outputKeys, this.tasks).next().value ?? null,
284
281
  });
285
282
  // after execution, check if we should interrupt
286
283
  if (shouldInterrupt(this.checkpoint, interruptAfter, this.tasks)) {
@@ -300,7 +297,7 @@ export class PregelLoop {
300
297
  this.status = "out_of_steps";
301
298
  return false;
302
299
  }
303
- const nextTasks = _prepareNextTasks(this.checkpoint, this.graph.nodes, this.channels, this.config, true, {
300
+ const nextTasks = _prepareNextTasks(this.checkpoint, this.nodes, this.channels, this.config, true, {
304
301
  step: this.step,
305
302
  checkpointer: this.checkpointer,
306
303
  isResuming: this.input === INPUT_RESUMING,
@@ -310,7 +307,7 @@ export class PregelLoop {
310
307
  // Produce debug output
311
308
  if (this.checkpointer) {
312
309
  this.stream.push(...(await gatherIterator(prefixGenerator(mapDebugCheckpoint(this.step - 1, // printing checkpoint for previous step
313
- this.checkpointConfig, this.channels, this.graph.streamChannelsAsIs, this.checkpointMetadata, this.tasks, this.checkpointPendingWrites), "debug"))));
310
+ this.checkpointConfig, this.channels, this.streamKeys, this.checkpointMetadata, this.tasks, this.checkpointPendingWrites), "debug"))));
314
311
  }
315
312
  if (this.tasks.length === 0) {
316
313
  this.status = "done";
@@ -331,6 +328,7 @@ export class PregelLoop {
331
328
  // if all tasks have finished, re-tick
332
329
  if (this.tasks.every((task) => task.writes.length > 0)) {
333
330
  return this.tick({
331
+ inputKeys,
334
332
  interruptAfter,
335
333
  interruptBefore,
336
334
  manager,
@@ -356,7 +354,7 @@ export class PregelLoop {
356
354
  * - finding a previous checkpoint
357
355
  * - receiving None input (outer graph) or RESUMING flag (subgraph)
358
356
  */
359
- async _first() {
357
+ async _first(inputKeys) {
360
358
  const isResuming = (Object.keys(this.checkpoint.channel_versions).length !== 0 &&
361
359
  this.config.configurable?.[CONFIG_KEY_RESUMING] !== undefined) ||
362
360
  this.input === null;
@@ -373,11 +371,11 @@ export class PregelLoop {
373
371
  // map inputs to channel updates
374
372
  }
375
373
  else {
376
- const inputWrites = await gatherIterator(mapInput(this.graph.inputChannels, this.input));
374
+ const inputWrites = await gatherIterator(mapInput(inputKeys, this.input));
377
375
  if (inputWrites.length === 0) {
378
- throw new EmptyInputError(`Received no input writes for ${JSON.stringify(this.graph.inputChannels, null, 2)}`);
376
+ throw new EmptyInputError(`Received no input writes for ${JSON.stringify(inputKeys, null, 2)}`);
379
377
  }
380
- const discardTasks = _prepareNextTasks(this.checkpoint, this.graph.nodes, this.channels, this.config, true, { step: this.step });
378
+ const discardTasks = _prepareNextTasks(this.checkpoint, this.nodes, this.channels, this.config, true, { step: this.step });
381
379
  _applyWrites(this.checkpoint, this.channels, discardTasks.concat([
382
380
  {
383
381
  name: INPUT,
@@ -1,5 +1,5 @@
1
1
  import type { Runnable, RunnableConfig } from "@langchain/core/runnables";
2
- import type { PendingWrite, CheckpointMetadata, BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
2
+ import type { All, PendingWrite, CheckpointMetadata, BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
3
3
  import type { BaseChannel } from "../channels/base.js";
4
4
  import type { PregelNode } from "./read.js";
5
5
  import { RetryPolicy } from "./utils.js";
@@ -93,5 +93,4 @@ export interface StateSnapshot {
93
93
  */
94
94
  readonly tasks: PregelTaskDescription[];
95
95
  }
96
- export type All = "*";
97
96
  export {};
@@ -1,6 +1,6 @@
1
+ import { All } from "@langchain/langgraph-checkpoint";
1
2
  import { BaseChannel } from "../channels/index.js";
2
3
  import { PregelNode } from "./read.js";
3
- import { All } from "./types.js";
4
4
  export declare class GraphValidationError extends Error {
5
5
  constructor(message?: string);
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph",
3
- "version": "0.1.9",
3
+ "version": "0.1.10-rc.0",
4
4
  "description": "LangGraph",
5
5
  "type": "module",
6
6
  "engines": {