@langchain/langgraph-api 1.1.8 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +3 -3
  2. package/dist/api/assistants.d.mts +3 -0
  3. package/dist/api/assistants.mjs +193 -0
  4. package/dist/api/meta.d.mts +3 -0
  5. package/dist/api/meta.mjs +65 -0
  6. package/dist/api/runs.d.mts +3 -0
  7. package/dist/api/runs.mjs +324 -0
  8. package/dist/api/store.d.mts +3 -0
  9. package/dist/api/store.mjs +111 -0
  10. package/dist/api/threads.d.mts +3 -0
  11. package/dist/api/threads.mjs +143 -0
  12. package/dist/auth/custom.d.mts +9 -0
  13. package/dist/auth/custom.mjs +32 -0
  14. package/dist/auth/index.d.mts +43 -0
  15. package/dist/auth/index.mjs +163 -0
  16. package/dist/cli/entrypoint.d.mts +1 -0
  17. package/dist/cli/entrypoint.mjs +41 -0
  18. package/dist/cli/spawn.d.mts +42 -0
  19. package/dist/cli/spawn.mjs +47 -0
  20. package/dist/cli/utils/ipc/client.d.mts +5 -0
  21. package/dist/cli/utils/ipc/client.mjs +47 -0
  22. package/dist/cli/utils/ipc/utils/get-pipe-path.d.mts +1 -0
  23. package/dist/cli/utils/ipc/utils/get-pipe-path.mjs +29 -0
  24. package/dist/cli/utils/ipc/utils/temporary-directory.d.mts +5 -0
  25. package/dist/cli/utils/ipc/utils/temporary-directory.mjs +40 -0
  26. package/dist/command.d.mts +11 -0
  27. package/dist/command.mjs +15 -0
  28. package/dist/experimental/embed.d.mts +42 -0
  29. package/dist/experimental/embed.mjs +299 -0
  30. package/dist/graph/api.d.mts +1 -0
  31. package/dist/graph/api.mjs +2 -0
  32. package/dist/graph/load.d.mts +19 -0
  33. package/dist/graph/load.hooks.d.mts +2 -0
  34. package/dist/graph/load.hooks.mjs +52 -0
  35. package/dist/graph/load.mjs +96 -0
  36. package/dist/graph/load.utils.d.mts +22 -0
  37. package/dist/graph/load.utils.mjs +49 -0
  38. package/dist/graph/parser/index.d.mts +23 -0
  39. package/dist/graph/parser/index.mjs +58 -0
  40. package/dist/graph/parser/parser.d.mts +77 -0
  41. package/dist/graph/parser/parser.mjs +429 -0
  42. package/dist/graph/parser/parser.worker.d.mts +1 -0
  43. package/dist/graph/parser/parser.worker.mjs +7 -0
  44. package/dist/graph/parser/schema/types.d.mts +154 -0
  45. package/dist/graph/parser/schema/types.mjs +1496 -0
  46. package/dist/graph/parser/schema/types.template.d.mts +1 -0
  47. package/dist/graph/parser/schema/types.template.mts +92 -0
  48. package/dist/http/custom.d.mts +6 -0
  49. package/dist/http/custom.mjs +10 -0
  50. package/dist/http/middleware.d.mts +11 -0
  51. package/dist/http/middleware.mjs +57 -0
  52. package/dist/logging.d.mts +10 -0
  53. package/dist/logging.mjs +115 -0
  54. package/dist/loopback.d.mts +4 -0
  55. package/dist/loopback.mjs +10 -0
  56. package/dist/preload.d.mts +1 -0
  57. package/dist/preload.mjs +29 -0
  58. package/dist/queue.d.mts +2 -0
  59. package/dist/queue.mjs +119 -0
  60. package/dist/schemas.d.mts +1552 -0
  61. package/dist/schemas.mjs +492 -0
  62. package/dist/semver/index.d.mts +15 -0
  63. package/dist/semver/index.mjs +46 -0
  64. package/dist/server.d.mts +175 -0
  65. package/dist/server.mjs +181 -0
  66. package/dist/state.d.mts +3 -0
  67. package/dist/state.mjs +30 -0
  68. package/dist/storage/checkpoint.d.mts +19 -0
  69. package/dist/storage/checkpoint.mjs +127 -0
  70. package/dist/storage/context.d.mts +3 -0
  71. package/dist/storage/context.mjs +11 -0
  72. package/dist/storage/importMap.d.mts +55 -0
  73. package/dist/storage/importMap.mjs +55 -0
  74. package/dist/storage/ops.d.mts +169 -0
  75. package/dist/storage/ops.mjs +1262 -0
  76. package/dist/storage/persist.d.mts +18 -0
  77. package/dist/storage/persist.mjs +81 -0
  78. package/dist/storage/store.d.mts +17 -0
  79. package/dist/storage/store.mjs +41 -0
  80. package/dist/storage/types.d.mts +301 -0
  81. package/dist/storage/types.mjs +1 -0
  82. package/dist/stream.d.mts +43 -0
  83. package/dist/stream.mjs +235 -0
  84. package/dist/ui/load.d.mts +8 -0
  85. package/dist/ui/load.mjs +53 -0
  86. package/dist/utils/abort.d.mts +1 -0
  87. package/dist/utils/abort.mjs +8 -0
  88. package/dist/utils/hono.d.mts +5 -0
  89. package/dist/utils/hono.mjs +24 -0
  90. package/dist/utils/importMap.d.mts +55 -0
  91. package/dist/utils/importMap.mjs +55 -0
  92. package/dist/utils/runnableConfig.d.mts +3 -0
  93. package/dist/utils/runnableConfig.mjs +45 -0
  94. package/dist/utils/serde.d.mts +5 -0
  95. package/dist/utils/serde.mjs +20 -0
  96. package/dist/vitest.config.d.ts +2 -0
  97. package/dist/vitest.config.js +11 -0
  98. package/dist/webhook.d.mts +11 -0
  99. package/dist/webhook.mjs +30 -0
  100. package/package.json +19 -19
package/README.md CHANGED
@@ -4,6 +4,6 @@ In-memory implementation of the LangGraph.js API.
4
4
 
5
5
  ## Tests
6
6
 
7
- 1. Build the latest code changes to test: `yarn build`
8
- 1. Start a local server: `yarn dev`
9
- 1. Run the tests: `yarn test`
7
+ 1. Build the latest code changes to test: `pnpm build`
8
+ 1. Start a local server: `pnpm dev`
9
+ 1. Run the tests: `pnpm test`
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ declare const api: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default api;
@@ -0,0 +1,193 @@
1
+ import { zValidator } from "@hono/zod-validator";
2
+ import { Hono } from "hono";
3
+ import { v4 as uuid } from "uuid";
4
+ import { z } from "zod/v3";
5
+ import { getAssistantId, getCachedStaticGraphSchema, getGraph, } from "../graph/load.mjs";
6
+ import { getRuntimeGraphSchema } from "../graph/parser/index.mjs";
7
+ import { HTTPException } from "hono/http-exception";
8
+ import * as schemas from "../schemas.mjs";
9
+ import { assistants } from "../storage/context.mjs";
10
+ const api = new Hono();
11
+ const RunnableConfigSchema = z.object({
12
+ tags: z.array(z.string()).optional(),
13
+ metadata: z.record(z.unknown()).optional(),
14
+ run_name: z.string().optional(),
15
+ max_concurrency: z.number().optional(),
16
+ recursion_limit: z.number().optional(),
17
+ configurable: z.record(z.unknown()).optional(),
18
+ run_id: z.string().uuid().optional(),
19
+ });
20
+ const getRunnableConfig = (userConfig) => {
21
+ if (!userConfig)
22
+ return {};
23
+ return {
24
+ configurable: userConfig.configurable,
25
+ tags: userConfig.tags,
26
+ metadata: userConfig.metadata,
27
+ runName: userConfig.run_name,
28
+ maxConcurrency: userConfig.max_concurrency,
29
+ recursionLimit: userConfig.recursion_limit,
30
+ runId: userConfig.run_id,
31
+ };
32
+ };
33
+ api.post("/assistants", zValidator("json", schemas.AssistantCreate), async (c) => {
34
+ // Create Assistant
35
+ const payload = c.req.valid("json");
36
+ const assistant = await assistants().put(payload.assistant_id ?? uuid(), {
37
+ config: payload.config ?? {},
38
+ context: payload.context ?? {},
39
+ graph_id: payload.graph_id,
40
+ metadata: payload.metadata ?? {},
41
+ if_exists: payload.if_exists ?? "raise",
42
+ name: payload.name ?? "Untitled",
43
+ description: payload.description,
44
+ }, c.var.auth);
45
+ return c.json(assistant);
46
+ });
47
+ api.post("/assistants/search", zValidator("json", schemas.AssistantSearchRequest), async (c) => {
48
+ // Search Assistants
49
+ const payload = c.req.valid("json");
50
+ const result = [];
51
+ let total = 0;
52
+ for await (const item of assistants().search({
53
+ graph_id: payload.graph_id,
54
+ name: payload.name,
55
+ metadata: payload.metadata,
56
+ limit: payload.limit ?? 10,
57
+ offset: payload.offset ?? 0,
58
+ sort_by: payload.sort_by,
59
+ sort_order: payload.sort_order,
60
+ select: payload.select,
61
+ }, c.var.auth)) {
62
+ result.push(Object.fromEntries(Object.entries(item.assistant).filter(([k]) => !payload.select || payload.select.includes(k))));
63
+ if (total === 0) {
64
+ total = item.total;
65
+ }
66
+ }
67
+ if (total === payload.limit) {
68
+ c.res.headers.set("X-Pagination-Next", ((payload.offset ?? 0) + total).toString());
69
+ c.res.headers.set("X-Pagination-Total", ((payload.offset ?? 0) + total + 1).toString());
70
+ }
71
+ else {
72
+ c.res.headers.set("X-Pagination-Total", ((payload.offset ?? 0) + total).toString());
73
+ }
74
+ return c.json(result);
75
+ });
76
+ api.post("/assistants/count", zValidator("json", schemas.AssistantCountRequest), async (c) => {
77
+ const payload = c.req.valid("json");
78
+ const total = await assistants().count(payload, c.var.auth);
79
+ return c.json(total);
80
+ });
81
+ api.get("/assistants/:assistant_id", async (c) => {
82
+ // Get Assistant
83
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
84
+ return c.json(await assistants().get(assistantId, c.var.auth));
85
+ });
86
+ api.delete("/assistants/:assistant_id", async (c) => {
87
+ // Delete Assistant
88
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
89
+ return c.json(await assistants().delete(assistantId, c.var.auth));
90
+ });
91
+ api.patch("/assistants/:assistant_id", zValidator("json", schemas.AssistantPatch), async (c) => {
92
+ // Patch Assistant
93
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
94
+ const payload = c.req.valid("json");
95
+ return c.json(await assistants().patch(assistantId, payload, c.var.auth));
96
+ });
97
+ api.get("/assistants/:assistant_id/graph", zValidator("query", z.object({ xray: schemas.coercedBoolean.optional() })), async (c) => {
98
+ // Get Assistant Graph
99
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
100
+ const assistant = await assistants().get(assistantId, c.var.auth);
101
+ const { xray } = c.req.valid("query");
102
+ const config = getRunnableConfig(assistant.config);
103
+ const graph = await getGraph(assistant.graph_id, config);
104
+ const drawable = await graph.getGraphAsync({
105
+ ...config,
106
+ xray: xray ?? undefined,
107
+ });
108
+ return c.json(drawable.toJSON());
109
+ });
110
+ api.get("/assistants/:assistant_id/schemas", zValidator("json", z.object({ config: RunnableConfigSchema.optional() })), async (c) => {
111
+ // Get Assistant Schemas
112
+ const json = c.req.valid("json");
113
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
114
+ const assistant = await assistants().get(assistantId, c.var.auth);
115
+ const config = getRunnableConfig(json.config);
116
+ const graph = await getGraph(assistant.graph_id, config);
117
+ const schema = await (async () => {
118
+ const runtimeSchema = await getRuntimeGraphSchema(graph);
119
+ if (runtimeSchema)
120
+ return runtimeSchema;
121
+ const graphSchema = await getCachedStaticGraphSchema(assistant.graph_id);
122
+ const rootGraphId = Object.keys(graphSchema).find((i) => !i.includes("|"));
123
+ if (!rootGraphId)
124
+ throw new HTTPException(404, { message: "Failed to find root graph" });
125
+ return graphSchema[rootGraphId];
126
+ })();
127
+ return c.json({
128
+ graph_id: assistant.graph_id,
129
+ input_schema: schema.input,
130
+ output_schema: schema.output,
131
+ state_schema: schema.state,
132
+ config_schema: schema.config,
133
+ // From JS PoV `configSchema` and `contextSchema` are indistinguishable,
134
+ // thus we use config_schema for context_schema.
135
+ context_schema: schema.config,
136
+ });
137
+ });
138
+ api.get("/assistants/:assistant_id/subgraphs/:namespace?", zValidator("param", z.object({ assistant_id: z.string(), namespace: z.string().optional() })), zValidator("query", z.object({ recurse: schemas.coercedBoolean.optional() })), async (c) => {
139
+ // Get Assistant Subgraphs
140
+ const { assistant_id, namespace } = c.req.valid("param");
141
+ const { recurse } = c.req.valid("query");
142
+ const assistantId = getAssistantId(assistant_id);
143
+ const assistant = await assistants().get(assistantId, c.var.auth);
144
+ const config = getRunnableConfig(assistant.config);
145
+ const graph = await getGraph(assistant.graph_id, config);
146
+ const result = [];
147
+ const subgraphsGenerator = "getSubgraphsAsync" in graph
148
+ ? graph.getSubgraphsAsync.bind(graph)
149
+ : // @ts-expect-error older versions of langgraph don't have getSubgraphsAsync
150
+ graph.getSubgraphs.bind(graph);
151
+ let graphSchemaPromise;
152
+ for await (const [ns, subgraph] of subgraphsGenerator(namespace, recurse)) {
153
+ const schema = await (async () => {
154
+ const runtimeSchema = await getRuntimeGraphSchema(subgraph);
155
+ if (runtimeSchema)
156
+ return runtimeSchema;
157
+ graphSchemaPromise ??= getCachedStaticGraphSchema(assistant.graph_id);
158
+ const graphSchema = await graphSchemaPromise;
159
+ const rootGraphId = Object.keys(graphSchema).find((i) => !i.includes("|"));
160
+ if (!rootGraphId) {
161
+ throw new HTTPException(404, {
162
+ message: "Failed to find root graph",
163
+ });
164
+ }
165
+ return graphSchema[`${rootGraphId}|${ns}`] || graphSchema[rootGraphId];
166
+ })();
167
+ result.push([ns, schema]);
168
+ }
169
+ return c.json(Object.fromEntries(result));
170
+ });
171
+ api.post("/assistants/:assistant_id/latest", zValidator("json", schemas.AssistantLatestVersion), async (c) => {
172
+ // Set Latest Assistant Version
173
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
174
+ const { version } = c.req.valid("json");
175
+ return c.json(await assistants().setLatest(assistantId, version, c.var.auth));
176
+ });
177
+ api.post("/assistants/:assistant_id/versions", zValidator("json", z.object({
178
+ limit: z.number().min(1).max(1000).optional().default(10),
179
+ offset: z.number().min(0).optional().default(0),
180
+ metadata: z.record(z.unknown()).optional(),
181
+ })), async (c) => {
182
+ // Get Assistant Versions
183
+ const assistantId = getAssistantId(c.req.param("assistant_id"));
184
+ const { limit, offset, metadata } = c.req.valid("json");
185
+ const versions = await assistants().getVersions(assistantId, { limit, offset, metadata }, c.var.auth);
186
+ if (!versions?.length) {
187
+ throw new HTTPException(404, {
188
+ message: `Assistant "${assistantId}" not found.`,
189
+ });
190
+ }
191
+ return c.json(versions);
192
+ });
193
+ export default api;
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ declare const api: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default api;
@@ -0,0 +1,65 @@
1
+ import { Hono } from "hono";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import * as url from "node:url";
5
+ const api = new Hono();
6
+ // Get the version using the same pattern as semver/index.mts
7
+ const packageJsonPath = path.resolve(url.fileURLToPath(import.meta.url), "../../../package.json");
8
+ let version;
9
+ let langgraph_js_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;
15
+ }
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
+ };
30
+ // read env variable
31
+ const env = process.env;
32
+ api.get("/info", async (c) => {
33
+ if (!versionInfoLoaded) {
34
+ await loadVersionInfo();
35
+ versionInfoLoaded = true;
36
+ }
37
+ const langsmithApiKey = env["LANGSMITH_API_KEY"] || env["LANGCHAIN_API_KEY"];
38
+ const langsmithTracing = (() => {
39
+ if (langsmithApiKey) {
40
+ // Check if any tracing variable is explicitly set to "false"
41
+ const tracingVars = [
42
+ env["LANGCHAIN_TRACING_V2"],
43
+ env["LANGCHAIN_TRACING"],
44
+ env["LANGSMITH_TRACING_V2"],
45
+ env["LANGSMITH_TRACING"],
46
+ ];
47
+ // Return true unless explicitly disabled
48
+ return !tracingVars.some((val) => val === "false" || val === "False");
49
+ }
50
+ return undefined;
51
+ })();
52
+ return c.json({
53
+ version,
54
+ langgraph_js_version,
55
+ context: "js",
56
+ flags: {
57
+ assistants: true,
58
+ crons: false,
59
+ langsmith: !!langsmithTracing,
60
+ langsmith_tracing_replicas: true,
61
+ },
62
+ });
63
+ });
64
+ api.get("/ok", (c) => c.json({ ok: true }));
65
+ export default api;
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ declare const api: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default api;
@@ -0,0 +1,324 @@
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;
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ declare const api: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export default api;