@langchain/langgraph-api 0.0.16 → 0.0.18
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/threads.mjs +3 -0
- package/dist/cli/entrypoint.mjs +1 -1
- package/dist/command.mjs +15 -0
- package/dist/graph/load.hooks.mjs +29 -3
- package/dist/schemas.mjs +29 -23
- package/dist/storage/ops.mjs +38 -1
- package/dist/storage/persist.mjs +5 -2
- package/dist/stream.mjs +2 -16
- package/dist/ui/bundler.d.mts +8 -2
- package/dist/ui/bundler.mjs +21 -17
- package/dist/ui/load.mjs +2 -3
- package/dist/utils/hono.mjs +0 -1
- package/package.json +5 -5
package/dist/api/threads.mjs
CHANGED
|
@@ -15,6 +15,9 @@ api.post("/threads", zValidator("json", schemas.ThreadCreate), async (c) => {
|
|
|
15
15
|
metadata: payload.metadata,
|
|
16
16
|
if_exists: payload.if_exists ?? "raise",
|
|
17
17
|
});
|
|
18
|
+
if (payload.supersteps?.length) {
|
|
19
|
+
await Threads.State.bulk({ configurable: { thread_id: thread.thread_id } }, payload.supersteps);
|
|
20
|
+
}
|
|
18
21
|
return jsonExtra(c, thread);
|
|
19
22
|
});
|
|
20
23
|
api.post("/threads/search", zValidator("json", schemas.ThreadSearchRequest), async (c) => {
|
package/dist/cli/entrypoint.mjs
CHANGED
|
@@ -37,5 +37,5 @@ logger.info(`Server running at ${host}`);
|
|
|
37
37
|
let queryParams = `?baseUrl=http://${options.host}:${options.port}`;
|
|
38
38
|
if (organizationId)
|
|
39
39
|
queryParams += `&organizationId=${organizationId}`;
|
|
40
|
-
asyncExitHook(cleanup, { wait:
|
|
40
|
+
asyncExitHook(cleanup, { wait: 3_000 });
|
|
41
41
|
sendToParent?.({ queryParams });
|
package/dist/command.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command, Send } from "@langchain/langgraph";
|
|
2
|
+
export const getLangGraphCommand = (command) => {
|
|
3
|
+
let goto = command.goto != null && !Array.isArray(command.goto)
|
|
4
|
+
? [command.goto]
|
|
5
|
+
: command.goto;
|
|
6
|
+
return new Command({
|
|
7
|
+
goto: goto?.map((item) => {
|
|
8
|
+
if (typeof item !== "string")
|
|
9
|
+
return new Send(item.node, item.input);
|
|
10
|
+
return item;
|
|
11
|
+
}),
|
|
12
|
+
update: command.update,
|
|
13
|
+
resume: command.resume,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
@@ -8,6 +8,7 @@ const OVERRIDE_RESOLVE = [
|
|
|
8
8
|
new RegExp(`^@langchain\/langgraph-checkpoint(\/.+)?$`),
|
|
9
9
|
];
|
|
10
10
|
let parentURL;
|
|
11
|
+
let langgraphPackageURL;
|
|
11
12
|
export async function initialize(args) {
|
|
12
13
|
parentURL = args.parentURL;
|
|
13
14
|
}
|
|
@@ -15,12 +16,37 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
15
16
|
// HACK: @tailwindcss/node internally uses an ESM loader cache, which does not play nicely with `tsx`.
|
|
16
17
|
// Node.js crashes with "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file".
|
|
17
18
|
// As it already is a valid URI, we can just short-circuit the resolution and avoid `tsx`.
|
|
18
|
-
if (specifier.includes("@tailwindcss/node/dist/esm-cache.loader
|
|
19
|
+
if (specifier.includes("@tailwindcss/node/dist/esm-cache.loader") &&
|
|
19
20
|
specifier.startsWith("file://")) {
|
|
20
|
-
return {
|
|
21
|
+
return {
|
|
22
|
+
shortCircuit: true,
|
|
23
|
+
// Node 18.x will for some reason attempt to load `.mts` instead of `.mjs`
|
|
24
|
+
url: specifier.replace(".mts", ".mjs"),
|
|
25
|
+
format: "module",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (specifier === "@langchain/langgraph-checkpoint") {
|
|
29
|
+
// resolve relative to @langchain/langgraph package instead
|
|
30
|
+
// This is done to avoid adding a direct dependency on @langchain/langgraph-checkpoint
|
|
31
|
+
// in project, which if not present will cause `pnpm` to not find the package.
|
|
32
|
+
if (!langgraphPackageURL) {
|
|
33
|
+
const main = await nextResolve("@langchain/langgraph", {
|
|
34
|
+
...context,
|
|
35
|
+
parentURL,
|
|
36
|
+
});
|
|
37
|
+
langgraphPackageURL = main.url.toString();
|
|
38
|
+
}
|
|
39
|
+
return await nextResolve(specifier, {
|
|
40
|
+
...context,
|
|
41
|
+
parentURL: langgraphPackageURL,
|
|
42
|
+
});
|
|
21
43
|
}
|
|
22
44
|
if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
|
|
23
|
-
|
|
45
|
+
const resolved = await nextResolve(specifier, { ...context, parentURL });
|
|
46
|
+
// If @langchain/langgraph is resolved first, cache it!
|
|
47
|
+
if (specifier === "@langchain/langgraph" && !langgraphPackageURL) {
|
|
48
|
+
langgraphPackageURL = resolved.url.toString();
|
|
49
|
+
}
|
|
24
50
|
}
|
|
25
51
|
return nextResolve(specifier, context);
|
|
26
52
|
}
|
package/dist/schemas.mjs
CHANGED
|
@@ -140,35 +140,31 @@ export const Run = z.object({
|
|
|
140
140
|
kwargs: z.object({}).catchall(z.any()),
|
|
141
141
|
multitask_strategy: z.enum(["reject", "rollback", "interrupt", "enqueue"]),
|
|
142
142
|
});
|
|
143
|
+
export const CommandSchema = z.object({
|
|
144
|
+
goto: z
|
|
145
|
+
.union([
|
|
146
|
+
z.union([
|
|
147
|
+
z.string(),
|
|
148
|
+
z.object({ node: z.string(), input: z.unknown().optional() }),
|
|
149
|
+
]),
|
|
150
|
+
z.array(z.union([
|
|
151
|
+
z.string(),
|
|
152
|
+
z.object({ node: z.string(), input: z.unknown().optional() }),
|
|
153
|
+
])),
|
|
154
|
+
])
|
|
155
|
+
.optional(),
|
|
156
|
+
update: z
|
|
157
|
+
.union([z.record(z.unknown()), z.array(z.tuple([z.string(), z.unknown()]))])
|
|
158
|
+
.optional(),
|
|
159
|
+
resume: z.unknown().optional(),
|
|
160
|
+
});
|
|
143
161
|
export const RunCreate = z
|
|
144
162
|
.object({
|
|
145
163
|
assistant_id: z.union([z.string().uuid(), z.string()]),
|
|
146
164
|
checkpoint_id: z.string().optional(),
|
|
147
165
|
checkpoint: CheckpointSchema.optional(),
|
|
148
166
|
input: z.union([z.unknown(), z.null()]).optional(),
|
|
149
|
-
command:
|
|
150
|
-
.object({
|
|
151
|
-
goto: z
|
|
152
|
-
.union([
|
|
153
|
-
z.union([
|
|
154
|
-
z.string(),
|
|
155
|
-
z.object({ node: z.string(), input: z.unknown().optional() }),
|
|
156
|
-
]),
|
|
157
|
-
z.array(z.union([
|
|
158
|
-
z.string(),
|
|
159
|
-
z.object({ node: z.string(), input: z.unknown().optional() }),
|
|
160
|
-
])),
|
|
161
|
-
])
|
|
162
|
-
.optional(),
|
|
163
|
-
update: z
|
|
164
|
-
.union([
|
|
165
|
-
z.record(z.unknown()),
|
|
166
|
-
z.array(z.tuple([z.string(), z.unknown()])),
|
|
167
|
-
])
|
|
168
|
-
.optional(),
|
|
169
|
-
resume: z.unknown().optional(),
|
|
170
|
-
})
|
|
171
|
-
.optional(),
|
|
167
|
+
command: CommandSchema.optional(),
|
|
172
168
|
metadata: z
|
|
173
169
|
.object({})
|
|
174
170
|
.catchall(z.any())
|
|
@@ -301,6 +297,16 @@ export const Thread = z.object({
|
|
|
301
297
|
});
|
|
302
298
|
export const ThreadCreate = z
|
|
303
299
|
.object({
|
|
300
|
+
supersteps: z
|
|
301
|
+
.array(z.object({
|
|
302
|
+
updates: z.array(z.object({
|
|
303
|
+
values: z.unknown().nullish(),
|
|
304
|
+
command: CommandSchema.nullish(),
|
|
305
|
+
as_node: z.string(),
|
|
306
|
+
})),
|
|
307
|
+
}))
|
|
308
|
+
.describe("The supersteps to apply to the thread.")
|
|
309
|
+
.optional(),
|
|
304
310
|
thread_id: z
|
|
305
311
|
.string()
|
|
306
312
|
.uuid()
|
package/dist/storage/ops.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { store } from "./store.mjs";
|
|
|
6
6
|
import { logger } from "../logging.mjs";
|
|
7
7
|
import { serializeError } from "../utils/serde.mjs";
|
|
8
8
|
import { FileSystemPersistence } from "./persist.mjs";
|
|
9
|
+
import { getLangGraphCommand } from "../command.mjs";
|
|
9
10
|
export const conn = new FileSystemPersistence(".langgraphjs_ops.json", () => ({
|
|
10
11
|
runs: {},
|
|
11
12
|
threads: {},
|
|
@@ -487,6 +488,41 @@ export class Threads {
|
|
|
487
488
|
});
|
|
488
489
|
return { checkpoint: nextConfig.configurable };
|
|
489
490
|
}
|
|
491
|
+
static async bulk(config, supersteps) {
|
|
492
|
+
const threadId = config.configurable?.thread_id;
|
|
493
|
+
if (!threadId)
|
|
494
|
+
return [];
|
|
495
|
+
const thread = await Threads.get(threadId);
|
|
496
|
+
const graphId = thread.metadata?.graph_id;
|
|
497
|
+
if (graphId == null) {
|
|
498
|
+
throw new HTTPException(400, {
|
|
499
|
+
message: `Thread ${threadId} has no graph ID`,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
config.configurable ??= {};
|
|
503
|
+
config.configurable.graph_id ??= graphId;
|
|
504
|
+
const graph = await getGraph(graphId, { checkpointer, store });
|
|
505
|
+
const updateConfig = structuredClone(config);
|
|
506
|
+
updateConfig.configurable ??= {};
|
|
507
|
+
updateConfig.configurable.checkpoint_ns ??= "";
|
|
508
|
+
const nextConfig = await graph.bulkUpdateState(updateConfig, supersteps.map((i) => ({
|
|
509
|
+
updates: i.updates.map((j) => ({
|
|
510
|
+
values: j.command != null ? getLangGraphCommand(j.command) : j.values,
|
|
511
|
+
asNode: j.as_node,
|
|
512
|
+
})),
|
|
513
|
+
})));
|
|
514
|
+
const state = await Threads.State.get(config, { subgraphs: false });
|
|
515
|
+
// update thread values
|
|
516
|
+
await conn.with(async (STORE) => {
|
|
517
|
+
for (const thread of Object.values(STORE.threads)) {
|
|
518
|
+
if (thread.thread_id === threadId) {
|
|
519
|
+
thread.values = state.values;
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
return { checkpoint: nextConfig.configurable };
|
|
525
|
+
}
|
|
490
526
|
static async list(config, options) {
|
|
491
527
|
const threadId = config.configurable?.thread_id;
|
|
492
528
|
if (!threadId)
|
|
@@ -513,7 +549,7 @@ export class Threads {
|
|
|
513
549
|
}
|
|
514
550
|
export class Runs {
|
|
515
551
|
static async *next() {
|
|
516
|
-
yield* conn.withGenerator(async function* (STORE) {
|
|
552
|
+
yield* conn.withGenerator(async function* (STORE, options) {
|
|
517
553
|
const now = new Date();
|
|
518
554
|
const pendingRuns = Object.values(STORE.runs)
|
|
519
555
|
.filter((run) => run.status === "pending" && run.created_at < now)
|
|
@@ -533,6 +569,7 @@ export class Runs {
|
|
|
533
569
|
continue;
|
|
534
570
|
try {
|
|
535
571
|
const signal = StreamManager.lock(runId);
|
|
572
|
+
options.schedulePersist();
|
|
536
573
|
STORE.retry_counter[runId] ??= 0;
|
|
537
574
|
STORE.retry_counter[runId] += 1;
|
|
538
575
|
yield { run, attempt: STORE.retry_counter[runId], signal };
|
package/dist/storage/persist.mjs
CHANGED
|
@@ -67,12 +67,15 @@ export class FileSystemPersistence {
|
|
|
67
67
|
if (this.filepath == null || this.data == null) {
|
|
68
68
|
throw new Error(`${this.name} not initialized`);
|
|
69
69
|
}
|
|
70
|
+
let shouldPersist = false;
|
|
71
|
+
let schedulePersist = () => void (shouldPersist = true);
|
|
70
72
|
try {
|
|
71
|
-
const gen = typeof fn === "function" ? fn(this.data) : fn;
|
|
73
|
+
const gen = typeof fn === "function" ? fn(this.data, { schedulePersist }) : fn;
|
|
72
74
|
yield* gen;
|
|
73
75
|
}
|
|
74
76
|
finally {
|
|
75
|
-
|
|
77
|
+
if (shouldPersist)
|
|
78
|
+
this.schedulePersist();
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
81
|
}
|
package/dist/stream.mjs
CHANGED
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
import { getGraph } from "./graph/load.mjs";
|
|
2
2
|
import { Client as LangSmithClient } from "langsmith";
|
|
3
|
-
import { Command, Send, } from "@langchain/langgraph";
|
|
4
3
|
import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
let goto = command.goto != null && !Array.isArray(command.goto)
|
|
8
|
-
? [command.goto]
|
|
9
|
-
: command.goto;
|
|
10
|
-
return new Command({
|
|
11
|
-
goto: goto?.map((item) => {
|
|
12
|
-
if (typeof item !== "string")
|
|
13
|
-
return new Send(item.node, item.input);
|
|
14
|
-
return item;
|
|
15
|
-
}),
|
|
16
|
-
update: command.update,
|
|
17
|
-
resume: command.resume,
|
|
18
|
-
});
|
|
19
|
-
};
|
|
4
|
+
import { isBaseMessage } from "@langchain/core/messages";
|
|
5
|
+
import { getLangGraphCommand } from "./command.mjs";
|
|
20
6
|
const isRunnableConfig = (config) => {
|
|
21
7
|
if (typeof config !== "object" || config == null)
|
|
22
8
|
return false;
|
package/dist/ui/bundler.d.mts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { type BuildOptions } from "esbuild";
|
|
2
|
-
export declare function build(agentName: string,
|
|
2
|
+
export declare function build(agentName: string, args: {
|
|
3
|
+
cwd: string;
|
|
4
|
+
userPath: string;
|
|
5
|
+
}): Promise<{
|
|
3
6
|
basename: string;
|
|
4
7
|
contents: Uint8Array;
|
|
5
8
|
}[]>;
|
|
6
|
-
export declare function watch(agentName: string,
|
|
9
|
+
export declare function watch(agentName: string, args: {
|
|
10
|
+
cwd: string;
|
|
11
|
+
userPath: string;
|
|
12
|
+
}, onResult: (result: {
|
|
7
13
|
basename: string;
|
|
8
14
|
contents: Uint8Array;
|
|
9
15
|
}[]) => void): Promise<import("esbuild").BuildContext<BuildOptions>>;
|
package/dist/ui/bundler.mjs
CHANGED
|
@@ -4,19 +4,27 @@ import * as fs from "node:fs";
|
|
|
4
4
|
import { build as runBuild, context as runContext, } from "esbuild";
|
|
5
5
|
import tailwind from "esbuild-plugin-tailwindcss";
|
|
6
6
|
const renderTemplate = await fs.promises.readFile(url.fileURLToPath(new URL("./render.template.mts", import.meta.url)), "utf-8");
|
|
7
|
-
function entrypointPlugin(
|
|
8
|
-
const
|
|
7
|
+
function entrypointPlugin(paths) {
|
|
8
|
+
const fullPath = path.resolve(paths.cwd, paths.userPath);
|
|
9
|
+
let relativeUiPath = path
|
|
10
|
+
.relative(paths.cwd, fullPath)
|
|
11
|
+
.replaceAll(path.sep, "/");
|
|
12
|
+
if (relativeUiPath.startsWith("../")) {
|
|
13
|
+
throw new Error(`UI path must be relative to the project root. Received: "${relativeUiPath}"`);
|
|
14
|
+
}
|
|
15
|
+
if (!relativeUiPath.startsWith("./"))
|
|
16
|
+
relativeUiPath = `./${relativeUiPath}`;
|
|
9
17
|
return {
|
|
10
18
|
name: "entrypoint",
|
|
11
19
|
setup(build) {
|
|
12
|
-
build.onResolve({ filter: /^entrypoint$/ }, (
|
|
13
|
-
path: path.resolve(
|
|
20
|
+
build.onResolve({ filter: /^entrypoint$/ }, () => ({
|
|
21
|
+
path: path.resolve(path.dirname(fullPath), "ui.entrypoint.tsx"),
|
|
14
22
|
namespace: "entrypoint-ns",
|
|
15
23
|
}));
|
|
16
24
|
build.onLoad({ filter: /.*/, namespace: "entrypoint-ns" }, () => ({
|
|
17
|
-
resolveDir:
|
|
25
|
+
resolveDir: paths.cwd,
|
|
18
26
|
contents: [
|
|
19
|
-
`import ui from "${
|
|
27
|
+
`import ui from "${relativeUiPath}"`,
|
|
20
28
|
renderTemplate,
|
|
21
29
|
`export const render = createRenderer(ui)`,
|
|
22
30
|
].join("\n"),
|
|
@@ -46,10 +54,10 @@ function registerPlugin(onEnd) {
|
|
|
46
54
|
},
|
|
47
55
|
};
|
|
48
56
|
}
|
|
49
|
-
function setup(agentName,
|
|
57
|
+
function setup(agentName, args, onResult) {
|
|
50
58
|
return {
|
|
51
59
|
write: false,
|
|
52
|
-
outdir: path.resolve(
|
|
60
|
+
outdir: path.resolve(args.cwd, "dist"),
|
|
53
61
|
entryPoints: ["entrypoint"],
|
|
54
62
|
bundle: true,
|
|
55
63
|
platform: "browser",
|
|
@@ -61,21 +69,17 @@ function setup(agentName, uiUserPath, onResult) {
|
|
|
61
69
|
"@langchain/langgraph-sdk",
|
|
62
70
|
"@langchain/langgraph-sdk/react-ui",
|
|
63
71
|
],
|
|
64
|
-
plugins: [
|
|
65
|
-
tailwind(),
|
|
66
|
-
entrypointPlugin(uiUserPath),
|
|
67
|
-
registerPlugin(onResult),
|
|
68
|
-
],
|
|
72
|
+
plugins: [tailwind(), entrypointPlugin(args), registerPlugin(onResult)],
|
|
69
73
|
globalName: `__LGUI_${agentName}`,
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
|
-
export async function build(agentName,
|
|
76
|
+
export async function build(agentName, args) {
|
|
73
77
|
let results = [];
|
|
74
|
-
await runBuild(setup(agentName,
|
|
78
|
+
await runBuild(setup(agentName, args, (result) => (results = result)));
|
|
75
79
|
return results;
|
|
76
80
|
}
|
|
77
|
-
export async function watch(agentName,
|
|
78
|
-
const ctx = await runContext(setup(agentName,
|
|
81
|
+
export async function watch(agentName, args, onResult) {
|
|
82
|
+
const ctx = await runContext(setup(agentName, args, onResult));
|
|
79
83
|
await ctx.watch();
|
|
80
84
|
return ctx;
|
|
81
85
|
}
|
package/dist/ui/load.mjs
CHANGED
|
@@ -6,9 +6,8 @@ import * as path from "node:path";
|
|
|
6
6
|
import { watch } from "./bundler.mjs";
|
|
7
7
|
const GRAPH_UI = {};
|
|
8
8
|
export async function registerGraphUi(defs, options) {
|
|
9
|
-
const result = await Promise.all(Object.entries(defs).map(async ([agentName,
|
|
10
|
-
const
|
|
11
|
-
const ctx = await watch(agentName, userPath, (result) => {
|
|
9
|
+
const result = await Promise.all(Object.entries(defs).map(async ([agentName, userPath]) => {
|
|
10
|
+
const ctx = await watch(agentName, { cwd: options.cwd, userPath }, (result) => {
|
|
12
11
|
GRAPH_UI[agentName] = result;
|
|
13
12
|
});
|
|
14
13
|
return [agentName, ctx];
|
package/dist/utils/hono.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph-api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": "^18.19.0 || >=20.16.0"
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"zod": "^3.23.8"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@langchain/core": "^0.3.
|
|
51
|
-
"@langchain/langgraph": "^0.2.
|
|
52
|
-
"@langchain/langgraph-checkpoint": "^0.0.
|
|
50
|
+
"@langchain/core": "^0.3.42",
|
|
51
|
+
"@langchain/langgraph": "^0.2.57",
|
|
52
|
+
"@langchain/langgraph-checkpoint": "^0.0.16",
|
|
53
53
|
"typescript": "^5.5.4"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@langchain/langgraph-sdk": "^0.0.
|
|
56
|
+
"@langchain/langgraph-sdk": "^0.0.60",
|
|
57
57
|
"@types/babel__code-frame": "^7.0.6",
|
|
58
58
|
"@types/react": "^19.0.8",
|
|
59
59
|
"@types/react-dom": "^19.0.3",
|