@langchain/langgraph-api 0.0.40 → 0.0.42
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/meta.mjs +2 -1
- package/dist/api/runs.mjs +1 -1
- package/dist/api/threads.mjs +2 -13
- package/dist/command.d.mts +1 -1
- package/dist/experimental/embed.d.mts +26 -0
- package/dist/experimental/embed.mjs +167 -0
- package/dist/graph/parser/schema/types.template.mts +31 -34
- package/dist/http/middleware.mjs +1 -1
- package/dist/queue.mjs +6 -3
- package/dist/schemas.d.mts +43 -0
- package/dist/schemas.mjs +15 -0
- package/dist/semver/index.mjs +2 -1
- package/dist/state.mjs +1 -3
- package/dist/storage/ops.d.mts +2 -2
- package/dist/storage/ops.mjs +24 -13
- package/dist/stream.d.mts +7 -2
- package/dist/stream.mjs +5 -6
- package/dist/ui/load.mjs +2 -1
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +12 -0
- package/package.json +19 -15
package/dist/api/meta.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
3
4
|
import * as url from "node:url";
|
|
4
5
|
const api = new Hono();
|
|
5
6
|
// Get the version using the same pattern as semver/index.mts
|
|
6
|
-
const packageJsonPath = url.fileURLToPath(
|
|
7
|
+
const packageJsonPath = path.resolve(url.fileURLToPath(import.meta.url), "../../../package.json");
|
|
7
8
|
let version;
|
|
8
9
|
try {
|
|
9
10
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
|
package/dist/api/runs.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { serialiseAsDict } from "../utils/serde.mjs";
|
|
|
13
13
|
const api = new Hono();
|
|
14
14
|
const createValidRun = async (threadId, payload, kwargs) => {
|
|
15
15
|
const { assistant_id: assistantId, ...run } = payload;
|
|
16
|
-
const { auth, headers } = kwargs;
|
|
16
|
+
const { auth, headers } = kwargs ?? {};
|
|
17
17
|
const runId = uuid4();
|
|
18
18
|
const streamMode = Array.isArray(payload.stream_mode)
|
|
19
19
|
? payload.stream_mode
|
package/dist/api/threads.mjs
CHANGED
|
@@ -111,18 +111,7 @@ api.get("/threads/:thread_id/history", zValidator("param", z.object({ thread_id:
|
|
|
111
111
|
const states = await Threads.State.list({ configurable: { thread_id, checkpoint_ns: "" } }, { limit, before }, c.var.auth);
|
|
112
112
|
return jsonExtra(c, states.map(stateSnapshotToThreadState));
|
|
113
113
|
});
|
|
114
|
-
api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json",
|
|
115
|
-
limit: z.number().optional().default(10),
|
|
116
|
-
before: z.string().optional(),
|
|
117
|
-
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
118
|
-
checkpoint: z
|
|
119
|
-
.object({
|
|
120
|
-
checkpoint_id: z.string().uuid().optional(),
|
|
121
|
-
checkpoint_ns: z.string().optional(),
|
|
122
|
-
checkpoint_map: z.record(z.string(), z.unknown()).optional(),
|
|
123
|
-
})
|
|
124
|
-
.optional(),
|
|
125
|
-
})), async (c) => {
|
|
114
|
+
api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
|
|
126
115
|
// Get Thread History Post
|
|
127
116
|
const { thread_id } = c.req.valid("param");
|
|
128
117
|
const { limit, before, metadata, checkpoint } = c.req.valid("json");
|
|
@@ -140,7 +129,7 @@ api.delete("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.st
|
|
|
140
129
|
await Threads.delete(thread_id, c.var.auth);
|
|
141
130
|
return new Response(null, { status: 204 });
|
|
142
131
|
});
|
|
143
|
-
api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json",
|
|
132
|
+
api.patch("/threads/:thread_id", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadPatchRequest), async (c) => {
|
|
144
133
|
// Patch Thread
|
|
145
134
|
const { thread_id } = c.req.valid("param");
|
|
146
135
|
const { metadata } = c.req.valid("json");
|
package/dist/command.d.mts
CHANGED
|
@@ -8,4 +8,4 @@ export interface RunCommand {
|
|
|
8
8
|
update?: Record<string, unknown> | [string, unknown][];
|
|
9
9
|
resume?: unknown;
|
|
10
10
|
}
|
|
11
|
-
export declare const getLangGraphCommand: (command: RunCommand) => Command<unknown>;
|
|
11
|
+
export declare const getLangGraphCommand: (command: RunCommand) => Command<unknown, Record<string, unknown>, string>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { BaseCheckpointSaver, BaseStore, Pregel } from "@langchain/langgraph";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import type { Metadata } from "../storage/ops.mjs";
|
|
4
|
+
type AnyPregel = Pregel<any, any, any, any, any>;
|
|
5
|
+
interface Thread {
|
|
6
|
+
thread_id: string;
|
|
7
|
+
metadata: Metadata;
|
|
8
|
+
}
|
|
9
|
+
interface ThreadSaver {
|
|
10
|
+
get: (id: string) => Promise<Thread>;
|
|
11
|
+
put: (id: string, options: {
|
|
12
|
+
metadata?: Metadata;
|
|
13
|
+
}) => Promise<void>;
|
|
14
|
+
delete: (id: string) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Attach LangGraph Platform-esque routes to a given Hono instance.
|
|
18
|
+
* @experimental Does not follow semver.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createEmbedServer(options: {
|
|
21
|
+
graph: Record<string, AnyPregel>;
|
|
22
|
+
threads: ThreadSaver;
|
|
23
|
+
checkpointer: BaseCheckpointSaver;
|
|
24
|
+
store?: BaseStore;
|
|
25
|
+
}): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { zValidator } from "@hono/zod-validator";
|
|
3
|
+
import { streamSSE } from "hono/streaming";
|
|
4
|
+
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
import * as schemas from "../schemas.mjs";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { streamState } from "../stream.mjs";
|
|
8
|
+
import { serialiseAsDict } from "../utils/serde.mjs";
|
|
9
|
+
import { getDisconnectAbortSignal, jsonExtra } from "../utils/hono.mjs";
|
|
10
|
+
import { stateSnapshotToThreadState } from "../state.mjs";
|
|
11
|
+
import { ensureContentType } from "../http/middleware.mjs";
|
|
12
|
+
function createStubRun(threadId, payload) {
|
|
13
|
+
const now = new Date();
|
|
14
|
+
const runId = uuidv4();
|
|
15
|
+
const streamMode = Array.isArray(payload.stream_mode)
|
|
16
|
+
? payload.stream_mode
|
|
17
|
+
: payload.stream_mode
|
|
18
|
+
? [payload.stream_mode]
|
|
19
|
+
: undefined;
|
|
20
|
+
const config = Object.assign({}, payload.config ?? {}, {
|
|
21
|
+
configurable: {
|
|
22
|
+
run_id: runId,
|
|
23
|
+
thread_id: threadId,
|
|
24
|
+
graph_id: payload.assistant_id,
|
|
25
|
+
},
|
|
26
|
+
}, { metadata: payload.metadata ?? {} });
|
|
27
|
+
return {
|
|
28
|
+
run_id: runId,
|
|
29
|
+
thread_id: threadId,
|
|
30
|
+
assistant_id: payload.assistant_id,
|
|
31
|
+
metadata: payload.metadata ?? {},
|
|
32
|
+
status: "running",
|
|
33
|
+
kwargs: {
|
|
34
|
+
input: payload.input,
|
|
35
|
+
command: payload.command,
|
|
36
|
+
config,
|
|
37
|
+
stream_mode: streamMode,
|
|
38
|
+
interrupt_before: payload.interrupt_before,
|
|
39
|
+
interrupt_after: payload.interrupt_after,
|
|
40
|
+
feedback_keys: payload.feedback_keys,
|
|
41
|
+
subgraphs: payload.stream_subgraphs,
|
|
42
|
+
temporary: false,
|
|
43
|
+
},
|
|
44
|
+
multitask_strategy: "reject",
|
|
45
|
+
created_at: now,
|
|
46
|
+
updated_at: now,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Attach LangGraph Platform-esque routes to a given Hono instance.
|
|
51
|
+
* @experimental Does not follow semver.
|
|
52
|
+
*/
|
|
53
|
+
export function createEmbedServer(options) {
|
|
54
|
+
async function getGraph(graphId) {
|
|
55
|
+
const targetGraph = options.graph[graphId];
|
|
56
|
+
targetGraph.store = options.store;
|
|
57
|
+
targetGraph.checkpointer = options.checkpointer;
|
|
58
|
+
return targetGraph;
|
|
59
|
+
}
|
|
60
|
+
const api = new Hono();
|
|
61
|
+
api.use(ensureContentType());
|
|
62
|
+
api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
|
|
63
|
+
// create a new threaad
|
|
64
|
+
const payload = c.req.valid("json");
|
|
65
|
+
const threadId = payload.thread_id || uuidv4();
|
|
66
|
+
await options.threads.put(threadId, payload);
|
|
67
|
+
return jsonExtra(c, { thread_id: threadId });
|
|
68
|
+
});
|
|
69
|
+
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) => {
|
|
70
|
+
// Get Latest Thread State
|
|
71
|
+
const { thread_id } = c.req.valid("param");
|
|
72
|
+
const { subgraphs } = c.req.valid("query");
|
|
73
|
+
const thread = await options.threads.get(thread_id);
|
|
74
|
+
const graphId = thread.metadata?.graph_id;
|
|
75
|
+
const graph = graphId ? options.graph[graphId] : undefined;
|
|
76
|
+
if (graph == null) {
|
|
77
|
+
return jsonExtra(c, stateSnapshotToThreadState({
|
|
78
|
+
values: {},
|
|
79
|
+
next: [],
|
|
80
|
+
config: {},
|
|
81
|
+
metadata: undefined,
|
|
82
|
+
createdAt: undefined,
|
|
83
|
+
parentConfig: undefined,
|
|
84
|
+
tasks: [],
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
const config = { configurable: { thread_id } };
|
|
88
|
+
const result = await graph.getState(config, { subgraphs });
|
|
89
|
+
return jsonExtra(c, stateSnapshotToThreadState(result));
|
|
90
|
+
});
|
|
91
|
+
api.post("/threads/:thread_id/history", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.ThreadHistoryRequest), async (c) => {
|
|
92
|
+
// Get Thread History Post
|
|
93
|
+
const { thread_id } = c.req.valid("param");
|
|
94
|
+
const { limit, before, metadata, checkpoint } = c.req.valid("json");
|
|
95
|
+
const thread = await options.threads.get(thread_id);
|
|
96
|
+
const graphId = thread.metadata?.graph_id;
|
|
97
|
+
const graph = graphId ? options.graph[graphId] : undefined;
|
|
98
|
+
if (graph == null)
|
|
99
|
+
return jsonExtra(c, []);
|
|
100
|
+
const config = { configurable: { thread_id, ...checkpoint } };
|
|
101
|
+
const result = [];
|
|
102
|
+
const beforeConfig = typeof before === "string"
|
|
103
|
+
? { configurable: { checkpoint_id: before } }
|
|
104
|
+
: before;
|
|
105
|
+
for await (const state of graph.getStateHistory(config, {
|
|
106
|
+
limit,
|
|
107
|
+
before: beforeConfig,
|
|
108
|
+
filter: metadata,
|
|
109
|
+
})) {
|
|
110
|
+
result.push(stateSnapshotToThreadState(state));
|
|
111
|
+
}
|
|
112
|
+
return jsonExtra(c, result);
|
|
113
|
+
});
|
|
114
|
+
api.post("/threads/:thread_id/runs/stream", zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator("json", schemas.RunCreate), async (c) => {
|
|
115
|
+
// Stream Run
|
|
116
|
+
return streamSSE(c, async (stream) => {
|
|
117
|
+
const { thread_id } = c.req.valid("param");
|
|
118
|
+
const payload = c.req.valid("json");
|
|
119
|
+
const signal = getDisconnectAbortSignal(c, stream);
|
|
120
|
+
const run = createStubRun(thread_id, payload);
|
|
121
|
+
// update thread with new graph_id
|
|
122
|
+
const thread = await options.threads.get(thread_id);
|
|
123
|
+
await options.threads.put(thread_id, {
|
|
124
|
+
metadata: {
|
|
125
|
+
...thread.metadata,
|
|
126
|
+
graph_id: payload.assistant_id,
|
|
127
|
+
assistant_id: payload.assistant_id,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
for await (const { event, data } of streamState(run, {
|
|
131
|
+
attempt: 1,
|
|
132
|
+
getGraph,
|
|
133
|
+
signal,
|
|
134
|
+
})) {
|
|
135
|
+
await stream.writeSSE({ data: serialiseAsDict(data), event });
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => {
|
|
140
|
+
// Stream Stateless Run
|
|
141
|
+
return streamSSE(c, async (stream) => {
|
|
142
|
+
const payload = c.req.valid("json");
|
|
143
|
+
const signal = getDisconnectAbortSignal(c, stream);
|
|
144
|
+
const threadId = uuidv4();
|
|
145
|
+
await options.threads.put(threadId, {
|
|
146
|
+
metadata: {
|
|
147
|
+
graph_id: payload.assistant_id,
|
|
148
|
+
assistant_id: payload.assistant_id,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
try {
|
|
152
|
+
const run = createStubRun(threadId, payload);
|
|
153
|
+
for await (const { event, data } of streamState(run, {
|
|
154
|
+
attempt: 1,
|
|
155
|
+
getGraph,
|
|
156
|
+
signal,
|
|
157
|
+
})) {
|
|
158
|
+
await stream.writeSSE({ data: serialiseAsDict(data), event });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
await options.threads.delete(threadId);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
return api;
|
|
167
|
+
}
|
|
@@ -20,12 +20,11 @@ type AnyGraph = {
|
|
|
20
20
|
|
|
21
21
|
type Wrap<T> = (a: T) => void;
|
|
22
22
|
type MatchBaseMessage<T> = T extends BaseMessage ? BaseMessage : never;
|
|
23
|
-
type MatchBaseMessageArray<T> =
|
|
24
|
-
|
|
25
|
-
?
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
: never;
|
|
23
|
+
type MatchBaseMessageArray<T> = T extends Array<infer C>
|
|
24
|
+
? Wrap<MatchBaseMessage<C>> extends Wrap<BaseMessage>
|
|
25
|
+
? BaseMessage[]
|
|
26
|
+
: never
|
|
27
|
+
: never;
|
|
29
28
|
|
|
30
29
|
type Defactorify<T> = T extends (...args: any[]) => infer R
|
|
31
30
|
? Awaited<R>
|
|
@@ -35,32 +34,31 @@ type Defactorify<T> = T extends (...args: any[]) => infer R
|
|
|
35
34
|
type Inspect<T, TDepth extends Array<0> = []> = TDepth extends [0, 0, 0]
|
|
36
35
|
? any
|
|
37
36
|
: T extends unknown
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
? {
|
|
38
|
+
[K in keyof T]: 0 extends 1 & T[K]
|
|
39
|
+
? T[K]
|
|
40
|
+
: Wrap<MatchBaseMessageArray<T[K]>> extends Wrap<BaseMessage[]>
|
|
41
|
+
? BaseMessage[]
|
|
42
|
+
: Wrap<MatchBaseMessage<T[K]>> extends Wrap<BaseMessage>
|
|
43
|
+
? BaseMessage
|
|
44
|
+
: Inspect<T[K], [0, ...TDepth]>;
|
|
45
|
+
}
|
|
46
|
+
: never;
|
|
48
47
|
|
|
49
48
|
type ReflectCompiled<T> = T extends { RunInput: infer S; RunOutput: infer U }
|
|
50
49
|
? { state: S; update: U }
|
|
51
50
|
: T extends { "~InputType": infer InputType; "~OutputType": infer OutputType }
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
? { state: OutputType; update: InputType }
|
|
52
|
+
: never;
|
|
54
53
|
|
|
55
54
|
// @ts-expect-error
|
|
56
|
-
type Reflect<T> =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
: never;
|
|
55
|
+
type Reflect<T> = Defactorify<T> extends infer DT
|
|
56
|
+
? DT extends {
|
|
57
|
+
compile(...args: any[]): infer Compiled;
|
|
58
|
+
}
|
|
59
|
+
? ReflectCompiled<Compiled>
|
|
60
|
+
: ReflectCompiled<DT>
|
|
61
|
+
: never;
|
|
64
62
|
|
|
65
63
|
type BuilderReflectCompiled<T> = T extends {
|
|
66
64
|
builder: {
|
|
@@ -77,14 +75,13 @@ type BuilderReflectCompiled<T> = T extends {
|
|
|
77
75
|
: never;
|
|
78
76
|
|
|
79
77
|
// @ts-expect-error
|
|
80
|
-
type BuilderReflect<T> =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
: never;
|
|
78
|
+
type BuilderReflect<T> = Defactorify<T> extends infer DT
|
|
79
|
+
? DT extends {
|
|
80
|
+
compile(...args: any[]): infer Compiled;
|
|
81
|
+
}
|
|
82
|
+
? BuilderReflectCompiled<Compiled>
|
|
83
|
+
: BuilderReflectCompiled<DT>
|
|
84
|
+
: never;
|
|
88
85
|
|
|
89
86
|
// @ts-expect-error
|
|
90
87
|
type FilterAny<T> = 0 extends 1 & T ? never : T;
|
package/dist/http/middleware.mjs
CHANGED
|
@@ -16,7 +16,7 @@ export const cors = (cors) => {
|
|
|
16
16
|
return origin;
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
|
-
:
|
|
19
|
+
: cors.allow_origins ?? [];
|
|
20
20
|
if (cors.expose_headers?.length) {
|
|
21
21
|
const headersSet = new Set(cors.expose_headers.map((h) => h.toLowerCase()));
|
|
22
22
|
if (!headersSet.has("content-location")) {
|
package/dist/queue.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { streamState, } from "./stream.mjs";
|
|
|
3
3
|
import { logError, logger } from "./logging.mjs";
|
|
4
4
|
import { serializeError } from "./utils/serde.mjs";
|
|
5
5
|
import { callWebhook } from "./webhook.mjs";
|
|
6
|
+
import { getGraph } from "./graph/load.mjs";
|
|
6
7
|
const MAX_RETRY_ATTEMPTS = 3;
|
|
7
8
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
9
|
export const queue = async () => {
|
|
@@ -14,7 +15,7 @@ export const queue = async () => {
|
|
|
14
15
|
await sleep(1000 * Math.random());
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
|
-
const worker = async (run, attempt,
|
|
18
|
+
const worker = async (run, attempt, signal) => {
|
|
18
19
|
const startedAt = new Date();
|
|
19
20
|
let endedAt = undefined;
|
|
20
21
|
let checkpoint = undefined;
|
|
@@ -48,8 +49,10 @@ const worker = async (run, attempt, abortSignal) => {
|
|
|
48
49
|
const runId = run.run_id;
|
|
49
50
|
const resumable = run.kwargs?.resumable ?? false;
|
|
50
51
|
try {
|
|
51
|
-
const stream = streamState(run,
|
|
52
|
-
|
|
52
|
+
const stream = streamState(run, {
|
|
53
|
+
getGraph,
|
|
54
|
+
attempt,
|
|
55
|
+
signal,
|
|
53
56
|
...(!temporary ? { onCheckpoint, onTaskResult } : undefined),
|
|
54
57
|
});
|
|
55
58
|
for await (const { event, data } of stream) {
|
package/dist/schemas.d.mts
CHANGED
|
@@ -1340,6 +1340,49 @@ export declare const ThreadStateUpdate: z.ZodObject<{
|
|
|
1340
1340
|
checkpoint_id?: string | undefined;
|
|
1341
1341
|
as_node?: string | undefined;
|
|
1342
1342
|
}>;
|
|
1343
|
+
export declare const ThreadHistoryRequest: z.ZodObject<{
|
|
1344
|
+
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
1345
|
+
before: z.ZodOptional<z.ZodString>;
|
|
1346
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1347
|
+
checkpoint: z.ZodOptional<z.ZodObject<{
|
|
1348
|
+
checkpoint_id: z.ZodOptional<z.ZodString>;
|
|
1349
|
+
checkpoint_ns: z.ZodOptional<z.ZodString>;
|
|
1350
|
+
checkpoint_map: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1351
|
+
}, "strip", z.ZodTypeAny, {
|
|
1352
|
+
checkpoint_ns?: string | undefined;
|
|
1353
|
+
checkpoint_id?: string | undefined;
|
|
1354
|
+
checkpoint_map?: Record<string, unknown> | undefined;
|
|
1355
|
+
}, {
|
|
1356
|
+
checkpoint_ns?: string | undefined;
|
|
1357
|
+
checkpoint_id?: string | undefined;
|
|
1358
|
+
checkpoint_map?: Record<string, unknown> | undefined;
|
|
1359
|
+
}>>;
|
|
1360
|
+
}, "strip", z.ZodTypeAny, {
|
|
1361
|
+
limit: number;
|
|
1362
|
+
metadata?: Record<string, unknown> | undefined;
|
|
1363
|
+
checkpoint?: {
|
|
1364
|
+
checkpoint_ns?: string | undefined;
|
|
1365
|
+
checkpoint_id?: string | undefined;
|
|
1366
|
+
checkpoint_map?: Record<string, unknown> | undefined;
|
|
1367
|
+
} | undefined;
|
|
1368
|
+
before?: string | undefined;
|
|
1369
|
+
}, {
|
|
1370
|
+
metadata?: Record<string, unknown> | undefined;
|
|
1371
|
+
checkpoint?: {
|
|
1372
|
+
checkpoint_ns?: string | undefined;
|
|
1373
|
+
checkpoint_id?: string | undefined;
|
|
1374
|
+
checkpoint_map?: Record<string, unknown> | undefined;
|
|
1375
|
+
} | undefined;
|
|
1376
|
+
limit?: number | undefined;
|
|
1377
|
+
before?: string | undefined;
|
|
1378
|
+
}>;
|
|
1379
|
+
export declare const ThreadPatchRequest: z.ZodObject<{
|
|
1380
|
+
metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
1381
|
+
}, "strip", z.ZodTypeAny, {
|
|
1382
|
+
metadata: Record<string, unknown>;
|
|
1383
|
+
}, {
|
|
1384
|
+
metadata: Record<string, unknown>;
|
|
1385
|
+
}>;
|
|
1343
1386
|
export declare const AssistantLatestVersion: z.ZodObject<{
|
|
1344
1387
|
version: z.ZodNumber;
|
|
1345
1388
|
}, "strip", z.ZodTypeAny, {
|
package/dist/schemas.mjs
CHANGED
|
@@ -388,6 +388,21 @@ export const ThreadStateUpdate = z
|
|
|
388
388
|
as_node: z.string().optional(),
|
|
389
389
|
})
|
|
390
390
|
.describe("Payload for adding state to a thread.");
|
|
391
|
+
export const ThreadHistoryRequest = z.object({
|
|
392
|
+
limit: z.number().optional().default(10),
|
|
393
|
+
before: z.string().optional(),
|
|
394
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
395
|
+
checkpoint: z
|
|
396
|
+
.object({
|
|
397
|
+
checkpoint_id: z.string().uuid().optional(),
|
|
398
|
+
checkpoint_ns: z.string().optional(),
|
|
399
|
+
checkpoint_map: z.record(z.string(), z.unknown()).optional(),
|
|
400
|
+
})
|
|
401
|
+
.optional(),
|
|
402
|
+
});
|
|
403
|
+
export const ThreadPatchRequest = z.object({
|
|
404
|
+
metadata: z.record(z.string(), z.unknown()),
|
|
405
|
+
});
|
|
391
406
|
export const AssistantLatestVersion = z.object({
|
|
392
407
|
version: z.number(),
|
|
393
408
|
});
|
package/dist/semver/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as url from "node:url";
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
3
4
|
import * as semver from "semver";
|
|
4
|
-
const packageJsonPath = url.fileURLToPath(
|
|
5
|
+
const packageJsonPath = path.resolve(url.fileURLToPath(import.meta.url), "../../../package.json");
|
|
5
6
|
export async function checkSemver(packages) {
|
|
6
7
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
|
|
7
8
|
const peerDependencies = packageJson.peerDependencies ?? {};
|
package/dist/state.mjs
CHANGED
|
@@ -15,13 +15,11 @@ export const stateSnapshotToThreadState = (state) => {
|
|
|
15
15
|
path: task.path,
|
|
16
16
|
// TODO: too many type assertions, check if this is actually correct
|
|
17
17
|
checkpoint: task.state != null && "configurable" in task.state
|
|
18
|
-
?
|
|
18
|
+
? task.state.configurable ?? null
|
|
19
19
|
: null,
|
|
20
20
|
state: task.state != null && isStateSnapshot(task.state)
|
|
21
21
|
? stateSnapshotToThreadState(task.state)
|
|
22
22
|
: null,
|
|
23
|
-
// TODO: add missing result to the library
|
|
24
|
-
// @ts-expect-error
|
|
25
23
|
result: task.result ?? null,
|
|
26
24
|
})),
|
|
27
25
|
metadata: state.metadata,
|
package/dist/storage/ops.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ import { FileSystemPersistence } from "./persist.mjs";
|
|
|
5
5
|
export type Metadata = Record<string, unknown>;
|
|
6
6
|
export type ThreadStatus = "idle" | "busy" | "interrupted" | "error";
|
|
7
7
|
export type RunStatus = "pending" | "running" | "error" | "success" | "timeout" | "interrupted";
|
|
8
|
-
export type StreamMode = "values" | "messages" | "messages-tuple" | "custom" | "updates" | "events" | "debug";
|
|
8
|
+
export type StreamMode = "values" | "messages" | "messages-tuple" | "custom" | "updates" | "events" | "debug" | "tasks" | "checkpoints";
|
|
9
9
|
export type MultitaskStrategy = "reject" | "rollback" | "interrupt" | "enqueue";
|
|
10
10
|
export type OnConflictBehavior = "raise" | "do_nothing";
|
|
11
11
|
export type IfNotExists = "create" | "reject";
|
|
@@ -183,7 +183,7 @@ interface ThreadTask {
|
|
|
183
183
|
interrupts: Record<string, unknown>[];
|
|
184
184
|
checkpoint: Checkpoint | null;
|
|
185
185
|
state: ThreadState | null;
|
|
186
|
-
result:
|
|
186
|
+
result: unknown | null;
|
|
187
187
|
}
|
|
188
188
|
export interface ThreadState {
|
|
189
189
|
values: Record<string, unknown>;
|
package/dist/storage/ops.mjs
CHANGED
|
@@ -744,27 +744,37 @@ export class Runs {
|
|
|
744
744
|
static async *next() {
|
|
745
745
|
yield* conn.withGenerator(async function* (STORE, options) {
|
|
746
746
|
const now = new Date();
|
|
747
|
-
const
|
|
747
|
+
const pendingRunIds = Object.values(STORE.runs)
|
|
748
748
|
.filter((run) => run.status === "pending" && run.created_at < now)
|
|
749
|
-
.sort((a, b) => a.created_at.getTime() - b.created_at.getTime())
|
|
750
|
-
|
|
749
|
+
.sort((a, b) => a.created_at.getTime() - b.created_at.getTime())
|
|
750
|
+
.map((run) => run.run_id);
|
|
751
|
+
if (!pendingRunIds.length) {
|
|
751
752
|
return;
|
|
752
753
|
}
|
|
753
|
-
for (const
|
|
754
|
-
const runId = run.run_id;
|
|
755
|
-
const threadId = run.thread_id;
|
|
756
|
-
const thread = STORE.threads[threadId];
|
|
757
|
-
if (!thread) {
|
|
758
|
-
await console.warn(`Unexpected missing thread in Runs.next: ${threadId}`);
|
|
759
|
-
continue;
|
|
760
|
-
}
|
|
754
|
+
for (const runId of pendingRunIds) {
|
|
761
755
|
if (StreamManager.isLocked(runId))
|
|
762
756
|
continue;
|
|
763
757
|
try {
|
|
764
758
|
const signal = StreamManager.lock(runId);
|
|
759
|
+
const run = STORE.runs[runId];
|
|
760
|
+
if (!run)
|
|
761
|
+
continue;
|
|
762
|
+
const threadId = run.thread_id;
|
|
763
|
+
const thread = STORE.threads[threadId];
|
|
764
|
+
if (!thread) {
|
|
765
|
+
logger.warn(`Unexpected missing thread in Runs.next: ${threadId}`);
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
// is the run still valid?
|
|
769
|
+
if (run.status !== "pending")
|
|
770
|
+
continue;
|
|
771
|
+
if (Object.values(STORE.runs).some((run) => run.thread_id === threadId && run.status === "running")) {
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
765
774
|
options.schedulePersist();
|
|
766
775
|
STORE.retry_counter[runId] ??= 0;
|
|
767
776
|
STORE.retry_counter[runId] += 1;
|
|
777
|
+
STORE.runs[runId].status = "running";
|
|
768
778
|
yield { run, attempt: STORE.retry_counter[runId], signal };
|
|
769
779
|
}
|
|
770
780
|
finally {
|
|
@@ -842,7 +852,8 @@ export class Runs {
|
|
|
842
852
|
}
|
|
843
853
|
// if multitask_mode = reject, check for inflight runs
|
|
844
854
|
// and if there are any, return them to reject putting a new run
|
|
845
|
-
const inflightRuns = Object.values(STORE.runs).filter((run) => run.thread_id === threadId &&
|
|
855
|
+
const inflightRuns = Object.values(STORE.runs).filter((run) => run.thread_id === threadId &&
|
|
856
|
+
(run.status === "pending" || run.status === "running"));
|
|
846
857
|
if (options?.preventInsertInInflight) {
|
|
847
858
|
if (inflightRuns.length > 0)
|
|
848
859
|
return inflightRuns;
|
|
@@ -1090,7 +1101,7 @@ export class Runs {
|
|
|
1090
1101
|
yield { event: "error", data: "Run not found" };
|
|
1091
1102
|
break;
|
|
1092
1103
|
}
|
|
1093
|
-
else if (run.status !== "pending") {
|
|
1104
|
+
else if (run.status !== "pending" && run.status !== "running") {
|
|
1094
1105
|
break;
|
|
1095
1106
|
}
|
|
1096
1107
|
}
|
package/dist/stream.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { BaseCheckpointSaver, LangGraphRunnableConfig, CheckpointMetadata, Interrupt, StateSnapshot } from "@langchain/langgraph";
|
|
2
|
+
import type { Pregel } from "@langchain/langgraph/pregel";
|
|
2
3
|
import type { Checkpoint, Run, RunnableConfig } from "./storage/ops.mjs";
|
|
3
4
|
interface DebugTask {
|
|
4
5
|
id: string;
|
|
@@ -27,7 +28,11 @@ export type StreamTaskResult = Prettify<Omit<DebugTask, "state"> & {
|
|
|
27
28
|
state?: StateSnapshot;
|
|
28
29
|
checkpoint?: Checkpoint;
|
|
29
30
|
}>;
|
|
30
|
-
export declare function streamState(run: Run,
|
|
31
|
+
export declare function streamState(run: Run, options: {
|
|
32
|
+
attempt: number;
|
|
33
|
+
getGraph: (graphId: string, config: LangGraphRunnableConfig | undefined, options?: {
|
|
34
|
+
checkpointer?: BaseCheckpointSaver | null;
|
|
35
|
+
}) => Promise<Pregel<any, any, any, any, any>>;
|
|
31
36
|
onCheckpoint?: (checkpoint: StreamCheckpoint) => void;
|
|
32
37
|
onTaskResult?: (taskResult: StreamTaskResult) => void;
|
|
33
38
|
signal?: AbortSignal;
|
package/dist/stream.mjs
CHANGED
|
@@ -2,7 +2,6 @@ import { isBaseMessage } from "@langchain/core/messages";
|
|
|
2
2
|
import { LangChainTracer } from "@langchain/core/tracers/tracer_langchain";
|
|
3
3
|
import { Client as LangSmithClient, getDefaultProjectName } from "langsmith";
|
|
4
4
|
import { getLangGraphCommand } from "./command.mjs";
|
|
5
|
-
import { getGraph } from "./graph/load.mjs";
|
|
6
5
|
import { checkLangGraphSemver } from "./semver/index.mjs";
|
|
7
6
|
import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
|
|
8
7
|
const isRunnableConfig = (config) => {
|
|
@@ -54,13 +53,13 @@ function preprocessDebugCheckpoint(payload) {
|
|
|
54
53
|
return result;
|
|
55
54
|
}
|
|
56
55
|
let LANGGRAPH_VERSION;
|
|
57
|
-
export async function* streamState(run,
|
|
56
|
+
export async function* streamState(run, options) {
|
|
58
57
|
const kwargs = run.kwargs;
|
|
59
58
|
const graphId = kwargs.config?.configurable?.graph_id;
|
|
60
59
|
if (!graphId || typeof graphId !== "string") {
|
|
61
60
|
throw new Error("Invalid or missing graph_id");
|
|
62
61
|
}
|
|
63
|
-
const graph = await getGraph(graphId, kwargs.config, {
|
|
62
|
+
const graph = await options.getGraph(graphId, kwargs.config, {
|
|
64
63
|
checkpointer: kwargs.temporary ? null : undefined,
|
|
65
64
|
});
|
|
66
65
|
const userStreamMode = kwargs.stream_mode ?? [];
|
|
@@ -75,7 +74,7 @@ export async function* streamState(run, attempt = 1, options) {
|
|
|
75
74
|
libStreamMode.add("debug");
|
|
76
75
|
yield {
|
|
77
76
|
event: "metadata",
|
|
78
|
-
data: { run_id: run.run_id, attempt },
|
|
77
|
+
data: { run_id: run.run_id, attempt: options.attempt },
|
|
79
78
|
};
|
|
80
79
|
if (!LANGGRAPH_VERSION) {
|
|
81
80
|
const version = await checkLangGraphSemver();
|
|
@@ -83,7 +82,7 @@ export async function* streamState(run, attempt = 1, options) {
|
|
|
83
82
|
}
|
|
84
83
|
const metadata = {
|
|
85
84
|
...kwargs.config?.metadata,
|
|
86
|
-
run_attempt: attempt,
|
|
85
|
+
run_attempt: options.attempt,
|
|
87
86
|
langgraph_version: LANGGRAPH_VERSION?.version ?? "0.0.0",
|
|
88
87
|
langgraph_plan: "developer",
|
|
89
88
|
langgraph_host: "self-hosted",
|
|
@@ -104,7 +103,7 @@ export async function* streamState(run, attempt = 1, options) {
|
|
|
104
103
|
: undefined;
|
|
105
104
|
const events = graph.streamEvents(kwargs.command != null
|
|
106
105
|
? getLangGraphCommand(kwargs.command)
|
|
107
|
-
:
|
|
106
|
+
: kwargs.input ?? null, {
|
|
108
107
|
version: "v2",
|
|
109
108
|
interruptAfter: kwargs.interrupt_after,
|
|
110
109
|
interruptBefore: kwargs.interrupt_before,
|
package/dist/ui/load.mjs
CHANGED
|
@@ -26,9 +26,10 @@ api.post("/ui/:agent", zValidator("json", z.object({ name: z.string() })), async
|
|
|
26
26
|
for (const css of files.filter((i) => path.extname(i.basename) === ".css")) {
|
|
27
27
|
result.push(`<link rel="stylesheet" href="http://${host}/ui/${agent}/${css.basename}" />`);
|
|
28
28
|
}
|
|
29
|
+
const stableName = agent.replace(/[^a-zA-Z0-9]/g, "_");
|
|
29
30
|
const js = files.find((i) => path.extname(i.basename) === ".js");
|
|
30
31
|
if (js) {
|
|
31
|
-
result.push(`<script src="http://${host}/ui/${agent}/${js.basename}" onload='__LGUI_${
|
|
32
|
+
result.push(`<script src="http://${host}/ui/${agent}/${js.basename}" onload='__LGUI_${stableName}.render(${messageName}, "{{shadowRootId}}")'></script>`);
|
|
32
33
|
}
|
|
33
34
|
return c.text(result.join("\n"), {
|
|
34
35
|
headers: { "Content-Type": "text/html" },
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { configDefaults, defineConfig } from "vitest/config";
|
|
2
|
+
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
|
3
|
+
export default defineConfig(() => {
|
|
4
|
+
/** @type {import("vitest/config").UserConfigExport} */
|
|
5
|
+
return {
|
|
6
|
+
test: {
|
|
7
|
+
hideSkippedTests: true,
|
|
8
|
+
testTimeout: 30_000,
|
|
9
|
+
fileParallelism: false,
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph-api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": "^18.19.0 || >=20.16.0"
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"types": "./dist/graph/parser/index.d.mts",
|
|
28
28
|
"default": "./dist/graph/parser/index.mjs"
|
|
29
29
|
},
|
|
30
|
+
"./experimental/embed": {
|
|
31
|
+
"types": "./dist/experimental/embed.d.mts",
|
|
32
|
+
"default": "./dist/experimental/embed.mjs"
|
|
33
|
+
},
|
|
30
34
|
"./package.json": "./package.json"
|
|
31
35
|
},
|
|
32
36
|
"repository": {
|
|
@@ -34,14 +38,13 @@
|
|
|
34
38
|
"url": "git@github.com:langchain-ai/langgraphjs-api.git"
|
|
35
39
|
},
|
|
36
40
|
"scripts": {
|
|
37
|
-
"clean": "
|
|
38
|
-
"build": "
|
|
41
|
+
"clean": "rm -rf dist/ .turbo/ ./tests/graphs/.langgraph_api/",
|
|
42
|
+
"build": "yarn turbo:command build:internal --filter=@langchain/langgraph-api",
|
|
43
|
+
"build:internal": "yarn clean && node scripts/build.mjs",
|
|
39
44
|
"dev": "tsx ./tests/utils.server.mts --dev",
|
|
40
45
|
"prepack": "yarn run build",
|
|
41
46
|
"typecheck": "tsc --noEmit",
|
|
42
|
-
"test": "vitest",
|
|
43
|
-
"test:parser": "vitest run ./tests/parser.test.mts --testTimeout 15000",
|
|
44
|
-
"test:api": "npx -y bun scripts/test.mjs",
|
|
47
|
+
"test": "vitest run",
|
|
45
48
|
"format": "prettier --write .",
|
|
46
49
|
"format:check": "prettier --check ."
|
|
47
50
|
},
|
|
@@ -49,7 +52,7 @@
|
|
|
49
52
|
"@babel/code-frame": "^7.26.2",
|
|
50
53
|
"@hono/node-server": "^1.12.0",
|
|
51
54
|
"@hono/zod-validator": "^0.2.2",
|
|
52
|
-
"@langchain/langgraph-ui": "
|
|
55
|
+
"@langchain/langgraph-ui": "workspace:*",
|
|
53
56
|
"@types/json-schema": "^7.0.15",
|
|
54
57
|
"@typescript/vfs": "^1.6.0",
|
|
55
58
|
"dedent": "^1.5.3",
|
|
@@ -81,19 +84,20 @@
|
|
|
81
84
|
},
|
|
82
85
|
"devDependencies": {
|
|
83
86
|
"@langchain/core": "^0.3.59",
|
|
84
|
-
"@langchain/langgraph": "
|
|
85
|
-
"@langchain/langgraph-checkpoint": "
|
|
86
|
-
"@langchain/langgraph-sdk": "
|
|
87
|
+
"@langchain/langgraph": "workspace:*",
|
|
88
|
+
"@langchain/langgraph-checkpoint": "workspace:*",
|
|
89
|
+
"@langchain/langgraph-sdk": "workspace:*",
|
|
87
90
|
"@types/babel__code-frame": "^7.0.6",
|
|
88
|
-
"@types/node": "^
|
|
91
|
+
"@types/node": "^18.15.11",
|
|
89
92
|
"@types/react": "^19.0.8",
|
|
90
93
|
"@types/react-dom": "^19.0.3",
|
|
91
94
|
"@types/semver": "^7.7.0",
|
|
92
95
|
"@types/uuid": "^10.0.0",
|
|
93
96
|
"jose": "^6.0.10",
|
|
94
97
|
"postgres": "^3.4.5",
|
|
95
|
-
"prettier": "^
|
|
96
|
-
"typescript": "^
|
|
97
|
-
"vitest": "^3.
|
|
98
|
+
"prettier": "^2.8.3",
|
|
99
|
+
"typescript": "^4.9.5 || ^5.4.5",
|
|
100
|
+
"vitest": "^3.1.2",
|
|
101
|
+
"wait-port": "^1.1.0"
|
|
98
102
|
}
|
|
99
|
-
}
|
|
103
|
+
}
|