@langchain/langgraph-checkpoint 0.0.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.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/base.cjs +67 -0
- package/dist/base.d.ts +75 -0
- package/dist/base.js +60 -0
- package/dist/id.cjs +20 -0
- package/dist/id.d.ts +2 -0
- package/dist/id.js +15 -0
- package/dist/index.cjs +24 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/memory.cjs +196 -0
- package/dist/memory.d.ts +13 -0
- package/dist/memory.js +192 -0
- package/dist/serde/base.cjs +8 -0
- package/dist/serde/base.d.ts +12 -0
- package/dist/serde/base.js +5 -0
- package/dist/serde/types.cjs +2 -0
- package/dist/serde/types.d.ts +44 -0
- package/dist/serde/types.js +1 -0
- package/dist/types.cjs +2 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.js +1 -0
- package/index.cjs +1 -0
- package/index.d.cts +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +88 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 LangChain
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @langchain/langgraph-checkpoint
|
|
2
|
+
|
|
3
|
+
This library defines the base interface for [LangGraph.js](https://github.com/langchain-ai/langgraphjs) checkpointers. Checkpointers provide persistence layer for LangGraph. They allow you to interact with and manage the graph's state. When you use a graph with a checkpointer, the checkpointer saves a _checkpoint_ of the graph state at every superstep, enabling several powerful capabilities like human-in-the-loop, "memory" between interactions and more.
|
|
4
|
+
|
|
5
|
+
## Key concepts
|
|
6
|
+
|
|
7
|
+
### Checkpoint
|
|
8
|
+
|
|
9
|
+
Checkpoint is a snapshot of the graph state at a given point in time. Checkpoint tuple refers to an object containing checkpoint and the associated config, metadata and pending writes.
|
|
10
|
+
|
|
11
|
+
### Thread
|
|
12
|
+
|
|
13
|
+
Threads enable the checkpointing of multiple different runs, making them essential for multi-tenant chat applications and other scenarios where maintaining separate states is necessary. A thread is a unique ID assigned to a series of checkpoints saved by a checkpointer. When using a checkpointer, you must specify a `thread_id` and optionally `checkpoint_id` when running the graph.
|
|
14
|
+
|
|
15
|
+
- `thread_id` is simply the ID of a thread. This is always required
|
|
16
|
+
- `checkpoint_id` can optionally be passed. This identifier refers to a specific checkpoint within a thread. This can be used to kick of a run of a graph from some point halfway through a thread.
|
|
17
|
+
|
|
18
|
+
You must pass these when invoking the graph as part of the configurable part of the config, e.g.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
{ configurable: { thread_id: "1" } } // valid config
|
|
22
|
+
{ configurable: { thread_id: "1", checkpoint_id: "0c62ca34-ac19-445d-bbb0-5b4984975b2a" } } // also valid config
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Serde
|
|
26
|
+
|
|
27
|
+
`@langchain/langgraph-checkpoint` also defines protocol for serialization/deserialization (serde) and provides an default implementation that handles a range of types.
|
|
28
|
+
|
|
29
|
+
### Pending writes
|
|
30
|
+
|
|
31
|
+
When a graph node fails mid-execution at a given superstep, LangGraph stores pending checkpoint writes from any other nodes that completed successfully at that superstep, so that whenever we resume graph execution from that superstep we don't re-run the successful nodes.
|
|
32
|
+
|
|
33
|
+
## Interface
|
|
34
|
+
|
|
35
|
+
Each checkpointer should conform to `BaseCheckpointSaver` interface and must implement the following methods:
|
|
36
|
+
|
|
37
|
+
- `.put` - Store a checkpoint with its configuration and metadata.
|
|
38
|
+
- `.putWrites` - Store intermediate writes linked to a checkpoint (i.e. pending writes).
|
|
39
|
+
- `.getTuple` - Fetch a checkpoint tuple using for a given configuration (`thread_id` and `thread_ts`).
|
|
40
|
+
- `.list` - List checkpoints that match a given configuration and filter criteria.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { MemorySaver } from "@langchain/langgraph-checkpoint";
|
|
46
|
+
|
|
47
|
+
const writeConfig = {
|
|
48
|
+
configurable: {
|
|
49
|
+
thread_id: "1",
|
|
50
|
+
checkpoint_ns: ""
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const readConfig = {
|
|
54
|
+
configurable: {
|
|
55
|
+
thread_id: "1"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const checkpointer = new MemorySaver();
|
|
60
|
+
const checkpoint = {
|
|
61
|
+
v: 1,
|
|
62
|
+
ts: "2024-07-31T20:14:19.804150+00:00",
|
|
63
|
+
id: "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
64
|
+
channel_values: {
|
|
65
|
+
my_key: "meow",
|
|
66
|
+
node: "node"
|
|
67
|
+
},
|
|
68
|
+
channel_versions: {
|
|
69
|
+
__start__: 2,
|
|
70
|
+
my_key: 3,
|
|
71
|
+
start:node: 3,
|
|
72
|
+
node: 3
|
|
73
|
+
},
|
|
74
|
+
versions_seen: {
|
|
75
|
+
__input__: {},
|
|
76
|
+
__start__: {
|
|
77
|
+
__start__: 1
|
|
78
|
+
},
|
|
79
|
+
node: {
|
|
80
|
+
start:node: 2
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
pending_sends: [],
|
|
84
|
+
current_tasks: {}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// store checkpoint
|
|
88
|
+
await checkpointer.put(writeConfig, checkpoint, {}, {})
|
|
89
|
+
|
|
90
|
+
// load checkpoint
|
|
91
|
+
await checkpointer.get(readConfig)
|
|
92
|
+
|
|
93
|
+
// list checkpoints
|
|
94
|
+
for await (const checkpoint of checkpointer.list(readConfig)) {
|
|
95
|
+
console.log(checkpoint);
|
|
96
|
+
}
|
|
97
|
+
```
|
package/dist/base.cjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseCheckpointSaver = exports.copyCheckpoint = exports.emptyCheckpoint = exports.deepCopy = void 0;
|
|
4
|
+
const base_js_1 = require("./serde/base.cjs");
|
|
5
|
+
const id_js_1 = require("./id.cjs");
|
|
6
|
+
function deepCopy(obj) {
|
|
7
|
+
if (typeof obj !== "object" || obj === null) {
|
|
8
|
+
return obj;
|
|
9
|
+
}
|
|
10
|
+
const newObj = Array.isArray(obj) ? [] : {};
|
|
11
|
+
for (const key in obj) {
|
|
12
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
13
|
+
newObj[key] = deepCopy(obj[key]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return newObj;
|
|
17
|
+
}
|
|
18
|
+
exports.deepCopy = deepCopy;
|
|
19
|
+
function emptyCheckpoint() {
|
|
20
|
+
return {
|
|
21
|
+
v: 1,
|
|
22
|
+
id: (0, id_js_1.uuid6)(-2),
|
|
23
|
+
ts: new Date().toISOString(),
|
|
24
|
+
channel_values: {},
|
|
25
|
+
channel_versions: {},
|
|
26
|
+
versions_seen: {},
|
|
27
|
+
pending_sends: [],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
exports.emptyCheckpoint = emptyCheckpoint;
|
|
31
|
+
function copyCheckpoint(checkpoint) {
|
|
32
|
+
return {
|
|
33
|
+
v: checkpoint.v,
|
|
34
|
+
id: checkpoint.id,
|
|
35
|
+
ts: checkpoint.ts,
|
|
36
|
+
channel_values: { ...checkpoint.channel_values },
|
|
37
|
+
channel_versions: { ...checkpoint.channel_versions },
|
|
38
|
+
versions_seen: deepCopy(checkpoint.versions_seen),
|
|
39
|
+
pending_sends: [...checkpoint.pending_sends],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
exports.copyCheckpoint = copyCheckpoint;
|
|
43
|
+
class BaseCheckpointSaver {
|
|
44
|
+
constructor(serde) {
|
|
45
|
+
Object.defineProperty(this, "serde", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
writable: true,
|
|
49
|
+
value: base_js_1.DefaultSerializer
|
|
50
|
+
});
|
|
51
|
+
this.serde = serde || this.serde;
|
|
52
|
+
}
|
|
53
|
+
async get(config) {
|
|
54
|
+
const value = await this.getTuple(config);
|
|
55
|
+
return value ? value.checkpoint : undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Generate the next version ID for a channel.
|
|
59
|
+
*
|
|
60
|
+
* Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,
|
|
61
|
+
* as long as they are monotonically increasing.
|
|
62
|
+
*/
|
|
63
|
+
getNextVersion(current, _channel) {
|
|
64
|
+
return current !== undefined ? current + 1 : 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.BaseCheckpointSaver = BaseCheckpointSaver;
|
package/dist/base.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
2
|
+
import { SerializerProtocol } from "./serde/base.js";
|
|
3
|
+
import type { PendingWrite, CheckpointPendingWrite, CheckpointMetadata } from "./types.js";
|
|
4
|
+
import type { ChannelProtocol, SendProtocol } from "./serde/types.js";
|
|
5
|
+
export type ChannelVersions = Record<string, string | number>;
|
|
6
|
+
export interface Checkpoint<N extends string = string, C extends string = string> {
|
|
7
|
+
/**
|
|
8
|
+
* Version number
|
|
9
|
+
*/
|
|
10
|
+
v: number;
|
|
11
|
+
/**
|
|
12
|
+
* Checkpoint ID {uuid6}
|
|
13
|
+
*/
|
|
14
|
+
id: string;
|
|
15
|
+
/**
|
|
16
|
+
* Timestamp {new Date().toISOString()}
|
|
17
|
+
*/
|
|
18
|
+
ts: string;
|
|
19
|
+
/**
|
|
20
|
+
* @default {}
|
|
21
|
+
*/
|
|
22
|
+
channel_values: Record<C, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* @default {}
|
|
25
|
+
*/
|
|
26
|
+
channel_versions: Record<C, number>;
|
|
27
|
+
/**
|
|
28
|
+
* @default {}
|
|
29
|
+
*/
|
|
30
|
+
versions_seen: Record<N, Record<C, number>>;
|
|
31
|
+
/**
|
|
32
|
+
* List of packets sent to nodes but not yet processed.
|
|
33
|
+
* Cleared by the next checkpoint.
|
|
34
|
+
*/
|
|
35
|
+
pending_sends: SendProtocol[];
|
|
36
|
+
}
|
|
37
|
+
export interface ReadonlyCheckpoint extends Readonly<Checkpoint> {
|
|
38
|
+
readonly channel_values: Readonly<Record<string, unknown>>;
|
|
39
|
+
readonly channel_versions: Readonly<Record<string, number>>;
|
|
40
|
+
readonly versions_seen: Readonly<Record<string, Readonly<Record<string, number>>>>;
|
|
41
|
+
}
|
|
42
|
+
export declare function deepCopy<T>(obj: T): T;
|
|
43
|
+
export declare function emptyCheckpoint(): Checkpoint;
|
|
44
|
+
export declare function copyCheckpoint(checkpoint: ReadonlyCheckpoint): Checkpoint;
|
|
45
|
+
export interface CheckpointTuple {
|
|
46
|
+
config: RunnableConfig;
|
|
47
|
+
checkpoint: Checkpoint;
|
|
48
|
+
metadata?: CheckpointMetadata;
|
|
49
|
+
parentConfig?: RunnableConfig;
|
|
50
|
+
pendingWrites?: CheckpointPendingWrite[];
|
|
51
|
+
}
|
|
52
|
+
export type CheckpointListOptions = {
|
|
53
|
+
limit?: number;
|
|
54
|
+
before?: RunnableConfig;
|
|
55
|
+
filter?: Record<string, any>;
|
|
56
|
+
};
|
|
57
|
+
export declare abstract class BaseCheckpointSaver<V = number> {
|
|
58
|
+
serde: SerializerProtocol<unknown>;
|
|
59
|
+
constructor(serde?: SerializerProtocol<unknown>);
|
|
60
|
+
get(config: RunnableConfig): Promise<Checkpoint | undefined>;
|
|
61
|
+
abstract getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
|
|
62
|
+
abstract list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
|
|
63
|
+
abstract put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, newVersions: ChannelVersions): Promise<RunnableConfig>;
|
|
64
|
+
/**
|
|
65
|
+
* Store intermediate writes linked to a checkpoint.
|
|
66
|
+
*/
|
|
67
|
+
abstract putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Generate the next version ID for a channel.
|
|
70
|
+
*
|
|
71
|
+
* Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,
|
|
72
|
+
* as long as they are monotonically increasing.
|
|
73
|
+
*/
|
|
74
|
+
getNextVersion(current: V | undefined, _channel: ChannelProtocol): number;
|
|
75
|
+
}
|
package/dist/base.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { DefaultSerializer } from "./serde/base.js";
|
|
2
|
+
import { uuid6 } from "./id.js";
|
|
3
|
+
export function deepCopy(obj) {
|
|
4
|
+
if (typeof obj !== "object" || obj === null) {
|
|
5
|
+
return obj;
|
|
6
|
+
}
|
|
7
|
+
const newObj = Array.isArray(obj) ? [] : {};
|
|
8
|
+
for (const key in obj) {
|
|
9
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
10
|
+
newObj[key] = deepCopy(obj[key]);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return newObj;
|
|
14
|
+
}
|
|
15
|
+
export function emptyCheckpoint() {
|
|
16
|
+
return {
|
|
17
|
+
v: 1,
|
|
18
|
+
id: uuid6(-2),
|
|
19
|
+
ts: new Date().toISOString(),
|
|
20
|
+
channel_values: {},
|
|
21
|
+
channel_versions: {},
|
|
22
|
+
versions_seen: {},
|
|
23
|
+
pending_sends: [],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function copyCheckpoint(checkpoint) {
|
|
27
|
+
return {
|
|
28
|
+
v: checkpoint.v,
|
|
29
|
+
id: checkpoint.id,
|
|
30
|
+
ts: checkpoint.ts,
|
|
31
|
+
channel_values: { ...checkpoint.channel_values },
|
|
32
|
+
channel_versions: { ...checkpoint.channel_versions },
|
|
33
|
+
versions_seen: deepCopy(checkpoint.versions_seen),
|
|
34
|
+
pending_sends: [...checkpoint.pending_sends],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export class BaseCheckpointSaver {
|
|
38
|
+
constructor(serde) {
|
|
39
|
+
Object.defineProperty(this, "serde", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: DefaultSerializer
|
|
44
|
+
});
|
|
45
|
+
this.serde = serde || this.serde;
|
|
46
|
+
}
|
|
47
|
+
async get(config) {
|
|
48
|
+
const value = await this.getTuple(config);
|
|
49
|
+
return value ? value.checkpoint : undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Generate the next version ID for a channel.
|
|
53
|
+
*
|
|
54
|
+
* Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,
|
|
55
|
+
* as long as they are monotonically increasing.
|
|
56
|
+
*/
|
|
57
|
+
getNextVersion(current, _channel) {
|
|
58
|
+
return current !== undefined ? current + 1 : 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
package/dist/id.cjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uuid5 = exports.uuid6 = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
function uuid6(clockseq) {
|
|
6
|
+
return (0, uuid_1.v6)({ clockseq });
|
|
7
|
+
}
|
|
8
|
+
exports.uuid6 = uuid6;
|
|
9
|
+
// Skip UUID validation check, since UUID6s
|
|
10
|
+
// generated with negative clockseq are not
|
|
11
|
+
// technically compliant, but still work.
|
|
12
|
+
// See: https://github.com/uuidjs/uuid/issues/511
|
|
13
|
+
function uuid5(name, namespace) {
|
|
14
|
+
const namespaceBytes = namespace
|
|
15
|
+
.replace(/-/g, "")
|
|
16
|
+
.match(/.{2}/g)
|
|
17
|
+
.map((byte) => parseInt(byte, 16));
|
|
18
|
+
return (0, uuid_1.v5)(name, new Uint8Array(namespaceBytes));
|
|
19
|
+
}
|
|
20
|
+
exports.uuid5 = uuid5;
|
package/dist/id.d.ts
ADDED
package/dist/id.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { v5, v6 } from "uuid";
|
|
2
|
+
export function uuid6(clockseq) {
|
|
3
|
+
return v6({ clockseq });
|
|
4
|
+
}
|
|
5
|
+
// Skip UUID validation check, since UUID6s
|
|
6
|
+
// generated with negative clockseq are not
|
|
7
|
+
// technically compliant, but still work.
|
|
8
|
+
// See: https://github.com/uuidjs/uuid/issues/511
|
|
9
|
+
export function uuid5(name, namespace) {
|
|
10
|
+
const namespaceBytes = namespace
|
|
11
|
+
.replace(/-/g, "")
|
|
12
|
+
.match(/.{2}/g)
|
|
13
|
+
.map((byte) => parseInt(byte, 16));
|
|
14
|
+
return v5(name, new Uint8Array(namespaceBytes));
|
|
15
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.MemorySaver = void 0;
|
|
18
|
+
var memory_js_1 = require("./memory.cjs");
|
|
19
|
+
Object.defineProperty(exports, "MemorySaver", { enumerable: true, get: function () { return memory_js_1.MemorySaver; } });
|
|
20
|
+
__exportStar(require("./base.cjs"), exports);
|
|
21
|
+
__exportStar(require("./id.cjs"), exports);
|
|
22
|
+
__exportStar(require("./types.cjs"), exports);
|
|
23
|
+
__exportStar(require("./serde/base.cjs"), exports);
|
|
24
|
+
__exportStar(require("./serde/types.cjs"), exports);
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/memory.cjs
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemorySaver = void 0;
|
|
4
|
+
const base_js_1 = require("./base.cjs");
|
|
5
|
+
function _generateKey(threadId, checkpointNamespace, checkpointId) {
|
|
6
|
+
return JSON.stringify([threadId, checkpointNamespace, checkpointId]);
|
|
7
|
+
}
|
|
8
|
+
class MemorySaver extends base_js_1.BaseCheckpointSaver {
|
|
9
|
+
constructor(serde) {
|
|
10
|
+
super(serde);
|
|
11
|
+
// thread ID -> checkpoint namespace -> checkpoint ID -> checkpoint mapping
|
|
12
|
+
Object.defineProperty(this, "storage", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: {}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(this, "writes", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: {}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async getTuple(config) {
|
|
26
|
+
const thread_id = config.configurable?.thread_id;
|
|
27
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
28
|
+
let checkpoint_id = config.configurable?.checkpoint_id;
|
|
29
|
+
if (checkpoint_id) {
|
|
30
|
+
const saved = this.storage[thread_id]?.[checkpoint_ns]?.[checkpoint_id];
|
|
31
|
+
if (saved !== undefined) {
|
|
32
|
+
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
33
|
+
const writes = this.writes[_generateKey(thread_id, checkpoint_ns, checkpoint_id)] ??
|
|
34
|
+
[];
|
|
35
|
+
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
36
|
+
return [taskId, channel, await this.serde.parse(value)];
|
|
37
|
+
}));
|
|
38
|
+
const parentConfig = parentCheckpointId !== undefined
|
|
39
|
+
? {
|
|
40
|
+
configurable: {
|
|
41
|
+
thread_id,
|
|
42
|
+
checkpoint_ns,
|
|
43
|
+
checkpoint_id,
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
: undefined;
|
|
47
|
+
return {
|
|
48
|
+
config,
|
|
49
|
+
checkpoint: (await this.serde.parse(checkpoint)),
|
|
50
|
+
metadata: (await this.serde.parse(metadata)),
|
|
51
|
+
pendingWrites,
|
|
52
|
+
parentConfig,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const checkpoints = this.storage[thread_id]?.[checkpoint_ns];
|
|
58
|
+
if (checkpoints !== undefined) {
|
|
59
|
+
// eslint-disable-next-line prefer-destructuring
|
|
60
|
+
checkpoint_id = Object.keys(checkpoints).sort((a, b) => b.localeCompare(a))[0];
|
|
61
|
+
const saved = checkpoints[checkpoint_id];
|
|
62
|
+
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
63
|
+
const writes = this.writes[_generateKey(thread_id, checkpoint_ns, checkpoint_id)] ??
|
|
64
|
+
[];
|
|
65
|
+
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
66
|
+
return [taskId, channel, await this.serde.parse(value)];
|
|
67
|
+
}));
|
|
68
|
+
const parentConfig = parentCheckpointId !== undefined
|
|
69
|
+
? {
|
|
70
|
+
configurable: {
|
|
71
|
+
thread_id,
|
|
72
|
+
checkpoint_ns,
|
|
73
|
+
checkpoint_id: parentCheckpointId,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: undefined;
|
|
77
|
+
return {
|
|
78
|
+
config: {
|
|
79
|
+
configurable: {
|
|
80
|
+
thread_id,
|
|
81
|
+
checkpoint_id,
|
|
82
|
+
checkpoint_ns,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
checkpoint: (await this.serde.parse(checkpoint)),
|
|
86
|
+
metadata: (await this.serde.parse(metadata)),
|
|
87
|
+
pendingWrites,
|
|
88
|
+
parentConfig,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
async *list(config, options) {
|
|
95
|
+
// eslint-disable-next-line prefer-const
|
|
96
|
+
let { before, limit } = options ?? {};
|
|
97
|
+
const threadIds = config.configurable?.thread_id
|
|
98
|
+
? [config.configurable?.thread_id]
|
|
99
|
+
: Object.keys(this.storage);
|
|
100
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
|
|
101
|
+
for (const threadId of threadIds) {
|
|
102
|
+
const checkpoints = this.storage[threadId]?.[checkpointNamespace] ?? {};
|
|
103
|
+
const sortedCheckpoints = Object.entries(checkpoints).sort((a, b) => b[0].localeCompare(a[0]));
|
|
104
|
+
for (const [checkpointId, [checkpoint, metadataStr, parentCheckpointId],] of sortedCheckpoints) {
|
|
105
|
+
// Filter by checkpoint ID
|
|
106
|
+
if (before &&
|
|
107
|
+
before.configurable?.checkpoint_id &&
|
|
108
|
+
checkpointId >= before.configurable.checkpoint_id) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Parse metadata
|
|
112
|
+
const metadata = (await this.serde.parse(metadataStr));
|
|
113
|
+
// Limit search results
|
|
114
|
+
if (limit !== undefined) {
|
|
115
|
+
if (limit <= 0)
|
|
116
|
+
break;
|
|
117
|
+
// eslint-disable-next-line no-param-reassign
|
|
118
|
+
limit -= 1;
|
|
119
|
+
}
|
|
120
|
+
const writes = this.writes[_generateKey(threadId, checkpointNamespace, checkpointId)] ?? [];
|
|
121
|
+
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
122
|
+
return [taskId, channel, await this.serde.parse(value)];
|
|
123
|
+
}));
|
|
124
|
+
yield {
|
|
125
|
+
config: {
|
|
126
|
+
configurable: {
|
|
127
|
+
thread_id: threadId,
|
|
128
|
+
checkpoint_ns: checkpointNamespace,
|
|
129
|
+
checkpoint_id: checkpointId,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
checkpoint: (await this.serde.parse(checkpoint)),
|
|
133
|
+
metadata,
|
|
134
|
+
pendingWrites,
|
|
135
|
+
parentConfig: parentCheckpointId
|
|
136
|
+
? {
|
|
137
|
+
configurable: {
|
|
138
|
+
thread_id: threadId,
|
|
139
|
+
checkpoint_ns: checkpointNamespace,
|
|
140
|
+
checkpoint_id: parentCheckpointId,
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
: undefined,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async put(config, checkpoint, metadata) {
|
|
149
|
+
const threadId = config.configurable?.thread_id;
|
|
150
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns;
|
|
151
|
+
if (threadId === undefined) {
|
|
152
|
+
throw new Error(`Failed to put checkpoint. The passed RunnableConfig is missing a required "thread_id" field in its "configurable" property.`);
|
|
153
|
+
}
|
|
154
|
+
if (checkpointNamespace === undefined) {
|
|
155
|
+
throw new Error(`Failed to put checkpoint. The passed RunnableConfig is missing a required "checkpoint_ns" field in its "configurable" property.`);
|
|
156
|
+
}
|
|
157
|
+
if (!this.storage[threadId]) {
|
|
158
|
+
this.storage[threadId] = {};
|
|
159
|
+
}
|
|
160
|
+
if (!this.storage[threadId][checkpointNamespace]) {
|
|
161
|
+
this.storage[threadId][checkpointNamespace] = {};
|
|
162
|
+
}
|
|
163
|
+
this.storage[threadId][checkpointNamespace][checkpoint.id] = [
|
|
164
|
+
this.serde.stringify(checkpoint),
|
|
165
|
+
this.serde.stringify(metadata),
|
|
166
|
+
config.configurable?.checkpoint_id, // parent
|
|
167
|
+
];
|
|
168
|
+
return {
|
|
169
|
+
configurable: {
|
|
170
|
+
thread_id: threadId,
|
|
171
|
+
checkpoint_ns: checkpointNamespace,
|
|
172
|
+
checkpoint_id: checkpoint.id,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async putWrites(config, writes, taskId) {
|
|
177
|
+
const threadId = config.configurable?.thread_id;
|
|
178
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns;
|
|
179
|
+
const checkpointId = config.configurable?.checkpoint_id;
|
|
180
|
+
if (threadId === undefined) {
|
|
181
|
+
throw new Error(`Failed to put writes. The passed RunnableConfig is missing a required "thread_id" field in its "configurable" property`);
|
|
182
|
+
}
|
|
183
|
+
if (checkpointId === undefined) {
|
|
184
|
+
throw new Error(`Failed to put writes. The passed RunnableConfig is missing a required "checkpoint_id" field in its "configurable" property.`);
|
|
185
|
+
}
|
|
186
|
+
const key = _generateKey(threadId, checkpointNamespace, checkpointId);
|
|
187
|
+
if (this.writes[key] === undefined) {
|
|
188
|
+
this.writes[key] = [];
|
|
189
|
+
}
|
|
190
|
+
const pendingWrites = writes.map(([channel, value]) => {
|
|
191
|
+
return [taskId, channel, this.serde.stringify(value)];
|
|
192
|
+
});
|
|
193
|
+
this.writes[key].push(...pendingWrites);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.MemorySaver = MemorySaver;
|
package/dist/memory.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
2
|
+
import { BaseCheckpointSaver, Checkpoint, CheckpointListOptions, CheckpointTuple } from "./base.js";
|
|
3
|
+
import { SerializerProtocol } from "./serde/base.js";
|
|
4
|
+
import { CheckpointMetadata, CheckpointPendingWrite, PendingWrite } from "./types.js";
|
|
5
|
+
export declare class MemorySaver extends BaseCheckpointSaver {
|
|
6
|
+
storage: Record<string, Record<string, Record<string, [string, string, string | undefined]>>>;
|
|
7
|
+
writes: Record<string, CheckpointPendingWrite[]>;
|
|
8
|
+
constructor(serde?: SerializerProtocol<unknown>);
|
|
9
|
+
getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
|
|
10
|
+
list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
|
|
11
|
+
put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata): Promise<RunnableConfig>;
|
|
12
|
+
putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void>;
|
|
13
|
+
}
|
package/dist/memory.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { BaseCheckpointSaver, } from "./base.js";
|
|
2
|
+
function _generateKey(threadId, checkpointNamespace, checkpointId) {
|
|
3
|
+
return JSON.stringify([threadId, checkpointNamespace, checkpointId]);
|
|
4
|
+
}
|
|
5
|
+
export class MemorySaver extends BaseCheckpointSaver {
|
|
6
|
+
constructor(serde) {
|
|
7
|
+
super(serde);
|
|
8
|
+
// thread ID -> checkpoint namespace -> checkpoint ID -> checkpoint mapping
|
|
9
|
+
Object.defineProperty(this, "storage", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true,
|
|
13
|
+
value: {}
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(this, "writes", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: {}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async getTuple(config) {
|
|
23
|
+
const thread_id = config.configurable?.thread_id;
|
|
24
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
25
|
+
let checkpoint_id = config.configurable?.checkpoint_id;
|
|
26
|
+
if (checkpoint_id) {
|
|
27
|
+
const saved = this.storage[thread_id]?.[checkpoint_ns]?.[checkpoint_id];
|
|
28
|
+
if (saved !== undefined) {
|
|
29
|
+
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
30
|
+
const writes = this.writes[_generateKey(thread_id, checkpoint_ns, checkpoint_id)] ??
|
|
31
|
+
[];
|
|
32
|
+
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
33
|
+
return [taskId, channel, await this.serde.parse(value)];
|
|
34
|
+
}));
|
|
35
|
+
const parentConfig = parentCheckpointId !== undefined
|
|
36
|
+
? {
|
|
37
|
+
configurable: {
|
|
38
|
+
thread_id,
|
|
39
|
+
checkpoint_ns,
|
|
40
|
+
checkpoint_id,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
: undefined;
|
|
44
|
+
return {
|
|
45
|
+
config,
|
|
46
|
+
checkpoint: (await this.serde.parse(checkpoint)),
|
|
47
|
+
metadata: (await this.serde.parse(metadata)),
|
|
48
|
+
pendingWrites,
|
|
49
|
+
parentConfig,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const checkpoints = this.storage[thread_id]?.[checkpoint_ns];
|
|
55
|
+
if (checkpoints !== undefined) {
|
|
56
|
+
// eslint-disable-next-line prefer-destructuring
|
|
57
|
+
checkpoint_id = Object.keys(checkpoints).sort((a, b) => b.localeCompare(a))[0];
|
|
58
|
+
const saved = checkpoints[checkpoint_id];
|
|
59
|
+
const [checkpoint, metadata, parentCheckpointId] = saved;
|
|
60
|
+
const writes = this.writes[_generateKey(thread_id, checkpoint_ns, checkpoint_id)] ??
|
|
61
|
+
[];
|
|
62
|
+
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
63
|
+
return [taskId, channel, await this.serde.parse(value)];
|
|
64
|
+
}));
|
|
65
|
+
const parentConfig = parentCheckpointId !== undefined
|
|
66
|
+
? {
|
|
67
|
+
configurable: {
|
|
68
|
+
thread_id,
|
|
69
|
+
checkpoint_ns,
|
|
70
|
+
checkpoint_id: parentCheckpointId,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
: undefined;
|
|
74
|
+
return {
|
|
75
|
+
config: {
|
|
76
|
+
configurable: {
|
|
77
|
+
thread_id,
|
|
78
|
+
checkpoint_id,
|
|
79
|
+
checkpoint_ns,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
checkpoint: (await this.serde.parse(checkpoint)),
|
|
83
|
+
metadata: (await this.serde.parse(metadata)),
|
|
84
|
+
pendingWrites,
|
|
85
|
+
parentConfig,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
async *list(config, options) {
|
|
92
|
+
// eslint-disable-next-line prefer-const
|
|
93
|
+
let { before, limit } = options ?? {};
|
|
94
|
+
const threadIds = config.configurable?.thread_id
|
|
95
|
+
? [config.configurable?.thread_id]
|
|
96
|
+
: Object.keys(this.storage);
|
|
97
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns ?? "";
|
|
98
|
+
for (const threadId of threadIds) {
|
|
99
|
+
const checkpoints = this.storage[threadId]?.[checkpointNamespace] ?? {};
|
|
100
|
+
const sortedCheckpoints = Object.entries(checkpoints).sort((a, b) => b[0].localeCompare(a[0]));
|
|
101
|
+
for (const [checkpointId, [checkpoint, metadataStr, parentCheckpointId],] of sortedCheckpoints) {
|
|
102
|
+
// Filter by checkpoint ID
|
|
103
|
+
if (before &&
|
|
104
|
+
before.configurable?.checkpoint_id &&
|
|
105
|
+
checkpointId >= before.configurable.checkpoint_id) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// Parse metadata
|
|
109
|
+
const metadata = (await this.serde.parse(metadataStr));
|
|
110
|
+
// Limit search results
|
|
111
|
+
if (limit !== undefined) {
|
|
112
|
+
if (limit <= 0)
|
|
113
|
+
break;
|
|
114
|
+
// eslint-disable-next-line no-param-reassign
|
|
115
|
+
limit -= 1;
|
|
116
|
+
}
|
|
117
|
+
const writes = this.writes[_generateKey(threadId, checkpointNamespace, checkpointId)] ?? [];
|
|
118
|
+
const pendingWrites = await Promise.all(writes.map(async ([taskId, channel, value]) => {
|
|
119
|
+
return [taskId, channel, await this.serde.parse(value)];
|
|
120
|
+
}));
|
|
121
|
+
yield {
|
|
122
|
+
config: {
|
|
123
|
+
configurable: {
|
|
124
|
+
thread_id: threadId,
|
|
125
|
+
checkpoint_ns: checkpointNamespace,
|
|
126
|
+
checkpoint_id: checkpointId,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
checkpoint: (await this.serde.parse(checkpoint)),
|
|
130
|
+
metadata,
|
|
131
|
+
pendingWrites,
|
|
132
|
+
parentConfig: parentCheckpointId
|
|
133
|
+
? {
|
|
134
|
+
configurable: {
|
|
135
|
+
thread_id: threadId,
|
|
136
|
+
checkpoint_ns: checkpointNamespace,
|
|
137
|
+
checkpoint_id: parentCheckpointId,
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
: undefined,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async put(config, checkpoint, metadata) {
|
|
146
|
+
const threadId = config.configurable?.thread_id;
|
|
147
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns;
|
|
148
|
+
if (threadId === undefined) {
|
|
149
|
+
throw new Error(`Failed to put checkpoint. The passed RunnableConfig is missing a required "thread_id" field in its "configurable" property.`);
|
|
150
|
+
}
|
|
151
|
+
if (checkpointNamespace === undefined) {
|
|
152
|
+
throw new Error(`Failed to put checkpoint. The passed RunnableConfig is missing a required "checkpoint_ns" field in its "configurable" property.`);
|
|
153
|
+
}
|
|
154
|
+
if (!this.storage[threadId]) {
|
|
155
|
+
this.storage[threadId] = {};
|
|
156
|
+
}
|
|
157
|
+
if (!this.storage[threadId][checkpointNamespace]) {
|
|
158
|
+
this.storage[threadId][checkpointNamespace] = {};
|
|
159
|
+
}
|
|
160
|
+
this.storage[threadId][checkpointNamespace][checkpoint.id] = [
|
|
161
|
+
this.serde.stringify(checkpoint),
|
|
162
|
+
this.serde.stringify(metadata),
|
|
163
|
+
config.configurable?.checkpoint_id, // parent
|
|
164
|
+
];
|
|
165
|
+
return {
|
|
166
|
+
configurable: {
|
|
167
|
+
thread_id: threadId,
|
|
168
|
+
checkpoint_ns: checkpointNamespace,
|
|
169
|
+
checkpoint_id: checkpoint.id,
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async putWrites(config, writes, taskId) {
|
|
174
|
+
const threadId = config.configurable?.thread_id;
|
|
175
|
+
const checkpointNamespace = config.configurable?.checkpoint_ns;
|
|
176
|
+
const checkpointId = config.configurable?.checkpoint_id;
|
|
177
|
+
if (threadId === undefined) {
|
|
178
|
+
throw new Error(`Failed to put writes. The passed RunnableConfig is missing a required "thread_id" field in its "configurable" property`);
|
|
179
|
+
}
|
|
180
|
+
if (checkpointId === undefined) {
|
|
181
|
+
throw new Error(`Failed to put writes. The passed RunnableConfig is missing a required "checkpoint_id" field in its "configurable" property.`);
|
|
182
|
+
}
|
|
183
|
+
const key = _generateKey(threadId, checkpointNamespace, checkpointId);
|
|
184
|
+
if (this.writes[key] === undefined) {
|
|
185
|
+
this.writes[key] = [];
|
|
186
|
+
}
|
|
187
|
+
const pendingWrites = writes.map(([channel, value]) => {
|
|
188
|
+
return [taskId, channel, this.serde.stringify(value)];
|
|
189
|
+
});
|
|
190
|
+
this.writes[key].push(...pendingWrites);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { load } from "@langchain/core/load";
|
|
2
|
+
export interface SerializerProtocol<D> {
|
|
3
|
+
stringify(obj: D): string;
|
|
4
|
+
parse(data: string): Promise<D>;
|
|
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
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface ChannelProtocol<ValueType = unknown, UpdateType = unknown, CheckpointType = unknown> {
|
|
2
|
+
ValueType: ValueType;
|
|
3
|
+
UpdateType: UpdateType;
|
|
4
|
+
/**
|
|
5
|
+
* The name of the channel.
|
|
6
|
+
*/
|
|
7
|
+
lc_graph_name: string;
|
|
8
|
+
/**
|
|
9
|
+
* Return a new identical channel, optionally initialized from a checkpoint.
|
|
10
|
+
* Can be thought of as a "restoration" from a checkpoint which is a "snapshot" of the channel's state.
|
|
11
|
+
*
|
|
12
|
+
* @param {CheckpointType | undefined} checkpoint
|
|
13
|
+
* @param {CheckpointType | undefined} initialValue
|
|
14
|
+
* @returns {this}
|
|
15
|
+
*/
|
|
16
|
+
fromCheckpoint(checkpoint?: CheckpointType): this;
|
|
17
|
+
/**
|
|
18
|
+
* Update the channel's value with the given sequence of updates.
|
|
19
|
+
* The order of the updates in the sequence is arbitrary.
|
|
20
|
+
*
|
|
21
|
+
* @throws {InvalidUpdateError} if the sequence of updates is invalid.
|
|
22
|
+
* @param {Array<UpdateType>} values
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
update(values: UpdateType[]): void;
|
|
26
|
+
/**
|
|
27
|
+
* Return the current value of the channel.
|
|
28
|
+
*
|
|
29
|
+
* @throws {EmptyChannelError} if the channel is empty (never updated yet).
|
|
30
|
+
* @returns {ValueType}
|
|
31
|
+
*/
|
|
32
|
+
get(): ValueType;
|
|
33
|
+
/**
|
|
34
|
+
* Return a string representation of the channel's current state.
|
|
35
|
+
*
|
|
36
|
+
* @throws {EmptyChannelError} if the channel is empty (never updated yet), or doesn't support checkpoints.
|
|
37
|
+
* @returns {CheckpointType | undefined}
|
|
38
|
+
*/
|
|
39
|
+
checkpoint(): CheckpointType | undefined;
|
|
40
|
+
}
|
|
41
|
+
export interface SendProtocol {
|
|
42
|
+
node: string;
|
|
43
|
+
args: any;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.cjs
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type All = "*";
|
|
2
|
+
export type PendingWriteValue = unknown;
|
|
3
|
+
export type PendingWrite<Channel = string> = [Channel, PendingWriteValue];
|
|
4
|
+
export type CheckpointPendingWrite<TaskId = string> = [
|
|
5
|
+
TaskId,
|
|
6
|
+
...PendingWrite<string>
|
|
7
|
+
];
|
|
8
|
+
export interface CheckpointMetadata {
|
|
9
|
+
/**
|
|
10
|
+
* The source of the checkpoint.
|
|
11
|
+
* - "input": The checkpoint was created from an input to invoke/stream/batch.
|
|
12
|
+
* - "loop": The checkpoint was created from inside the pregel loop.
|
|
13
|
+
* - "update": The checkpoint was created from a manual state update.
|
|
14
|
+
*/
|
|
15
|
+
source: "input" | "loop" | "update";
|
|
16
|
+
/**
|
|
17
|
+
* The step number of the checkpoint.
|
|
18
|
+
* -1 for the first "input" checkpoint.
|
|
19
|
+
* 0 for the first "loop" checkpoint.
|
|
20
|
+
* ... for the nth checkpoint afterwards.
|
|
21
|
+
*/
|
|
22
|
+
step: number;
|
|
23
|
+
/**
|
|
24
|
+
* The writes that were made between the previous checkpoint and this one.
|
|
25
|
+
* Mapping from node name to writes emitted by that node.
|
|
26
|
+
*/
|
|
27
|
+
writes: Record<string, unknown> | null;
|
|
28
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/index.cjs');
|
package/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/index.js'
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/index.js'
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/index.js'
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@langchain/langgraph-checkpoint",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Library with base interfaces for LangGraph checkpoint savers.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"main": "./index.js",
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git@github.com:langchain-ai/langgraphjs.git"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "yarn turbo:command build:internal --filter=@langchain/langgraph-checkpoint",
|
|
17
|
+
"build:internal": "yarn lc_build_v2 --create-entrypoints --pre --tree-shaking",
|
|
18
|
+
"lint:eslint": "NODE_OPTIONS=--max-old-space-size=4096 eslint --cache --ext .ts,.js src/",
|
|
19
|
+
"lint:dpdm": "dpdm --exit-code circular:1 --no-warning --no-tree src/*.ts src/**/*.ts",
|
|
20
|
+
"lint": "yarn lint:eslint && yarn lint:dpdm",
|
|
21
|
+
"lint:fix": "yarn lint:eslint --fix && yarn lint:dpdm",
|
|
22
|
+
"prepack": "yarn build",
|
|
23
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000 --maxWorkers=50%",
|
|
24
|
+
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --testPathIgnorePatterns=\\.int\\.test.ts",
|
|
25
|
+
"test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
|
|
26
|
+
"test:int": "NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
|
|
27
|
+
"format": "prettier --config .prettierrc --write \"src\"",
|
|
28
|
+
"format:check": "prettier --config .prettierrc --check \"src\""
|
|
29
|
+
},
|
|
30
|
+
"author": "LangChain",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"uuid": "^10.0.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@langchain/core": ">=0.2.20 <0.3.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@jest/globals": "^29.5.0",
|
|
40
|
+
"@langchain/scripts": "^0.0.22",
|
|
41
|
+
"@swc/core": "^1.3.90",
|
|
42
|
+
"@swc/jest": "^0.2.29",
|
|
43
|
+
"@tsconfig/recommended": "^1.0.3",
|
|
44
|
+
"@types/uuid": "^10",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
|
46
|
+
"@typescript-eslint/parser": "^6.12.0",
|
|
47
|
+
"dotenv": "^16.3.1",
|
|
48
|
+
"dpdm": "^3.12.0",
|
|
49
|
+
"eslint": "^8.33.0",
|
|
50
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
51
|
+
"eslint-config-prettier": "^8.6.0",
|
|
52
|
+
"eslint-plugin-import": "^2.29.1",
|
|
53
|
+
"eslint-plugin-jest": "^28.8.0",
|
|
54
|
+
"eslint-plugin-no-instanceof": "^1.0.1",
|
|
55
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
56
|
+
"jest": "^29.5.0",
|
|
57
|
+
"jest-environment-node": "^29.6.4",
|
|
58
|
+
"prettier": "^2.8.3",
|
|
59
|
+
"release-it": "^17.6.0",
|
|
60
|
+
"rollup": "^4.5.2",
|
|
61
|
+
"ts-jest": "^29.1.0",
|
|
62
|
+
"tsx": "^4.7.0",
|
|
63
|
+
"typescript": "^4.9.5 || ^5.4.5"
|
|
64
|
+
},
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public",
|
|
67
|
+
"registry": "https://registry.npmjs.org/"
|
|
68
|
+
},
|
|
69
|
+
"exports": {
|
|
70
|
+
".": {
|
|
71
|
+
"types": {
|
|
72
|
+
"import": "./index.d.ts",
|
|
73
|
+
"require": "./index.d.cts",
|
|
74
|
+
"default": "./index.d.ts"
|
|
75
|
+
},
|
|
76
|
+
"import": "./index.js",
|
|
77
|
+
"require": "./index.cjs"
|
|
78
|
+
},
|
|
79
|
+
"./package.json": "./package.json"
|
|
80
|
+
},
|
|
81
|
+
"files": [
|
|
82
|
+
"dist/",
|
|
83
|
+
"index.cjs",
|
|
84
|
+
"index.js",
|
|
85
|
+
"index.d.ts",
|
|
86
|
+
"index.d.cts"
|
|
87
|
+
]
|
|
88
|
+
}
|