@langchain/langgraph 0.0.13 → 0.0.15

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.
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/checkpoint/sqlite.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/checkpoint/sqlite.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/checkpoint/sqlite.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/checkpoint/sqlite.js'
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
4
+ const base_js_1 = require("../serde/base.cjs");
4
5
  const id_js_1 = require("./id.cjs");
5
6
  function deepCopy(obj) {
6
7
  if (typeof obj !== "object" || obj === null) {
@@ -43,7 +44,7 @@ class BaseCheckpointSaver {
43
44
  enumerable: true,
44
45
  configurable: true,
45
46
  writable: true,
46
- value: JSON
47
+ value: base_js_1.DefaultSerializer
47
48
  });
48
49
  this.serde = serde || this.serde;
49
50
  }
@@ -60,6 +60,6 @@ export declare abstract class BaseCheckpointSaver {
60
60
  constructor(serde?: SerializerProtocol<unknown>);
61
61
  get(config: RunnableConfig): Promise<Checkpoint | undefined>;
62
62
  abstract getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
63
- abstract list(config: RunnableConfig): AsyncGenerator<CheckpointTuple>;
63
+ abstract list(config: RunnableConfig, limit?: number, before?: RunnableConfig): AsyncGenerator<CheckpointTuple>;
64
64
  abstract put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata): Promise<RunnableConfig>;
65
65
  }
@@ -1,3 +1,4 @@
1
+ import { DefaultSerializer } from "../serde/base.js";
1
2
  import { uuid6 } from "./id.js";
2
3
  export function deepCopy(obj) {
3
4
  if (typeof obj !== "object" || obj === null) {
@@ -37,7 +38,7 @@ export class BaseCheckpointSaver {
37
38
  enumerable: true,
38
39
  configurable: true,
39
40
  writable: true,
40
- value: JSON
41
+ value: DefaultSerializer
41
42
  });
42
43
  this.serde = serde || this.serde;
43
44
  }
@@ -22,8 +22,8 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
22
22
  if (checkpoint) {
23
23
  return {
24
24
  config,
25
- checkpoint: this.serde.parse(checkpoint[0]),
26
- metadata: this.serde.parse(checkpoint[1]),
25
+ checkpoint: (await this.serde.parse(checkpoint[0])),
26
+ metadata: (await this.serde.parse(checkpoint[1])),
27
27
  };
28
28
  }
29
29
  }
@@ -33,22 +33,25 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
33
33
  const checkpoint = checkpoints[maxThreadTs];
34
34
  return {
35
35
  config: { configurable: { thread_id, checkpoint_id: maxThreadTs } },
36
- checkpoint: this.serde.parse(checkpoint[0]),
37
- metadata: this.serde.parse(checkpoint[1]),
36
+ checkpoint: (await this.serde.parse(checkpoint[0])),
37
+ metadata: (await this.serde.parse(checkpoint[1])),
38
38
  };
39
39
  }
40
40
  }
41
41
  return undefined;
42
42
  }
43
- async *list(config) {
43
+ async *list(config, limit, before) {
44
44
  const thread_id = config.configurable?.thread_id;
45
45
  const checkpoints = this.storage[thread_id] ?? {};
46
46
  // sort in desc order
47
- for (const [checkpoint_id, checkpoint] of Object.entries(checkpoints).sort((a, b) => b[0].localeCompare(a[0]))) {
47
+ for (const [checkpoint_id, checkpoint] of Object.entries(checkpoints)
48
+ .filter((c) => before ? c[0] < before.configurable?.checkpoint_id : true)
49
+ .sort((a, b) => b[0].localeCompare(a[0]))
50
+ .slice(0, limit)) {
48
51
  yield {
49
52
  config: { configurable: { thread_id, checkpoint_id } },
50
- checkpoint: this.serde.parse(checkpoint[0]),
51
- metadata: this.serde.parse(checkpoint[1]),
53
+ checkpoint: (await this.serde.parse(checkpoint[0])),
54
+ metadata: (await this.serde.parse(checkpoint[1])),
52
55
  };
53
56
  }
54
57
  }
@@ -5,6 +5,6 @@ export declare class MemorySaver extends BaseCheckpointSaver {
5
5
  storage: Record<string, Record<string, [string, string]>>;
6
6
  constructor(serde?: SerializerProtocol<unknown>);
7
7
  getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
8
- list(config: RunnableConfig): AsyncGenerator<CheckpointTuple>;
8
+ list(config: RunnableConfig, limit?: number, before?: RunnableConfig): AsyncGenerator<CheckpointTuple>;
9
9
  put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata): Promise<RunnableConfig>;
10
10
  }
@@ -19,8 +19,8 @@ export class MemorySaver extends BaseCheckpointSaver {
19
19
  if (checkpoint) {
20
20
  return {
21
21
  config,
22
- checkpoint: this.serde.parse(checkpoint[0]),
23
- metadata: this.serde.parse(checkpoint[1]),
22
+ checkpoint: (await this.serde.parse(checkpoint[0])),
23
+ metadata: (await this.serde.parse(checkpoint[1])),
24
24
  };
25
25
  }
26
26
  }
@@ -30,22 +30,25 @@ export class MemorySaver extends BaseCheckpointSaver {
30
30
  const checkpoint = checkpoints[maxThreadTs];
31
31
  return {
32
32
  config: { configurable: { thread_id, checkpoint_id: maxThreadTs } },
33
- checkpoint: this.serde.parse(checkpoint[0]),
34
- metadata: this.serde.parse(checkpoint[1]),
33
+ checkpoint: (await this.serde.parse(checkpoint[0])),
34
+ metadata: (await this.serde.parse(checkpoint[1])),
35
35
  };
36
36
  }
37
37
  }
38
38
  return undefined;
39
39
  }
40
- async *list(config) {
40
+ async *list(config, limit, before) {
41
41
  const thread_id = config.configurable?.thread_id;
42
42
  const checkpoints = this.storage[thread_id] ?? {};
43
43
  // sort in desc order
44
- for (const [checkpoint_id, checkpoint] of Object.entries(checkpoints).sort((a, b) => b[0].localeCompare(a[0]))) {
44
+ for (const [checkpoint_id, checkpoint] of Object.entries(checkpoints)
45
+ .filter((c) => before ? c[0] < before.configurable?.checkpoint_id : true)
46
+ .sort((a, b) => b[0].localeCompare(a[0]))
47
+ .slice(0, limit)) {
45
48
  yield {
46
49
  config: { configurable: { thread_id, checkpoint_id } },
47
- checkpoint: this.serde.parse(checkpoint[0]),
48
- metadata: this.serde.parse(checkpoint[1]),
50
+ checkpoint: (await this.serde.parse(checkpoint[0])),
51
+ metadata: (await this.serde.parse(checkpoint[1])),
49
52
  };
50
53
  }
51
54
  }
@@ -61,8 +61,8 @@ CREATE TABLE IF NOT EXISTS checkpoints (
61
61
  if (row) {
62
62
  return {
63
63
  config,
64
- checkpoint: this.serde.parse(row.checkpoint),
65
- metadata: this.serde.parse(row.metadata),
64
+ checkpoint: (await this.serde.parse(row.checkpoint)),
65
+ metadata: (await this.serde.parse(row.metadata)),
66
66
  parentConfig: row.parent_id
67
67
  ? {
68
68
  configurable: {
@@ -91,8 +91,8 @@ CREATE TABLE IF NOT EXISTS checkpoints (
91
91
  checkpoint_id: row.checkpoint_id,
92
92
  },
93
93
  },
94
- checkpoint: this.serde.parse(row.checkpoint),
95
- metadata: this.serde.parse(row.metadata),
94
+ checkpoint: (await this.serde.parse(row.checkpoint)),
95
+ metadata: (await this.serde.parse(row.metadata)),
96
96
  parentConfig: row.parent_id
97
97
  ? {
98
98
  configurable: {
@@ -106,13 +106,16 @@ CREATE TABLE IF NOT EXISTS checkpoints (
106
106
  }
107
107
  return undefined;
108
108
  }
109
- async *list(config) {
109
+ async *list(config, limit, before) {
110
110
  this.setup();
111
111
  const thread_id = config.configurable?.thread_id;
112
+ let sql = `SELECT thread_id, checkpoint_id, parent_id, checkpoint, metadata FROM checkpoints WHERE thread_id = ? ${before ? "AND checkpoint_id < ?" : ""} ORDER BY checkpoint_id DESC`;
113
+ if (limit) {
114
+ sql += ` LIMIT ${limit}`;
115
+ }
116
+ const args = [thread_id, before?.configurable?.checkpoint_id].filter(Boolean);
112
117
  try {
113
- const rows = this.db
114
- .prepare(`SELECT thread_id, checkpoint_id, parent_id, checkpoint, metadata FROM checkpoints WHERE thread_id = ? ORDER BY checkpoint_id DESC`)
115
- .all(thread_id);
118
+ const rows = this.db.prepare(sql).all(...args);
116
119
  if (rows) {
117
120
  for (const row of rows) {
118
121
  yield {
@@ -122,8 +125,8 @@ CREATE TABLE IF NOT EXISTS checkpoints (
122
125
  checkpoint_id: row.checkpoint_id,
123
126
  },
124
127
  },
125
- checkpoint: this.serde.parse(row.checkpoint),
126
- metadata: this.serde.parse(row.metadata),
128
+ checkpoint: (await this.serde.parse(row.checkpoint)),
129
+ metadata: (await this.serde.parse(row.metadata)),
127
130
  parentConfig: row.parent_id
128
131
  ? {
129
132
  configurable: {
@@ -9,6 +9,6 @@ export declare class SqliteSaver extends BaseCheckpointSaver {
9
9
  static fromConnString(connStringOrLocalPath: string): SqliteSaver;
10
10
  private setup;
11
11
  getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
12
- list(config: RunnableConfig): AsyncGenerator<CheckpointTuple>;
12
+ list(config: RunnableConfig, limit?: number, before?: RunnableConfig): AsyncGenerator<CheckpointTuple>;
13
13
  put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata): Promise<RunnableConfig>;
14
14
  }
@@ -55,8 +55,8 @@ CREATE TABLE IF NOT EXISTS checkpoints (
55
55
  if (row) {
56
56
  return {
57
57
  config,
58
- checkpoint: this.serde.parse(row.checkpoint),
59
- metadata: this.serde.parse(row.metadata),
58
+ checkpoint: (await this.serde.parse(row.checkpoint)),
59
+ metadata: (await this.serde.parse(row.metadata)),
60
60
  parentConfig: row.parent_id
61
61
  ? {
62
62
  configurable: {
@@ -85,8 +85,8 @@ CREATE TABLE IF NOT EXISTS checkpoints (
85
85
  checkpoint_id: row.checkpoint_id,
86
86
  },
87
87
  },
88
- checkpoint: this.serde.parse(row.checkpoint),
89
- metadata: this.serde.parse(row.metadata),
88
+ checkpoint: (await this.serde.parse(row.checkpoint)),
89
+ metadata: (await this.serde.parse(row.metadata)),
90
90
  parentConfig: row.parent_id
91
91
  ? {
92
92
  configurable: {
@@ -100,13 +100,16 @@ CREATE TABLE IF NOT EXISTS checkpoints (
100
100
  }
101
101
  return undefined;
102
102
  }
103
- async *list(config) {
103
+ async *list(config, limit, before) {
104
104
  this.setup();
105
105
  const thread_id = config.configurable?.thread_id;
106
+ let sql = `SELECT thread_id, checkpoint_id, parent_id, checkpoint, metadata FROM checkpoints WHERE thread_id = ? ${before ? "AND checkpoint_id < ?" : ""} ORDER BY checkpoint_id DESC`;
107
+ if (limit) {
108
+ sql += ` LIMIT ${limit}`;
109
+ }
110
+ const args = [thread_id, before?.configurable?.checkpoint_id].filter(Boolean);
106
111
  try {
107
- const rows = this.db
108
- .prepare(`SELECT thread_id, checkpoint_id, parent_id, checkpoint, metadata FROM checkpoints WHERE thread_id = ? ORDER BY checkpoint_id DESC`)
109
- .all(thread_id);
112
+ const rows = this.db.prepare(sql).all(...args);
110
113
  if (rows) {
111
114
  for (const row of rows) {
112
115
  yield {
@@ -116,8 +119,8 @@ CREATE TABLE IF NOT EXISTS checkpoints (
116
119
  checkpoint_id: row.checkpoint_id,
117
120
  },
118
121
  },
119
- checkpoint: this.serde.parse(row.checkpoint),
120
- metadata: this.serde.parse(row.metadata),
122
+ checkpoint: (await this.serde.parse(row.checkpoint)),
123
+ metadata: (await this.serde.parse(row.metadata)),
121
124
  parentConfig: row.parent_id
122
125
  ? {
123
126
  configurable: {
package/dist/index.cjs CHANGED
@@ -1,17 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EmptyChannelError = exports.InvalidUpdateError = exports.GraphValueError = exports.GraphRecursionError = exports.BaseCheckpointSaver = exports.emptyCheckpoint = exports.MemorySaver = exports.MessageGraph = exports.StateGraph = exports.START = exports.Graph = exports.END = void 0;
3
+ exports.EmptyChannelError = exports.InvalidUpdateError = exports.GraphValueError = exports.GraphRecursionError = exports.BaseCheckpointSaver = exports.emptyCheckpoint = exports.copyCheckpoint = exports.MemorySaver = exports.MessageGraph = exports.StateGraph = exports.START = exports.Graph = exports.END = void 0;
4
4
  var index_js_1 = require("./graph/index.cjs");
5
5
  Object.defineProperty(exports, "END", { enumerable: true, get: function () { return index_js_1.END; } });
6
6
  Object.defineProperty(exports, "Graph", { enumerable: true, get: function () { return index_js_1.Graph; } });
7
7
  Object.defineProperty(exports, "START", { enumerable: true, get: function () { return index_js_1.START; } });
8
8
  Object.defineProperty(exports, "StateGraph", { enumerable: true, get: function () { return index_js_1.StateGraph; } });
9
9
  Object.defineProperty(exports, "MessageGraph", { enumerable: true, get: function () { return index_js_1.MessageGraph; } });
10
- var index_js_2 = require("./checkpoint/index.cjs");
11
- Object.defineProperty(exports, "MemorySaver", { enumerable: true, get: function () { return index_js_2.MemorySaver; } });
12
- var index_js_3 = require("./checkpoint/index.cjs");
13
- Object.defineProperty(exports, "emptyCheckpoint", { enumerable: true, get: function () { return index_js_3.emptyCheckpoint; } });
14
- Object.defineProperty(exports, "BaseCheckpointSaver", { enumerable: true, get: function () { return index_js_3.BaseCheckpointSaver; } });
10
+ var memory_js_1 = require("./checkpoint/memory.cjs");
11
+ Object.defineProperty(exports, "MemorySaver", { enumerable: true, get: function () { return memory_js_1.MemorySaver; } });
12
+ var base_js_1 = require("./checkpoint/base.cjs");
13
+ Object.defineProperty(exports, "copyCheckpoint", { enumerable: true, get: function () { return base_js_1.copyCheckpoint; } });
14
+ Object.defineProperty(exports, "emptyCheckpoint", { enumerable: true, get: function () { return base_js_1.emptyCheckpoint; } });
15
+ Object.defineProperty(exports, "BaseCheckpointSaver", { enumerable: true, get: function () { return base_js_1.BaseCheckpointSaver; } });
15
16
  var errors_js_1 = require("./errors.cjs");
16
17
  Object.defineProperty(exports, "GraphRecursionError", { enumerable: true, get: function () { return errors_js_1.GraphRecursionError; } });
17
18
  Object.defineProperty(exports, "GraphValueError", { enumerable: true, get: function () { return errors_js_1.GraphValueError; } });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { END, Graph, type StateGraphArgs, START, StateGraph, MessageGraph, } from "./graph/index.js";
2
- export { MemorySaver } from "./checkpoint/index.js";
3
- export { type Checkpoint, emptyCheckpoint, BaseCheckpointSaver, } from "./checkpoint/index.js";
2
+ export { MemorySaver } from "./checkpoint/memory.js";
3
+ export { type Checkpoint, type CheckpointMetadata, copyCheckpoint, emptyCheckpoint, BaseCheckpointSaver, } from "./checkpoint/base.js";
4
4
  export { GraphRecursionError, GraphValueError, InvalidUpdateError, EmptyChannelError, } from "./errors.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { END, Graph, START, StateGraph, MessageGraph, } from "./graph/index.js";
2
- export { MemorySaver } from "./checkpoint/index.js";
3
- export { emptyCheckpoint, BaseCheckpointSaver, } from "./checkpoint/index.js";
2
+ export { MemorySaver } from "./checkpoint/memory.js";
3
+ export { copyCheckpoint, emptyCheckpoint, BaseCheckpointSaver, } from "./checkpoint/base.js";
4
4
  export { GraphRecursionError, GraphValueError, InvalidUpdateError, EmptyChannelError, } from "./errors.js";
@@ -208,6 +208,108 @@ class Pregel extends runnables_1.Runnable {
208
208
  return Object.keys(this.channels);
209
209
  }
210
210
  }
211
+ async getState(config) {
212
+ if (!this.checkpointer) {
213
+ throw new errors_js_1.GraphValueError("No checkpointer set");
214
+ }
215
+ const saved = await this.checkpointer.getTuple(config);
216
+ const checkpoint = saved ? saved.checkpoint : (0, base_js_2.emptyCheckpoint)();
217
+ const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
218
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
219
+ const [_, nextTasks] = _prepareNextTasks(checkpoint, this.nodes, channels, false);
220
+ return {
221
+ values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
222
+ next: nextTasks.map((task) => task.name),
223
+ metadata: saved?.metadata,
224
+ config: saved ? saved.config : config,
225
+ parentConfig: saved?.parentConfig,
226
+ };
227
+ }
228
+ async *getStateHistory(config, limit, before) {
229
+ if (!this.checkpointer) {
230
+ throw new errors_js_1.GraphValueError("No checkpointer set");
231
+ }
232
+ for await (const saved of this.checkpointer.list(config, limit, before)) {
233
+ const channels = (0, base_js_1.emptyChannels)(this.channels, saved.checkpoint);
234
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
235
+ const [_, nextTasks] = _prepareNextTasks(saved.checkpoint, this.nodes, channels, false);
236
+ yield {
237
+ values: (0, io_js_1.readChannels)(channels, this.streamChannelsAsIs),
238
+ next: nextTasks.map((task) => task.name),
239
+ metadata: saved.metadata,
240
+ config: saved.config,
241
+ parentConfig: saved.parentConfig,
242
+ };
243
+ }
244
+ }
245
+ async updateState(config, values, asNode) {
246
+ if (!this.checkpointer) {
247
+ throw new errors_js_1.GraphValueError("No checkpointer set");
248
+ }
249
+ // Get the latest checkpoint
250
+ const saved = await this.checkpointer.getTuple(config);
251
+ const checkpoint = saved
252
+ ? (0, base_js_2.copyCheckpoint)(saved.checkpoint)
253
+ : (0, base_js_2.emptyCheckpoint)();
254
+ // Find last that updated the state, if not provided
255
+ const maxSeens = Object.entries(checkpoint.versions_seen).reduce((acc, [node, versions]) => {
256
+ const maxSeen = Math.max(...Object.values(versions));
257
+ if (maxSeen) {
258
+ if (!acc[maxSeen]) {
259
+ acc[maxSeen] = [];
260
+ }
261
+ acc[maxSeen].push(node);
262
+ }
263
+ return acc;
264
+ }, {});
265
+ if (!asNode && !Object.keys(maxSeens).length) {
266
+ if (!Array.isArray(this.inputs) && this.inputs in this.nodes) {
267
+ asNode = this.inputs;
268
+ }
269
+ }
270
+ else if (!asNode) {
271
+ const maxSeen = Math.max(...Object.keys(maxSeens).map(Number));
272
+ const nodes = maxSeens[maxSeen];
273
+ if (nodes.length === 1) {
274
+ asNode = nodes[0];
275
+ }
276
+ }
277
+ if (!asNode) {
278
+ throw new errors_js_1.InvalidUpdateError("Ambiguous update, specify as_node");
279
+ }
280
+ // update channels
281
+ const channels = (0, base_js_1.emptyChannels)(this.channels, checkpoint);
282
+ // create task to run all writers of the chosen node
283
+ const writers = this.nodes[asNode].getWriters();
284
+ if (!writers.length) {
285
+ throw new errors_js_1.InvalidUpdateError(`No writers found for node ${asNode}`);
286
+ }
287
+ const task = {
288
+ name: asNode,
289
+ input: values,
290
+ proc:
291
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
292
+ writers.length > 1 ? runnables_1.RunnableSequence.from(writers) : writers[0],
293
+ writes: [],
294
+ config: undefined,
295
+ };
296
+ // execute task
297
+ await task.proc.invoke(task.input, (0, runnables_1.patchConfig)(config, {
298
+ runName: `${this.name}UpdateState`,
299
+ configurable: {
300
+ [constants_js_1.CONFIG_KEY_SEND]: (items) => task.writes.push(...items),
301
+ [constants_js_1.CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, task.writes),
302
+ },
303
+ }));
304
+ // apply to checkpoint and save
305
+ _applyWrites(checkpoint, channels, task.writes);
306
+ const step = (saved?.metadata?.step ?? -2) + 1;
307
+ return await this.checkpointer.put(saved?.config ?? config, (0, base_js_1.createCheckpoint)(checkpoint, channels, step), {
308
+ source: "update",
309
+ step,
310
+ writes: { [asNode]: values },
311
+ });
312
+ }
211
313
  _defaults(config) {
212
314
  const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
213
315
  const defaultDebug = debug !== undefined ? debug : this.debug;
@@ -5,7 +5,7 @@ import { BaseChannel } from "../channels/base.js";
5
5
  import { BaseCheckpointSaver, Checkpoint, ReadonlyCheckpoint } from "../checkpoint/base.js";
6
6
  import { PregelNode } from "./read.js";
7
7
  import { ChannelWrite } from "./write.js";
8
- import { All, PregelExecutableTask, PregelTaskDescription } from "./types.js";
8
+ import { All, PregelExecutableTask, PregelTaskDescription, StateSnapshot } from "./types.js";
9
9
  type WriteValue = Runnable | RunnableFunc<unknown, unknown> | unknown;
10
10
  export declare class Channel {
11
11
  static subscribeTo(channels: string, options?: {
@@ -85,6 +85,9 @@ export declare class Pregel<const Nn extends StrRecord<string, PregelNode>, cons
85
85
  validate(): this;
86
86
  get streamChannelsList(): Array<keyof Cc>;
87
87
  get streamChannelsAsIs(): keyof Cc | Array<keyof Cc>;
88
+ getState(config: RunnableConfig): Promise<StateSnapshot>;
89
+ getStateHistory(config: RunnableConfig, limit?: number, before?: RunnableConfig): AsyncIterableIterator<StateSnapshot>;
90
+ updateState(config: RunnableConfig, values: Record<string, unknown> | unknown, asNode?: keyof Nn): Promise<RunnableConfig>;
88
91
  _defaults(config: PregelOptions<Nn, Cc>): [
89
92
  boolean,
90
93
  StreamMode,
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable no-param-reassign */
2
- import { Runnable, _coerceToRunnable, ensureConfig, patchConfig, } from "@langchain/core/runnables";
2
+ import { Runnable, RunnableSequence, _coerceToRunnable, ensureConfig, patchConfig, } from "@langchain/core/runnables";
3
3
  import { IterableReadableStream } from "@langchain/core/utils/stream";
4
4
  import { createCheckpoint, emptyChannels, } from "../channels/base.js";
5
5
  import { copyCheckpoint, emptyCheckpoint, } from "../checkpoint/base.js";
@@ -204,6 +204,108 @@ export class Pregel extends Runnable {
204
204
  return Object.keys(this.channels);
205
205
  }
206
206
  }
207
+ async getState(config) {
208
+ if (!this.checkpointer) {
209
+ throw new GraphValueError("No checkpointer set");
210
+ }
211
+ const saved = await this.checkpointer.getTuple(config);
212
+ const checkpoint = saved ? saved.checkpoint : emptyCheckpoint();
213
+ const channels = emptyChannels(this.channels, checkpoint);
214
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
215
+ const [_, nextTasks] = _prepareNextTasks(checkpoint, this.nodes, channels, false);
216
+ return {
217
+ values: readChannels(channels, this.streamChannelsAsIs),
218
+ next: nextTasks.map((task) => task.name),
219
+ metadata: saved?.metadata,
220
+ config: saved ? saved.config : config,
221
+ parentConfig: saved?.parentConfig,
222
+ };
223
+ }
224
+ async *getStateHistory(config, limit, before) {
225
+ if (!this.checkpointer) {
226
+ throw new GraphValueError("No checkpointer set");
227
+ }
228
+ for await (const saved of this.checkpointer.list(config, limit, before)) {
229
+ const channels = emptyChannels(this.channels, saved.checkpoint);
230
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
231
+ const [_, nextTasks] = _prepareNextTasks(saved.checkpoint, this.nodes, channels, false);
232
+ yield {
233
+ values: readChannels(channels, this.streamChannelsAsIs),
234
+ next: nextTasks.map((task) => task.name),
235
+ metadata: saved.metadata,
236
+ config: saved.config,
237
+ parentConfig: saved.parentConfig,
238
+ };
239
+ }
240
+ }
241
+ async updateState(config, values, asNode) {
242
+ if (!this.checkpointer) {
243
+ throw new GraphValueError("No checkpointer set");
244
+ }
245
+ // Get the latest checkpoint
246
+ const saved = await this.checkpointer.getTuple(config);
247
+ const checkpoint = saved
248
+ ? copyCheckpoint(saved.checkpoint)
249
+ : emptyCheckpoint();
250
+ // Find last that updated the state, if not provided
251
+ const maxSeens = Object.entries(checkpoint.versions_seen).reduce((acc, [node, versions]) => {
252
+ const maxSeen = Math.max(...Object.values(versions));
253
+ if (maxSeen) {
254
+ if (!acc[maxSeen]) {
255
+ acc[maxSeen] = [];
256
+ }
257
+ acc[maxSeen].push(node);
258
+ }
259
+ return acc;
260
+ }, {});
261
+ if (!asNode && !Object.keys(maxSeens).length) {
262
+ if (!Array.isArray(this.inputs) && this.inputs in this.nodes) {
263
+ asNode = this.inputs;
264
+ }
265
+ }
266
+ else if (!asNode) {
267
+ const maxSeen = Math.max(...Object.keys(maxSeens).map(Number));
268
+ const nodes = maxSeens[maxSeen];
269
+ if (nodes.length === 1) {
270
+ asNode = nodes[0];
271
+ }
272
+ }
273
+ if (!asNode) {
274
+ throw new InvalidUpdateError("Ambiguous update, specify as_node");
275
+ }
276
+ // update channels
277
+ const channels = emptyChannels(this.channels, checkpoint);
278
+ // create task to run all writers of the chosen node
279
+ const writers = this.nodes[asNode].getWriters();
280
+ if (!writers.length) {
281
+ throw new InvalidUpdateError(`No writers found for node ${asNode}`);
282
+ }
283
+ const task = {
284
+ name: asNode,
285
+ input: values,
286
+ proc:
287
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
288
+ writers.length > 1 ? RunnableSequence.from(writers) : writers[0],
289
+ writes: [],
290
+ config: undefined,
291
+ };
292
+ // execute task
293
+ await task.proc.invoke(task.input, patchConfig(config, {
294
+ runName: `${this.name}UpdateState`,
295
+ configurable: {
296
+ [CONFIG_KEY_SEND]: (items) => task.writes.push(...items),
297
+ [CONFIG_KEY_READ]: _localRead.bind(undefined, checkpoint, channels, task.writes),
298
+ },
299
+ }));
300
+ // apply to checkpoint and save
301
+ _applyWrites(checkpoint, channels, task.writes);
302
+ const step = (saved?.metadata?.step ?? -2) + 1;
303
+ return await this.checkpointer.put(saved?.config ?? config, createCheckpoint(checkpoint, channels, step), {
304
+ source: "update",
305
+ step,
306
+ writes: { [asNode]: values },
307
+ });
308
+ }
207
309
  _defaults(config) {
208
310
  const { debug, streamMode, inputKeys, outputKeys, interruptAfter, interruptBefore, ...rest } = config;
209
311
  const defaultDebug = debug !== undefined ? debug : this.debug;
@@ -1,4 +1,5 @@
1
1
  import { Runnable, RunnableConfig } from "@langchain/core/runnables";
2
+ import { CheckpointMetadata } from "../checkpoint/base.js";
2
3
  export interface PregelTaskDescription {
3
4
  readonly name: string;
4
5
  readonly input: unknown;
@@ -23,6 +24,10 @@ export interface StateSnapshot {
23
24
  * Config used to fetch this snapshot
24
25
  */
25
26
  readonly config: RunnableConfig;
27
+ /**
28
+ * Metadata about the checkpoint
29
+ */
30
+ readonly metadata?: CheckpointMetadata;
26
31
  /**
27
32
  * Config used to fetch the parent snapshot, if any
28
33
  * @default undefined
@@ -1,2 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultSerializer = void 0;
4
+ const load_1 = require("@langchain/core/load");
5
+ exports.DefaultSerializer = {
6
+ stringify: JSON.stringify,
7
+ parse: load_1.load,
8
+ };
@@ -1,4 +1,12 @@
1
+ import { load } from "@langchain/core/load";
1
2
  export interface SerializerProtocol<D> {
2
3
  stringify(obj: D): string;
3
- parse(data: string): D;
4
+ parse(data: string): Promise<D>;
4
5
  }
6
+ export declare const DefaultSerializer: {
7
+ stringify: {
8
+ (value: any, replacer?: ((this: any, key: string, value: any) => any) | undefined, space?: string | number | undefined): string;
9
+ (value: any, replacer?: (string | number)[] | null | undefined, space?: string | number | undefined): string;
10
+ };
11
+ parse: typeof load;
12
+ };
@@ -1 +1,5 @@
1
- export {};
1
+ import { load } from "@langchain/core/load";
2
+ export const DefaultSerializer = {
3
+ stringify: JSON.stringify,
4
+ parse: load,
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "LangGraph",
5
5
  "type": "module",
6
6
  "engines": {
@@ -38,7 +38,6 @@
38
38
  "license": "MIT",
39
39
  "dependencies": {
40
40
  "@langchain/core": "^0.1.61",
41
- "better-sqlite3": "^9.5.0",
42
41
  "uuid": "^9.0.1"
43
42
  },
44
43
  "devDependencies": {
@@ -53,6 +52,7 @@
53
52
  "@types/uuid": "^9",
54
53
  "@typescript-eslint/eslint-plugin": "^6.12.0",
55
54
  "@typescript-eslint/parser": "^6.12.0",
55
+ "better-sqlite3": "^9.5.0",
56
56
  "dotenv": "^16.3.1",
57
57
  "dpdm": "^3.12.0",
58
58
  "eslint": "^8.33.0",
@@ -73,6 +73,14 @@
73
73
  "zod": "^3.22.4",
74
74
  "zod-to-json-schema": "^3.22.4"
75
75
  },
76
+ "peerDependencies": {
77
+ "better-sqlite3": "^9.5.0"
78
+ },
79
+ "peerDependenciesMeta": {
80
+ "better-sqlite3": {
81
+ "optional": true
82
+ }
83
+ },
76
84
  "publishConfig": {
77
85
  "access": "public",
78
86
  "registry": "https://registry.npmjs.org/"
@@ -105,6 +113,15 @@
105
113
  "import": "./prebuilt.js",
106
114
  "require": "./prebuilt.cjs"
107
115
  },
116
+ "./checkpoint/sqlite": {
117
+ "types": {
118
+ "import": "./checkpoint/sqlite.d.ts",
119
+ "require": "./checkpoint/sqlite.d.cts",
120
+ "default": "./checkpoint/sqlite.d.ts"
121
+ },
122
+ "import": "./checkpoint/sqlite.js",
123
+ "require": "./checkpoint/sqlite.cjs"
124
+ },
108
125
  "./package.json": "./package.json"
109
126
  },
110
127
  "files": [
@@ -120,6 +137,10 @@
120
137
  "prebuilt.cjs",
121
138
  "prebuilt.js",
122
139
  "prebuilt.d.ts",
123
- "prebuilt.d.cts"
140
+ "prebuilt.d.cts",
141
+ "checkpoint/sqlite.cjs",
142
+ "checkpoint/sqlite.js",
143
+ "checkpoint/sqlite.d.ts",
144
+ "checkpoint/sqlite.d.cts"
124
145
  ]
125
146
  }