@langchain/langgraph-api 0.0.26 → 0.0.28

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.
@@ -1,10 +1,10 @@
1
1
  import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
3
  import { v4 as uuid4 } from "uuid";
4
- import * as schemas from "../schemas.mjs";
5
- import { Threads } from "../storage/ops.mjs";
6
4
  import { z } from "zod";
5
+ import * as schemas from "../schemas.mjs";
7
6
  import { stateSnapshotToThreadState } from "../state.mjs";
7
+ import { Threads } from "../storage/ops.mjs";
8
8
  import { jsonExtra } from "../utils/hono.mjs";
9
9
  const api = new Hono();
10
10
  // Threads Routes
@@ -21,19 +21,27 @@ api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), asy
21
21
  // Search Threads
22
22
  const payload = c.req.valid("json");
23
23
  const result = [];
24
+ let total = 0;
24
25
  for await (const item of Threads.search({
25
26
  status: payload.status,
26
27
  values: payload.values,
27
28
  metadata: payload.metadata,
28
29
  limit: payload.limit ?? 10,
29
30
  offset: payload.offset ?? 0,
31
+ sort_by: payload.sort_by ?? "created_at",
32
+ sort_order: payload.sort_order ?? "desc",
30
33
  }, c.var.auth)) {
31
34
  result.push({
32
- ...item,
33
- created_at: item.created_at.toISOString(),
34
- updated_at: item.updated_at.toISOString(),
35
+ ...item.thread,
36
+ created_at: item.thread.created_at.toISOString(),
37
+ updated_at: item.thread.updated_at.toISOString(),
35
38
  });
39
+ // Only set total if it's the first item
40
+ if (total === 0) {
41
+ total = item.total;
42
+ }
36
43
  }
44
+ c.res.headers.set("X-Pagination-Total", total.toString());
37
45
  return jsonExtra(c, result);
38
46
  });
39
47
  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) => {
package/dist/schemas.mjs CHANGED
@@ -287,6 +287,11 @@ export const ThreadSearchRequest = z
287
287
  .gte(0)
288
288
  .describe("Offset to start from.")
289
289
  .optional(),
290
+ sort_by: z
291
+ .enum(["thread_id", "status", "created_at", "updated_at"])
292
+ .describe("Sort by field.")
293
+ .optional(),
294
+ sort_order: z.enum(["asc", "desc"]).describe("Sort order.").optional(),
290
295
  })
291
296
  .describe("Payload for listing threads.");
292
297
  export const Thread = z.object({
@@ -0,0 +1,15 @@
1
+ export declare function checkSemver(packages: {
2
+ name: string;
3
+ version: string;
4
+ }[]): Promise<{
5
+ name: string;
6
+ version: string;
7
+ required: string;
8
+ satisfies: boolean;
9
+ }[]>;
10
+ export declare function checkLangGraphSemver(): Promise<{
11
+ name: string;
12
+ version: string;
13
+ required: string;
14
+ satisfies: boolean;
15
+ }[]>;
@@ -0,0 +1,35 @@
1
+ import * as url from "node:url";
2
+ import * as fs from "node:fs/promises";
3
+ import * as semver from "semver";
4
+ const packageJsonPath = url.fileURLToPath(new URL("../../package.json", import.meta.url));
5
+ export async function checkSemver(packages) {
6
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
7
+ const peerDependencies = packageJson.peerDependencies ?? {};
8
+ return packages.flatMap((pkg) => {
9
+ const required = peerDependencies[pkg.name];
10
+ if (!required)
11
+ return [];
12
+ const satisfies = semver.satisfies(pkg.version, required);
13
+ return { ...pkg, required, satisfies };
14
+ });
15
+ }
16
+ export async function checkLangGraphSemver() {
17
+ const resolveVersion = async (name) => {
18
+ let version = "0.0.0";
19
+ try {
20
+ const pkgJson = await import(`${name}/package.json`);
21
+ version = pkgJson.version || version;
22
+ }
23
+ catch {
24
+ // pass
25
+ }
26
+ return { name, version };
27
+ };
28
+ const validate = [
29
+ "@langchain/core",
30
+ "@langchain/langgraph",
31
+ "@langchain/langgraph-checkpoint",
32
+ ];
33
+ const resolved = await Promise.all(validate.map((name) => resolveVersion(name)));
34
+ return checkSemver(resolved);
35
+ }
package/dist/server.mjs CHANGED
@@ -18,6 +18,7 @@ import { registerAuth } from "./auth/index.mjs";
18
18
  import { registerHttp } from "./http/custom.mjs";
19
19
  import { cors, ensureContentType } from "./http/middleware.mjs";
20
20
  import { bindLoopbackFetch } from "./loopback.mjs";
21
+ import { checkLangGraphSemver } from "./semver/index.mjs";
21
22
  export const StartServerSchema = z.object({
22
23
  port: z.number(),
23
24
  nWorkers: z.number(),
@@ -55,6 +56,14 @@ export const StartServerSchema = z.object({
55
56
  .optional(),
56
57
  });
57
58
  export async function startServer(options) {
59
+ const semver = await checkLangGraphSemver();
60
+ const invalidPackages = semver.filter((s) => !s.satisfies);
61
+ if (invalidPackages.length > 0) {
62
+ logger.warn(`Some LangGraph.js dependencies are not up to date. Please make sure to update them to the required version.`, Object.fromEntries(invalidPackages.map(({ name, version, required }) => [
63
+ name,
64
+ { version, required },
65
+ ])));
66
+ }
58
67
  logger.info(`Initializing storage...`);
59
68
  const callbacks = await Promise.all([
60
69
  opsConn.initialize(options.cwd),
@@ -81,9 +90,6 @@ export async function startServer(options) {
81
90
  truncate({ runs, threads, assistants, checkpointer, store });
82
91
  return c.json({ ok: true });
83
92
  });
84
- app.use(cors(options.http?.cors));
85
- app.use(requestLogger());
86
- app.use(ensureContentType());
87
93
  if (options.auth?.path) {
88
94
  logger.info(`Loading auth from ${options.auth.path}`);
89
95
  await registerAuth(options.auth, { cwd: options.cwd });
@@ -94,6 +100,9 @@ export async function startServer(options) {
94
100
  const { api } = await registerHttp(options.http.app, { cwd: options.cwd });
95
101
  app.route("/", api);
96
102
  }
103
+ app.use(cors(options.http?.cors));
104
+ app.use(requestLogger());
105
+ app.use(ensureContentType());
97
106
  if (!options.http?.disable_meta)
98
107
  app.route("/", meta);
99
108
  if (!options.http?.disable_assistants)
@@ -1,13 +1,13 @@
1
1
  import { HTTPException } from "hono/http-exception";
2
2
  import { v4 as uuid4, v5 as uuid5 } from "uuid";
3
+ import { handleAuthEvent, isAuthMatching } from "../auth/custom.mjs";
4
+ import { getLangGraphCommand } from "../command.mjs";
3
5
  import { getGraph, NAMESPACE_GRAPH } from "../graph/load.mjs";
4
- import { checkpointer } from "./checkpoint.mjs";
5
- import { store } from "./store.mjs";
6
6
  import { logger } from "../logging.mjs";
7
7
  import { serializeError } from "../utils/serde.mjs";
8
+ import { checkpointer } from "./checkpoint.mjs";
8
9
  import { FileSystemPersistence } from "./persist.mjs";
9
- import { getLangGraphCommand } from "../command.mjs";
10
- import { handleAuthEvent, isAuthMatching } from "../auth/custom.mjs";
10
+ import { store } from "./store.mjs";
11
11
  export const conn = new FileSystemPersistence(".langgraphjs_ops.json", () => ({
12
12
  runs: {},
13
13
  threads: {},
@@ -374,9 +374,27 @@ export class Threads {
374
374
  return false;
375
375
  return true;
376
376
  })
377
- .sort((a, b) => b["created_at"].getTime() - a["created_at"].getTime());
377
+ .sort((a, b) => {
378
+ const sortBy = options.sort_by ?? "created_at";
379
+ const sortOrder = options.sort_order ?? "desc";
380
+ if (sortBy === "created_at" || sortBy === "updated_at") {
381
+ const aTime = a[sortBy].getTime();
382
+ const bTime = b[sortBy].getTime();
383
+ return sortOrder === "desc" ? bTime - aTime : aTime - bTime;
384
+ }
385
+ if (sortBy === "thread_id" || sortBy === "status") {
386
+ const aVal = a[sortBy];
387
+ const bVal = b[sortBy];
388
+ return sortOrder === "desc"
389
+ ? bVal.localeCompare(aVal)
390
+ : aVal.localeCompare(bVal);
391
+ }
392
+ return 0;
393
+ });
394
+ // Calculate total count before pagination
395
+ const total = filtered.length;
378
396
  for (const thread of filtered.slice(options.offset, options.offset + options.limit)) {
379
- yield thread;
397
+ yield { thread, total };
380
398
  }
381
399
  });
382
400
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-api",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^18.19.0 || >=20.16.0"
@@ -18,7 +18,12 @@
18
18
  "./auth": {
19
19
  "types": "./dist/auth/index.d.ts",
20
20
  "default": "./dist/auth/index.mjs"
21
- }
21
+ },
22
+ "./semver": {
23
+ "types": "./dist/semver/index.d.ts",
24
+ "default": "./dist/semver/index.mjs"
25
+ },
26
+ "./package.json": "./package.json"
22
27
  },
23
28
  "repository": {
24
29
  "type": "git",
@@ -36,6 +41,7 @@
36
41
  "hono": "^4.5.4",
37
42
  "langsmith": "^0.2.15",
38
43
  "open": "^10.1.0",
44
+ "semver": "^7.7.1",
39
45
  "stacktrace-parser": "^0.1.10",
40
46
  "superjson": "^2.2.2",
41
47
  "tsx": "^4.19.3",
@@ -43,13 +49,13 @@
43
49
  "winston": "^3.17.0",
44
50
  "winston-console-format": "^1.0.8",
45
51
  "zod": "^3.23.8",
46
- "@langchain/langgraph-ui": "0.0.26"
52
+ "@langchain/langgraph-ui": "0.0.28"
47
53
  },
48
54
  "peerDependencies": {
49
55
  "@langchain/core": "^0.3.42",
50
56
  "@langchain/langgraph": "^0.2.57",
51
57
  "@langchain/langgraph-checkpoint": "^0.0.16",
52
- "@langchain/langgraph-sdk": "^0.0.67",
58
+ "@langchain/langgraph-sdk": "^0.0.70",
53
59
  "typescript": "^5.5.4"
54
60
  },
55
61
  "peerDependenciesMeta": {
@@ -58,13 +64,15 @@
58
64
  }
59
65
  },
60
66
  "devDependencies": {
61
- "@langchain/langgraph-sdk": "^0.0.67",
67
+ "typescript": "^5.5.4",
68
+ "@langchain/langgraph-sdk": "^0.0.70",
62
69
  "@types/babel__code-frame": "^7.0.6",
70
+ "@types/node": "^22.2.0",
63
71
  "@types/react": "^19.0.8",
64
72
  "@types/react-dom": "^19.0.3",
65
- "@types/node": "^22.2.0",
66
- "jose": "^6.0.10",
73
+ "@types/semver": "^7.7.0",
67
74
  "@types/uuid": "^10.0.0",
75
+ "jose": "^6.0.10",
68
76
  "postgres": "^3.4.5",
69
77
  "prettier": "^3.3.3",
70
78
  "vitest": "^3.0.5"