@langchain/langgraph-api 1.1.14 → 1.1.16
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/dist/api/assistants.mjs +1 -1
- package/dist/api/runs.mjs +2 -2
- package/dist/api/threads.mjs +2 -2
- package/dist/experimental/embed.mjs +131 -11
- package/dist/storage/ops.mjs +3 -3
- package/package.json +6 -6
package/dist/api/assistants.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
|
-
import {
|
|
3
|
+
import { v7 as uuid } from "uuid";
|
|
4
4
|
import { z } from "zod/v3";
|
|
5
5
|
import { getAssistantId, getCachedStaticGraphSchema, getGraph, } from "../graph/load.mjs";
|
|
6
6
|
import { getRuntimeGraphSchema } from "../graph/parser/index.mjs";
|
package/dist/api/runs.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { zValidator } from "@hono/zod-validator";
|
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { HTTPException } from "hono/http-exception";
|
|
4
4
|
import { streamSSE } from "hono/streaming";
|
|
5
|
-
import {
|
|
5
|
+
import { v7 as uuid7 } from "uuid";
|
|
6
6
|
import { z } from "zod/v3";
|
|
7
7
|
import { getAssistantId } from "../graph/load.mjs";
|
|
8
8
|
import { logError, logger } from "../logging.mjs";
|
|
@@ -14,7 +14,7 @@ const api = new Hono();
|
|
|
14
14
|
const createValidRun = async (threadId, payload, kwargs) => {
|
|
15
15
|
const { assistant_id: assistantId, ...run } = payload;
|
|
16
16
|
const { auth, headers } = kwargs ?? {};
|
|
17
|
-
const runId =
|
|
17
|
+
const runId = uuid7();
|
|
18
18
|
const streamMode = Array.isArray(payload.stream_mode)
|
|
19
19
|
? payload.stream_mode
|
|
20
20
|
: payload.stream_mode != null
|
package/dist/api/threads.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
|
-
import {
|
|
3
|
+
import { v7 as uuid7 } from "uuid";
|
|
4
4
|
import { z } from "zod/v3";
|
|
5
5
|
import * as schemas from "../schemas.mjs";
|
|
6
6
|
import { stateSnapshotToThreadState } from "../state.mjs";
|
|
@@ -11,7 +11,7 @@ const api = new Hono();
|
|
|
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 ||
|
|
14
|
+
const thread = await threads().put(payload.thread_id || uuid7(), { metadata: payload.metadata, if_exists: payload.if_exists ?? "raise" }, c.var.auth);
|
|
15
15
|
if (payload.supersteps?.length) {
|
|
16
16
|
await threads().state.bulk({ configurable: { thread_id: thread.thread_id } }, payload.supersteps, c.var.auth);
|
|
17
17
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { zValidator } from "@hono/zod-validator";
|
|
3
3
|
import { streamSSE } from "hono/streaming";
|
|
4
|
-
import {
|
|
4
|
+
import { v7 as uuidv7 } from "uuid";
|
|
5
5
|
import * as schemas from "../schemas.mjs";
|
|
6
6
|
import { z } from "zod/v3";
|
|
7
7
|
import { streamState } from "../stream.mjs";
|
|
@@ -9,9 +9,9 @@ import { serialiseAsDict, serializeError } from "../utils/serde.mjs";
|
|
|
9
9
|
import { getDisconnectAbortSignal, jsonExtra } from "../utils/hono.mjs";
|
|
10
10
|
import { stateSnapshotToThreadState } from "../state.mjs";
|
|
11
11
|
import { ensureContentType } from "../http/middleware.mjs";
|
|
12
|
-
function createStubRun(threadId, payload) {
|
|
12
|
+
function createStubRun(threadId, payload, overrides) {
|
|
13
13
|
const now = new Date();
|
|
14
|
-
const runId =
|
|
14
|
+
const runId = uuidv7();
|
|
15
15
|
let streamMode = Array.isArray(payload.stream_mode)
|
|
16
16
|
? payload.stream_mode
|
|
17
17
|
: payload.stream_mode
|
|
@@ -41,7 +41,7 @@ function createStubRun(threadId, payload) {
|
|
|
41
41
|
thread_id: threadId,
|
|
42
42
|
assistant_id: payload.assistant_id,
|
|
43
43
|
metadata: payload.metadata ?? {},
|
|
44
|
-
status: "running",
|
|
44
|
+
status: overrides?.status ?? "running",
|
|
45
45
|
kwargs: {
|
|
46
46
|
input: payload.input,
|
|
47
47
|
command: payload.command,
|
|
@@ -54,7 +54,9 @@ function createStubRun(threadId, payload) {
|
|
|
54
54
|
subgraphs: payload.stream_subgraphs,
|
|
55
55
|
temporary: false,
|
|
56
56
|
},
|
|
57
|
-
multitask_strategy:
|
|
57
|
+
multitask_strategy: (overrides?.multitask_strategy ??
|
|
58
|
+
payload.multitask_strategy ??
|
|
59
|
+
"reject"),
|
|
58
60
|
created_at: now,
|
|
59
61
|
updated_at: now,
|
|
60
62
|
};
|
|
@@ -65,6 +67,32 @@ function createStubRun(threadId, payload) {
|
|
|
65
67
|
* @experimental Does not follow semver.
|
|
66
68
|
*/
|
|
67
69
|
export function createEmbedServer(options) {
|
|
70
|
+
const threadRunState = new Map();
|
|
71
|
+
function getThreadState(threadId) {
|
|
72
|
+
let state = threadRunState.get(threadId);
|
|
73
|
+
if (!state) {
|
|
74
|
+
state = { activeRunId: null, pendingRuns: [] };
|
|
75
|
+
threadRunState.set(threadId, state);
|
|
76
|
+
}
|
|
77
|
+
return state;
|
|
78
|
+
}
|
|
79
|
+
async function waitForRunReady(threadId, runId, signal) {
|
|
80
|
+
const state = getThreadState(threadId);
|
|
81
|
+
const run = state.pendingRuns.find((r) => r.run_id === runId);
|
|
82
|
+
if (!run)
|
|
83
|
+
return null;
|
|
84
|
+
while (true) {
|
|
85
|
+
if (signal?.aborted) {
|
|
86
|
+
throw new DOMException("Aborted", "AbortError");
|
|
87
|
+
}
|
|
88
|
+
const isHead = state.pendingRuns[0]?.run_id === runId;
|
|
89
|
+
const noActive = !state.activeRunId;
|
|
90
|
+
if (isHead && noActive)
|
|
91
|
+
break;
|
|
92
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
93
|
+
}
|
|
94
|
+
return run;
|
|
95
|
+
}
|
|
68
96
|
async function getGraph(graphId) {
|
|
69
97
|
const targetGraph = options.graph[graphId];
|
|
70
98
|
targetGraph.store = options.store;
|
|
@@ -76,7 +104,7 @@ export function createEmbedServer(options) {
|
|
|
76
104
|
api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
|
|
77
105
|
// create a new thread
|
|
78
106
|
const payload = c.req.valid("json");
|
|
79
|
-
const threadId = payload.thread_id ||
|
|
107
|
+
const threadId = payload.thread_id || uuidv7();
|
|
80
108
|
return jsonExtra(c, await options.threads.set(threadId, {
|
|
81
109
|
kind: "put",
|
|
82
110
|
metadata: payload.metadata,
|
|
@@ -222,16 +250,102 @@ export function createEmbedServer(options) {
|
|
|
222
250
|
}
|
|
223
251
|
return jsonExtra(c, result);
|
|
224
252
|
});
|
|
253
|
+
api.post("/threads/:thread_id/runs", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
|
|
254
|
+
const { thread_id } = c.req.valid("param");
|
|
255
|
+
const payload = c.req.valid("json");
|
|
256
|
+
const thread = await options.threads.get(thread_id);
|
|
257
|
+
if (thread == null)
|
|
258
|
+
return c.json({ error: "Thread not found" }, 404);
|
|
259
|
+
const state = getThreadState(thread_id);
|
|
260
|
+
const multitaskStrategy = payload.multitask_strategy ?? "reject";
|
|
261
|
+
const shouldEnqueue = multitaskStrategy === "enqueue" && state.activeRunId != null;
|
|
262
|
+
const run = createStubRun(thread_id, payload, {
|
|
263
|
+
status: shouldEnqueue ? "pending" : "running",
|
|
264
|
+
multitask_strategy: multitaskStrategy,
|
|
265
|
+
});
|
|
266
|
+
state.pendingRuns.push(run);
|
|
267
|
+
c.header("Content-Location", `/threads/${thread_id}/runs/${run.run_id}`);
|
|
268
|
+
return jsonExtra(c, run);
|
|
269
|
+
});
|
|
270
|
+
api.get("/threads/:thread_id/runs/:run_id/stream", zValidator("param", z.object({
|
|
271
|
+
thread_id: z.string().uuid(),
|
|
272
|
+
run_id: z.string().uuid(),
|
|
273
|
+
})), async (c) => {
|
|
274
|
+
const { thread_id, run_id } = c.req.valid("param");
|
|
275
|
+
const thread = await options.threads.get(thread_id);
|
|
276
|
+
if (thread == null)
|
|
277
|
+
return c.json({ error: "Thread not found" }, 404);
|
|
278
|
+
return streamSSE(c, async (stream) => {
|
|
279
|
+
const signal = getDisconnectAbortSignal(c, stream);
|
|
280
|
+
const state = getThreadState(thread_id);
|
|
281
|
+
try {
|
|
282
|
+
const run = await waitForRunReady(thread_id, run_id, signal);
|
|
283
|
+
if (!run) {
|
|
284
|
+
await stream.writeSSE({
|
|
285
|
+
data: serialiseAsDict({ error: "Run not found" }),
|
|
286
|
+
event: "error",
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const idx = state.pendingRuns.findIndex((r) => r.run_id === run_id);
|
|
291
|
+
if (idx >= 0)
|
|
292
|
+
state.pendingRuns.splice(idx, 1);
|
|
293
|
+
state.activeRunId = run_id;
|
|
294
|
+
run.status = "running";
|
|
295
|
+
try {
|
|
296
|
+
for await (const { event, data } of streamState(run, {
|
|
297
|
+
attempt: 1,
|
|
298
|
+
getGraph,
|
|
299
|
+
signal,
|
|
300
|
+
})) {
|
|
301
|
+
await stream.writeSSE({ data: serialiseAsDict(data), event });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
await stream.writeSSE({
|
|
306
|
+
data: serialiseAsDict(serializeError(error)),
|
|
307
|
+
event: "error",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
if (state.activeRunId === run_id) {
|
|
312
|
+
state.activeRunId = null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
throw err;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
api.post("/threads/:thread_id/runs/:run_id/cancel", zValidator("param", z.object({
|
|
325
|
+
thread_id: z.string().uuid(),
|
|
326
|
+
run_id: z.string().uuid(),
|
|
327
|
+
})), async (c) => {
|
|
328
|
+
const { thread_id, run_id } = c.req.valid("param");
|
|
329
|
+
const state = getThreadState(thread_id);
|
|
330
|
+
const idx = state.pendingRuns.findIndex((r) => r.run_id === run_id);
|
|
331
|
+
if (idx >= 0) {
|
|
332
|
+
state.pendingRuns.splice(idx, 1);
|
|
333
|
+
}
|
|
334
|
+
return new Response(null, { status: 204 });
|
|
335
|
+
});
|
|
225
336
|
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
|
|
337
|
+
// Stream Run (create + stream in one request)
|
|
227
338
|
const { thread_id } = c.req.valid("param");
|
|
228
339
|
const payload = c.req.valid("json");
|
|
229
340
|
const thread = await options.threads.get(thread_id);
|
|
230
341
|
if (thread == null)
|
|
231
342
|
return c.json({ error: "Thread not found" }, 404);
|
|
343
|
+
const state = getThreadState(thread_id);
|
|
344
|
+
const run = createStubRun(thread_id, payload);
|
|
345
|
+
c.header("Content-Location", `/threads/${thread_id}/runs/${run.run_id}`);
|
|
232
346
|
return streamSSE(c, async (stream) => {
|
|
233
347
|
const signal = getDisconnectAbortSignal(c, stream);
|
|
234
|
-
|
|
348
|
+
state.activeRunId = run.run_id;
|
|
235
349
|
await options.threads.set(thread_id, {
|
|
236
350
|
kind: "patch",
|
|
237
351
|
metadata: {
|
|
@@ -254,14 +368,21 @@ export function createEmbedServer(options) {
|
|
|
254
368
|
event: "error",
|
|
255
369
|
});
|
|
256
370
|
}
|
|
371
|
+
finally {
|
|
372
|
+
if (state.activeRunId === run.run_id) {
|
|
373
|
+
state.activeRunId = null;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
257
376
|
});
|
|
258
377
|
});
|
|
259
378
|
api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => {
|
|
260
379
|
// Stream Stateless Run
|
|
380
|
+
const payload = c.req.valid("json");
|
|
381
|
+
const threadId = uuidv7();
|
|
382
|
+
const run = createStubRun(threadId, payload);
|
|
383
|
+
c.header("Content-Location", `/threads/${threadId}/runs/${run.run_id}`);
|
|
261
384
|
return streamSSE(c, async (stream) => {
|
|
262
|
-
const payload = c.req.valid("json");
|
|
263
385
|
const signal = getDisconnectAbortSignal(c, stream);
|
|
264
|
-
const threadId = uuidv4();
|
|
265
386
|
await options.threads.set(threadId, {
|
|
266
387
|
kind: "put",
|
|
267
388
|
metadata: {
|
|
@@ -270,7 +391,6 @@ export function createEmbedServer(options) {
|
|
|
270
391
|
},
|
|
271
392
|
});
|
|
272
393
|
try {
|
|
273
|
-
const run = createStubRun(threadId, payload);
|
|
274
394
|
try {
|
|
275
395
|
for await (const { event, data } of streamState(run, {
|
|
276
396
|
attempt: 1,
|
package/dist/storage/ops.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HTTPException } from "hono/http-exception";
|
|
2
|
-
import {
|
|
2
|
+
import { v7 as uuid7, v5 as uuid5 } from "uuid";
|
|
3
3
|
import { handleAuthEvent, isAuthMatching } from "../auth/index.mjs";
|
|
4
4
|
import { getLangGraphCommand } from "../command.mjs";
|
|
5
5
|
import { getGraph, NAMESPACE_GRAPH } from "../graph/load.mjs";
|
|
@@ -650,7 +650,7 @@ export class FileSystemThreads {
|
|
|
650
650
|
}
|
|
651
651
|
return thread;
|
|
652
652
|
});
|
|
653
|
-
const newThreadId =
|
|
653
|
+
const newThreadId = uuid7();
|
|
654
654
|
const now = new Date();
|
|
655
655
|
const newMetadata = { ...fromThread.metadata, thread_id: newThreadId };
|
|
656
656
|
await handleAuthEvent(auth, "threads:create", {
|
|
@@ -948,7 +948,7 @@ export class FileSystemRuns {
|
|
|
948
948
|
}
|
|
949
949
|
const now = new Date();
|
|
950
950
|
if (!existingThread && (threadId == null || ifNotExists === "create")) {
|
|
951
|
-
threadId ??=
|
|
951
|
+
threadId ??= uuid7();
|
|
952
952
|
const thread = {
|
|
953
953
|
thread_id: threadId,
|
|
954
954
|
status: "busy",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph-api",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": "^18.19.0 || >=20.16.0"
|
|
@@ -70,13 +70,13 @@
|
|
|
70
70
|
"winston": "^3.17.0",
|
|
71
71
|
"winston-console-format": "^1.0.8",
|
|
72
72
|
"zod": "^3.25.76 || ^4",
|
|
73
|
-
"@langchain/langgraph-ui": "1.1.
|
|
73
|
+
"@langchain/langgraph-ui": "1.1.16"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@langchain/core": "^0.3.59 || ^1.0.1",
|
|
77
77
|
"@langchain/langgraph": "^0.2.57 || ^0.3.0 || ^0.4.0 || ^1.0.0-alpha || ^1.0.0",
|
|
78
78
|
"@langchain/langgraph-checkpoint": "~0.0.16 || ^0.1.0 || ~1.0.0",
|
|
79
|
-
"@langchain/langgraph-sdk": "
|
|
79
|
+
"@langchain/langgraph-sdk": "^1.6.5",
|
|
80
80
|
"typescript": "^5.5.4"
|
|
81
81
|
},
|
|
82
82
|
"peerDependenciesMeta": {
|
|
@@ -98,9 +98,9 @@
|
|
|
98
98
|
"typescript": "^4.9.5 || ^5.4.5",
|
|
99
99
|
"vitest": "^3.2.4",
|
|
100
100
|
"wait-port": "^1.1.0",
|
|
101
|
-
"@langchain/langgraph": "1.2.
|
|
102
|
-
"@langchain/langgraph-checkpoint": "1.0.
|
|
103
|
-
"@langchain/langgraph-sdk": "1.
|
|
101
|
+
"@langchain/langgraph": "1.2.3",
|
|
102
|
+
"@langchain/langgraph-checkpoint": "1.0.1",
|
|
103
|
+
"@langchain/langgraph-sdk": "1.7.3"
|
|
104
104
|
},
|
|
105
105
|
"scripts": {
|
|
106
106
|
"clean": "rm -rf dist/ .turbo/ ./tests/graphs/.langgraph_api/",
|