@langchain/langgraph-api 0.0.14 → 0.0.15
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/cli/entrypoint.mjs +0 -1
- package/dist/cli/spawn.mjs +2 -0
- package/dist/graph/load.hooks.mjs +13 -11
- package/dist/graph/load.utils.mjs +6 -2
- package/dist/graph/parser/parser.mjs +30 -31
- package/dist/graph/parser/schema/types.template.mts +13 -11
- package/dist/preload.mjs +19 -2
- package/dist/ui/load.mjs +2 -2
- package/package.json +1 -1
package/dist/cli/entrypoint.mjs
CHANGED
package/dist/cli/spawn.mjs
CHANGED
|
@@ -21,6 +21,8 @@ For production use, please use LangGraph Cloud.
|
|
|
21
21
|
fileURLToPath(new URL("../../cli.mjs", import.meta.resolve("tsx/esm/api"))),
|
|
22
22
|
"watch",
|
|
23
23
|
"--clear-screen=false",
|
|
24
|
+
"--import",
|
|
25
|
+
new URL(import.meta.resolve("../preload.mjs")).toString(),
|
|
24
26
|
fileURLToPath(new URL(import.meta.resolve("./entrypoint.mjs"))),
|
|
25
27
|
options.pid.toString(),
|
|
26
28
|
JSON.stringify({
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
// This hook is to ensure that @langchain/langgraph package
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// This module hook is used to ensure that @langchain/langgraph package
|
|
2
|
+
// is imported from a consistent location.
|
|
3
|
+
// Accepts `{ parentURL: string }` as argument when registering the hook.
|
|
4
4
|
const OVERRIDE_RESOLVE = [
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// Override `@langchain/langgraph` or `@langchain/langgraph/prebuilt`,
|
|
6
|
+
// but not `@langchain/langgraph-sdk`
|
|
7
|
+
new RegExp(`^@langchain\/langgraph(\/.+)?$`),
|
|
8
|
+
new RegExp(`^@langchain\/langgraph-checkpoint(\/.+)?$`),
|
|
7
9
|
];
|
|
10
|
+
let parentURL;
|
|
11
|
+
export async function initialize(args) {
|
|
12
|
+
parentURL = args.parentURL;
|
|
13
|
+
}
|
|
8
14
|
export async function resolve(specifier, context, nextResolve) {
|
|
9
|
-
if (OVERRIDE_RESOLVE.
|
|
10
|
-
|
|
11
|
-
return await nextResolve(specifier, {
|
|
12
|
-
...context,
|
|
13
|
-
parentURL,
|
|
14
|
-
});
|
|
15
|
+
if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
|
|
16
|
+
return await nextResolve(specifier, { ...context, parentURL });
|
|
15
17
|
}
|
|
16
18
|
return nextResolve(specifier, context);
|
|
17
19
|
}
|
|
@@ -30,7 +30,7 @@ export async function resolveGraph(spec, options) {
|
|
|
30
30
|
})();
|
|
31
31
|
return { sourceFile, exportSymbol, resolved };
|
|
32
32
|
}
|
|
33
|
-
export async function runGraphSchemaWorker(spec) {
|
|
33
|
+
export async function runGraphSchemaWorker(spec, options) {
|
|
34
34
|
let SCHEMA_RESOLVE_TIMEOUT_MS = 30_000;
|
|
35
35
|
try {
|
|
36
36
|
const envTimeout = Number.parseInt(process.env.LANGGRAPH_SCHEMA_RESOLVE_TIMEOUT_MS ?? "0", 10);
|
|
@@ -41,8 +41,12 @@ export async function runGraphSchemaWorker(spec) {
|
|
|
41
41
|
catch {
|
|
42
42
|
// ignore
|
|
43
43
|
}
|
|
44
|
+
if (options?.mainThread) {
|
|
45
|
+
const { SubgraphExtractor } = await import("./parser/parser.mjs");
|
|
46
|
+
return SubgraphExtractor.extractSchemas(spec.sourceFile, spec.exportSymbol, { strict: false });
|
|
47
|
+
}
|
|
44
48
|
return await new Promise((resolve, reject) => {
|
|
45
|
-
const worker = new Worker(fileURLToPath(new URL("./parser/parser.worker.mjs", import.meta.url)));
|
|
49
|
+
const worker = new Worker(fileURLToPath(new URL("./parser/parser.worker.mjs", import.meta.url)), { argv: process.argv.slice(-1) });
|
|
46
50
|
// Set a timeout to reject if the worker takes too long
|
|
47
51
|
const timeoutId = setTimeout(() => {
|
|
48
52
|
worker.terminate();
|
|
@@ -5,6 +5,12 @@ import dedent from "dedent";
|
|
|
5
5
|
import { buildGenerator } from "./schema/types.mjs";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
8
|
+
const OVERRIDE_RESOLVE = [
|
|
9
|
+
// Override `@langchain/langgraph` or `@langchain/langgraph/prebuilt`,
|
|
10
|
+
// but not `@langchain/langgraph-sdk`
|
|
11
|
+
new RegExp(`^@langchain\/langgraph(\/.+)?$`),
|
|
12
|
+
new RegExp(`^@langchain\/langgraph-checkpoint(\/.+)?$`),
|
|
13
|
+
];
|
|
8
14
|
const compilerOptions = {
|
|
9
15
|
noEmit: true,
|
|
10
16
|
strict: true,
|
|
@@ -227,12 +233,16 @@ export class SubgraphExtractor {
|
|
|
227
233
|
// This API is not well made for Windows, ensure that the paths are UNIX slashes
|
|
228
234
|
const fsMap = new Map();
|
|
229
235
|
const system = vfs.createFSBackedSystem(fsMap, dirname, ts);
|
|
236
|
+
// TODO: investigate if we should create a PR in @typescript/vfs
|
|
237
|
+
const oldReadFile = system.readFile.bind(system);
|
|
238
|
+
system.readFile = (fileName) => oldReadFile(fileName) ?? "// Non-existent file";
|
|
230
239
|
const vfsPath = (inputPath) => {
|
|
231
240
|
if (process.platform === "win32")
|
|
232
241
|
return inputPath.replace(/\\/g, "/");
|
|
233
242
|
return inputPath;
|
|
234
243
|
};
|
|
235
|
-
const
|
|
244
|
+
const vfsHost = vfs.createVirtualCompilerHost(system, compilerOptions, ts);
|
|
245
|
+
const host = vfsHost.compilerHost;
|
|
236
246
|
const targetPath = typeof target === "string"
|
|
237
247
|
? target
|
|
238
248
|
: path.resolve(dirname, "./__langgraph__target.mts");
|
|
@@ -243,38 +253,27 @@ export class SubgraphExtractor {
|
|
|
243
253
|
fsMap.set(vfsPath(path.resolve(dirname, name)), contents);
|
|
244
254
|
}
|
|
245
255
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
// resolvedModules.push(
|
|
264
|
-
// ts.resolveModuleName(
|
|
265
|
-
// moduleName,
|
|
266
|
-
// target,
|
|
267
|
-
// compilerOptions,
|
|
268
|
-
// host.compilerHost
|
|
269
|
-
// ).resolvedModule
|
|
270
|
-
// );
|
|
271
|
-
// }
|
|
272
|
-
// return resolvedModules;
|
|
273
|
-
// };
|
|
256
|
+
const moduleCache = ts.createModuleResolutionCache(dirname, (x) => x);
|
|
257
|
+
host.resolveModuleNameLiterals = (entries, containingFile, redirectedReference, options) => entries.flatMap((entry) => {
|
|
258
|
+
const specifier = entry.text;
|
|
259
|
+
// Force module resolution to use @langchain/langgraph from the local project
|
|
260
|
+
// rather than from API/CLI.
|
|
261
|
+
let targetFile = containingFile;
|
|
262
|
+
if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
|
|
263
|
+
// check if we're not already importing from node_modules
|
|
264
|
+
if (!containingFile.split(path.sep).includes("node_modules")) {
|
|
265
|
+
// Doesn't matter if the file exists, only used to nudge `ts.resolveModuleName`
|
|
266
|
+
targetFile = path.resolve(dirname, "__langgraph__resolve.mts");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return [
|
|
270
|
+
ts.resolveModuleName(specifier, targetFile, options, host, moduleCache, redirectedReference),
|
|
271
|
+
];
|
|
272
|
+
});
|
|
274
273
|
const research = ts.createProgram({
|
|
275
274
|
rootNames: [inferTemplatePath, targetPath],
|
|
276
275
|
options: compilerOptions,
|
|
277
|
-
host
|
|
276
|
+
host,
|
|
278
277
|
});
|
|
279
278
|
const extractor = new SubgraphExtractor(research, research.getSourceFile(targetPath), research.getSourceFile(inferTemplatePath), options);
|
|
280
279
|
const { files, exports } = extractor.getAugmentedSourceFile(name);
|
|
@@ -284,7 +283,7 @@ export class SubgraphExtractor {
|
|
|
284
283
|
const extract = ts.createProgram({
|
|
285
284
|
rootNames: [path.resolve(dirname, "./__langraph__infer.mts")],
|
|
286
285
|
options: compilerOptions,
|
|
287
|
-
host
|
|
286
|
+
host,
|
|
288
287
|
});
|
|
289
288
|
const schemaGenerator = buildGenerator(extract);
|
|
290
289
|
const trySymbol = (schema, symbol) => {
|
|
@@ -27,17 +27,19 @@ type Defactorify<T> = T extends (...args: any[]) => infer R
|
|
|
27
27
|
: Awaited<T>;
|
|
28
28
|
|
|
29
29
|
// @ts-expect-error
|
|
30
|
-
type Inspect<T> =
|
|
31
|
-
?
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
?
|
|
36
|
-
: Wrap<
|
|
37
|
-
? BaseMessage
|
|
38
|
-
:
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
type Inspect<T, TDepth extends Array<0> = []> = TDepth extends [0, 0, 0]
|
|
31
|
+
? any
|
|
32
|
+
: T extends unknown
|
|
33
|
+
? {
|
|
34
|
+
[K in keyof T]: 0 extends 1 & T[K]
|
|
35
|
+
? T[K]
|
|
36
|
+
: Wrap<MatchBaseMessageArray<T[K]>> extends Wrap<BaseMessage[]>
|
|
37
|
+
? BaseMessage[]
|
|
38
|
+
: Wrap<MatchBaseMessage<T[K]>> extends Wrap<BaseMessage>
|
|
39
|
+
? BaseMessage
|
|
40
|
+
: Inspect<T[K], [0, ...TDepth]>;
|
|
41
|
+
}
|
|
42
|
+
: never;
|
|
41
43
|
|
|
42
44
|
type ReflectCompiled<T> = T extends { RunInput: infer S; RunOutput: infer U }
|
|
43
45
|
? { state: S; update: U }
|
package/dist/preload.mjs
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
import { register } from "node:module";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
// arguments passed to the entrypoint: [ppid, payload]
|
|
5
|
+
// we only care about the payload, which contains the server definition
|
|
6
|
+
const lastArg = process.argv.at(-1);
|
|
7
|
+
const options = JSON.parse(lastArg || "{}");
|
|
8
|
+
// find the first file, as `parentURL` needs to be a valid file URL
|
|
9
|
+
// if no graph found, just assume a dummy default file, which should
|
|
10
|
+
// be working fine as well.
|
|
11
|
+
const firstGraphFile = Object.values(options.graphs)
|
|
12
|
+
.flatMap((i) => i.split(":").at(0))
|
|
13
|
+
.at(0) || "index.mts";
|
|
14
|
+
// enforce API @langchain/langgraph resolution
|
|
15
|
+
register("./graph/load.hooks.mjs", import.meta.url, {
|
|
16
|
+
parentURL: "data:",
|
|
17
|
+
data: {
|
|
18
|
+
parentURL: pathToFileURL(join(options.cwd, firstGraphFile)).toString(),
|
|
19
|
+
},
|
|
20
|
+
});
|
package/dist/ui/load.mjs
CHANGED
|
@@ -26,11 +26,11 @@ api.post("/ui/:agent", zValidator("json", z.object({ name: z.string() })), async
|
|
|
26
26
|
const messageName = JSON.stringify(message.name);
|
|
27
27
|
const result = [];
|
|
28
28
|
for (const css of files.filter((i) => path.extname(i.basename) === ".css")) {
|
|
29
|
-
result.push(`<link rel="stylesheet" href="
|
|
29
|
+
result.push(`<link rel="stylesheet" href="//${host}/ui/${agent}/${css.basename}" />`);
|
|
30
30
|
}
|
|
31
31
|
const js = files.find((i) => path.extname(i.basename) === ".js");
|
|
32
32
|
if (js) {
|
|
33
|
-
result.push(`<script src="
|
|
33
|
+
result.push(`<script src="//${host}/ui/${agent}/${js.basename}" onload='__LGUI_${agent}.render(${messageName}, "{{shadowRootId}}")'></script>`);
|
|
34
34
|
}
|
|
35
35
|
return c.text(result.join("\n"), {
|
|
36
36
|
headers: { "Content-Type": "text/html" },
|