@langchain/langgraph-api 1.1.2 → 1.1.8
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/package.json +9 -8
- package/CHANGELOG.md +0 -297
- package/dist/api/assistants.d.mts +0 -3
- package/dist/api/assistants.mjs +0 -193
- package/dist/api/meta.d.mts +0 -3
- package/dist/api/meta.mjs +0 -65
- package/dist/api/runs.d.mts +0 -3
- package/dist/api/runs.mjs +0 -324
- package/dist/api/store.d.mts +0 -3
- package/dist/api/store.mjs +0 -111
- package/dist/api/threads.d.mts +0 -3
- package/dist/api/threads.mjs +0 -143
- package/dist/auth/custom.d.mts +0 -9
- package/dist/auth/custom.mjs +0 -32
- package/dist/auth/index.d.mts +0 -43
- package/dist/auth/index.mjs +0 -163
- package/dist/cli/entrypoint.d.mts +0 -1
- package/dist/cli/entrypoint.mjs +0 -41
- package/dist/cli/spawn.d.mts +0 -42
- package/dist/cli/spawn.mjs +0 -47
- package/dist/cli/utils/ipc/client.d.mts +0 -5
- package/dist/cli/utils/ipc/client.mjs +0 -47
- package/dist/cli/utils/ipc/utils/get-pipe-path.d.mts +0 -1
- package/dist/cli/utils/ipc/utils/get-pipe-path.mjs +0 -29
- package/dist/cli/utils/ipc/utils/temporary-directory.d.mts +0 -5
- package/dist/cli/utils/ipc/utils/temporary-directory.mjs +0 -40
- package/dist/command.d.mts +0 -11
- package/dist/command.mjs +0 -15
- package/dist/experimental/embed.d.mts +0 -42
- package/dist/experimental/embed.mjs +0 -299
- package/dist/graph/api.d.mts +0 -1
- package/dist/graph/api.mjs +0 -2
- package/dist/graph/load.d.mts +0 -19
- package/dist/graph/load.hooks.d.mts +0 -2
- package/dist/graph/load.hooks.mjs +0 -52
- package/dist/graph/load.mjs +0 -96
- package/dist/graph/load.utils.d.mts +0 -22
- package/dist/graph/load.utils.mjs +0 -49
- package/dist/graph/parser/index.d.mts +0 -23
- package/dist/graph/parser/index.mjs +0 -58
- package/dist/graph/parser/parser.d.mts +0 -77
- package/dist/graph/parser/parser.mjs +0 -429
- package/dist/graph/parser/parser.worker.d.mts +0 -1
- package/dist/graph/parser/parser.worker.mjs +0 -7
- package/dist/graph/parser/schema/types.d.mts +0 -154
- package/dist/graph/parser/schema/types.mjs +0 -1496
- package/dist/graph/parser/schema/types.template.d.mts +0 -1
- package/dist/graph/parser/schema/types.template.mts +0 -92
- package/dist/http/custom.d.mts +0 -6
- package/dist/http/custom.mjs +0 -10
- package/dist/http/middleware.d.mts +0 -11
- package/dist/http/middleware.mjs +0 -57
- package/dist/logging.d.mts +0 -10
- package/dist/logging.mjs +0 -115
- package/dist/loopback.d.mts +0 -4
- package/dist/loopback.mjs +0 -10
- package/dist/preload.d.mts +0 -1
- package/dist/preload.mjs +0 -29
- package/dist/queue.d.mts +0 -2
- package/dist/queue.mjs +0 -119
- package/dist/schemas.d.mts +0 -1552
- package/dist/schemas.mjs +0 -492
- package/dist/semver/index.d.mts +0 -15
- package/dist/semver/index.mjs +0 -46
- package/dist/server.d.mts +0 -175
- package/dist/server.mjs +0 -181
- package/dist/state.d.mts +0 -3
- package/dist/state.mjs +0 -30
- package/dist/storage/checkpoint.d.mts +0 -19
- package/dist/storage/checkpoint.mjs +0 -127
- package/dist/storage/context.d.mts +0 -3
- package/dist/storage/context.mjs +0 -11
- package/dist/storage/importMap.d.mts +0 -55
- package/dist/storage/importMap.mjs +0 -55
- package/dist/storage/ops.d.mts +0 -169
- package/dist/storage/ops.mjs +0 -1262
- package/dist/storage/persist.d.mts +0 -18
- package/dist/storage/persist.mjs +0 -81
- package/dist/storage/store.d.mts +0 -17
- package/dist/storage/store.mjs +0 -41
- package/dist/storage/types.d.mts +0 -301
- package/dist/storage/types.mjs +0 -1
- package/dist/stream.d.mts +0 -43
- package/dist/stream.mjs +0 -235
- package/dist/ui/load.d.mts +0 -8
- package/dist/ui/load.mjs +0 -53
- package/dist/utils/abort.d.mts +0 -1
- package/dist/utils/abort.mjs +0 -8
- package/dist/utils/hono.d.mts +0 -5
- package/dist/utils/hono.mjs +0 -24
- package/dist/utils/importMap.d.mts +0 -55
- package/dist/utils/importMap.mjs +0 -55
- package/dist/utils/runnableConfig.d.mts +0 -3
- package/dist/utils/runnableConfig.mjs +0 -45
- package/dist/utils/serde.d.mts +0 -5
- package/dist/utils/serde.mjs +0 -20
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -12
- package/dist/webhook.d.mts +0 -11
- package/dist/webhook.mjs +0 -30
package/dist/api/runs.mjs
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
import { zValidator } from "@hono/zod-validator";
|
|
2
|
-
import { Hono } from "hono";
|
|
3
|
-
import { HTTPException } from "hono/http-exception";
|
|
4
|
-
import { streamSSE } from "hono/streaming";
|
|
5
|
-
import { v4 as uuid4 } from "uuid";
|
|
6
|
-
import { z } from "zod/v3";
|
|
7
|
-
import { getAssistantId } from "../graph/load.mjs";
|
|
8
|
-
import { logError, logger } from "../logging.mjs";
|
|
9
|
-
import * as schemas from "../schemas.mjs";
|
|
10
|
-
import { runs, threads } from "../storage/context.mjs";
|
|
11
|
-
import { getDisconnectAbortSignal, jsonExtra, waitKeepAlive, } from "../utils/hono.mjs";
|
|
12
|
-
import { serialiseAsDict } from "../utils/serde.mjs";
|
|
13
|
-
const api = new Hono();
|
|
14
|
-
const createValidRun = async (threadId, payload, kwargs) => {
|
|
15
|
-
const { assistant_id: assistantId, ...run } = payload;
|
|
16
|
-
const { auth, headers } = kwargs ?? {};
|
|
17
|
-
const runId = uuid4();
|
|
18
|
-
const streamMode = Array.isArray(payload.stream_mode)
|
|
19
|
-
? payload.stream_mode
|
|
20
|
-
: payload.stream_mode != null
|
|
21
|
-
? [payload.stream_mode]
|
|
22
|
-
: [];
|
|
23
|
-
if (streamMode.length === 0)
|
|
24
|
-
streamMode.push("values");
|
|
25
|
-
const multitaskStrategy = payload.multitask_strategy ?? "reject";
|
|
26
|
-
const preventInsertInInflight = multitaskStrategy === "reject";
|
|
27
|
-
const config = { ...run.config };
|
|
28
|
-
if (run.checkpoint_id) {
|
|
29
|
-
config.configurable ??= {};
|
|
30
|
-
config.configurable.checkpoint_id = run.checkpoint_id;
|
|
31
|
-
}
|
|
32
|
-
if (run.checkpoint) {
|
|
33
|
-
config.configurable ??= {};
|
|
34
|
-
Object.assign(config.configurable, run.checkpoint);
|
|
35
|
-
}
|
|
36
|
-
if (run.langsmith_tracer) {
|
|
37
|
-
config.configurable ??= {};
|
|
38
|
-
Object.assign(config.configurable, {
|
|
39
|
-
langsmith_project: run.langsmith_tracer.project_name,
|
|
40
|
-
langsmith_example_id: run.langsmith_tracer.example_id,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
if (headers) {
|
|
44
|
-
for (const [rawKey, value] of headers.entries()) {
|
|
45
|
-
const key = rawKey.toLowerCase();
|
|
46
|
-
if (key.startsWith("x-")) {
|
|
47
|
-
if (["x-api-key", "x-tenant-id", "x-service-key"].includes(key)) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
config.configurable ??= {};
|
|
51
|
-
config.configurable[key] = value;
|
|
52
|
-
}
|
|
53
|
-
else if (key === "user-agent") {
|
|
54
|
-
config.configurable ??= {};
|
|
55
|
-
config.configurable[key] = value;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
let userId;
|
|
60
|
-
if (auth) {
|
|
61
|
-
userId = auth.user.identity ?? auth.user.id;
|
|
62
|
-
config.configurable ??= {};
|
|
63
|
-
config.configurable["langgraph_auth_user"] = auth.user;
|
|
64
|
-
config.configurable["langgraph_auth_user_id"] = userId;
|
|
65
|
-
config.configurable["langgraph_auth_permissions"] = auth.scopes;
|
|
66
|
-
}
|
|
67
|
-
let feedbackKeys = run.feedback_keys != null
|
|
68
|
-
? Array.isArray(run.feedback_keys)
|
|
69
|
-
? run.feedback_keys
|
|
70
|
-
: [run.feedback_keys]
|
|
71
|
-
: undefined;
|
|
72
|
-
if (!feedbackKeys?.length)
|
|
73
|
-
feedbackKeys = undefined;
|
|
74
|
-
const [first, ...inflight] = await runs().put(runId, getAssistantId(assistantId), {
|
|
75
|
-
input: run.input,
|
|
76
|
-
command: run.command,
|
|
77
|
-
config,
|
|
78
|
-
context: run.context,
|
|
79
|
-
stream_mode: streamMode,
|
|
80
|
-
interrupt_before: run.interrupt_before,
|
|
81
|
-
interrupt_after: run.interrupt_after,
|
|
82
|
-
webhook: run.webhook,
|
|
83
|
-
feedback_keys: feedbackKeys,
|
|
84
|
-
temporary: threadId == null && (run.on_completion ?? "delete") === "delete",
|
|
85
|
-
subgraphs: run.stream_subgraphs ?? false,
|
|
86
|
-
resumable: run.stream_resumable ?? false,
|
|
87
|
-
}, {
|
|
88
|
-
threadId,
|
|
89
|
-
userId,
|
|
90
|
-
metadata: run.metadata,
|
|
91
|
-
status: "pending",
|
|
92
|
-
multitaskStrategy,
|
|
93
|
-
preventInsertInInflight,
|
|
94
|
-
afterSeconds: payload.after_seconds,
|
|
95
|
-
ifNotExists: payload.if_not_exists,
|
|
96
|
-
}, auth);
|
|
97
|
-
if (first?.run_id === runId) {
|
|
98
|
-
logger.info("Created run", { run_id: runId, thread_id: threadId });
|
|
99
|
-
if ((multitaskStrategy === "interrupt" || multitaskStrategy === "rollback") &&
|
|
100
|
-
inflight.length > 0) {
|
|
101
|
-
try {
|
|
102
|
-
await runs().cancel(threadId, inflight.map((run) => run.run_id), { action: multitaskStrategy }, auth);
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
logger.warn("Failed to cancel inflight runs, might be already cancelled", {
|
|
106
|
-
error,
|
|
107
|
-
run_ids: inflight.map((run) => run.run_id),
|
|
108
|
-
thread_id: threadId,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return first;
|
|
113
|
-
}
|
|
114
|
-
else if (multitaskStrategy === "reject") {
|
|
115
|
-
throw new HTTPException(422, {
|
|
116
|
-
message: "Thread is already running a task. Wait for it to finish or choose a different multitask strategy.",
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
throw new HTTPException(500, {
|
|
120
|
-
message: "Unreachable state when creating run",
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
api.post("/runs/crons", zValidator("json", schemas.CronCreate), async () => {
|
|
124
|
-
// Create Thread Cron
|
|
125
|
-
throw new HTTPException(500, { message: "Not implemented" });
|
|
126
|
-
});
|
|
127
|
-
api.post("/runs/crons/search", zValidator("json", schemas.CronSearch), async () => {
|
|
128
|
-
// Search Crons
|
|
129
|
-
throw new HTTPException(500, { message: "Not implemented" });
|
|
130
|
-
});
|
|
131
|
-
api.delete("/runs/crons/:cron_id", zValidator("param", z.object({ cron_id: z.string().uuid() })), async () => {
|
|
132
|
-
// Delete Cron
|
|
133
|
-
throw new HTTPException(500, { message: "Not implemented" });
|
|
134
|
-
});
|
|
135
|
-
api.post("/threads/:thread_id/runs/crons", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.CronCreate), async () => {
|
|
136
|
-
// Create Thread Cron
|
|
137
|
-
throw new HTTPException(500, { message: "Not implemented" });
|
|
138
|
-
});
|
|
139
|
-
api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => {
|
|
140
|
-
// Stream Stateless Run
|
|
141
|
-
const payload = c.req.valid("json");
|
|
142
|
-
const run = await createValidRun(undefined, payload, {
|
|
143
|
-
auth: c.var.auth,
|
|
144
|
-
headers: c.req.raw.headers,
|
|
145
|
-
});
|
|
146
|
-
c.header("Content-Location", `/runs/${run.run_id}`);
|
|
147
|
-
return streamSSE(c, async (stream) => {
|
|
148
|
-
const cancelOnDisconnect = payload.on_disconnect === "cancel"
|
|
149
|
-
? getDisconnectAbortSignal(c, stream)
|
|
150
|
-
: undefined;
|
|
151
|
-
try {
|
|
152
|
-
for await (const { event, data } of runs().stream.join(run.run_id, undefined, {
|
|
153
|
-
cancelOnDisconnect,
|
|
154
|
-
lastEventId: run.kwargs.resumable ? "-1" : undefined,
|
|
155
|
-
ignore404: true,
|
|
156
|
-
}, c.var.auth)) {
|
|
157
|
-
await stream.writeSSE({ data: serialiseAsDict(data), event });
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch (error) {
|
|
161
|
-
logError(error, { prefix: "Error streaming run" });
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
// TODO: port to Python API
|
|
166
|
-
api.get("/runs/:run_id/stream", zValidator("param", z.object({ run_id: z.string().uuid() })), zValidator("query", z.object({ cancel_on_disconnect: schemas.coercedBoolean.optional() })), async (c) => {
|
|
167
|
-
const { run_id } = c.req.valid("param");
|
|
168
|
-
const query = c.req.valid("query");
|
|
169
|
-
const lastEventId = c.req.header("Last-Event-ID") || undefined;
|
|
170
|
-
c.header("Content-Location", `/runs/${run_id}`);
|
|
171
|
-
return streamSSE(c, async (stream) => {
|
|
172
|
-
const cancelOnDisconnect = query.cancel_on_disconnect
|
|
173
|
-
? getDisconnectAbortSignal(c, stream)
|
|
174
|
-
: undefined;
|
|
175
|
-
try {
|
|
176
|
-
for await (const { id, event, data } of runs().stream.join(run_id, undefined, { cancelOnDisconnect, lastEventId, ignore404: true }, c.var.auth)) {
|
|
177
|
-
await stream.writeSSE({ id, data: serialiseAsDict(data), event });
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch (error) {
|
|
181
|
-
logError(error, { prefix: "Error streaming run" });
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
api.post("/runs/wait", zValidator("json", schemas.RunCreate), async (c) => {
|
|
186
|
-
// Wait Stateless Run
|
|
187
|
-
const payload = c.req.valid("json");
|
|
188
|
-
const run = await createValidRun(undefined, payload, {
|
|
189
|
-
auth: c.var.auth,
|
|
190
|
-
headers: c.req.raw.headers,
|
|
191
|
-
});
|
|
192
|
-
c.header("Content-Location", `/runs/${run.run_id}`);
|
|
193
|
-
return waitKeepAlive(c, runs().wait(run.run_id, undefined, c.var.auth));
|
|
194
|
-
});
|
|
195
|
-
api.post("/runs", zValidator("json", schemas.RunCreate), async (c) => {
|
|
196
|
-
// Create Stateless Run
|
|
197
|
-
const payload = c.req.valid("json");
|
|
198
|
-
const run = await createValidRun(undefined, payload, {
|
|
199
|
-
auth: c.var.auth,
|
|
200
|
-
headers: c.req.raw.headers,
|
|
201
|
-
});
|
|
202
|
-
c.header("Content-Location", `/runs/${run.run_id}`);
|
|
203
|
-
return jsonExtra(c, run);
|
|
204
|
-
});
|
|
205
|
-
api.post("/runs/batch", zValidator("json", schemas.RunBatchCreate), async (c) => {
|
|
206
|
-
// Batch Runs
|
|
207
|
-
const payload = c.req.valid("json");
|
|
208
|
-
const runs = await Promise.all(payload.map((run) => createValidRun(undefined, run, {
|
|
209
|
-
auth: c.var.auth,
|
|
210
|
-
headers: c.req.raw.headers,
|
|
211
|
-
})));
|
|
212
|
-
return jsonExtra(c, runs);
|
|
213
|
-
});
|
|
214
|
-
api.get("/threads/:thread_id/runs", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("query", z.object({
|
|
215
|
-
limit: z.coerce.number().nullish(),
|
|
216
|
-
offset: z.coerce.number().nullish(),
|
|
217
|
-
status: z.string().nullish(),
|
|
218
|
-
metadata: z.record(z.string(), z.unknown()).nullish(),
|
|
219
|
-
})), async (c) => {
|
|
220
|
-
// List runs
|
|
221
|
-
const { thread_id } = c.req.valid("param");
|
|
222
|
-
const { limit, offset, status, metadata } = c.req.valid("query");
|
|
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
|
-
]);
|
|
227
|
-
return jsonExtra(c, runsResponse);
|
|
228
|
-
});
|
|
229
|
-
api.post("/threads/:thread_id/runs", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
|
|
230
|
-
// Create Run
|
|
231
|
-
const { thread_id } = c.req.valid("param");
|
|
232
|
-
const payload = c.req.valid("json");
|
|
233
|
-
const run = await createValidRun(thread_id, payload, {
|
|
234
|
-
auth: c.var.auth,
|
|
235
|
-
headers: c.req.raw.headers,
|
|
236
|
-
});
|
|
237
|
-
c.header("Content-Location", `/threads/${thread_id}/runs/${run.run_id}`);
|
|
238
|
-
return jsonExtra(c, run);
|
|
239
|
-
});
|
|
240
|
-
api.post("/threads/:thread_id/runs/stream", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
|
|
241
|
-
// Stream Run
|
|
242
|
-
const { thread_id } = c.req.valid("param");
|
|
243
|
-
const payload = c.req.valid("json");
|
|
244
|
-
const run = await createValidRun(thread_id, payload, {
|
|
245
|
-
auth: c.var.auth,
|
|
246
|
-
headers: c.req.raw.headers,
|
|
247
|
-
});
|
|
248
|
-
c.header("Content-Location", `/threads/${thread_id}/runs/${run.run_id}`);
|
|
249
|
-
return streamSSE(c, async (stream) => {
|
|
250
|
-
const cancelOnDisconnect = payload.on_disconnect === "cancel"
|
|
251
|
-
? getDisconnectAbortSignal(c, stream)
|
|
252
|
-
: undefined;
|
|
253
|
-
try {
|
|
254
|
-
for await (const { id, event, data } of runs().stream.join(run.run_id, thread_id, {
|
|
255
|
-
cancelOnDisconnect,
|
|
256
|
-
lastEventId: run.kwargs.resumable ? "-1" : undefined,
|
|
257
|
-
}, c.var.auth)) {
|
|
258
|
-
await stream.writeSSE({ id, data: serialiseAsDict(data), event });
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
catch (error) {
|
|
262
|
-
logError(error, { prefix: "Error streaming run" });
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
api.post("/threads/:thread_id/runs/wait", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
|
|
267
|
-
// Wait Run
|
|
268
|
-
const { thread_id } = c.req.valid("param");
|
|
269
|
-
const payload = c.req.valid("json");
|
|
270
|
-
const run = await createValidRun(thread_id, payload, {
|
|
271
|
-
auth: c.var.auth,
|
|
272
|
-
headers: c.req.raw.headers,
|
|
273
|
-
});
|
|
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));
|
|
276
|
-
});
|
|
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
|
-
const { thread_id, run_id } = c.req.valid("param");
|
|
279
|
-
const [run] = await Promise.all([
|
|
280
|
-
runs().get(run_id, thread_id, c.var.auth),
|
|
281
|
-
threads().get(thread_id, c.var.auth),
|
|
282
|
-
]);
|
|
283
|
-
if (run == null)
|
|
284
|
-
throw new HTTPException(404, { message: "Run not found" });
|
|
285
|
-
return jsonExtra(c, run);
|
|
286
|
-
});
|
|
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
|
-
// Delete Run
|
|
289
|
-
const { thread_id, run_id } = c.req.valid("param");
|
|
290
|
-
await runs().delete(run_id, thread_id, c.var.auth);
|
|
291
|
-
return c.body(null, 204);
|
|
292
|
-
});
|
|
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
|
-
// Join Run Http
|
|
295
|
-
const { thread_id, run_id } = c.req.valid("param");
|
|
296
|
-
return jsonExtra(c, await runs().join(run_id, thread_id, c.var.auth));
|
|
297
|
-
});
|
|
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
|
-
// Stream Run Http
|
|
300
|
-
const { thread_id, run_id } = c.req.valid("param");
|
|
301
|
-
const { cancel_on_disconnect } = c.req.valid("query");
|
|
302
|
-
const lastEventId = c.req.header("Last-Event-ID") || undefined;
|
|
303
|
-
return streamSSE(c, async (stream) => {
|
|
304
|
-
const signal = cancel_on_disconnect
|
|
305
|
-
? getDisconnectAbortSignal(c, stream)
|
|
306
|
-
: undefined;
|
|
307
|
-
for await (const { id, event, data } of runs().stream.join(run_id, thread_id, { cancelOnDisconnect: signal, lastEventId }, c.var.auth)) {
|
|
308
|
-
await stream.writeSSE({ id, data: serialiseAsDict(data), event });
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
api.post("/threads/:thread_id/runs/:run_id/cancel", zValidator("param", z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() })), zValidator("query", z.object({
|
|
313
|
-
wait: z.coerce.boolean().optional().default(false),
|
|
314
|
-
action: z.enum(["interrupt", "rollback"]).optional().default("interrupt"),
|
|
315
|
-
})), async (c) => {
|
|
316
|
-
// Cancel Run Http
|
|
317
|
-
const { thread_id, run_id } = c.req.valid("param");
|
|
318
|
-
const { wait, action } = c.req.valid("query");
|
|
319
|
-
await runs().cancel(thread_id, [run_id], { action }, c.var.auth);
|
|
320
|
-
if (wait)
|
|
321
|
-
await runs().join(run_id, thread_id, c.var.auth);
|
|
322
|
-
return c.body(null, wait ? 204 : 202);
|
|
323
|
-
});
|
|
324
|
-
export default api;
|
package/dist/api/store.d.mts
DELETED
package/dist/api/store.mjs
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { Hono } from "hono";
|
|
2
|
-
import { zValidator } from "@hono/zod-validator";
|
|
3
|
-
import * as schemas from "../schemas.mjs";
|
|
4
|
-
import { HTTPException } from "hono/http-exception";
|
|
5
|
-
import { store as storageStore } from "../storage/store.mjs";
|
|
6
|
-
import { handleAuthEvent } from "../auth/index.mjs";
|
|
7
|
-
const api = new Hono();
|
|
8
|
-
const validateNamespace = (namespace) => {
|
|
9
|
-
if (!namespace || namespace.length === 0) {
|
|
10
|
-
throw new HTTPException(400, { message: "Namespace is required" });
|
|
11
|
-
}
|
|
12
|
-
for (const label of namespace) {
|
|
13
|
-
if (!label || label.includes(".")) {
|
|
14
|
-
throw new HTTPException(422, {
|
|
15
|
-
message: "Namespace labels cannot be empty or contain periods. Received: " +
|
|
16
|
-
namespace.join("."),
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
const mapItemsToApi = (item) => {
|
|
22
|
-
if (item == null)
|
|
23
|
-
return null;
|
|
24
|
-
const clonedItem = { ...item };
|
|
25
|
-
delete clonedItem.createdAt;
|
|
26
|
-
delete clonedItem.updatedAt;
|
|
27
|
-
clonedItem.created_at = item.createdAt;
|
|
28
|
-
clonedItem.updated_at = item.updatedAt;
|
|
29
|
-
return clonedItem;
|
|
30
|
-
};
|
|
31
|
-
api.post("/store/namespaces", zValidator("json", schemas.StoreListNamespaces), async (c) => {
|
|
32
|
-
// List Namespaces
|
|
33
|
-
const payload = c.req.valid("json");
|
|
34
|
-
if (payload.prefix)
|
|
35
|
-
validateNamespace(payload.prefix);
|
|
36
|
-
if (payload.suffix)
|
|
37
|
-
validateNamespace(payload.suffix);
|
|
38
|
-
await handleAuthEvent(c.var.auth, "store:list_namespaces", {
|
|
39
|
-
namespace: payload.prefix,
|
|
40
|
-
suffix: payload.suffix,
|
|
41
|
-
max_depth: payload.max_depth,
|
|
42
|
-
limit: payload.limit,
|
|
43
|
-
offset: payload.offset,
|
|
44
|
-
});
|
|
45
|
-
return c.json({
|
|
46
|
-
namespaces: await storageStore.listNamespaces({
|
|
47
|
-
limit: payload.limit ?? 100,
|
|
48
|
-
offset: payload.offset ?? 0,
|
|
49
|
-
prefix: payload.prefix,
|
|
50
|
-
suffix: payload.suffix,
|
|
51
|
-
maxDepth: payload.max_depth,
|
|
52
|
-
}),
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
api.post("/store/items/search", zValidator("json", schemas.StoreSearchItems), async (c) => {
|
|
56
|
-
// Search Items
|
|
57
|
-
const payload = c.req.valid("json");
|
|
58
|
-
if (payload.namespace_prefix)
|
|
59
|
-
validateNamespace(payload.namespace_prefix);
|
|
60
|
-
await handleAuthEvent(c.var.auth, "store:search", {
|
|
61
|
-
namespace: payload.namespace_prefix,
|
|
62
|
-
filter: payload.filter,
|
|
63
|
-
limit: payload.limit,
|
|
64
|
-
offset: payload.offset,
|
|
65
|
-
query: payload.query,
|
|
66
|
-
});
|
|
67
|
-
const items = await storageStore.search(payload.namespace_prefix, {
|
|
68
|
-
filter: payload.filter,
|
|
69
|
-
limit: payload.limit ?? 10,
|
|
70
|
-
offset: payload.offset ?? 0,
|
|
71
|
-
query: payload.query,
|
|
72
|
-
});
|
|
73
|
-
return c.json({ items: items.map(mapItemsToApi) });
|
|
74
|
-
});
|
|
75
|
-
api.put("/store/items", zValidator("json", schemas.StorePutItem), async (c) => {
|
|
76
|
-
// Put Item
|
|
77
|
-
const payload = c.req.valid("json");
|
|
78
|
-
if (payload.namespace)
|
|
79
|
-
validateNamespace(payload.namespace);
|
|
80
|
-
await handleAuthEvent(c.var.auth, "store:put", {
|
|
81
|
-
namespace: payload.namespace,
|
|
82
|
-
key: payload.key,
|
|
83
|
-
value: payload.value,
|
|
84
|
-
});
|
|
85
|
-
await storageStore.put(payload.namespace, payload.key, payload.value);
|
|
86
|
-
return c.body(null, 204);
|
|
87
|
-
});
|
|
88
|
-
api.delete("/store/items", zValidator("json", schemas.StoreDeleteItem), async (c) => {
|
|
89
|
-
// Delete Item
|
|
90
|
-
const payload = c.req.valid("json");
|
|
91
|
-
if (payload.namespace)
|
|
92
|
-
validateNamespace(payload.namespace);
|
|
93
|
-
await handleAuthEvent(c.var.auth, "store:delete", {
|
|
94
|
-
namespace: payload.namespace,
|
|
95
|
-
key: payload.key,
|
|
96
|
-
});
|
|
97
|
-
await storageStore.delete(payload.namespace ?? [], payload.key);
|
|
98
|
-
return c.body(null, 204);
|
|
99
|
-
});
|
|
100
|
-
api.get("/store/items", zValidator("query", schemas.StoreGetItem), async (c) => {
|
|
101
|
-
// Get Item
|
|
102
|
-
const payload = c.req.valid("query");
|
|
103
|
-
await handleAuthEvent(c.var.auth, "store:get", {
|
|
104
|
-
namespace: payload.namespace,
|
|
105
|
-
key: payload.key,
|
|
106
|
-
});
|
|
107
|
-
const key = payload.key;
|
|
108
|
-
const namespace = payload.namespace;
|
|
109
|
-
return c.json(mapItemsToApi(await storageStore.get(namespace, key)));
|
|
110
|
-
});
|
|
111
|
-
export default api;
|
package/dist/api/threads.d.mts
DELETED
package/dist/api/threads.mjs
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { zValidator } from "@hono/zod-validator";
|
|
2
|
-
import { Hono } from "hono";
|
|
3
|
-
import { v4 as uuid4 } from "uuid";
|
|
4
|
-
import { z } from "zod/v3";
|
|
5
|
-
import * as schemas from "../schemas.mjs";
|
|
6
|
-
import { stateSnapshotToThreadState } from "../state.mjs";
|
|
7
|
-
import { threads } from "../storage/context.mjs";
|
|
8
|
-
import { jsonExtra } from "../utils/hono.mjs";
|
|
9
|
-
const api = new Hono();
|
|
10
|
-
// Threads Routes
|
|
11
|
-
api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
|
|
12
|
-
// Create Thread
|
|
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);
|
|
15
|
-
if (payload.supersteps?.length) {
|
|
16
|
-
await threads().state.bulk({ configurable: { thread_id: thread.thread_id } }, payload.supersteps, c.var.auth);
|
|
17
|
-
}
|
|
18
|
-
return jsonExtra(c, thread);
|
|
19
|
-
});
|
|
20
|
-
api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), async (c) => {
|
|
21
|
-
// Search Threads
|
|
22
|
-
const payload = c.req.valid("json");
|
|
23
|
-
const result = [];
|
|
24
|
-
let total = 0;
|
|
25
|
-
for await (const item of threads().search({
|
|
26
|
-
status: payload.status,
|
|
27
|
-
values: payload.values,
|
|
28
|
-
metadata: payload.metadata,
|
|
29
|
-
ids: payload.ids,
|
|
30
|
-
limit: payload.limit ?? 10,
|
|
31
|
-
offset: payload.offset ?? 0,
|
|
32
|
-
sort_by: payload.sort_by ?? "created_at",
|
|
33
|
-
sort_order: payload.sort_order ?? "desc",
|
|
34
|
-
select: payload.select,
|
|
35
|
-
}, c.var.auth)) {
|
|
36
|
-
result.push(Object.fromEntries(Object.entries(item.thread).filter(([k]) => !payload.select || payload.select.includes(k))));
|
|
37
|
-
// Only set total if it's the first item
|
|
38
|
-
if (total === 0) {
|
|
39
|
-
total = item.total;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const nextOffset = (payload.offset ?? 0) + total;
|
|
43
|
-
if (total === payload.limit) {
|
|
44
|
-
c.res.headers.set("X-Pagination-Next", nextOffset.toString());
|
|
45
|
-
c.res.headers.set("X-Pagination-Total", (nextOffset + 1).toString());
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
c.res.headers.set("X-Pagination-Total", nextOffset.toString());
|
|
49
|
-
}
|
|
50
|
-
return jsonExtra(c, result);
|
|
51
|
-
});
|
|
52
|
-
api.post("/threads/count", zValidator("json", schemas.ThreadCountRequest), async (c) => {
|
|
53
|
-
const payload = c.req.valid("json");
|
|
54
|
-
const total = await threads().count(payload, c.var.auth);
|
|
55
|
-
return c.json(total);
|
|
56
|
-
});
|
|
57
|
-
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) => {
|
|
58
|
-
// Get Latest Thread State
|
|
59
|
-
const { thread_id } = c.req.valid("param");
|
|
60
|
-
const { subgraphs } = c.req.valid("query");
|
|
61
|
-
const state = stateSnapshotToThreadState(await threads().state.get({ configurable: { thread_id } }, { subgraphs }, c.var.auth));
|
|
62
|
-
return jsonExtra(c, state);
|
|
63
|
-
});
|
|
64
|
-
api.post("/threads/:thread_id/state", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadStateUpdate), async (c) => {
|
|
65
|
-
// Update Thread State
|
|
66
|
-
const { thread_id } = c.req.valid("param");
|
|
67
|
-
const payload = c.req.valid("json");
|
|
68
|
-
const config = { configurable: { thread_id } };
|
|
69
|
-
if (payload.checkpoint_id) {
|
|
70
|
-
config.configurable ??= {};
|
|
71
|
-
config.configurable.checkpoint_id = payload.checkpoint_id;
|
|
72
|
-
}
|
|
73
|
-
if (payload.checkpoint) {
|
|
74
|
-
config.configurable ??= {};
|
|
75
|
-
Object.assign(config.configurable, payload.checkpoint);
|
|
76
|
-
}
|
|
77
|
-
const inserted = await threads().state.post(config, payload.values, payload.as_node, c.var.auth);
|
|
78
|
-
return jsonExtra(c, inserted);
|
|
79
|
-
});
|
|
80
|
-
api.get("/threads/:thread_id/state/:checkpoint_id", zValidator("param", z.object({
|
|
81
|
-
thread_id: z.string().uuid(),
|
|
82
|
-
checkpoint_id: z.string().uuid(),
|
|
83
|
-
})), zValidator("query", z.object({ subgraphs: schemas.coercedBoolean.optional() })), async (c) => {
|
|
84
|
-
// Get Thread State At Checkpoint
|
|
85
|
-
const { thread_id, checkpoint_id } = c.req.valid("param");
|
|
86
|
-
const { subgraphs } = c.req.valid("query");
|
|
87
|
-
const state = stateSnapshotToThreadState(await threads().state.get({ configurable: { thread_id, checkpoint_id } }, { subgraphs }, c.var.auth));
|
|
88
|
-
return jsonExtra(c, state);
|
|
89
|
-
});
|
|
90
|
-
api.post("/threads/:thread_id/state/checkpoint", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", z.object({
|
|
91
|
-
subgraphs: schemas.coercedBoolean.optional(),
|
|
92
|
-
checkpoint: schemas.CheckpointSchema.nullish(),
|
|
93
|
-
})), async (c) => {
|
|
94
|
-
// Get Thread State At Checkpoint Post
|
|
95
|
-
const { thread_id } = c.req.valid("param");
|
|
96
|
-
const { checkpoint, subgraphs } = c.req.valid("json");
|
|
97
|
-
const state = stateSnapshotToThreadState(await threads().state.get({ configurable: { thread_id, ...checkpoint } }, { subgraphs }, c.var.auth));
|
|
98
|
-
return jsonExtra(c, state);
|
|
99
|
-
});
|
|
100
|
-
api.get("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("query", z.object({
|
|
101
|
-
limit: z
|
|
102
|
-
.string()
|
|
103
|
-
.optional()
|
|
104
|
-
.default("10")
|
|
105
|
-
.transform((value) => parseInt(value, 10)),
|
|
106
|
-
before: z.string().optional(),
|
|
107
|
-
})), async (c) => {
|
|
108
|
-
// Get Thread History
|
|
109
|
-
const { thread_id } = c.req.valid("param");
|
|
110
|
-
const { limit, before } = c.req.valid("query");
|
|
111
|
-
const states = await threads().state.list({ configurable: { thread_id, checkpoint_ns: "" } }, { limit, before }, c.var.auth);
|
|
112
|
-
return jsonExtra(c, states.map(stateSnapshotToThreadState));
|
|
113
|
-
});
|
|
114
|
-
api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
|
|
115
|
-
// Get Thread History Post
|
|
116
|
-
const { thread_id } = c.req.valid("param");
|
|
117
|
-
const { limit, before, metadata, checkpoint } = c.req.valid("json");
|
|
118
|
-
const states = await threads().state.list({ configurable: { thread_id, checkpoint_ns: "", ...checkpoint } }, { limit, before, metadata }, c.var.auth);
|
|
119
|
-
return jsonExtra(c, states.map(stateSnapshotToThreadState));
|
|
120
|
-
});
|
|
121
|
-
api.get("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
|
|
122
|
-
// Get Thread
|
|
123
|
-
const { thread_id } = c.req.valid("param");
|
|
124
|
-
return jsonExtra(c, await threads().get(thread_id, c.var.auth));
|
|
125
|
-
});
|
|
126
|
-
api.delete("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
|
|
127
|
-
// Delete Thread
|
|
128
|
-
const { thread_id } = c.req.valid("param");
|
|
129
|
-
await threads().delete(thread_id, c.var.auth);
|
|
130
|
-
return new Response(null, { status: 204 });
|
|
131
|
-
});
|
|
132
|
-
api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadPatchRequest), async (c) => {
|
|
133
|
-
// Patch Thread
|
|
134
|
-
const { thread_id } = c.req.valid("param");
|
|
135
|
-
const { metadata } = c.req.valid("json");
|
|
136
|
-
return jsonExtra(c, await threads().patch(thread_id, { metadata }, c.var.auth));
|
|
137
|
-
});
|
|
138
|
-
api.post("/threads/:thread_id/copy", zValidator("param", z.object({ thread_id: z.string().uuid() })), async (c) => {
|
|
139
|
-
// Copy Thread
|
|
140
|
-
const { thread_id } = c.req.valid("param");
|
|
141
|
-
return jsonExtra(c, await threads().copy(thread_id, c.var.auth));
|
|
142
|
-
});
|
|
143
|
-
export default api;
|
package/dist/auth/custom.d.mts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { MiddlewareHandler } from "hono";
|
|
2
|
-
import { type AuthContext } from "./index.mjs";
|
|
3
|
-
declare module "hono" {
|
|
4
|
-
interface ContextVariableMap {
|
|
5
|
-
auth?: AuthContext | undefined;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
export declare const auth: () => MiddlewareHandler;
|
|
9
|
-
export { registerAuth } from "./index.mjs";
|
package/dist/auth/custom.mjs
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { authenticate, isAuthRegistered, isStudioAuthDisabled, } from "./index.mjs";
|
|
2
|
-
const STUDIO_USER = {
|
|
3
|
-
kind: "StudioUser",
|
|
4
|
-
display_name: "langgraph-studio-user",
|
|
5
|
-
identity: "langgraph-studio-user",
|
|
6
|
-
permissions: [],
|
|
7
|
-
is_authenticated: true,
|
|
8
|
-
};
|
|
9
|
-
export const auth = () => {
|
|
10
|
-
return async (c, next) => {
|
|
11
|
-
if (!isAuthRegistered())
|
|
12
|
-
return next();
|
|
13
|
-
// skip for /info
|
|
14
|
-
if (c.req.path === "/info")
|
|
15
|
-
return next();
|
|
16
|
-
// skip for UI asset requests
|
|
17
|
-
if (c.req.path.startsWith("/ui") && c.req.method === "GET")
|
|
18
|
-
return next();
|
|
19
|
-
if (!isStudioAuthDisabled() &&
|
|
20
|
-
c.req.header("x-auth-scheme") === "langsmith") {
|
|
21
|
-
c.set("auth", {
|
|
22
|
-
user: STUDIO_USER,
|
|
23
|
-
scopes: STUDIO_USER.permissions.slice(),
|
|
24
|
-
});
|
|
25
|
-
return next();
|
|
26
|
-
}
|
|
27
|
-
const auth = await authenticate(c.req.raw);
|
|
28
|
-
c.set("auth", auth);
|
|
29
|
-
return next();
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
export { registerAuth } from "./index.mjs";
|
package/dist/auth/index.d.mts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { AuthEventValueMap } from "@langchain/langgraph-sdk/auth";
|
|
2
|
-
export declare const isAuthRegistered: () => boolean;
|
|
3
|
-
export declare const isStudioAuthDisabled: () => boolean;
|
|
4
|
-
export type AuthFilters = Record<string, string | {
|
|
5
|
-
$eq?: string;
|
|
6
|
-
$contains?: string | string[];
|
|
7
|
-
}> | undefined;
|
|
8
|
-
export interface AuthContext {
|
|
9
|
-
user: {
|
|
10
|
-
identity: string;
|
|
11
|
-
permissions: string[];
|
|
12
|
-
display_name: string;
|
|
13
|
-
is_authenticated: boolean;
|
|
14
|
-
[key: string]: unknown;
|
|
15
|
-
};
|
|
16
|
-
scopes: string[];
|
|
17
|
-
}
|
|
18
|
-
export declare function authorize(payload: {
|
|
19
|
-
resource: string;
|
|
20
|
-
action: string;
|
|
21
|
-
value: unknown;
|
|
22
|
-
context: AuthContext | undefined | null;
|
|
23
|
-
}): Promise<{
|
|
24
|
-
filters: AuthFilters;
|
|
25
|
-
value: unknown;
|
|
26
|
-
}>;
|
|
27
|
-
export declare function authenticate(request: Request): Promise<{
|
|
28
|
-
scopes: string[];
|
|
29
|
-
user: {
|
|
30
|
-
permissions: string[];
|
|
31
|
-
is_authenticated: boolean;
|
|
32
|
-
display_name: string;
|
|
33
|
-
identity: string;
|
|
34
|
-
};
|
|
35
|
-
} | undefined>;
|
|
36
|
-
export declare function registerAuth(auth: {
|
|
37
|
-
path?: string;
|
|
38
|
-
disable_studio_auth?: boolean;
|
|
39
|
-
}, options: {
|
|
40
|
-
cwd: string;
|
|
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;
|