@langchain/langgraph-api 1.1.8 → 1.1.9

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.
Files changed (99) hide show
  1. package/dist/api/assistants.d.mts +3 -0
  2. package/dist/api/assistants.mjs +193 -0
  3. package/dist/api/meta.d.mts +3 -0
  4. package/dist/api/meta.mjs +65 -0
  5. package/dist/api/runs.d.mts +3 -0
  6. package/dist/api/runs.mjs +324 -0
  7. package/dist/api/store.d.mts +3 -0
  8. package/dist/api/store.mjs +111 -0
  9. package/dist/api/threads.d.mts +3 -0
  10. package/dist/api/threads.mjs +143 -0
  11. package/dist/auth/custom.d.mts +9 -0
  12. package/dist/auth/custom.mjs +32 -0
  13. package/dist/auth/index.d.mts +43 -0
  14. package/dist/auth/index.mjs +163 -0
  15. package/dist/cli/entrypoint.d.mts +1 -0
  16. package/dist/cli/entrypoint.mjs +41 -0
  17. package/dist/cli/spawn.d.mts +42 -0
  18. package/dist/cli/spawn.mjs +47 -0
  19. package/dist/cli/utils/ipc/client.d.mts +5 -0
  20. package/dist/cli/utils/ipc/client.mjs +47 -0
  21. package/dist/cli/utils/ipc/utils/get-pipe-path.d.mts +1 -0
  22. package/dist/cli/utils/ipc/utils/get-pipe-path.mjs +29 -0
  23. package/dist/cli/utils/ipc/utils/temporary-directory.d.mts +5 -0
  24. package/dist/cli/utils/ipc/utils/temporary-directory.mjs +40 -0
  25. package/dist/command.d.mts +11 -0
  26. package/dist/command.mjs +15 -0
  27. package/dist/experimental/embed.d.mts +42 -0
  28. package/dist/experimental/embed.mjs +299 -0
  29. package/dist/graph/api.d.mts +1 -0
  30. package/dist/graph/api.mjs +2 -0
  31. package/dist/graph/load.d.mts +19 -0
  32. package/dist/graph/load.hooks.d.mts +2 -0
  33. package/dist/graph/load.hooks.mjs +52 -0
  34. package/dist/graph/load.mjs +96 -0
  35. package/dist/graph/load.utils.d.mts +22 -0
  36. package/dist/graph/load.utils.mjs +49 -0
  37. package/dist/graph/parser/index.d.mts +23 -0
  38. package/dist/graph/parser/index.mjs +58 -0
  39. package/dist/graph/parser/parser.d.mts +77 -0
  40. package/dist/graph/parser/parser.mjs +429 -0
  41. package/dist/graph/parser/parser.worker.d.mts +1 -0
  42. package/dist/graph/parser/parser.worker.mjs +7 -0
  43. package/dist/graph/parser/schema/types.d.mts +154 -0
  44. package/dist/graph/parser/schema/types.mjs +1496 -0
  45. package/dist/graph/parser/schema/types.template.d.mts +1 -0
  46. package/dist/graph/parser/schema/types.template.mts +92 -0
  47. package/dist/http/custom.d.mts +6 -0
  48. package/dist/http/custom.mjs +10 -0
  49. package/dist/http/middleware.d.mts +11 -0
  50. package/dist/http/middleware.mjs +57 -0
  51. package/dist/logging.d.mts +10 -0
  52. package/dist/logging.mjs +115 -0
  53. package/dist/loopback.d.mts +4 -0
  54. package/dist/loopback.mjs +10 -0
  55. package/dist/preload.d.mts +1 -0
  56. package/dist/preload.mjs +29 -0
  57. package/dist/queue.d.mts +2 -0
  58. package/dist/queue.mjs +119 -0
  59. package/dist/schemas.d.mts +1552 -0
  60. package/dist/schemas.mjs +492 -0
  61. package/dist/semver/index.d.mts +15 -0
  62. package/dist/semver/index.mjs +46 -0
  63. package/dist/server.d.mts +175 -0
  64. package/dist/server.mjs +181 -0
  65. package/dist/state.d.mts +3 -0
  66. package/dist/state.mjs +30 -0
  67. package/dist/storage/checkpoint.d.mts +19 -0
  68. package/dist/storage/checkpoint.mjs +127 -0
  69. package/dist/storage/context.d.mts +3 -0
  70. package/dist/storage/context.mjs +11 -0
  71. package/dist/storage/importMap.d.mts +55 -0
  72. package/dist/storage/importMap.mjs +55 -0
  73. package/dist/storage/ops.d.mts +169 -0
  74. package/dist/storage/ops.mjs +1262 -0
  75. package/dist/storage/persist.d.mts +18 -0
  76. package/dist/storage/persist.mjs +81 -0
  77. package/dist/storage/store.d.mts +17 -0
  78. package/dist/storage/store.mjs +41 -0
  79. package/dist/storage/types.d.mts +301 -0
  80. package/dist/storage/types.mjs +1 -0
  81. package/dist/stream.d.mts +43 -0
  82. package/dist/stream.mjs +235 -0
  83. package/dist/ui/load.d.mts +8 -0
  84. package/dist/ui/load.mjs +53 -0
  85. package/dist/utils/abort.d.mts +1 -0
  86. package/dist/utils/abort.mjs +8 -0
  87. package/dist/utils/hono.d.mts +5 -0
  88. package/dist/utils/hono.mjs +24 -0
  89. package/dist/utils/importMap.d.mts +55 -0
  90. package/dist/utils/importMap.mjs +55 -0
  91. package/dist/utils/runnableConfig.d.mts +3 -0
  92. package/dist/utils/runnableConfig.mjs +45 -0
  93. package/dist/utils/serde.d.mts +5 -0
  94. package/dist/utils/serde.mjs +20 -0
  95. package/dist/vitest.config.d.ts +2 -0
  96. package/dist/vitest.config.js +12 -0
  97. package/dist/webhook.d.mts +11 -0
  98. package/dist/webhook.mjs +30 -0
  99. package/package.json +1 -1
@@ -0,0 +1,47 @@
1
+ // MIT License
2
+ //
3
+ // Copyright (c) Hiroki Osame <hiroki.osame@gmail.com>
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.
22
+ //
23
+ // https://github.com/privatenumber/tsx/tree/28a3e7d2b8fd72b683aab8a98dd1fcee4624e4cb
24
+ import net from "node:net";
25
+ import { getPipePath } from "./utils/get-pipe-path.mjs";
26
+ export const connectToServer = (processId = process.ppid) => new Promise((resolve) => {
27
+ const pipePath = getPipePath(processId);
28
+ const socket = net.createConnection(pipePath, () => {
29
+ const sendToParent = (data) => {
30
+ const messageBuffer = Buffer.from(JSON.stringify(data));
31
+ const lengthBuffer = Buffer.alloc(4);
32
+ lengthBuffer.writeInt32BE(messageBuffer.length, 0);
33
+ socket.write(Buffer.concat([lengthBuffer, messageBuffer]));
34
+ };
35
+ resolve(sendToParent);
36
+ });
37
+ /**
38
+ * Ignore error when:
39
+ * - Called as a loader and there is no server
40
+ * - Nested process when using --test and the ppid is incorrect
41
+ */
42
+ socket.on("error", () => {
43
+ resolve(undefined);
44
+ });
45
+ // Prevent Node from waiting for this socket to close before exiting
46
+ socket.unref();
47
+ });
@@ -0,0 +1 @@
1
+ export declare const getPipePath: (processId: number) => string;
@@ -0,0 +1,29 @@
1
+ // MIT License
2
+ //
3
+ // Copyright (c) Hiroki Osame <hiroki.osame@gmail.com>
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.
22
+ //
23
+ // https://github.com/privatenumber/tsx/tree/28a3e7d2b8fd72b683aab8a98dd1fcee4624e4cb
24
+ import path from "node:path";
25
+ import { tmpdir } from "./temporary-directory.mjs";
26
+ export const getPipePath = (processId) => {
27
+ const pipePath = path.join(tmpdir, `${processId}.pipe`);
28
+ return process.platform === "win32" ? `\\\\?\\pipe\\${pipePath}` : pipePath;
29
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * This ensures that the cache directory is unique per user
3
+ * and has the appropriate permissions
4
+ */
5
+ export declare const tmpdir: string;
@@ -0,0 +1,40 @@
1
+ // MIT License
2
+ //
3
+ // Copyright (c) Hiroki Osame <hiroki.osame@gmail.com>
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.
22
+ //
23
+ // https://github.com/privatenumber/tsx/tree/28a3e7d2b8fd72b683aab8a98dd1fcee4624e4cb
24
+ import path from "node:path";
25
+ import os from "node:os";
26
+ /**
27
+ * Cache directory is based on the user's identifier
28
+ * to avoid permission issues when accessed by a different user
29
+ */
30
+ const { geteuid } = process;
31
+ const userId = geteuid
32
+ ? // For Linux users with virtual users on CI (e.g. Docker)
33
+ geteuid()
34
+ : // Use username on Windows because it doesn't have id
35
+ os.userInfo().username;
36
+ /**
37
+ * This ensures that the cache directory is unique per user
38
+ * and has the appropriate permissions
39
+ */
40
+ export const tmpdir = path.join(os.tmpdir(), `tsx-${userId}`);
@@ -0,0 +1,11 @@
1
+ import { Command } from "@langchain/langgraph";
2
+ export interface RunSend {
3
+ node: string;
4
+ input?: unknown;
5
+ }
6
+ export interface RunCommand {
7
+ goto?: string | RunSend | Array<RunSend | string>;
8
+ update?: Record<string, unknown> | [string, unknown][];
9
+ resume?: unknown;
10
+ }
11
+ export declare const getLangGraphCommand: (command: RunCommand) => Command<unknown, Record<string, unknown>, string>;
@@ -0,0 +1,15 @@
1
+ import { Command, Send } from "@langchain/langgraph";
2
+ export const getLangGraphCommand = (command) => {
3
+ let goto = command.goto != null && !Array.isArray(command.goto)
4
+ ? [command.goto]
5
+ : command.goto;
6
+ return new Command({
7
+ goto: goto?.map((item) => {
8
+ if (typeof item !== "string")
9
+ return new Send(item.node, item.input);
10
+ return item;
11
+ }),
12
+ update: command.update,
13
+ resume: command.resume,
14
+ });
15
+ };
@@ -0,0 +1,42 @@
1
+ import type { BaseCheckpointSaver, BaseStore, Pregel } from "@langchain/langgraph";
2
+ import { Hono } from "hono";
3
+ import type { Metadata } from "../storage/types.mjs";
4
+ type AnyPregel = Pregel<any, any, any, any, any>;
5
+ interface Thread {
6
+ thread_id: string;
7
+ metadata: Metadata;
8
+ }
9
+ /**
10
+ * Interface for storing and retrieving threads used by `createEmbedServer`.
11
+ * @experimental Does not follow semver.
12
+ */
13
+ export interface ThreadSaver {
14
+ get: (id: string) => Promise<Thread>;
15
+ set: (id: string, options: {
16
+ kind: "put" | "patch";
17
+ metadata?: Metadata;
18
+ }) => Promise<Thread>;
19
+ delete: (id: string) => Promise<void>;
20
+ search?: (options: {
21
+ metadata?: Metadata;
22
+ limit: number;
23
+ offset: number;
24
+ sortBy: "created_at" | "updated_at";
25
+ sortOrder: "asc" | "desc";
26
+ }) => AsyncGenerator<{
27
+ thread: Thread;
28
+ total: number;
29
+ }>;
30
+ }
31
+ /**
32
+ * Create a Hono server with a subset of LangGraph Platform routes.
33
+ *
34
+ * @experimental Does not follow semver.
35
+ */
36
+ export declare function createEmbedServer(options: {
37
+ graph: Record<string, AnyPregel>;
38
+ threads: ThreadSaver;
39
+ checkpointer: BaseCheckpointSaver;
40
+ store?: BaseStore;
41
+ }): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
42
+ export {};
@@ -0,0 +1,299 @@
1
+ import { Hono } from "hono";
2
+ import { zValidator } from "@hono/zod-validator";
3
+ import { streamSSE } from "hono/streaming";
4
+ import { v4 as uuidv4 } from "uuid";
5
+ import * as schemas from "../schemas.mjs";
6
+ import { z } from "zod/v3";
7
+ import { streamState } from "../stream.mjs";
8
+ import { serialiseAsDict, serializeError } from "../utils/serde.mjs";
9
+ import { getDisconnectAbortSignal, jsonExtra } from "../utils/hono.mjs";
10
+ import { stateSnapshotToThreadState } from "../state.mjs";
11
+ import { ensureContentType } from "../http/middleware.mjs";
12
+ function createStubRun(threadId, payload) {
13
+ const now = new Date();
14
+ const runId = uuidv4();
15
+ let streamMode = Array.isArray(payload.stream_mode)
16
+ ? payload.stream_mode
17
+ : payload.stream_mode
18
+ ? [payload.stream_mode]
19
+ : undefined;
20
+ if (streamMode == null || streamMode.length === 0)
21
+ streamMode = ["values"];
22
+ const config = Object.assign({}, payload.config ?? {}, {
23
+ configurable: {
24
+ run_id: runId,
25
+ thread_id: threadId,
26
+ graph_id: payload.assistant_id,
27
+ ...(payload.checkpoint_id
28
+ ? { checkpoint_id: payload.checkpoint_id }
29
+ : null),
30
+ ...payload.checkpoint,
31
+ ...(payload.langsmith_tracer
32
+ ? {
33
+ langsmith_project: payload.langsmith_tracer.project_name,
34
+ langsmith_example_id: payload.langsmith_tracer.example_id,
35
+ }
36
+ : null),
37
+ },
38
+ }, { metadata: payload.metadata ?? {} });
39
+ return {
40
+ run_id: runId,
41
+ thread_id: threadId,
42
+ assistant_id: payload.assistant_id,
43
+ metadata: payload.metadata ?? {},
44
+ status: "running",
45
+ kwargs: {
46
+ input: payload.input,
47
+ command: payload.command,
48
+ config,
49
+ context: payload.context,
50
+ stream_mode: streamMode,
51
+ interrupt_before: payload.interrupt_before,
52
+ interrupt_after: payload.interrupt_after,
53
+ feedback_keys: payload.feedback_keys,
54
+ subgraphs: payload.stream_subgraphs,
55
+ temporary: false,
56
+ },
57
+ multitask_strategy: "reject",
58
+ created_at: now,
59
+ updated_at: now,
60
+ };
61
+ }
62
+ /**
63
+ * Create a Hono server with a subset of LangGraph Platform routes.
64
+ *
65
+ * @experimental Does not follow semver.
66
+ */
67
+ export function createEmbedServer(options) {
68
+ async function getGraph(graphId) {
69
+ const targetGraph = options.graph[graphId];
70
+ targetGraph.store = options.store;
71
+ targetGraph.checkpointer = options.checkpointer;
72
+ return targetGraph;
73
+ }
74
+ const api = new Hono();
75
+ api.use(ensureContentType());
76
+ api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
77
+ // create a new thread
78
+ const payload = c.req.valid("json");
79
+ const threadId = payload.thread_id || uuidv4();
80
+ return jsonExtra(c, await options.threads.set(threadId, {
81
+ kind: "put",
82
+ metadata: payload.metadata,
83
+ }));
84
+ });
85
+ api.get("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
86
+ // Get Thread
87
+ const { thread_id } = c.req.valid("param");
88
+ return jsonExtra(c, await options.threads.get(thread_id));
89
+ });
90
+ api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadCreate), async (c) => {
91
+ // Update Thread
92
+ const { thread_id } = c.req.valid("param");
93
+ const payload = c.req.valid("json");
94
+ return jsonExtra(c, await options.threads.set(thread_id, {
95
+ kind: "patch",
96
+ metadata: payload.metadata,
97
+ }));
98
+ });
99
+ api.delete("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
100
+ // Delete Thread
101
+ const { thread_id } = c.req.valid("param");
102
+ await options.threads.delete(thread_id);
103
+ return new Response(null, { status: 204 });
104
+ });
105
+ api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), async (c) => {
106
+ const payload = c.req.valid("json");
107
+ const result = [];
108
+ if (!options.threads.search)
109
+ return c.json({ error: "Threads search not implemented" }, 422);
110
+ const sortBy = payload.sort_by === "created_at" || payload.sort_by === "updated_at"
111
+ ? payload.sort_by
112
+ : "created_at";
113
+ let total = 0;
114
+ for await (const item of options.threads.search({
115
+ metadata: payload.metadata,
116
+ limit: payload.limit ?? 10,
117
+ offset: payload.offset ?? 0,
118
+ sortBy,
119
+ sortOrder: payload.sort_order ?? "desc",
120
+ })) {
121
+ result.push(item.thread);
122
+ // Only set total if it's the first item
123
+ if (total === 0)
124
+ total = item.total;
125
+ }
126
+ c.res.headers.set("X-Pagination-Total", total.toString());
127
+ return jsonExtra(c, result);
128
+ });
129
+ api.get("/threads/:thread_id/state", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("query", z.object({ subgraphs: schemas.coercedBoolean.optional() })), async (c) => {
130
+ // Get Latest Thread State
131
+ const { thread_id } = c.req.valid("param");
132
+ const { subgraphs } = c.req.valid("query");
133
+ const thread = await options.threads.get(thread_id);
134
+ const graphId = thread.metadata?.graph_id;
135
+ const graph = graphId ? await getGraph(graphId) : undefined;
136
+ if (graph == null) {
137
+ return jsonExtra(c, stateSnapshotToThreadState({
138
+ values: {},
139
+ next: [],
140
+ config: {},
141
+ metadata: undefined,
142
+ createdAt: undefined,
143
+ parentConfig: undefined,
144
+ tasks: [],
145
+ }));
146
+ }
147
+ const config = { configurable: { thread_id } };
148
+ const result = await graph.getState(config, { subgraphs });
149
+ return jsonExtra(c, stateSnapshotToThreadState(result));
150
+ });
151
+ api.post("/threads/:thread_id/state", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadStateUpdate), async (c) => {
152
+ // Update Thread State
153
+ const { thread_id } = c.req.valid("param");
154
+ const payload = c.req.valid("json");
155
+ const config = { configurable: { thread_id } };
156
+ config.configurable ??= {};
157
+ if (payload.checkpoint_id) {
158
+ config.configurable.checkpoint_id = payload.checkpoint_id;
159
+ }
160
+ if (payload.checkpoint) {
161
+ Object.assign(config.configurable, payload.checkpoint);
162
+ }
163
+ const thread = await options.threads.get(thread_id);
164
+ const graphId = thread.metadata?.graph_id;
165
+ const graph = graphId ? await getGraph(graphId) : undefined;
166
+ if (graph == null)
167
+ return c.json({ error: "Graph not found" }, 404);
168
+ const result = await graph.updateState(config, payload.values, payload.as_node);
169
+ return jsonExtra(c, { checkpoint: result.configurable });
170
+ });
171
+ // get thread state at checkpoint
172
+ api.get("/threads/:thread_id/state/:checkpoint_id", zValidator("param", z.object({
173
+ thread_id: z.string().uuid(),
174
+ checkpoint_id: z.string().uuid(),
175
+ })), zValidator("query", z.object({ subgraphs: schemas.coercedBoolean.optional() })), async (c) => {
176
+ // Get Thread State At Checkpoint
177
+ const { thread_id, checkpoint_id } = c.req.valid("param");
178
+ const { subgraphs } = c.req.valid("query");
179
+ const thread = await options.threads.get(thread_id);
180
+ const graphId = thread.metadata?.graph_id;
181
+ const graph = graphId ? await getGraph(graphId) : undefined;
182
+ if (graph == null)
183
+ return c.json({ error: "Graph not found" }, 404);
184
+ const result = await graph.getState({ configurable: { thread_id, checkpoint_id } }, { subgraphs });
185
+ return jsonExtra(c, stateSnapshotToThreadState(result));
186
+ });
187
+ api.post("/threads/:thread_id/state/checkpoint", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", z.object({
188
+ subgraphs: schemas.coercedBoolean.optional(),
189
+ checkpoint: schemas.CheckpointSchema.nullish(),
190
+ })), async (c) => {
191
+ // Get Thread State At Checkpoint post
192
+ const { thread_id } = c.req.valid("param");
193
+ const { checkpoint, subgraphs } = c.req.valid("json");
194
+ const thread = await options.threads.get(thread_id);
195
+ const graphId = thread.metadata?.graph_id;
196
+ const graph = graphId ? await getGraph(graphId) : undefined;
197
+ if (graph == null)
198
+ return c.json({ error: "Graph not found" }, 404);
199
+ const result = await graph.getState({ configurable: { thread_id, ...checkpoint } }, { subgraphs });
200
+ return jsonExtra(c, stateSnapshotToThreadState(result));
201
+ });
202
+ api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
203
+ // Get Thread History Post
204
+ const { thread_id } = c.req.valid("param");
205
+ const { limit, before, metadata, checkpoint } = c.req.valid("json");
206
+ const thread = await options.threads.get(thread_id);
207
+ const graphId = thread.metadata?.graph_id;
208
+ const graph = graphId ? await getGraph(graphId) : undefined;
209
+ if (graph == null)
210
+ return jsonExtra(c, []);
211
+ const config = { configurable: { thread_id, ...checkpoint } };
212
+ const result = [];
213
+ const beforeConfig = typeof before === "string"
214
+ ? { configurable: { checkpoint_id: before } }
215
+ : before;
216
+ for await (const state of graph.getStateHistory(config, {
217
+ limit,
218
+ before: beforeConfig,
219
+ filter: metadata,
220
+ })) {
221
+ result.push(stateSnapshotToThreadState(state));
222
+ }
223
+ return jsonExtra(c, result);
224
+ });
225
+ api.post("/threads/:thread_id/runs/stream", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
226
+ // Stream Run
227
+ const { thread_id } = c.req.valid("param");
228
+ const payload = c.req.valid("json");
229
+ const thread = await options.threads.get(thread_id);
230
+ if (thread == null)
231
+ return c.json({ error: "Thread not found" }, 404);
232
+ return streamSSE(c, async (stream) => {
233
+ const signal = getDisconnectAbortSignal(c, stream);
234
+ const run = createStubRun(thread_id, payload);
235
+ await options.threads.set(thread_id, {
236
+ kind: "patch",
237
+ metadata: {
238
+ graph_id: payload.assistant_id,
239
+ assistant_id: payload.assistant_id,
240
+ },
241
+ });
242
+ try {
243
+ for await (const { event, data } of streamState(run, {
244
+ attempt: 1,
245
+ getGraph,
246
+ signal,
247
+ })) {
248
+ await stream.writeSSE({ data: serialiseAsDict(data), event });
249
+ }
250
+ }
251
+ catch (error) {
252
+ await stream.writeSSE({
253
+ data: serialiseAsDict(serializeError(error)),
254
+ event: "error",
255
+ });
256
+ }
257
+ });
258
+ });
259
+ api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => {
260
+ // Stream Stateless Run
261
+ return streamSSE(c, async (stream) => {
262
+ const payload = c.req.valid("json");
263
+ const signal = getDisconnectAbortSignal(c, stream);
264
+ const threadId = uuidv4();
265
+ await options.threads.set(threadId, {
266
+ kind: "put",
267
+ metadata: {
268
+ graph_id: payload.assistant_id,
269
+ assistant_id: payload.assistant_id,
270
+ },
271
+ });
272
+ try {
273
+ const run = createStubRun(threadId, payload);
274
+ try {
275
+ for await (const { event, data } of streamState(run, {
276
+ attempt: 1,
277
+ getGraph,
278
+ signal,
279
+ })) {
280
+ await stream.writeSSE({ data: serialiseAsDict(data), event });
281
+ }
282
+ }
283
+ catch (error) {
284
+ await stream.writeSSE({
285
+ data: serialiseAsDict(serializeError(error)),
286
+ event: "error",
287
+ });
288
+ }
289
+ }
290
+ finally {
291
+ await options.threads.delete(threadId);
292
+ }
293
+ });
294
+ });
295
+ api.notFound((c) => {
296
+ return c.json({ error: `${c.req.method} ${c.req.path} not implemented` }, 404);
297
+ });
298
+ return api;
299
+ }
@@ -0,0 +1 @@
1
+ export { assertGraphExists, getAssistantId, getGraph, getGraphKeys, } from "./load.mjs";
@@ -0,0 +1,2 @@
1
+ // Public API for graph operations (useful for writing custom operation backends).
2
+ export { assertGraphExists, getAssistantId, getGraph, getGraphKeys, } from "./load.mjs";
@@ -0,0 +1,19 @@
1
+ import type { AssistantsRepo } from "../storage/types.mjs";
2
+ import type { BaseCheckpointSaver, BaseStore, CompiledGraph, LangGraphRunnableConfig } from "@langchain/langgraph";
3
+ import { type CompiledGraphFactory } from "./load.utils.mjs";
4
+ import type { GraphSchema, GraphSpec } from "./parser/index.mjs";
5
+ export declare const GRAPHS: Record<string, CompiledGraph<string> | CompiledGraphFactory<string>>;
6
+ export declare const GRAPH_SPEC: Record<string, GraphSpec>;
7
+ export declare const GRAPH_SCHEMA: Record<string, Record<string, GraphSchema>>;
8
+ export declare const NAMESPACE_GRAPH: Uint8Array<ArrayBufferLike>;
9
+ export declare const getAssistantId: (graphId: string) => string;
10
+ export declare function registerFromEnv(assistants: AssistantsRepo, specs: Record<string, string>, options: {
11
+ cwd: string;
12
+ }): Promise<(CompiledGraph<string, any, any, Record<string, any>, any, any, unknown, unknown, any> | CompiledGraphFactory<string>)[]>;
13
+ export declare function getGraph(graphId: string, config: LangGraphRunnableConfig | undefined, options?: {
14
+ checkpointer?: BaseCheckpointSaver | null;
15
+ store?: BaseStore;
16
+ }): Promise<CompiledGraph<string, any, any, Record<string, any>, any, any, unknown, unknown, any>>;
17
+ export declare function assertGraphExists(graphId: string): void;
18
+ export declare function getGraphKeys(): string[];
19
+ export declare function getCachedStaticGraphSchema(graphId: string): Promise<Record<string, GraphSchema>>;
@@ -0,0 +1,2 @@
1
+ export function initialize(args: any): Promise<void>;
2
+ export function resolve(specifier: any, context: any, nextResolve: any): Promise<any>;
@@ -0,0 +1,52 @@
1
+ // This module hook is used to ensure that @langchain/langgraph package
2
+ // is imported from a consistent location.
3
+ // Accepts `{ parentURL: string }` as argument when registering the hook.
4
+ const OVERRIDE_RESOLVE = [
5
+ // Override `@langchain/langgraph` or `@langchain/langgraph/prebuilt`,
6
+ // but not `@langchain/langgraph-sdk`
7
+ new RegExp(`^@langchain\/langgraph(\/.+)?$`),
8
+ new RegExp(`^@langchain\/langgraph-checkpoint(\/.+)?$`),
9
+ ];
10
+ let parentURL;
11
+ let langgraphPackageURL;
12
+ export async function initialize(args) {
13
+ parentURL = args.parentURL;
14
+ }
15
+ export async function resolve(specifier, context, nextResolve) {
16
+ // HACK: @tailwindcss/node internally uses an ESM loader cache, which does not play nicely with `tsx`.
17
+ // Node.js crashes with "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file".
18
+ // As it already is a valid URI, we can just short-circuit the resolution and avoid `tsx`.
19
+ if (specifier.includes("@tailwindcss/node/dist/esm-cache.loader") &&
20
+ specifier.startsWith("file://")) {
21
+ return {
22
+ shortCircuit: true,
23
+ // Node 18.x will for some reason attempt to load `.mts` instead of `.mjs`
24
+ url: specifier.replace(".mts", ".mjs"),
25
+ format: "module",
26
+ };
27
+ }
28
+ if (specifier === "@langchain/langgraph-checkpoint") {
29
+ // resolve relative to @langchain/langgraph package instead
30
+ // This is done to avoid adding a direct dependency on @langchain/langgraph-checkpoint
31
+ // in project, which if not present will cause `pnpm` to not find the package.
32
+ if (!langgraphPackageURL) {
33
+ const main = await nextResolve("@langchain/langgraph", {
34
+ ...context,
35
+ parentURL,
36
+ });
37
+ langgraphPackageURL = main.url.toString();
38
+ }
39
+ return await nextResolve(specifier, {
40
+ ...context,
41
+ parentURL: langgraphPackageURL,
42
+ });
43
+ }
44
+ if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
45
+ const resolved = await nextResolve(specifier, { ...context, parentURL });
46
+ // If @langchain/langgraph is resolved first, cache it!
47
+ if (specifier === "@langchain/langgraph" && !langgraphPackageURL) {
48
+ langgraphPackageURL = resolved.url.toString();
49
+ }
50
+ }
51
+ return nextResolve(specifier, context);
52
+ }