@langchain/langgraph-checkpoint 0.0.13 → 0.0.14
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.
- package/dist/base.cjs +5 -1
- package/dist/base.d.ts +1 -0
- package/dist/base.js +3 -0
- package/dist/memory.cjs +29 -17
- package/dist/memory.d.ts +2 -2
- package/dist/memory.js +30 -18
- package/dist/store/batch.cjs +11 -0
- package/dist/store/batch.d.ts +10 -0
- package/dist/store/batch.js +11 -0
- package/package.json +2 -2
package/dist/base.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WRITES_IDX_MAP = exports.maxChannelVersion = exports.compareChannelVersions = exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
|
|
3
|
+
exports.getCheckpointId = exports.WRITES_IDX_MAP = exports.maxChannelVersion = exports.compareChannelVersions = exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
|
|
4
4
|
const id_js_1 = require("./id.cjs");
|
|
5
5
|
const types_js_1 = require("./serde/types.cjs");
|
|
6
6
|
const jsonplus_js_1 = require("./serde/jsonplus.cjs");
|
|
@@ -99,3 +99,7 @@ exports.WRITES_IDX_MAP = {
|
|
|
99
99
|
[types_js_1.INTERRUPT]: -3,
|
|
100
100
|
[types_js_1.RESUME]: -4,
|
|
101
101
|
};
|
|
102
|
+
function getCheckpointId(config) {
|
|
103
|
+
return (config.configurable?.checkpoint_id || config.configurable?.thread_ts || "");
|
|
104
|
+
}
|
|
105
|
+
exports.getCheckpointId = getCheckpointId;
|
package/dist/base.d.ts
CHANGED
|
@@ -86,4 +86,5 @@ export declare function maxChannelVersion(...versions: ChannelVersion[]): Channe
|
|
|
86
86
|
* Each Checkpointer implementation should use this mapping in put_writes.
|
|
87
87
|
*/
|
|
88
88
|
export declare const WRITES_IDX_MAP: Record<string, number>;
|
|
89
|
+
export declare function getCheckpointId(config: RunnableConfig): string;
|
|
89
90
|
export {};
|
package/dist/base.js
CHANGED
package/dist/memory.cjs
CHANGED
|
@@ -26,7 +26,8 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
26
26
|
async _getPendingSends(threadId, checkpointNs, parentCheckpointId) {
|
|
27
27
|
let pendingSends = [];
|
|
28
28
|
if (parentCheckpointId !== undefined) {
|
|
29
|
-
|
|
29
|
+
const key = _generateKey(threadId, checkpointNs, parentCheckpointId);
|
|
30
|
+
pendingSends = await Promise.all(Object.values(this.writes[key] || {})
|
|
30
31
|
?.filter(([_taskId, channel]) => {
|
|
31
32
|
return channel === types_js_1.TASKS;
|
|
32
33
|
})
|
|
@@ -39,19 +40,18 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
39
40
|
async getTuple(config) {
|
|
40
41
|
const thread_id = config.configurable?.thread_id;
|
|
41
42
|
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
42
|
-
let checkpoint_id = config
|
|
43
|
+
let checkpoint_id = (0, base_js_1.getCheckpointId)(config);
|
|
43
44
|
if (checkpoint_id) {
|
|
44
45
|
const saved = this.storage[thread_id]?.[checkpoint_ns]?.[checkpoint_id];
|
|
45
46
|
if (saved !== undefined) {
|
|
46
47
|
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
47
|
-
const
|
|
48
|
-
[];
|
|
48
|
+
const key = _generateKey(thread_id, checkpoint_ns, checkpoint_id);
|
|
49
49
|
const pending_sends = await this._getPendingSends(thread_id, checkpoint_ns, parentCheckpointId);
|
|
50
50
|
const deserializedCheckpoint = {
|
|
51
51
|
...(await this.serde.loadsTyped("json", checkpoint)),
|
|
52
52
|
pending_sends,
|
|
53
53
|
};
|
|
54
|
-
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
54
|
+
const pendingWrites = await Promise.all(Object.values(this.writes[key] || {}).map(async ([taskId, channel, value]) => {
|
|
55
55
|
return [
|
|
56
56
|
taskId,
|
|
57
57
|
channel,
|
|
@@ -83,14 +83,13 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
83
83
|
checkpoint_id = Object.keys(checkpoints).sort((a, b) => b.localeCompare(a))[0];
|
|
84
84
|
const saved = checkpoints[checkpoint_id];
|
|
85
85
|
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
86
|
-
const
|
|
87
|
-
[];
|
|
86
|
+
const key = _generateKey(thread_id, checkpoint_ns, checkpoint_id);
|
|
88
87
|
const pending_sends = await this._getPendingSends(thread_id, checkpoint_ns, parentCheckpointId);
|
|
89
88
|
const deserializedCheckpoint = {
|
|
90
89
|
...(await this.serde.loadsTyped("json", checkpoint)),
|
|
91
90
|
pending_sends,
|
|
92
91
|
};
|
|
93
|
-
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
92
|
+
const pendingWrites = await Promise.all(Object.values(this.writes[key] || {}).map(async ([taskId, channel, value]) => {
|
|
94
93
|
return [
|
|
95
94
|
taskId,
|
|
96
95
|
channel,
|
|
@@ -130,6 +129,7 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
130
129
|
? [config.configurable?.thread_id]
|
|
131
130
|
: Object.keys(this.storage);
|
|
132
131
|
const configCheckpointNamespace = config.configurable?.checkpoint_ns;
|
|
132
|
+
const configCheckpointId = config.configurable?.checkpoint_id;
|
|
133
133
|
for (const threadId of threadIds) {
|
|
134
134
|
for (const checkpointNamespace of Object.keys(this.storage[threadId] ?? {})) {
|
|
135
135
|
if (configCheckpointNamespace !== undefined &&
|
|
@@ -139,7 +139,11 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
139
139
|
const checkpoints = this.storage[threadId]?.[checkpointNamespace] ?? {};
|
|
140
140
|
const sortedCheckpoints = Object.entries(checkpoints).sort((a, b) => b[0].localeCompare(a[0]));
|
|
141
141
|
for (const [checkpointId, [checkpoint, metadataStr, parentCheckpointId],] of sortedCheckpoints) {
|
|
142
|
-
// Filter by checkpoint ID
|
|
142
|
+
// Filter by checkpoint ID from config
|
|
143
|
+
if (configCheckpointId && checkpointId !== configCheckpointId) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// Filter by checkpoint ID from before config
|
|
143
147
|
if (before &&
|
|
144
148
|
before.configurable?.checkpoint_id &&
|
|
145
149
|
checkpointId >= before.configurable.checkpoint_id) {
|
|
@@ -155,10 +159,10 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
155
159
|
if (limit !== undefined) {
|
|
156
160
|
if (limit <= 0)
|
|
157
161
|
break;
|
|
158
|
-
// eslint-disable-next-line no-param-reassign
|
|
159
162
|
limit -= 1;
|
|
160
163
|
}
|
|
161
|
-
const
|
|
164
|
+
const key = _generateKey(threadId, checkpointNamespace, checkpointId);
|
|
165
|
+
const writes = Object.values(this.writes[key] || {});
|
|
162
166
|
const pending_sends = await this._getPendingSends(threadId, checkpointNamespace, parentCheckpointId);
|
|
163
167
|
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
164
168
|
return [
|
|
@@ -236,15 +240,23 @@ class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
|
236
240
|
if (checkpointId === undefined) {
|
|
237
241
|
throw new Error(`Failed to put writes. The passed RunnableConfig is missing a required "checkpoint_id" field in its "configurable" property.`);
|
|
238
242
|
}
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
const outerKey = _generateKey(threadId, checkpointNamespace, checkpointId);
|
|
244
|
+
const outerWrites_ = this.writes[outerKey];
|
|
245
|
+
if (this.writes[outerKey] === undefined) {
|
|
246
|
+
this.writes[outerKey] = {};
|
|
242
247
|
}
|
|
243
|
-
|
|
248
|
+
writes.forEach(([channel, value], idx) => {
|
|
244
249
|
const [, serializedValue] = this.serde.dumpsTyped(value);
|
|
245
|
-
|
|
250
|
+
const innerKey = [
|
|
251
|
+
taskId,
|
|
252
|
+
base_js_1.WRITES_IDX_MAP[channel] || idx,
|
|
253
|
+
];
|
|
254
|
+
const innerKeyStr = `${innerKey[0]},${innerKey[1]}`;
|
|
255
|
+
if (innerKey[1] >= 0 && outerWrites_ && innerKeyStr in outerWrites_) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.writes[outerKey][innerKeyStr] = [taskId, channel, serializedValue];
|
|
246
259
|
});
|
|
247
|
-
this.writes[key].push(...pendingWrites);
|
|
248
260
|
}
|
|
249
261
|
}
|
|
250
262
|
exports.MemorySaver = MemorySaver;
|
package/dist/memory.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
2
2
|
import { BaseCheckpointSaver, Checkpoint, CheckpointListOptions, CheckpointTuple } from "./base.js";
|
|
3
3
|
import { SerializerProtocol } from "./serde/base.js";
|
|
4
|
-
import { CheckpointMetadata,
|
|
4
|
+
import { CheckpointMetadata, PendingWrite } from "./types.js";
|
|
5
5
|
import { SendProtocol } from "./serde/types.js";
|
|
6
6
|
export declare class MemorySaver extends BaseCheckpointSaver {
|
|
7
7
|
storage: Record<string, Record<string, Record<string, [Uint8Array, Uint8Array, string | undefined]>>>;
|
|
8
|
-
writes: Record<string,
|
|
8
|
+
writes: Record<string, Record<string, [string, string, Uint8Array]>>;
|
|
9
9
|
constructor(serde?: SerializerProtocol);
|
|
10
10
|
_getPendingSends(threadId: string, checkpointNs: string, parentCheckpointId?: string): Promise<SendProtocol[]>;
|
|
11
11
|
getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
|
package/dist/memory.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseCheckpointSaver, copyCheckpoint, } from "./base.js";
|
|
1
|
+
import { BaseCheckpointSaver, copyCheckpoint, getCheckpointId, WRITES_IDX_MAP, } from "./base.js";
|
|
2
2
|
import { TASKS } from "./serde/types.js";
|
|
3
3
|
function _generateKey(threadId, checkpointNamespace, checkpointId) {
|
|
4
4
|
return JSON.stringify([threadId, checkpointNamespace, checkpointId]);
|
|
@@ -23,7 +23,8 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
23
23
|
async _getPendingSends(threadId, checkpointNs, parentCheckpointId) {
|
|
24
24
|
let pendingSends = [];
|
|
25
25
|
if (parentCheckpointId !== undefined) {
|
|
26
|
-
|
|
26
|
+
const key = _generateKey(threadId, checkpointNs, parentCheckpointId);
|
|
27
|
+
pendingSends = await Promise.all(Object.values(this.writes[key] || {})
|
|
27
28
|
?.filter(([_taskId, channel]) => {
|
|
28
29
|
return channel === TASKS;
|
|
29
30
|
})
|
|
@@ -36,19 +37,18 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
36
37
|
async getTuple(config) {
|
|
37
38
|
const thread_id = config.configurable?.thread_id;
|
|
38
39
|
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
39
|
-
let checkpoint_id = config
|
|
40
|
+
let checkpoint_id = getCheckpointId(config);
|
|
40
41
|
if (checkpoint_id) {
|
|
41
42
|
const saved = this.storage[thread_id]?.[checkpoint_ns]?.[checkpoint_id];
|
|
42
43
|
if (saved !== undefined) {
|
|
43
44
|
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
44
|
-
const
|
|
45
|
-
[];
|
|
45
|
+
const key = _generateKey(thread_id, checkpoint_ns, checkpoint_id);
|
|
46
46
|
const pending_sends = await this._getPendingSends(thread_id, checkpoint_ns, parentCheckpointId);
|
|
47
47
|
const deserializedCheckpoint = {
|
|
48
48
|
...(await this.serde.loadsTyped("json", checkpoint)),
|
|
49
49
|
pending_sends,
|
|
50
50
|
};
|
|
51
|
-
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
51
|
+
const pendingWrites = await Promise.all(Object.values(this.writes[key] || {}).map(async ([taskId, channel, value]) => {
|
|
52
52
|
return [
|
|
53
53
|
taskId,
|
|
54
54
|
channel,
|
|
@@ -80,14 +80,13 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
80
80
|
checkpoint_id = Object.keys(checkpoints).sort((a, b) => b.localeCompare(a))[0];
|
|
81
81
|
const saved = checkpoints[checkpoint_id];
|
|
82
82
|
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
83
|
-
const
|
|
84
|
-
[];
|
|
83
|
+
const key = _generateKey(thread_id, checkpoint_ns, checkpoint_id);
|
|
85
84
|
const pending_sends = await this._getPendingSends(thread_id, checkpoint_ns, parentCheckpointId);
|
|
86
85
|
const deserializedCheckpoint = {
|
|
87
86
|
...(await this.serde.loadsTyped("json", checkpoint)),
|
|
88
87
|
pending_sends,
|
|
89
88
|
};
|
|
90
|
-
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
89
|
+
const pendingWrites = await Promise.all(Object.values(this.writes[key] || {}).map(async ([taskId, channel, value]) => {
|
|
91
90
|
return [
|
|
92
91
|
taskId,
|
|
93
92
|
channel,
|
|
@@ -127,6 +126,7 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
127
126
|
? [config.configurable?.thread_id]
|
|
128
127
|
: Object.keys(this.storage);
|
|
129
128
|
const configCheckpointNamespace = config.configurable?.checkpoint_ns;
|
|
129
|
+
const configCheckpointId = config.configurable?.checkpoint_id;
|
|
130
130
|
for (const threadId of threadIds) {
|
|
131
131
|
for (const checkpointNamespace of Object.keys(this.storage[threadId] ?? {})) {
|
|
132
132
|
if (configCheckpointNamespace !== undefined &&
|
|
@@ -136,7 +136,11 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
136
136
|
const checkpoints = this.storage[threadId]?.[checkpointNamespace] ?? {};
|
|
137
137
|
const sortedCheckpoints = Object.entries(checkpoints).sort((a, b) => b[0].localeCompare(a[0]));
|
|
138
138
|
for (const [checkpointId, [checkpoint, metadataStr, parentCheckpointId],] of sortedCheckpoints) {
|
|
139
|
-
// Filter by checkpoint ID
|
|
139
|
+
// Filter by checkpoint ID from config
|
|
140
|
+
if (configCheckpointId && checkpointId !== configCheckpointId) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Filter by checkpoint ID from before config
|
|
140
144
|
if (before &&
|
|
141
145
|
before.configurable?.checkpoint_id &&
|
|
142
146
|
checkpointId >= before.configurable.checkpoint_id) {
|
|
@@ -152,10 +156,10 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
152
156
|
if (limit !== undefined) {
|
|
153
157
|
if (limit <= 0)
|
|
154
158
|
break;
|
|
155
|
-
// eslint-disable-next-line no-param-reassign
|
|
156
159
|
limit -= 1;
|
|
157
160
|
}
|
|
158
|
-
const
|
|
161
|
+
const key = _generateKey(threadId, checkpointNamespace, checkpointId);
|
|
162
|
+
const writes = Object.values(this.writes[key] || {});
|
|
159
163
|
const pending_sends = await this._getPendingSends(threadId, checkpointNamespace, parentCheckpointId);
|
|
160
164
|
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
161
165
|
return [
|
|
@@ -233,14 +237,22 @@ export class MemorySaver extends BaseCheckpointSaver {
|
|
|
233
237
|
if (checkpointId === undefined) {
|
|
234
238
|
throw new Error(`Failed to put writes. The passed RunnableConfig is missing a required "checkpoint_id" field in its "configurable" property.`);
|
|
235
239
|
}
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
const outerKey = _generateKey(threadId, checkpointNamespace, checkpointId);
|
|
241
|
+
const outerWrites_ = this.writes[outerKey];
|
|
242
|
+
if (this.writes[outerKey] === undefined) {
|
|
243
|
+
this.writes[outerKey] = {};
|
|
239
244
|
}
|
|
240
|
-
|
|
245
|
+
writes.forEach(([channel, value], idx) => {
|
|
241
246
|
const [, serializedValue] = this.serde.dumpsTyped(value);
|
|
242
|
-
|
|
247
|
+
const innerKey = [
|
|
248
|
+
taskId,
|
|
249
|
+
WRITES_IDX_MAP[channel] || idx,
|
|
250
|
+
];
|
|
251
|
+
const innerKeyStr = `${innerKey[0]},${innerKey[1]}`;
|
|
252
|
+
if (innerKey[1] >= 0 && outerWrites_ && innerKeyStr in outerWrites_) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
this.writes[outerKey][innerKeyStr] = [taskId, channel, serializedValue];
|
|
243
256
|
});
|
|
244
|
-
this.writes[key].push(...pendingWrites);
|
|
245
257
|
}
|
|
246
258
|
}
|
package/dist/store/batch.cjs
CHANGED
|
@@ -117,5 +117,16 @@ class AsyncBatchedStore extends base_js_1.BaseStore {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
+
// AsyncBatchedStore is internal and gets passed as args into traced tasks
|
|
121
|
+
// some BaseStores contain circular references so just serialize without it
|
|
122
|
+
// as this causes warnings when tracing with LangSmith.
|
|
123
|
+
toJSON() {
|
|
124
|
+
return {
|
|
125
|
+
queue: this.queue,
|
|
126
|
+
nextKey: this.nextKey,
|
|
127
|
+
running: this.running,
|
|
128
|
+
store: "[LangGraphStore]",
|
|
129
|
+
};
|
|
130
|
+
}
|
|
120
131
|
}
|
|
121
132
|
exports.AsyncBatchedStore = AsyncBatchedStore;
|
package/dist/store/batch.d.ts
CHANGED
|
@@ -26,4 +26,14 @@ export declare class AsyncBatchedStore extends BaseStore {
|
|
|
26
26
|
stop(): Promise<void>;
|
|
27
27
|
private enqueueOperation;
|
|
28
28
|
private processBatchQueue;
|
|
29
|
+
toJSON(): {
|
|
30
|
+
queue: Map<number, {
|
|
31
|
+
operation: Operation;
|
|
32
|
+
resolve: (value: any) => void;
|
|
33
|
+
reject: (reason?: any) => void;
|
|
34
|
+
}>;
|
|
35
|
+
nextKey: number;
|
|
36
|
+
running: boolean;
|
|
37
|
+
store: string;
|
|
38
|
+
};
|
|
29
39
|
}
|
package/dist/store/batch.js
CHANGED
|
@@ -114,4 +114,15 @@ export class AsyncBatchedStore extends BaseStore {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
+
// AsyncBatchedStore is internal and gets passed as args into traced tasks
|
|
118
|
+
// some BaseStores contain circular references so just serialize without it
|
|
119
|
+
// as this causes warnings when tracing with LangSmith.
|
|
120
|
+
toJSON() {
|
|
121
|
+
return {
|
|
122
|
+
queue: this.queue,
|
|
123
|
+
nextKey: this.nextKey,
|
|
124
|
+
running: this.running,
|
|
125
|
+
store: "[LangGraphStore]",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
117
128
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph-checkpoint",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "Library with base interfaces for LangGraph checkpoint savers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"jest-environment-node": "^29.6.4",
|
|
59
59
|
"prettier": "^2.8.3",
|
|
60
60
|
"release-it": "^17.6.0",
|
|
61
|
-
"rollup": "^4.
|
|
61
|
+
"rollup": "^4.29.2",
|
|
62
62
|
"ts-jest": "^29.1.0",
|
|
63
63
|
"tsx": "^4.7.0",
|
|
64
64
|
"typescript": "^4.9.5 || ^5.4.5"
|