agentsmcp-langgraph 0.1.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 +98 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/os-shim.d.ts +3 -0
- package/dist/os-shim.d.ts.map +1 -0
- package/dist/os-shim.js +41 -0
- package/dist/os-shim.js.map +1 -0
- package/dist/saver.d.ts +53 -0
- package/dist/saver.d.ts.map +1 -0
- package/dist/saver.js +287 -0
- package/dist/saver.js.map +1 -0
- package/dist/serializer.d.ts +13 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/serializer.js +20 -0
- package/dist/serializer.js.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AgentMailbox contributors
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# agentsmcp-langgraph
|
|
2
|
+
|
|
3
|
+
LangGraph checkpointer backed by [agentsmcp](https://www.npmjs.com/package/agentsmcp).
|
|
4
|
+
Drop-in `BaseCheckpointSaver` — your graph state lives in an AgentMailbox
|
|
5
|
+
thread, so it survives process restarts, runs across machines, and is
|
|
6
|
+
inspectable from any other agentsmcp client.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install agentsmcp-langgraph @langchain/langgraph
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
You'll also need an agentsmcp HTTP server reachable from your process.
|
|
15
|
+
Run it locally with `npx agentsmcp-server`, or point at any deployment.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { StateGraph } from "@langchain/langgraph";
|
|
21
|
+
import { AgentsmcpSaver } from "agentsmcp-langgraph";
|
|
22
|
+
|
|
23
|
+
const checkpointer = new AgentsmcpSaver({
|
|
24
|
+
server: process.env.AGENTSMCP_SERVER ?? "http://localhost:3000",
|
|
25
|
+
agentId: "langgraph@my-app", // stable identity = stable threads
|
|
26
|
+
apiKey: process.env.AGENTSMCP_API_KEY,
|
|
27
|
+
});
|
|
28
|
+
await checkpointer.connect();
|
|
29
|
+
|
|
30
|
+
const graph = workflow.compile({ checkpointer });
|
|
31
|
+
|
|
32
|
+
await graph.invoke(input, {
|
|
33
|
+
configurable: { thread_id: "session-abc" },
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Restart the process, invoke again with the same `thread_id`, and the
|
|
38
|
+
graph picks up exactly where it left off. Same property in another
|
|
39
|
+
process on another machine, as long as `agentId` and `thread_id` match.
|
|
40
|
+
|
|
41
|
+
## How it maps
|
|
42
|
+
|
|
43
|
+
| LangGraph | agentsmcp |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `thread_id` (RunnableConfig) | One thread per `thread_id` |
|
|
46
|
+
| `checkpoint_id` (uuid6) | Stored in the message payload |
|
|
47
|
+
| `Checkpoint` bytes | Base64'd into `payload.checkpoint` |
|
|
48
|
+
| `CheckpointMetadata` bytes | Base64'd into `payload.metadata` |
|
|
49
|
+
| `pendingWrites` | Sibling messages of `kind: "writes"`, merged on read |
|
|
50
|
+
| `checkpoint_ns` | Filter tag inside the payload — subgraphs isolated |
|
|
51
|
+
|
|
52
|
+
The recipient on every message is the synthetic agent
|
|
53
|
+
`{thread_id}@checkpoints`. It's never real; it just gives the thread
|
|
54
|
+
a stable identity so cold-restart can look it up by participant.
|
|
55
|
+
|
|
56
|
+
## What you get vs `MemorySaver` / `SqliteSaver`
|
|
57
|
+
|
|
58
|
+
- **Cross-process** — write from one node, read from another. No file
|
|
59
|
+
to share, no DB to provision; just an HTTP URL.
|
|
60
|
+
- **Inspectable** — every checkpoint is a message on a thread. Any
|
|
61
|
+
agentsmcp client (the JS/Python SDK, the MCP adapter, `curl`) can
|
|
62
|
+
read the state of your graph at any point in its history.
|
|
63
|
+
- **Compressed when long** — once a thread crosses the configured
|
|
64
|
+
compression threshold (default 20 messages), the agentsmcp server
|
|
65
|
+
folds older checkpoints into a structured summary that you can use
|
|
66
|
+
alongside the verbatim recent window. Useful for very long graphs
|
|
67
|
+
where re-reading every checkpoint is wasteful.
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
new AgentsmcpSaver({
|
|
73
|
+
server, // default: AGENTSMCP_SERVER env, then localhost:3000
|
|
74
|
+
agentId, // default: AGENTSMCP_AGENT_ID env, then `langgraph@<hostname>`
|
|
75
|
+
apiKey, // default: AGENTSMCP_API_KEY env
|
|
76
|
+
serde, // default: LangGraph's JsonPlusSerializer
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If you want every process to share state, pin `agentId` to a stable
|
|
81
|
+
string. If you want each process to have its own slice, let it default
|
|
82
|
+
to the hostname.
|
|
83
|
+
|
|
84
|
+
## Limitations (worth knowing)
|
|
85
|
+
|
|
86
|
+
- **`list()` reads the whole thread.** Fine for ~hundreds of
|
|
87
|
+
checkpoints. For very long threads, lean on compression and accept
|
|
88
|
+
that `list()` is paginated client-side.
|
|
89
|
+
- **No deduplication of repeat `put()`.** The agentsmcp server assigns
|
|
90
|
+
message IDs server-side, so a re-put produces a duplicate row;
|
|
91
|
+
`getTuple()` and `list()` dedupe by `checkpoint_id` on read.
|
|
92
|
+
- **Checkpoint writes are O(1) — but always a network round-trip.**
|
|
93
|
+
If your graph checkpoints aggressively in a hot loop, that's a real
|
|
94
|
+
cost; pair this saver with a local agentsmcp server for low latency.
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT — see [LICENSE](../LICENSE).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentsmcpSaver = void 0;
|
|
4
|
+
var saver_1 = require("./saver");
|
|
5
|
+
Object.defineProperty(exports, "AgentsmcpSaver", { enumerable: true, get: function () { return saver_1.AgentsmcpSaver; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iCAAqE;AAA5D,uGAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"os-shim.d.ts","sourceRoot":"","sources":["../src/os-shim.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,IAAI,CAAC;AAC7B,eAAO,MAAM,EAAE,eAAS,CAAC"}
|
package/dist/os-shim.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.os = void 0;
|
|
37
|
+
// Small re-export so the saver can import "os" without TS module-resolution
|
|
38
|
+
// gymnastics under commonjs+esModuleInterop=true.
|
|
39
|
+
const nodeOs = __importStar(require("os"));
|
|
40
|
+
exports.os = nodeOs;
|
|
41
|
+
//# sourceMappingURL=os-shim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"os-shim.js","sourceRoot":"","sources":["../src/os-shim.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4EAA4E;AAC5E,kDAAkD;AAClD,2CAA6B;AAChB,QAAA,EAAE,GAAG,MAAM,CAAC"}
|
package/dist/saver.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
2
|
+
import { BaseCheckpointSaver, type Checkpoint, type CheckpointListOptions, type CheckpointMetadata, type CheckpointTuple, type ChannelVersions, type PendingWrite, type SerializerProtocol } from "@langchain/langgraph-checkpoint";
|
|
3
|
+
import type { ContextFrame } from "agentsmcp";
|
|
4
|
+
export interface AgentsmcpSaverOptions {
|
|
5
|
+
/** Where the agentsmcp HTTP server lives. Defaults to env or localhost:3000. */
|
|
6
|
+
server?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Agent identity this saver writes as. Defaults to
|
|
9
|
+
* `langgraph@<hostname>`. Use a stable id so threads persist across
|
|
10
|
+
* process restarts.
|
|
11
|
+
*/
|
|
12
|
+
agentId?: string;
|
|
13
|
+
/** Bearer token forwarded to agentsmcp. Defaults to env. */
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
/** Plug your own LangGraph serializer if you have a custom one. */
|
|
16
|
+
serde?: SerializerProtocol;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* LangGraph BaseCheckpointSaver backed by an agentsmcp HTTP server.
|
|
20
|
+
*
|
|
21
|
+
* One LangGraph thread (`config.configurable.thread_id`) maps to one
|
|
22
|
+
* agentsmcp thread. Every checkpoint and every batch of intermediate
|
|
23
|
+
* writes becomes one message on that thread. Process restart resumes
|
|
24
|
+
* by reading the thread.
|
|
25
|
+
*
|
|
26
|
+
* AgentsmcpSaver intentionally does not implement deterministic message
|
|
27
|
+
* IDs — the agentsmcp server generates them. Instead the LangGraph
|
|
28
|
+
* `checkpoint_id` is carried inside the payload and used as the
|
|
29
|
+
* primary key on read.
|
|
30
|
+
*/
|
|
31
|
+
export declare class AgentsmcpSaver extends BaseCheckpointSaver {
|
|
32
|
+
private readonly mail;
|
|
33
|
+
private readonly agentId;
|
|
34
|
+
private connected;
|
|
35
|
+
/** langgraph thread_id → agentsmcp threadId (resolved lazily) */
|
|
36
|
+
private readonly threadCache;
|
|
37
|
+
constructor(opts?: AgentsmcpSaverOptions);
|
|
38
|
+
/** Register this saver's agent identity with the server. Idempotent. */
|
|
39
|
+
connect(): Promise<void>;
|
|
40
|
+
getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined>;
|
|
41
|
+
list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
|
|
42
|
+
put(config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata, _newVersions: ChannelVersions): Promise<RunnableConfig>;
|
|
43
|
+
putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Look up the agentsmcp threadId for a given LangGraph thread_id.
|
|
46
|
+
* Hits the cache first; falls back to a thread listing on first call
|
|
47
|
+
* after a process restart.
|
|
48
|
+
*/
|
|
49
|
+
private resolveThread;
|
|
50
|
+
private messageToTuple;
|
|
51
|
+
}
|
|
52
|
+
export type { ContextFrame };
|
|
53
|
+
//# sourceMappingURL=saver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saver.d.ts","sourceRoot":"","sources":["../src/saver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EACL,mBAAmB,EACnB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EAEvB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,WAAW,CAAC;AAUvD,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAe,SAAQ,mBAAmB;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAE7C,IAAI,GAAE,qBAA0B;IAqB5C,wEAAwE;IAClE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAUxB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAgCrE,IAAI,CACT,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAAC,eAAe,CAAC;IAmD5B,GAAG,CACP,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,kBAAkB,EAC5B,YAAY,EAAE,eAAe,GAC5B,OAAO,CAAC,cAAc,CAAC;IAsDpB,SAAS,CACb,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IA2ChB;;;;OAIG;YACW,aAAa;YAmBb,cAAc;CAwE7B;AAuCD,YAAY,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/saver.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentsmcpSaver = void 0;
|
|
4
|
+
const os_shim_1 = require("./os-shim");
|
|
5
|
+
const langgraph_checkpoint_1 = require("@langchain/langgraph-checkpoint");
|
|
6
|
+
const agentsmcp_1 = require("agentsmcp");
|
|
7
|
+
const serializer_1 = require("./serializer");
|
|
8
|
+
/**
|
|
9
|
+
* LangGraph BaseCheckpointSaver backed by an agentsmcp HTTP server.
|
|
10
|
+
*
|
|
11
|
+
* One LangGraph thread (`config.configurable.thread_id`) maps to one
|
|
12
|
+
* agentsmcp thread. Every checkpoint and every batch of intermediate
|
|
13
|
+
* writes becomes one message on that thread. Process restart resumes
|
|
14
|
+
* by reading the thread.
|
|
15
|
+
*
|
|
16
|
+
* AgentsmcpSaver intentionally does not implement deterministic message
|
|
17
|
+
* IDs — the agentsmcp server generates them. Instead the LangGraph
|
|
18
|
+
* `checkpoint_id` is carried inside the payload and used as the
|
|
19
|
+
* primary key on read.
|
|
20
|
+
*/
|
|
21
|
+
class AgentsmcpSaver extends langgraph_checkpoint_1.BaseCheckpointSaver {
|
|
22
|
+
constructor(opts = {}) {
|
|
23
|
+
super(opts.serde);
|
|
24
|
+
this.connected = false;
|
|
25
|
+
/** langgraph thread_id → agentsmcp threadId (resolved lazily) */
|
|
26
|
+
this.threadCache = new Map();
|
|
27
|
+
const server = opts.server ??
|
|
28
|
+
process.env.AGENTSMCP_SERVER ??
|
|
29
|
+
process.env.AGENTMAILBOX_SERVER ??
|
|
30
|
+
"http://localhost:3000";
|
|
31
|
+
this.agentId =
|
|
32
|
+
opts.agentId ??
|
|
33
|
+
process.env.AGENTSMCP_AGENT_ID ??
|
|
34
|
+
`langgraph@${os_shim_1.os.hostname()}`;
|
|
35
|
+
this.mail = new agentsmcp_1.AgentMailbox({
|
|
36
|
+
agentId: this.agentId,
|
|
37
|
+
server,
|
|
38
|
+
apiKey: opts.apiKey ??
|
|
39
|
+
process.env.AGENTSMCP_API_KEY ??
|
|
40
|
+
process.env.AGENTMAILBOX_API_KEY,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** Register this saver's agent identity with the server. Idempotent. */
|
|
44
|
+
async connect() {
|
|
45
|
+
if (this.connected)
|
|
46
|
+
return;
|
|
47
|
+
await this.mail.connect();
|
|
48
|
+
this.connected = true;
|
|
49
|
+
}
|
|
50
|
+
// ─────────────────────────────────────────────────────────────────
|
|
51
|
+
// BaseCheckpointSaver surface
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────
|
|
53
|
+
async getTuple(config) {
|
|
54
|
+
await this.connect();
|
|
55
|
+
const thread_id = requireThreadId(config);
|
|
56
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
57
|
+
const requested_id = config.configurable?.checkpoint_id;
|
|
58
|
+
const agentsmcpThreadId = await this.resolveThread(thread_id);
|
|
59
|
+
if (!agentsmcpThreadId)
|
|
60
|
+
return undefined;
|
|
61
|
+
const messages = await this.mail.threads().then(async (threads) => {
|
|
62
|
+
const t = threads.find((x) => x.id === agentsmcpThreadId);
|
|
63
|
+
return t ? t.messages : [];
|
|
64
|
+
});
|
|
65
|
+
const checkpointMsgs = messages.filter((m) => isCheckpointPayload(m.payload) && m.payload.checkpoint_ns === checkpoint_ns);
|
|
66
|
+
let target = requested_id
|
|
67
|
+
? checkpointMsgs.find((m) => isCheckpointPayload(m.payload) &&
|
|
68
|
+
m.payload.checkpoint_id === requested_id)
|
|
69
|
+
: checkpointMsgs[checkpointMsgs.length - 1];
|
|
70
|
+
if (!target)
|
|
71
|
+
return undefined;
|
|
72
|
+
return this.messageToTuple(target, messages, thread_id, checkpoint_ns);
|
|
73
|
+
}
|
|
74
|
+
async *list(config, options) {
|
|
75
|
+
await this.connect();
|
|
76
|
+
const thread_id = requireThreadId(config);
|
|
77
|
+
const configured_ns = config.configurable?.checkpoint_ns;
|
|
78
|
+
const agentsmcpThreadId = await this.resolveThread(thread_id);
|
|
79
|
+
if (!agentsmcpThreadId)
|
|
80
|
+
return;
|
|
81
|
+
const threads = await this.mail.threads();
|
|
82
|
+
const t = threads.find((x) => x.id === agentsmcpThreadId);
|
|
83
|
+
if (!t)
|
|
84
|
+
return;
|
|
85
|
+
const messages = t.messages;
|
|
86
|
+
const checkpointMsgs = messages.filter((m) => {
|
|
87
|
+
if (!isCheckpointPayload(m.payload))
|
|
88
|
+
return false;
|
|
89
|
+
if (configured_ns !== undefined && m.payload.checkpoint_ns !== configured_ns) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (options?.before?.configurable?.checkpoint_id) {
|
|
93
|
+
const cutoff = options.before.configurable.checkpoint_id;
|
|
94
|
+
// LangGraph checkpoint_ids are uuid6 / lexicographically sortable.
|
|
95
|
+
return m.payload.checkpoint_id < cutoff;
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
});
|
|
99
|
+
// Newest first. agentsmcp returns messages timestamp-ascending.
|
|
100
|
+
checkpointMsgs.reverse();
|
|
101
|
+
const seenCheckpointIds = new Set();
|
|
102
|
+
let emitted = 0;
|
|
103
|
+
for (const m of checkpointMsgs) {
|
|
104
|
+
const cpId = m.payload.checkpoint_id;
|
|
105
|
+
if (seenCheckpointIds.has(cpId))
|
|
106
|
+
continue; // dedupe repeated put
|
|
107
|
+
seenCheckpointIds.add(cpId);
|
|
108
|
+
if (options?.limit !== undefined && emitted >= options.limit)
|
|
109
|
+
break;
|
|
110
|
+
yield await this.messageToTuple(m, messages, thread_id, m.payload.checkpoint_ns);
|
|
111
|
+
emitted += 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async put(config, checkpoint, metadata, _newVersions) {
|
|
115
|
+
await this.connect();
|
|
116
|
+
const thread_id = requireThreadId(config);
|
|
117
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
118
|
+
const parent_checkpoint_id = config.configurable?.checkpoint_id;
|
|
119
|
+
const checkpointBlob = await (0, serializer_1.dumpToBase64)(this.serde, checkpoint);
|
|
120
|
+
const metadataBlob = await (0, serializer_1.dumpToBase64)(this.serde, metadata);
|
|
121
|
+
const payload = {
|
|
122
|
+
kind: "checkpoint",
|
|
123
|
+
checkpoint: checkpointBlob.data,
|
|
124
|
+
metadata: metadataBlob.data,
|
|
125
|
+
checkpoint_ns,
|
|
126
|
+
checkpoint_id: checkpoint.id,
|
|
127
|
+
parent_checkpoint_id,
|
|
128
|
+
};
|
|
129
|
+
// Stash the serializer type tags alongside in contextSnapshot so we
|
|
130
|
+
// can round-trip without hardcoding "json".
|
|
131
|
+
const ctx = {
|
|
132
|
+
checkpoint_id: checkpoint.id,
|
|
133
|
+
checkpoint_ns,
|
|
134
|
+
thread_id,
|
|
135
|
+
step: metadata.step ?? -1,
|
|
136
|
+
source: metadata.source ?? "input",
|
|
137
|
+
_checkpoint_type: checkpointBlob.type,
|
|
138
|
+
_metadata_type: metadataBlob.type,
|
|
139
|
+
};
|
|
140
|
+
const existing = this.threadCache.get(thread_id);
|
|
141
|
+
const sendResult = await this.mail.send(syntheticRecipient(thread_id), payload, {
|
|
142
|
+
threadId: existing,
|
|
143
|
+
contextSnapshot: ctx,
|
|
144
|
+
});
|
|
145
|
+
this.threadCache.set(thread_id, sendResult.threadId);
|
|
146
|
+
return {
|
|
147
|
+
configurable: {
|
|
148
|
+
thread_id,
|
|
149
|
+
checkpoint_ns,
|
|
150
|
+
checkpoint_id: checkpoint.id,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async putWrites(config, writes, taskId) {
|
|
155
|
+
await this.connect();
|
|
156
|
+
const thread_id = requireThreadId(config);
|
|
157
|
+
const checkpoint_ns = config.configurable?.checkpoint_ns ?? "";
|
|
158
|
+
const checkpoint_id = config.configurable?.checkpoint_id;
|
|
159
|
+
if (!checkpoint_id) {
|
|
160
|
+
throw new Error("AgentsmcpSaver.putWrites: config.configurable.checkpoint_id is required");
|
|
161
|
+
}
|
|
162
|
+
const wireWrites = await Promise.all(writes.map(async ([channel, value]) => {
|
|
163
|
+
const blob = await (0, serializer_1.dumpToBase64)(this.serde, value);
|
|
164
|
+
return { taskId, channel, value: blob.data, type: blob.type };
|
|
165
|
+
}));
|
|
166
|
+
const payload = {
|
|
167
|
+
kind: "writes",
|
|
168
|
+
checkpoint_id,
|
|
169
|
+
checkpoint_ns,
|
|
170
|
+
writes: wireWrites,
|
|
171
|
+
};
|
|
172
|
+
const existing = this.threadCache.get(thread_id);
|
|
173
|
+
const sendResult = await this.mail.send(syntheticRecipient(thread_id), payload, {
|
|
174
|
+
threadId: existing,
|
|
175
|
+
contextSnapshot: { kind: "writes", checkpoint_id, taskId, checkpoint_ns },
|
|
176
|
+
});
|
|
177
|
+
this.threadCache.set(thread_id, sendResult.threadId);
|
|
178
|
+
}
|
|
179
|
+
// ─────────────────────────────────────────────────────────────────
|
|
180
|
+
// Private helpers
|
|
181
|
+
// ─────────────────────────────────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* Look up the agentsmcp threadId for a given LangGraph thread_id.
|
|
184
|
+
* Hits the cache first; falls back to a thread listing on first call
|
|
185
|
+
* after a process restart.
|
|
186
|
+
*/
|
|
187
|
+
async resolveThread(langgraphThreadId) {
|
|
188
|
+
const cached = this.threadCache.get(langgraphThreadId);
|
|
189
|
+
if (cached)
|
|
190
|
+
return cached;
|
|
191
|
+
const recipient = syntheticRecipient(langgraphThreadId);
|
|
192
|
+
const threads = await this.mail.threads();
|
|
193
|
+
const match = threads.find((t) => t.participants.includes(recipient) ||
|
|
194
|
+
t.silentParticipants.includes(recipient));
|
|
195
|
+
if (match) {
|
|
196
|
+
this.threadCache.set(langgraphThreadId, match.id);
|
|
197
|
+
return match.id;
|
|
198
|
+
}
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
async messageToTuple(checkpointMsg, allMessages, thread_id, checkpoint_ns) {
|
|
202
|
+
if (!isCheckpointPayload(checkpointMsg.payload)) {
|
|
203
|
+
throw new Error("messageToTuple called with non-checkpoint message");
|
|
204
|
+
}
|
|
205
|
+
const cp = checkpointMsg.payload;
|
|
206
|
+
const ctx = checkpointMsg.contextSnapshot;
|
|
207
|
+
const checkpoint = await (0, serializer_1.loadFromBase64)(this.serde, {
|
|
208
|
+
type: ctx._checkpoint_type ?? "json",
|
|
209
|
+
data: cp.checkpoint,
|
|
210
|
+
});
|
|
211
|
+
const metadata = await (0, serializer_1.loadFromBase64)(this.serde, {
|
|
212
|
+
type: ctx._metadata_type ?? "json",
|
|
213
|
+
data: cp.metadata,
|
|
214
|
+
});
|
|
215
|
+
// Merge any writes messages that came AFTER this checkpoint message
|
|
216
|
+
// but before the next checkpoint message on the same ns. Those are
|
|
217
|
+
// this checkpoint's pendingWrites.
|
|
218
|
+
const idx = allMessages.findIndex((m) => m.id === checkpointMsg.id);
|
|
219
|
+
const pendingWrites = [];
|
|
220
|
+
for (let i = idx + 1; i < allMessages.length; i++) {
|
|
221
|
+
const m = allMessages[i];
|
|
222
|
+
if (isCheckpointPayload(m.payload)) {
|
|
223
|
+
if (m.payload.checkpoint_ns === cp.checkpoint_ns)
|
|
224
|
+
break;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (isWritesPayload(m.payload) &&
|
|
228
|
+
m.payload.checkpoint_id === cp.checkpoint_id &&
|
|
229
|
+
m.payload.checkpoint_ns === cp.checkpoint_ns) {
|
|
230
|
+
for (const w of m.payload.writes) {
|
|
231
|
+
const value = await (0, serializer_1.loadFromBase64)(this.serde, {
|
|
232
|
+
type: w.type,
|
|
233
|
+
data: w.value,
|
|
234
|
+
});
|
|
235
|
+
pendingWrites.push([w.taskId, w.channel, value]);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const tuple = {
|
|
240
|
+
config: {
|
|
241
|
+
configurable: {
|
|
242
|
+
thread_id,
|
|
243
|
+
checkpoint_ns: cp.checkpoint_ns,
|
|
244
|
+
checkpoint_id: cp.checkpoint_id,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
checkpoint,
|
|
248
|
+
metadata,
|
|
249
|
+
pendingWrites,
|
|
250
|
+
};
|
|
251
|
+
if (cp.parent_checkpoint_id) {
|
|
252
|
+
tuple.parentConfig = {
|
|
253
|
+
configurable: {
|
|
254
|
+
thread_id,
|
|
255
|
+
checkpoint_ns: cp.checkpoint_ns,
|
|
256
|
+
checkpoint_id: cp.parent_checkpoint_id,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return tuple;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
exports.AgentsmcpSaver = AgentsmcpSaver;
|
|
264
|
+
// ───────────────────────────────────────────────────────────────────
|
|
265
|
+
// Module-private helpers
|
|
266
|
+
// ───────────────────────────────────────────────────────────────────
|
|
267
|
+
function syntheticRecipient(threadId) {
|
|
268
|
+
return `${threadId}@checkpoints`;
|
|
269
|
+
}
|
|
270
|
+
function requireThreadId(config) {
|
|
271
|
+
const id = config.configurable?.thread_id;
|
|
272
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
273
|
+
throw new Error("config.configurable.thread_id is required for AgentsmcpSaver");
|
|
274
|
+
}
|
|
275
|
+
return id;
|
|
276
|
+
}
|
|
277
|
+
function isCheckpointPayload(p) {
|
|
278
|
+
return (typeof p === "object" &&
|
|
279
|
+
p !== null &&
|
|
280
|
+
p.kind === "checkpoint");
|
|
281
|
+
}
|
|
282
|
+
function isWritesPayload(p) {
|
|
283
|
+
return (typeof p === "object" &&
|
|
284
|
+
p !== null &&
|
|
285
|
+
p.kind === "writes");
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=saver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saver.js","sourceRoot":"","sources":["../src/saver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SerializerProtocol } from "@langchain/langgraph-checkpoint";
|
|
2
|
+
/**
|
|
3
|
+
* LangGraph's serializer returns `[type: string, bytes: Uint8Array]`.
|
|
4
|
+
* agentsmcp's JSON wire format can't carry binary, so we base64-encode
|
|
5
|
+
* the bytes and keep the type tag alongside.
|
|
6
|
+
*/
|
|
7
|
+
export interface SerializedTyped {
|
|
8
|
+
type: string;
|
|
9
|
+
data: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function dumpToBase64(serde: SerializerProtocol, value: unknown): Promise<SerializedTyped>;
|
|
12
|
+
export declare function loadFromBase64<T = unknown>(serde: SerializerProtocol, s: SerializedTyped): Promise<T>;
|
|
13
|
+
//# sourceMappingURL=serializer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,eAAe,CAAC,CAG1B;AAED,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,KAAK,EAAE,kBAAkB,EACzB,CAAC,EAAE,eAAe,GACjB,OAAO,CAAC,CAAC,CAAC,CAGZ"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dumpToBase64 = dumpToBase64;
|
|
4
|
+
exports.loadFromBase64 = loadFromBase64;
|
|
5
|
+
async function dumpToBase64(serde, value) {
|
|
6
|
+
const [type, bytes] = await serde.dumpsTyped(value);
|
|
7
|
+
return { type, data: bytesToBase64(bytes) };
|
|
8
|
+
}
|
|
9
|
+
async function loadFromBase64(serde, s) {
|
|
10
|
+
const bytes = base64ToBytes(s.data);
|
|
11
|
+
return (await serde.loadsTyped(s.type, bytes));
|
|
12
|
+
}
|
|
13
|
+
function bytesToBase64(bytes) {
|
|
14
|
+
// Buffer is available everywhere we run (Node 18+).
|
|
15
|
+
return Buffer.from(bytes).toString("base64");
|
|
16
|
+
}
|
|
17
|
+
function base64ToBytes(b64) {
|
|
18
|
+
return new Uint8Array(Buffer.from(b64, "base64"));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=serializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":";;AAaA,oCAMC;AAED,wCAMC;AAdM,KAAK,UAAU,YAAY,CAChC,KAAyB,EACzB,KAAc;IAEd,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACpD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;AAC9C,CAAC;AAEM,KAAK,UAAU,cAAc,CAClC,KAAyB,EACzB,CAAkB;IAElB,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAM,CAAC;AACtD,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,oDAAoD;IACpD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AACpD,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire shapes the checkpointer writes into agentsmcp messages.
|
|
3
|
+
*
|
|
4
|
+
* Two kinds of messages live on the underlying thread:
|
|
5
|
+
* - kind="checkpoint" — a full LangGraph checkpoint snapshot
|
|
6
|
+
* - kind="writes" — intermediate writes (putWrites) that get
|
|
7
|
+
* merged into the next checkpoint's pendingWrites
|
|
8
|
+
*
|
|
9
|
+
* Both are tagged so getTuple/list can filter without ambiguity.
|
|
10
|
+
*/
|
|
11
|
+
export interface CheckpointPayload {
|
|
12
|
+
kind: "checkpoint";
|
|
13
|
+
/** base64-encoded bytes from the LangGraph serializer */
|
|
14
|
+
checkpoint: string;
|
|
15
|
+
/** base64-encoded CheckpointMetadata bytes */
|
|
16
|
+
metadata: string;
|
|
17
|
+
/** "" for the root graph, "sub:name" for subgraphs */
|
|
18
|
+
checkpoint_ns: string;
|
|
19
|
+
/** LangGraph's checkpoint id (uuid6) — distinct from agentsmcp message id */
|
|
20
|
+
checkpoint_id: string;
|
|
21
|
+
/** id of the previous checkpoint on this thread/ns; undefined for the first */
|
|
22
|
+
parent_checkpoint_id?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PendingWriteWire {
|
|
25
|
+
taskId: string;
|
|
26
|
+
channel: string;
|
|
27
|
+
/** base64-encoded value bytes */
|
|
28
|
+
value: string;
|
|
29
|
+
/** LangGraph's value type tag returned by the serializer */
|
|
30
|
+
type: string;
|
|
31
|
+
}
|
|
32
|
+
export interface WritesPayload {
|
|
33
|
+
kind: "writes";
|
|
34
|
+
/** which checkpoint these writes belong to */
|
|
35
|
+
checkpoint_id: string;
|
|
36
|
+
checkpoint_ns: string;
|
|
37
|
+
writes: PendingWriteWire[];
|
|
38
|
+
}
|
|
39
|
+
/** Shape stored in agentsmcp's contextSnapshot for each checkpoint message. */
|
|
40
|
+
export interface CheckpointContext extends Record<string, unknown> {
|
|
41
|
+
checkpoint_id: string;
|
|
42
|
+
checkpoint_ns: string;
|
|
43
|
+
thread_id: string;
|
|
44
|
+
step: number;
|
|
45
|
+
source: string;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAkB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Wire shapes the checkpointer writes into agentsmcp messages.
|
|
4
|
+
*
|
|
5
|
+
* Two kinds of messages live on the underlying thread:
|
|
6
|
+
* - kind="checkpoint" — a full LangGraph checkpoint snapshot
|
|
7
|
+
* - kind="writes" — intermediate writes (putWrites) that get
|
|
8
|
+
* merged into the next checkpoint's pendingWrites
|
|
9
|
+
*
|
|
10
|
+
* Both are tagged so getTuple/list can filter without ambiguity.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentsmcp-langgraph",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "LangGraph BaseCheckpointSaver backed by agentsmcp (AgentMailbox). Drop-in checkpointer for LangGraph.js — your graph state lives in an AgentMailbox thread.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "rm -rf dist && tsc",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
"prepublishOnly": "npm run build && npm test"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"langgraph",
|
|
21
|
+
"langchain",
|
|
22
|
+
"checkpointer",
|
|
23
|
+
"agents",
|
|
24
|
+
"agentsmcp",
|
|
25
|
+
"agentmailbox"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/RagavRida/agentsmcp.git",
|
|
30
|
+
"directory": "langgraph"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/RagavRida/agentsmcp/tree/main/langgraph",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/RagavRida/agentsmcp/issues"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"agentsmcp": ">=0.3.5 <0.5.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@langchain/langgraph-checkpoint": ">=0.0.10"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@langchain/langgraph-checkpoint": "^0.0.10",
|
|
48
|
+
"@types/node": "^22.5.0",
|
|
49
|
+
"typescript": "^5.5.4",
|
|
50
|
+
"vitest": "^2.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|