@langchain/langgraph-api 0.0.59 → 0.0.61

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @langchain/langgraph-api
2
2
 
3
+ ## 0.0.61
4
+
5
+ ### Patch Changes
6
+
7
+ - a334897: feat(api): add /count endpoints for threads and assistants
8
+ - 9357bb7: chore(api): abstract internal operations away from createServer
9
+ - 9f13d74: fix(api): prevent overriding default CORS config when applying a single override
10
+ - @langchain/langgraph-ui@0.0.61
11
+
12
+ ## 0.0.60
13
+
14
+ ### Patch Changes
15
+
16
+ - 9c57526: fix(api): serialization of "checkpoints" and "tasks" stream modes
17
+ - @langchain/langgraph-ui@0.0.60
18
+
3
19
  ## 0.0.59
4
20
 
5
21
  ### Patch Changes
@@ -6,7 +6,7 @@ import { getAssistantId, getCachedStaticGraphSchema, getGraph, } from "../graph/
6
6
  import { getRuntimeGraphSchema } from "../graph/parser/index.mjs";
7
7
  import { HTTPException } from "hono/http-exception";
8
8
  import * as schemas from "../schemas.mjs";
9
- import { Assistants } from "../storage/ops.mjs";
9
+ import { assistants } from "../storage/context.mjs";
10
10
  const api = new Hono();
11
11
  const RunnableConfigSchema = z.object({
12
12
  tags: z.array(z.string()).optional(),
@@ -33,7 +33,7 @@ const getRunnableConfig = (userConfig) => {
33
33
  api.post("/assistants", zValidator("json", schemas.AssistantCreate), async (c) => {
34
34
  // Create Assistant
35
35
  const payload = c.req.valid("json");
36
- const assistant = await Assistants.put(payload.assistant_id ?? uuid(), {
36
+ const assistant = await assistants().put(payload.assistant_id ?? uuid(), {
37
37
  config: payload.config ?? {},
38
38
  context: payload.context ?? {},
39
39
  graph_id: payload.graph_id,
@@ -48,7 +48,7 @@ api.post("/assistants/search", zValidator("json", schemas.AssistantSearchRequest
48
48
  const payload = c.req.valid("json");
49
49
  const result = [];
50
50
  let total = 0;
51
- for await (const item of Assistants.search({
51
+ for await (const item of assistants().search({
52
52
  graph_id: payload.graph_id,
53
53
  metadata: payload.metadata,
54
54
  limit: payload.limit ?? 10,
@@ -62,26 +62,31 @@ api.post("/assistants/search", zValidator("json", schemas.AssistantSearchRequest
62
62
  c.res.headers.set("X-Pagination-Total", total.toString());
63
63
  return c.json(result);
64
64
  });
65
+ api.post("/assistants/count", zValidator("json", schemas.AssistantCountRequest), async (c) => {
66
+ const payload = c.req.valid("json");
67
+ const total = await assistants().count(payload, c.var.auth);
68
+ return c.json(total);
69
+ });
65
70
  api.get("/assistants/:assistant_id", async (c) => {
66
71
  // Get Assistant
67
72
  const assistantId = getAssistantId(c.req.param("assistant_id"));
68
- return c.json(await Assistants.get(assistantId, c.var.auth));
73
+ return c.json(await assistants().get(assistantId, c.var.auth));
69
74
  });
70
75
  api.delete("/assistants/:assistant_id", async (c) => {
71
76
  // Delete Assistant
72
77
  const assistantId = getAssistantId(c.req.param("assistant_id"));
73
- return c.json(await Assistants.delete(assistantId, c.var.auth));
78
+ return c.json(await assistants().delete(assistantId, c.var.auth));
74
79
  });
75
80
  api.patch("/assistants/:assistant_id", zValidator("json", schemas.AssistantPatch), async (c) => {
76
81
  // Patch Assistant
77
82
  const assistantId = getAssistantId(c.req.param("assistant_id"));
78
83
  const payload = c.req.valid("json");
79
- return c.json(await Assistants.patch(assistantId, payload, c.var.auth));
84
+ return c.json(await assistants().patch(assistantId, payload, c.var.auth));
80
85
  });
81
86
  api.get("/assistants/:assistant_id/graph", zValidator("query", z.object({ xray: schemas.coercedBoolean.optional() })), async (c) => {
82
87
  // Get Assistant Graph
83
88
  const assistantId = getAssistantId(c.req.param("assistant_id"));
84
- const assistant = await Assistants.get(assistantId, c.var.auth);
89
+ const assistant = await assistants().get(assistantId, c.var.auth);
85
90
  const { xray } = c.req.valid("query");
86
91
  const config = getRunnableConfig(assistant.config);
87
92
  const graph = await getGraph(assistant.graph_id, config);
@@ -95,7 +100,7 @@ api.get("/assistants/:assistant_id/schemas", zValidator("json", z.object({ confi
95
100
  // Get Assistant Schemas
96
101
  const json = c.req.valid("json");
97
102
  const assistantId = getAssistantId(c.req.param("assistant_id"));
98
- const assistant = await Assistants.get(assistantId, c.var.auth);
103
+ const assistant = await assistants().get(assistantId, c.var.auth);
99
104
  const config = getRunnableConfig(json.config);
100
105
  const graph = await getGraph(assistant.graph_id, config);
101
106
  const schema = await (async () => {
@@ -124,7 +129,7 @@ api.get("/assistants/:assistant_id/subgraphs/:namespace?", zValidator("param", z
124
129
  const { assistant_id, namespace } = c.req.valid("param");
125
130
  const { recurse } = c.req.valid("query");
126
131
  const assistantId = getAssistantId(assistant_id);
127
- const assistant = await Assistants.get(assistantId, c.var.auth);
132
+ const assistant = await assistants().get(assistantId, c.var.auth);
128
133
  const config = getRunnableConfig(assistant.config);
129
134
  const graph = await getGraph(assistant.graph_id, config);
130
135
  const result = [];
@@ -156,7 +161,7 @@ api.post("/assistants/:assistant_id/latest", zValidator("json", schemas.Assistan
156
161
  // Set Latest Assistant Version
157
162
  const assistantId = getAssistantId(c.req.param("assistant_id"));
158
163
  const { version } = c.req.valid("json");
159
- return c.json(await Assistants.setLatest(assistantId, version, c.var.auth));
164
+ return c.json(await assistants().setLatest(assistantId, version, c.var.auth));
160
165
  });
161
166
  api.post("/assistants/:assistant_id/versions", zValidator("json", z.object({
162
167
  limit: z.number().min(1).max(1000).optional().default(10),
@@ -166,7 +171,7 @@ api.post("/assistants/:assistant_id/versions", zValidator("json", z.object({
166
171
  // Get Assistant Versions
167
172
  const assistantId = getAssistantId(c.req.param("assistant_id"));
168
173
  const { limit, offset, metadata } = c.req.valid("json");
169
- const versions = await Assistants.getVersions(assistantId, { limit, offset, metadata }, c.var.auth);
174
+ const versions = await assistants().getVersions(assistantId, { limit, offset, metadata }, c.var.auth);
170
175
  if (!versions?.length) {
171
176
  throw new HTTPException(404, {
172
177
  message: `Assistant "${assistantId}" not found.`,
package/dist/api/meta.mjs CHANGED
@@ -7,26 +7,33 @@ const api = new Hono();
7
7
  const packageJsonPath = path.resolve(url.fileURLToPath(import.meta.url), "../../../package.json");
8
8
  let version;
9
9
  let langgraph_js_version;
10
- try {
11
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
12
- version = packageJson.version;
13
- }
14
- catch {
15
- console.warn("Could not determine version of langgraph-api");
16
- }
17
- // Get the installed version of @langchain/langgraph
18
- try {
19
- const langgraphPkg = await import("@langchain/langgraph/package.json");
20
- if (langgraphPkg?.default?.version) {
21
- langgraph_js_version = langgraphPkg.default.version;
10
+ let versionInfoLoaded = false;
11
+ const loadVersionInfo = async () => {
12
+ try {
13
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
14
+ version = packageJson.version;
22
15
  }
23
- }
24
- catch {
25
- console.warn("Could not determine version of @langchain/langgraph");
26
- }
16
+ catch {
17
+ console.warn("Could not determine version of langgraph-api");
18
+ }
19
+ // Get the installed version of @langchain/langgraph
20
+ try {
21
+ const langgraphPkg = await import("@langchain/langgraph/package.json");
22
+ if (langgraphPkg?.default?.version) {
23
+ langgraph_js_version = langgraphPkg.default.version;
24
+ }
25
+ }
26
+ catch {
27
+ console.warn("Could not determine version of @langchain/langgraph");
28
+ }
29
+ };
27
30
  // read env variable
28
31
  const env = process.env;
29
- api.get("/info", (c) => {
32
+ api.get("/info", async (c) => {
33
+ if (!versionInfoLoaded) {
34
+ await loadVersionInfo();
35
+ versionInfoLoaded = true;
36
+ }
30
37
  const langsmithApiKey = env["LANGSMITH_API_KEY"] || env["LANGCHAIN_API_KEY"];
31
38
  const langsmithTracing = (() => {
32
39
  if (langsmithApiKey) {
package/dist/api/runs.mjs CHANGED
@@ -7,7 +7,7 @@ import { z } from "zod";
7
7
  import { getAssistantId } from "../graph/load.mjs";
8
8
  import { logError, logger } from "../logging.mjs";
9
9
  import * as schemas from "../schemas.mjs";
10
- import { Runs, Threads } from "../storage/ops.mjs";
10
+ import { runs, threads } from "../storage/context.mjs";
11
11
  import { getDisconnectAbortSignal, jsonExtra, waitKeepAlive, } from "../utils/hono.mjs";
12
12
  import { serialiseAsDict } from "../utils/serde.mjs";
13
13
  const api = new Hono();
@@ -71,7 +71,7 @@ const createValidRun = async (threadId, payload, kwargs) => {
71
71
  : undefined;
72
72
  if (!feedbackKeys?.length)
73
73
  feedbackKeys = undefined;
74
- const [first, ...inflight] = await Runs.put(runId, getAssistantId(assistantId), {
74
+ const [first, ...inflight] = await runs().put(runId, getAssistantId(assistantId), {
75
75
  input: run.input,
76
76
  command: run.command,
77
77
  config,
@@ -99,7 +99,7 @@ const createValidRun = async (threadId, payload, kwargs) => {
99
99
  if ((multitaskStrategy === "interrupt" || multitaskStrategy === "rollback") &&
100
100
  inflight.length > 0) {
101
101
  try {
102
- await Runs.cancel(threadId, inflight.map((run) => run.run_id), { action: multitaskStrategy }, auth);
102
+ await runs().cancel(threadId, inflight.map((run) => run.run_id), { action: multitaskStrategy }, auth);
103
103
  }
104
104
  catch (error) {
105
105
  logger.warn("Failed to cancel inflight runs, might be already cancelled", {
@@ -149,7 +149,7 @@ api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => {
149
149
  ? getDisconnectAbortSignal(c, stream)
150
150
  : undefined;
151
151
  try {
152
- for await (const { event, data } of Runs.Stream.join(run.run_id, undefined, {
152
+ for await (const { event, data } of runs().stream.join(run.run_id, undefined, {
153
153
  cancelOnDisconnect,
154
154
  lastEventId: run.kwargs.resumable ? "-1" : undefined,
155
155
  ignore404: true,
@@ -173,7 +173,7 @@ api.get("/runs/:run_id/stream", zValidator("param", z.object({ run_id: z.string(
173
173
  ? getDisconnectAbortSignal(c, stream)
174
174
  : undefined;
175
175
  try {
176
- for await (const { id, event, data } of Runs.Stream.join(run_id, undefined, { cancelOnDisconnect, lastEventId, ignore404: true }, c.var.auth)) {
176
+ for await (const { id, event, data } of runs().stream.join(run_id, undefined, { cancelOnDisconnect, lastEventId, ignore404: true }, c.var.auth)) {
177
177
  await stream.writeSSE({ id, data: serialiseAsDict(data), event });
178
178
  }
179
179
  }
@@ -190,7 +190,7 @@ api.post("/runs/wait", zValidator("json", schemas.RunCreate), async (c) => {
190
190
  headers: c.req.raw.headers,
191
191
  });
192
192
  c.header("Content-Location", `/runs/${run.run_id}`);
193
- return waitKeepAlive(c, Runs.wait(run.run_id, undefined, c.var.auth));
193
+ return waitKeepAlive(c, runs().wait(run.run_id, undefined, c.var.auth));
194
194
  });
195
195
  api.post("/runs", zValidator("json", schemas.RunCreate), async (c) => {
196
196
  // Create Stateless Run
@@ -220,11 +220,11 @@ api.get("/threads/:thread_id/runs", zValidator("param", z.object({ thread_id: z.
220
220
  // List runs
221
221
  const { thread_id } = c.req.valid("param");
222
222
  const { limit, offset, status, metadata } = c.req.valid("query");
223
- const [runs] = await Promise.all([
224
- Runs.search(thread_id, { limit, offset, status, metadata }, c.var.auth),
225
- Threads.get(thread_id, c.var.auth),
223
+ const [runsResponse] = await Promise.all([
224
+ runs().search(thread_id, { limit, offset, status, metadata }, c.var.auth),
225
+ threads().get(thread_id, c.var.auth),
226
226
  ]);
227
- return jsonExtra(c, runs);
227
+ return jsonExtra(c, runsResponse);
228
228
  });
229
229
  api.post("/threads/:thread_id/runs", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
230
230
  // Create Run
@@ -251,7 +251,7 @@ api.post("/threads/:thread_id/runs/stream", zValidator("param", z.object({ threa
251
251
  ? getDisconnectAbortSignal(c, stream)
252
252
  : undefined;
253
253
  try {
254
- for await (const { id, event, data } of Runs.Stream.join(run.run_id, thread_id, {
254
+ for await (const { id, event, data } of runs().stream.join(run.run_id, thread_id, {
255
255
  cancelOnDisconnect,
256
256
  lastEventId: run.kwargs.resumable ? "-1" : undefined,
257
257
  }, c.var.auth)) {
@@ -272,13 +272,13 @@ api.post("/threads/:thread_id/runs/wait", zValidator("param", z.object({ thread_
272
272
  headers: c.req.raw.headers,
273
273
  });
274
274
  c.header("Content-Location", `/threads/${thread_id}/runs/${run.run_id}`);
275
- return waitKeepAlive(c, Runs.join(run.run_id, thread_id, c.var.auth));
275
+ return waitKeepAlive(c, runs().join(run.run_id, thread_id, c.var.auth));
276
276
  });
277
277
  api.get("/threads/:thread_id/runs/:run_id", zValidator("param", z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() })), async (c) => {
278
278
  const { thread_id, run_id } = c.req.valid("param");
279
279
  const [run] = await Promise.all([
280
- Runs.get(run_id, thread_id, c.var.auth),
281
- Threads.get(thread_id, c.var.auth),
280
+ runs().get(run_id, thread_id, c.var.auth),
281
+ threads().get(thread_id, c.var.auth),
282
282
  ]);
283
283
  if (run == null)
284
284
  throw new HTTPException(404, { message: "Run not found" });
@@ -287,13 +287,13 @@ api.get("/threads/:thread_id/runs/:run_id", zValidator("param", z.object({ threa
287
287
  api.delete("/threads/:thread_id/runs/:run_id", zValidator("param", z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() })), async (c) => {
288
288
  // Delete Run
289
289
  const { thread_id, run_id } = c.req.valid("param");
290
- await Runs.delete(run_id, thread_id, c.var.auth);
290
+ await runs().delete(run_id, thread_id, c.var.auth);
291
291
  return c.body(null, 204);
292
292
  });
293
293
  api.get("/threads/:thread_id/runs/:run_id/join", zValidator("param", z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() })), async (c) => {
294
294
  // Join Run Http
295
295
  const { thread_id, run_id } = c.req.valid("param");
296
- return jsonExtra(c, await Runs.join(run_id, thread_id, c.var.auth));
296
+ return jsonExtra(c, await runs().join(run_id, thread_id, c.var.auth));
297
297
  });
298
298
  api.get("/threads/:thread_id/runs/:run_id/stream", zValidator("param", z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() })), zValidator("query", z.object({ cancel_on_disconnect: schemas.coercedBoolean.optional() })), async (c) => {
299
299
  // Stream Run Http
@@ -304,7 +304,7 @@ api.get("/threads/:thread_id/runs/:run_id/stream", zValidator("param", z.object(
304
304
  const signal = cancel_on_disconnect
305
305
  ? getDisconnectAbortSignal(c, stream)
306
306
  : undefined;
307
- for await (const { id, event, data } of Runs.Stream.join(run_id, thread_id, { cancelOnDisconnect: signal, lastEventId }, c.var.auth)) {
307
+ for await (const { id, event, data } of runs().stream.join(run_id, thread_id, { cancelOnDisconnect: signal, lastEventId }, c.var.auth)) {
308
308
  await stream.writeSSE({ id, data: serialiseAsDict(data), event });
309
309
  }
310
310
  });
@@ -316,9 +316,9 @@ api.post("/threads/:thread_id/runs/:run_id/cancel", zValidator("param", z.object
316
316
  // Cancel Run Http
317
317
  const { thread_id, run_id } = c.req.valid("param");
318
318
  const { wait, action } = c.req.valid("query");
319
- await Runs.cancel(thread_id, [run_id], { action }, c.var.auth);
319
+ await runs().cancel(thread_id, [run_id], { action }, c.var.auth);
320
320
  if (wait)
321
- await Runs.join(run_id, thread_id, c.var.auth);
321
+ await runs().join(run_id, thread_id, c.var.auth);
322
322
  return c.body(null, wait ? 204 : 202);
323
323
  });
324
324
  export default api;
@@ -3,7 +3,7 @@ import { zValidator } from "@hono/zod-validator";
3
3
  import * as schemas from "../schemas.mjs";
4
4
  import { HTTPException } from "hono/http-exception";
5
5
  import { store as storageStore } from "../storage/store.mjs";
6
- import { handleAuthEvent } from "../auth/custom.mjs";
6
+ import { handleAuthEvent } from "../auth/index.mjs";
7
7
  const api = new Hono();
8
8
  const validateNamespace = (namespace) => {
9
9
  if (!namespace || namespace.length === 0) {
@@ -4,16 +4,16 @@ import { v4 as uuid4 } from "uuid";
4
4
  import { z } from "zod";
5
5
  import * as schemas from "../schemas.mjs";
6
6
  import { stateSnapshotToThreadState } from "../state.mjs";
7
- import { Threads } from "../storage/ops.mjs";
7
+ import { threads } from "../storage/context.mjs";
8
8
  import { jsonExtra } from "../utils/hono.mjs";
9
9
  const api = new Hono();
10
10
  // Threads Routes
11
11
  api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
12
12
  // Create Thread
13
13
  const payload = c.req.valid("json");
14
- const thread = await Threads.put(payload.thread_id || uuid4(), { metadata: payload.metadata, if_exists: payload.if_exists ?? "raise" }, c.var.auth);
14
+ const thread = await threads().put(payload.thread_id || uuid4(), { metadata: payload.metadata, if_exists: payload.if_exists ?? "raise" }, c.var.auth);
15
15
  if (payload.supersteps?.length) {
16
- await Threads.State.bulk({ configurable: { thread_id: thread.thread_id } }, payload.supersteps, c.var.auth);
16
+ await threads().state.bulk({ configurable: { thread_id: thread.thread_id } }, payload.supersteps, c.var.auth);
17
17
  }
18
18
  return jsonExtra(c, thread);
19
19
  });
@@ -22,7 +22,7 @@ api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), asy
22
22
  const payload = c.req.valid("json");
23
23
  const result = [];
24
24
  let total = 0;
25
- for await (const item of Threads.search({
25
+ for await (const item of threads().search({
26
26
  status: payload.status,
27
27
  values: payload.values,
28
28
  metadata: payload.metadata,
@@ -44,11 +44,16 @@ api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), asy
44
44
  c.res.headers.set("X-Pagination-Total", total.toString());
45
45
  return jsonExtra(c, result);
46
46
  });
47
+ api.post("/threads/count", zValidator("json", schemas.ThreadCountRequest), async (c) => {
48
+ const payload = c.req.valid("json");
49
+ const total = await threads().count(payload, c.var.auth);
50
+ return c.json(total);
51
+ });
47
52
  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) => {
48
53
  // Get Latest Thread State
49
54
  const { thread_id } = c.req.valid("param");
50
55
  const { subgraphs } = c.req.valid("query");
51
- const state = stateSnapshotToThreadState(await Threads.State.get({ configurable: { thread_id } }, { subgraphs }, c.var.auth));
56
+ const state = stateSnapshotToThreadState(await threads().state.get({ configurable: { thread_id } }, { subgraphs }, c.var.auth));
52
57
  return jsonExtra(c, state);
53
58
  });
54
59
  api.post("/threads/:thread_id/state", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadStateUpdate), async (c) => {
@@ -64,7 +69,7 @@ api.post("/threads/:thread_id/state", zValidator("param", z.object({ thread_id:
64
69
  config.configurable ??= {};
65
70
  Object.assign(config.configurable, payload.checkpoint);
66
71
  }
67
- const inserted = await Threads.State.post(config, payload.values, payload.as_node, c.var.auth);
72
+ const inserted = await threads().state.post(config, payload.values, payload.as_node, c.var.auth);
68
73
  return jsonExtra(c, inserted);
69
74
  });
70
75
  api.get("/threads/:thread_id/state/:checkpoint_id", zValidator("param", z.object({
@@ -74,7 +79,7 @@ api.get("/threads/:thread_id/state/:checkpoint_id", zValidator("param", z.object
74
79
  // Get Thread State At Checkpoint
75
80
  const { thread_id, checkpoint_id } = c.req.valid("param");
76
81
  const { subgraphs } = c.req.valid("query");
77
- const state = stateSnapshotToThreadState(await Threads.State.get({ configurable: { thread_id, checkpoint_id } }, { subgraphs }, c.var.auth));
82
+ const state = stateSnapshotToThreadState(await threads().state.get({ configurable: { thread_id, checkpoint_id } }, { subgraphs }, c.var.auth));
78
83
  return jsonExtra(c, state);
79
84
  });
80
85
  api.post("/threads/:thread_id/state/checkpoint", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", z.object({
@@ -84,7 +89,7 @@ api.post("/threads/:thread_id/state/checkpoint", zValidator("param", z.object({
84
89
  // Get Thread State At Checkpoint Post
85
90
  const { thread_id } = c.req.valid("param");
86
91
  const { checkpoint, subgraphs } = c.req.valid("json");
87
- const state = stateSnapshotToThreadState(await Threads.State.get({ configurable: { thread_id, ...checkpoint } }, { subgraphs }, c.var.auth));
92
+ const state = stateSnapshotToThreadState(await threads().state.get({ configurable: { thread_id, ...checkpoint } }, { subgraphs }, c.var.auth));
88
93
  return jsonExtra(c, state);
89
94
  });
90
95
  api.get("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("query", z.object({
@@ -98,36 +103,36 @@ api.get("/threads/:thread_id/history", zValidator("param", z.object({ thread_id:
98
103
  // Get Thread History
99
104
  const { thread_id } = c.req.valid("param");
100
105
  const { limit, before } = c.req.valid("query");
101
- const states = await Threads.State.list({ configurable: { thread_id, checkpoint_ns: "" } }, { limit, before }, c.var.auth);
106
+ const states = await threads().state.list({ configurable: { thread_id, checkpoint_ns: "" } }, { limit, before }, c.var.auth);
102
107
  return jsonExtra(c, states.map(stateSnapshotToThreadState));
103
108
  });
104
109
  api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
105
110
  // Get Thread History Post
106
111
  const { thread_id } = c.req.valid("param");
107
112
  const { limit, before, metadata, checkpoint } = c.req.valid("json");
108
- const states = await Threads.State.list({ configurable: { thread_id, checkpoint_ns: "", ...checkpoint } }, { limit, before, metadata }, c.var.auth);
113
+ const states = await threads().state.list({ configurable: { thread_id, checkpoint_ns: "", ...checkpoint } }, { limit, before, metadata }, c.var.auth);
109
114
  return jsonExtra(c, states.map(stateSnapshotToThreadState));
110
115
  });
111
116
  api.get("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
112
117
  // Get Thread
113
118
  const { thread_id } = c.req.valid("param");
114
- return jsonExtra(c, await Threads.get(thread_id, c.var.auth));
119
+ return jsonExtra(c, await threads().get(thread_id, c.var.auth));
115
120
  });
116
121
  api.delete("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
117
122
  // Delete Thread
118
123
  const { thread_id } = c.req.valid("param");
119
- await Threads.delete(thread_id, c.var.auth);
124
+ await threads().delete(thread_id, c.var.auth);
120
125
  return new Response(null, { status: 204 });
121
126
  });
122
127
  api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadPatchRequest), async (c) => {
123
128
  // Patch Thread
124
129
  const { thread_id } = c.req.valid("param");
125
130
  const { metadata } = c.req.valid("json");
126
- return jsonExtra(c, await Threads.patch(thread_id, { metadata }, c.var.auth));
131
+ return jsonExtra(c, await threads().patch(thread_id, { metadata }, c.var.auth));
127
132
  });
128
133
  api.post("/threads/:thread_id/copy", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
129
134
  // Copy Thread
130
135
  const { thread_id } = c.req.valid("param");
131
- return jsonExtra(c, await Threads.copy(thread_id, c.var.auth));
136
+ return jsonExtra(c, await threads().copy(thread_id, c.var.auth));
132
137
  });
133
138
  export default api;
@@ -1,12 +1,9 @@
1
- import type { AuthEventValueMap } from "@langchain/langgraph-sdk/auth";
2
1
  import type { MiddlewareHandler } from "hono";
3
- import { type AuthContext, type AuthFilters } from "./index.mjs";
2
+ import { type AuthContext } from "./index.mjs";
4
3
  declare module "hono" {
5
4
  interface ContextVariableMap {
6
5
  auth?: AuthContext | undefined;
7
6
  }
8
7
  }
9
- export declare function isAuthMatching(metadata: Record<string, unknown> | undefined, filters: AuthFilters): boolean;
10
- export declare const handleAuthEvent: <T extends keyof AuthEventValueMap>(context: AuthContext | undefined, event: T, value: AuthEventValueMap[T]) => Promise<[AuthFilters | undefined, value: AuthEventValueMap[T]]>;
11
8
  export declare const auth: () => MiddlewareHandler;
12
9
  export { registerAuth } from "./index.mjs";
@@ -1,37 +1,4 @@
1
- import { authorize, authenticate, isAuthRegistered, isStudioAuthDisabled, } from "./index.mjs";
2
- export function isAuthMatching(metadata, filters) {
3
- if (filters == null)
4
- return true;
5
- for (const [key, value] of Object.entries(filters)) {
6
- if (typeof value === "object" && value != null) {
7
- if (value.$eq) {
8
- if (metadata?.[key] !== value.$eq)
9
- return false;
10
- }
11
- else if (value.$contains) {
12
- if (!Array.isArray(metadata?.[key]) ||
13
- !metadata?.[key].includes(value.$contains)) {
14
- return false;
15
- }
16
- }
17
- }
18
- else {
19
- if (metadata?.[key] !== value)
20
- return false;
21
- }
22
- }
23
- return true;
24
- }
25
- export const handleAuthEvent = async (context, event, value) => {
26
- const [resource, action] = event.split(":");
27
- const result = await authorize({
28
- resource,
29
- action,
30
- context,
31
- value,
32
- });
33
- return [result.filters, result.value];
34
- };
1
+ import { authenticate, isAuthRegistered, isStudioAuthDisabled, } from "./index.mjs";
35
2
  const STUDIO_USER = {
36
3
  kind: "StudioUser",
37
4
  display_name: "langgraph-studio-user",
@@ -1,3 +1,4 @@
1
+ import type { AuthEventValueMap } from "@langchain/langgraph-sdk/auth";
1
2
  export declare const isAuthRegistered: () => boolean;
2
3
  export declare const isStudioAuthDisabled: () => boolean;
3
4
  export type AuthFilters = Record<string, string | {
@@ -38,3 +39,5 @@ export declare function registerAuth(auth: {
38
39
  }, options: {
39
40
  cwd: string;
40
41
  }): Promise<void>;
42
+ export declare const handleAuthEvent: <T extends keyof AuthEventValueMap>(context: AuthContext | undefined, event: T, value: AuthEventValueMap[T]) => Promise<[AuthFilters | undefined, value: AuthEventValueMap[T]]>;
43
+ export declare function isAuthMatching(metadata: Record<string, unknown> | undefined, filters: AuthFilters): boolean;
@@ -118,3 +118,36 @@ export async function registerAuth(auth, options) {
118
118
  CUSTOM_AUTH = module;
119
119
  DISABLE_STUDIO_AUTH = auth.disable_studio_auth ?? false;
120
120
  }
121
+ export const handleAuthEvent = async (context, event, value) => {
122
+ const [resource, action] = event.split(":");
123
+ const result = await authorize({
124
+ resource,
125
+ action,
126
+ context,
127
+ value,
128
+ });
129
+ return [result.filters, result.value];
130
+ };
131
+ export function isAuthMatching(metadata, filters) {
132
+ if (filters == null)
133
+ return true;
134
+ for (const [key, value] of Object.entries(filters)) {
135
+ if (typeof value === "object" && value != null) {
136
+ if (value.$eq) {
137
+ if (metadata?.[key] !== value.$eq)
138
+ return false;
139
+ }
140
+ else if (value.$contains) {
141
+ if (!Array.isArray(metadata?.[key]) ||
142
+ !metadata?.[key].includes(value.$contains)) {
143
+ return false;
144
+ }
145
+ }
146
+ }
147
+ else {
148
+ if (metadata?.[key] !== value)
149
+ return false;
150
+ }
151
+ }
152
+ return true;
153
+ }
@@ -1,6 +1,6 @@
1
1
  import type { BaseCheckpointSaver, BaseStore, Pregel } from "@langchain/langgraph";
2
2
  import { Hono } from "hono";
3
- import type { Metadata } from "../storage/ops.mjs";
3
+ import type { Metadata } from "../storage/types.mjs";
4
4
  type AnyPregel = Pregel<any, any, any, any, any>;
5
5
  interface Thread {
6
6
  thread_id: string;
@@ -0,0 +1 @@
1
+ export { getGraph, assertGraphExists } from "./load.mjs";
@@ -0,0 +1,2 @@
1
+ // Public API for graph operations (useful for writing custom operation backends).
2
+ export { getGraph, assertGraphExists } from "./load.mjs";
@@ -1,3 +1,4 @@
1
+ import type { AssistantsRepo } from "../storage/types.mjs";
1
2
  import type { BaseCheckpointSaver, BaseStore, CompiledGraph, LangGraphRunnableConfig } from "@langchain/langgraph";
2
3
  import { type CompiledGraphFactory } from "./load.utils.mjs";
3
4
  import type { GraphSchema, GraphSpec } from "./parser/index.mjs";
@@ -6,11 +7,12 @@ export declare const GRAPH_SPEC: Record<string, GraphSpec>;
6
7
  export declare const GRAPH_SCHEMA: Record<string, Record<string, GraphSchema>>;
7
8
  export declare const NAMESPACE_GRAPH: Uint8Array<ArrayBufferLike>;
8
9
  export declare const getAssistantId: (graphId: string) => string;
9
- export declare function registerFromEnv(specs: Record<string, string>, options: {
10
+ export declare function registerFromEnv(assistants: AssistantsRepo, specs: Record<string, string>, options: {
10
11
  cwd: string;
11
12
  }): Promise<(CompiledGraph<string, any, any, Record<string, any>, any, any, unknown> | CompiledGraphFactory<string>)[]>;
12
13
  export declare function getGraph(graphId: string, config: LangGraphRunnableConfig | undefined, options?: {
13
14
  checkpointer?: BaseCheckpointSaver | null;
14
15
  store?: BaseStore;
15
16
  }): Promise<CompiledGraph<string, any, any, Record<string, any>, any, any, unknown>>;
17
+ export declare function assertGraphExists(graphId: string): void;
16
18
  export declare function getCachedStaticGraphSchema(graphId: string): Promise<Record<string, GraphSchema>>;
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import * as uuid from "uuid";
3
- import { Assistants } from "../storage/ops.mjs";
4
3
  import { HTTPException } from "hono/http-exception";
5
4
  import { resolveGraph } from "./load.utils.mjs";
6
5
  import { getStaticGraphSchema } from "./parser/index.mjs";
@@ -17,7 +16,7 @@ export const getAssistantId = (graphId) => {
17
16
  return uuid.v5(graphId, NAMESPACE_GRAPH);
18
17
  return graphId;
19
18
  };
20
- export async function registerFromEnv(specs, options) {
19
+ export async function registerFromEnv(assistants, specs, options) {
21
20
  const envConfig = process.env.LANGGRAPH_CONFIG
22
21
  ? ConfigSchema.parse(JSON.parse(process.env.LANGGRAPH_CONFIG))
23
22
  : undefined;
@@ -32,7 +31,7 @@ export async function registerFromEnv(specs, options) {
32
31
  // registering the graph runtime
33
32
  GRAPHS[graphId] = resolved;
34
33
  GRAPH_SPEC[graphId] = spec;
35
- await Assistants.put(uuid.v5(graphId, NAMESPACE_GRAPH), {
34
+ await assistants.put(uuid.v5(graphId, NAMESPACE_GRAPH), {
36
35
  graph_id: graphId,
37
36
  metadata: { created_by: "system" },
38
37
  config,
@@ -44,8 +43,7 @@ export async function registerFromEnv(specs, options) {
44
43
  }));
45
44
  }
46
45
  export async function getGraph(graphId, config, options) {
47
- if (!GRAPHS[graphId])
48
- throw new HTTPException(404, { message: `Graph "${graphId}" not found` });
46
+ assertGraphExists(graphId);
49
47
  const compiled = typeof GRAPHS[graphId] === "function"
50
48
  ? await GRAPHS[graphId](config ?? { configurable: {} })
51
49
  : GRAPHS[graphId];
@@ -58,6 +56,12 @@ export async function getGraph(graphId, config, options) {
58
56
  compiled.store = options?.store ?? store;
59
57
  return compiled;
60
58
  }
59
+ export function assertGraphExists(graphId) {
60
+ if (!GRAPHS[graphId])
61
+ throw new HTTPException(404, {
62
+ message: `Graph "${graphId}" not found`,
63
+ });
64
+ }
61
65
  export async function getCachedStaticGraphSchema(graphId) {
62
66
  if (!GRAPH_SPEC[graphId])
63
67
  throw new HTTPException(404, {