mirror of
https://github.com/langchain-ai/langgraphjs-api.git
synced 2026-07-18 18:34:27 -04:00
Simplify build process at the expense of emitting all declaration files
This commit is contained in:
@@ -12,17 +12,21 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/cli/spawn.d.ts",
|
||||
"types": "./dist/cli/spawn.d.mts",
|
||||
"default": "./dist/cli/spawn.mjs"
|
||||
},
|
||||
"./auth": {
|
||||
"types": "./dist/auth/index.d.ts",
|
||||
"types": "./dist/auth/index.d.mts",
|
||||
"default": "./dist/auth/index.mjs"
|
||||
},
|
||||
"./semver": {
|
||||
"types": "./dist/semver/index.d.ts",
|
||||
"types": "./dist/semver/index.d.mts",
|
||||
"default": "./dist/semver/index.mjs"
|
||||
},
|
||||
"./schema": {
|
||||
"types": "./dist/graph/parser/index.d.mts",
|
||||
"default": "./dist/graph/parser/index.mjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -4,12 +4,6 @@ import { $ } from "./utils.mjs";
|
||||
await $`rm -rf dist`;
|
||||
await $`pnpm tsc --outDir dist`;
|
||||
|
||||
await Promise.all([
|
||||
$`pnpm tsc --module nodenext --outDir dist/src/cli -d src/cli/spawn.mts`,
|
||||
$`pnpm tsc --module nodenext --outDir dist/src/auth -d src/auth/index.mts`,
|
||||
$`pnpm tsc --module nodenext --outDir dist/src/semver -d src/semver/index.mts`,
|
||||
]);
|
||||
|
||||
await $`cp src/graph/parser/schema/types.template.mts dist/src/graph/parser/schema`;
|
||||
await $`rm -rf dist/src/graph/parser/schema/types.template.mjs`;
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ import { z } from "zod";
|
||||
import {
|
||||
getAssistantId,
|
||||
getGraph,
|
||||
getGraphSchema,
|
||||
getRuntimeGraphSchema,
|
||||
getCachedStaticGraphSchema,
|
||||
} from "../graph/load.mjs";
|
||||
import { getRuntimeGraphSchema } from "../graph/parser/index.mjs";
|
||||
|
||||
import { Assistants } from "../storage/ops.mjs";
|
||||
import * as schemas from "../schemas.mjs";
|
||||
@@ -146,7 +146,7 @@ api.get(
|
||||
const runtimeSchema = await getRuntimeGraphSchema(graph);
|
||||
if (runtimeSchema) return runtimeSchema;
|
||||
|
||||
const graphSchema = await getGraphSchema(assistant.graph_id);
|
||||
const graphSchema = await getCachedStaticGraphSchema(assistant.graph_id);
|
||||
const rootGraphId = Object.keys(graphSchema).find(
|
||||
(i) => !i.includes("|"),
|
||||
);
|
||||
@@ -191,13 +191,16 @@ api.get(
|
||||
: // @ts-expect-error older versions of langgraph don't have getSubgraphsAsync
|
||||
graph.getSubgraphs.bind(graph);
|
||||
|
||||
let graphSchemaPromise: ReturnType<typeof getGraphSchema> | undefined;
|
||||
let graphSchemaPromise:
|
||||
| ReturnType<typeof getCachedStaticGraphSchema>
|
||||
| undefined;
|
||||
|
||||
for await (const [ns, subgraph] of subgraphsGenerator(namespace, recurse)) {
|
||||
const schema = await (async () => {
|
||||
const runtimeSchema = await getRuntimeGraphSchema(subgraph);
|
||||
if (runtimeSchema) return runtimeSchema;
|
||||
|
||||
graphSchemaPromise ??= getGraphSchema(assistant.graph_id);
|
||||
graphSchemaPromise ??= getCachedStaticGraphSchema(assistant.graph_id);
|
||||
const graphSchema = await graphSchemaPromise;
|
||||
|
||||
const rootGraphId = Object.keys(graphSchema).find(
|
||||
|
||||
@@ -2,22 +2,16 @@ import { z } from "zod";
|
||||
|
||||
import * as uuid from "uuid";
|
||||
import { Assistants } from "../storage/ops.mjs";
|
||||
import type { JSONSchema7 } from "json-schema";
|
||||
import type {
|
||||
Pregel,
|
||||
BaseCheckpointSaver,
|
||||
BaseStore,
|
||||
CompiledGraph,
|
||||
LangGraphRunnableConfig,
|
||||
} from "@langchain/langgraph";
|
||||
import { HTTPException } from "hono/http-exception";
|
||||
import {
|
||||
type CompiledGraphFactory,
|
||||
type GraphSchema,
|
||||
type GraphSpec,
|
||||
resolveGraph,
|
||||
runGraphSchemaWorker,
|
||||
} from "./load.utils.mjs";
|
||||
import { type CompiledGraphFactory, resolveGraph } from "./load.utils.mjs";
|
||||
import type { GraphSchema, GraphSpec } from "./parser/index.mjs";
|
||||
import { getStaticGraphSchema } from "./parser/index.mjs";
|
||||
import { checkpointer } from "../storage/checkpoint.mjs";
|
||||
import { store } from "../storage/store.mjs";
|
||||
import { logger } from "../logging.mjs";
|
||||
@@ -107,42 +101,30 @@ export async function getGraph(
|
||||
return compiled;
|
||||
}
|
||||
|
||||
export async function getRuntimeGraphSchema(
|
||||
graph: Pregel<any, any, any, any, any>,
|
||||
): Promise<GraphSchema | undefined> {
|
||||
try {
|
||||
const {
|
||||
getInputTypeSchema,
|
||||
getOutputTypeSchema,
|
||||
getStateTypeSchema,
|
||||
getConfigTypeSchema,
|
||||
} = await import("@langchain/langgraph/zod/schema");
|
||||
|
||||
const result = {
|
||||
input: getInputTypeSchema(graph) as JSONSchema7 | undefined,
|
||||
output: getOutputTypeSchema(graph) as JSONSchema7 | undefined,
|
||||
state: getStateTypeSchema(graph) as JSONSchema7 | undefined,
|
||||
config: getConfigTypeSchema(graph) as JSONSchema7 | undefined,
|
||||
};
|
||||
|
||||
if (Object.values(result).every((i) => i == null)) return undefined;
|
||||
return result;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function getGraphSchema(graphId: string) {
|
||||
export async function getCachedStaticGraphSchema(graphId: string) {
|
||||
if (!GRAPH_SPEC[graphId])
|
||||
throw new HTTPException(404, {
|
||||
message: `Spec for "${graphId}" not found`,
|
||||
});
|
||||
|
||||
if (!GRAPH_SCHEMA[graphId] || true) {
|
||||
if (!GRAPH_SCHEMA[graphId]) {
|
||||
let timeoutMs = 30_000;
|
||||
try {
|
||||
GRAPH_SCHEMA[graphId] = await runGraphSchemaWorker(GRAPH_SPEC[graphId]);
|
||||
const envTimeout = Number.parseInt(
|
||||
process.env.LANGGRAPH_SCHEMA_RESOLVE_TIMEOUT_MS ?? "0",
|
||||
10,
|
||||
);
|
||||
if (!Number.isNaN(envTimeout) && envTimeout > 0) {
|
||||
timeoutMs = envTimeout;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
GRAPH_SCHEMA[graphId] = await getStaticGraphSchema(GRAPH_SPEC[graphId], {
|
||||
timeoutMs,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to extract schema for "${graphId}"`, {
|
||||
cause: error,
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
import { Worker } from "node:worker_threads";
|
||||
import * as fs from "node:fs/promises";
|
||||
import type { CompiledGraph, Graph } from "@langchain/langgraph";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import * as uuid from "uuid";
|
||||
import type { JSONSchema7 } from "json-schema";
|
||||
import * as path from "node:path";
|
||||
import * as fs from "node:fs/promises";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
export const GRAPHS: Record<string, CompiledGraph<string>> = {};
|
||||
export const NAMESPACE_GRAPH = uuid.parse(
|
||||
"6ba7b821-9dad-11d1-80b4-00c04fd430c8",
|
||||
);
|
||||
|
||||
export interface GraphSchema {
|
||||
state: JSONSchema7 | undefined;
|
||||
input: JSONSchema7 | undefined;
|
||||
output: JSONSchema7 | undefined;
|
||||
config: JSONSchema7 | undefined;
|
||||
}
|
||||
|
||||
export interface GraphSpec {
|
||||
sourceFile: string;
|
||||
exportSymbol: string;
|
||||
}
|
||||
|
||||
export type CompiledGraphFactory<T extends string> = (config: {
|
||||
configurable?: Record<string, unknown>;
|
||||
}) => Promise<CompiledGraph<T>>;
|
||||
@@ -51,7 +37,7 @@ export async function resolveGraph(
|
||||
// validate file exists
|
||||
await fs.stat(sourceFile);
|
||||
if (options?.onlyFilePresence) {
|
||||
return { sourceFile: userFile, exportSymbol, resolved: undefined };
|
||||
return { sourceFile, exportSymbol, resolved: undefined };
|
||||
}
|
||||
|
||||
type GraphLike = CompiledGraph<string> | Graph<string>;
|
||||
@@ -95,52 +81,3 @@ export async function resolveGraph(
|
||||
|
||||
return { sourceFile, exportSymbol, resolved };
|
||||
}
|
||||
|
||||
export async function runGraphSchemaWorker(
|
||||
spec: GraphSpec,
|
||||
options?: { mainThread?: boolean },
|
||||
) {
|
||||
let SCHEMA_RESOLVE_TIMEOUT_MS = 30_000;
|
||||
try {
|
||||
const envTimeout = Number.parseInt(
|
||||
process.env.LANGGRAPH_SCHEMA_RESOLVE_TIMEOUT_MS ?? "0",
|
||||
10,
|
||||
);
|
||||
if (!Number.isNaN(envTimeout) && envTimeout > 0) {
|
||||
SCHEMA_RESOLVE_TIMEOUT_MS = envTimeout;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (options?.mainThread) {
|
||||
const { SubgraphExtractor } = await import("./parser/parser.mjs");
|
||||
return SubgraphExtractor.extractSchemas(
|
||||
spec.sourceFile,
|
||||
spec.exportSymbol,
|
||||
{ strict: false },
|
||||
);
|
||||
}
|
||||
|
||||
return await new Promise<Record<string, GraphSchema>>((resolve, reject) => {
|
||||
const worker = new Worker(
|
||||
fileURLToPath(new URL("./parser/parser.worker.mjs", import.meta.url)),
|
||||
{ argv: process.argv.slice(-1) },
|
||||
);
|
||||
|
||||
// Set a timeout to reject if the worker takes too long
|
||||
const timeoutId = setTimeout(() => {
|
||||
worker.terminate();
|
||||
reject(new Error("Schema extract worker timed out"));
|
||||
}, SCHEMA_RESOLVE_TIMEOUT_MS);
|
||||
|
||||
worker.on("message", (result) => {
|
||||
worker.terminate();
|
||||
clearTimeout(timeoutId);
|
||||
resolve(result);
|
||||
});
|
||||
|
||||
worker.on("error", reject);
|
||||
worker.postMessage(spec);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { Worker } from "node:worker_threads";
|
||||
import type { JSONSchema7 } from "json-schema";
|
||||
import type { Pregel } from "@langchain/langgraph";
|
||||
|
||||
export interface GraphSchema {
|
||||
state: JSONSchema7 | undefined;
|
||||
input: JSONSchema7 | undefined;
|
||||
output: JSONSchema7 | undefined;
|
||||
config: JSONSchema7 | undefined;
|
||||
}
|
||||
|
||||
export interface GraphSpec {
|
||||
sourceFile: string;
|
||||
exportSymbol: string;
|
||||
}
|
||||
|
||||
export async function getStaticGraphSchema(
|
||||
spec: GraphSpec,
|
||||
options?: { mainThread?: boolean; timeoutMs?: number },
|
||||
): Promise<Record<string, GraphSchema>> {
|
||||
if (options?.mainThread) {
|
||||
const { SubgraphExtractor } = await import("./parser.mjs");
|
||||
return SubgraphExtractor.extractSchemas(
|
||||
spec.sourceFile,
|
||||
spec.exportSymbol,
|
||||
{ strict: false },
|
||||
);
|
||||
}
|
||||
|
||||
return await new Promise<Record<string, GraphSchema>>((resolve, reject) => {
|
||||
const worker = new Worker(
|
||||
fileURLToPath(new URL("./parser/parser.worker.mjs", import.meta.url)),
|
||||
{ argv: process.argv.slice(-1) },
|
||||
);
|
||||
|
||||
// Set a timeout to reject if the worker takes too long
|
||||
const timeoutId = setTimeout(() => {
|
||||
worker.terminate();
|
||||
reject(new Error("Schema extract worker timed out"));
|
||||
}, options?.timeoutMs ?? 30000);
|
||||
|
||||
worker.on("message", (result) => {
|
||||
worker.terminate();
|
||||
clearTimeout(timeoutId);
|
||||
resolve(result);
|
||||
});
|
||||
|
||||
worker.on("error", reject);
|
||||
worker.postMessage(spec);
|
||||
});
|
||||
}
|
||||
|
||||
export async function getRuntimeGraphSchema(
|
||||
graph: Pregel<any, any, any, any, any>,
|
||||
): Promise<GraphSchema | undefined> {
|
||||
try {
|
||||
const {
|
||||
getInputTypeSchema,
|
||||
getOutputTypeSchema,
|
||||
getUpdateTypeSchema,
|
||||
getConfigTypeSchema,
|
||||
} = await import("@langchain/langgraph/zod/schema");
|
||||
|
||||
const result = {
|
||||
state: getUpdateTypeSchema(graph),
|
||||
input: getInputTypeSchema(graph),
|
||||
output: getOutputTypeSchema(graph),
|
||||
config: getConfigTypeSchema(graph),
|
||||
} as GraphSchema;
|
||||
|
||||
if (Object.values(result).every((i) => i == null)) return undefined;
|
||||
return result;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
@@ -4,6 +4,14 @@ import * as path from "node:path";
|
||||
import dedent from "dedent";
|
||||
import { buildGenerator } from "./schema/types.mjs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import type { JSONSchema7 } from "json-schema";
|
||||
|
||||
interface GraphSchema {
|
||||
state: JSONSchema7 | undefined;
|
||||
input: JSONSchema7 | undefined;
|
||||
output: JSONSchema7 | undefined;
|
||||
config: JSONSchema7 | undefined;
|
||||
}
|
||||
|
||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||
|
||||
@@ -249,7 +257,7 @@ export class SubgraphExtractor {
|
||||
),
|
||||
].join("\n\n");
|
||||
|
||||
const inferFilePath = "__langraph__infer.mts";
|
||||
const inferFilePath = "__langgraph__infer.mts";
|
||||
const inferContents = [
|
||||
...typeExports.map(
|
||||
({ typeName }) =>
|
||||
@@ -351,7 +359,7 @@ export class SubgraphExtractor {
|
||||
},
|
||||
name: string,
|
||||
options?: { strict?: boolean },
|
||||
) {
|
||||
): Record<string, GraphSchema> {
|
||||
const dirname =
|
||||
typeof target === "string" ? path.dirname(target) : __dirname;
|
||||
|
||||
@@ -441,7 +449,7 @@ export class SubgraphExtractor {
|
||||
}
|
||||
|
||||
const extract = ts.createProgram({
|
||||
rootNames: [path.resolve(dirname, "./__langraph__infer.mts")],
|
||||
rootNames: [path.resolve(dirname, "./__langgraph__infer.mts")],
|
||||
options: compilerOptions,
|
||||
host,
|
||||
});
|
||||
@@ -463,9 +471,9 @@ export class SubgraphExtractor {
|
||||
exports.map(({ typeName, graphName }) => [
|
||||
graphName,
|
||||
{
|
||||
state: trySymbol(schemaGenerator, `${typeName}__update`),
|
||||
input: trySymbol(schemaGenerator, `${typeName}__input`),
|
||||
output: trySymbol(schemaGenerator, `${typeName}__output`),
|
||||
state: trySymbol(schemaGenerator, `${typeName}__update`),
|
||||
config: trySymbol(schemaGenerator, `${typeName}__config`),
|
||||
},
|
||||
]),
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"declaration": true,
|
||||
"module": "NodeNext",
|
||||
"allowJs": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
Reference in New Issue
Block a user