Merge pull request #23 from langchain-ai/dqbd/api-ts-prefer-resolve-from-project

fix(api): nudge typescript to use @langchain/langgraph from user project rather than API
This commit is contained in:
David Duong
2025-03-11 14:25:11 +01:00
committed by GitHub
2 changed files with 54 additions and 33 deletions
+13 -1
View File
@@ -79,7 +79,10 @@ export async function resolveGraph(
return { sourceFile, exportSymbol, resolved };
}
export async function runGraphSchemaWorker(spec: GraphSpec) {
export async function runGraphSchemaWorker(
spec: GraphSpec,
options?: { mainThread?: boolean },
) {
let SCHEMA_RESOLVE_TIMEOUT_MS = 30_000;
try {
const envTimeout = Number.parseInt(
@@ -93,6 +96,15 @@ export async function runGraphSchemaWorker(spec: GraphSpec) {
// 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)),
+41 -32
View File
@@ -7,6 +7,13 @@ import { fileURLToPath } from "node:url";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const OVERRIDE_RESOLVE = [
// Override `@langchain/langgraph` or `@langchain/langgraph/prebuilt`,
// but not `@langchain/langgraph-sdk`
new RegExp(`^@langchain\/langgraph(\/.+)?$`),
new RegExp(`^@langchain\/langgraph-checkpoint(\/.+)?$`),
];
const compilerOptions = {
noEmit: true,
strict: true,
@@ -362,7 +369,8 @@ export class SubgraphExtractor {
return inputPath;
};
const host = vfs.createVirtualCompilerHost(system, compilerOptions, ts);
const vfsHost = vfs.createVirtualCompilerHost(system, compilerOptions, ts);
const host = vfsHost.compilerHost;
const targetPath =
typeof target === "string"
@@ -381,42 +389,43 @@ export class SubgraphExtractor {
}
}
// TODO: this is in all instances broken, will need to address in a way
// that allows loading fs-backed modules from different vfs
// host.compilerHost.resolveModuleNames = (moduleNames, containingFile) => {
// const resolvedModules: (ts.ResolvedModule | undefined)[] = [];
// for (const moduleName of moduleNames) {
// let target = containingFile;
// const relative = path.relative(dirname, containingFile);
const moduleCache = ts.createModuleResolutionCache(dirname, (x) => x);
host.resolveModuleNameLiterals = (
entries,
containingFile,
redirectedReference,
options,
) =>
entries.flatMap((entry) => {
const specifier = entry.text;
// logger.debug(`${moduleName} ${containingFile}`);
// if (
// moduleName.startsWith("@langchain/langgraph") &&
// relative &&
// !relative.startsWith("..") &&
// !path.isAbsolute(relative)
// ) {
// target = path.resolve(__dirname, "../", relative);
// process.stderr.write(`${moduleName} ${relative} -> ${target}\n`);
// }
// Force module resolution to use @langchain/langgraph from the local project
// rather than from API/CLI.
let targetFile = containingFile;
if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
// check if we're not already importing from node_modules
if (!containingFile.split(path.sep).includes("node_modules")) {
// Doesn't matter if the file exists, only used to nudge `ts.resolveModuleName`
targetFile = path.resolve(dirname, "__langgraph__resolve.mts");
}
}
// resolvedModules.push(
// ts.resolveModuleName(
// moduleName,
// target,
// compilerOptions,
// host.compilerHost
// ).resolvedModule
// );
// }
// return resolvedModules;
// };
return [
ts.resolveModuleName(
specifier,
targetFile,
options,
host,
moduleCache,
redirectedReference,
),
];
});
const research = ts.createProgram({
rootNames: [inferTemplatePath, targetPath],
options: compilerOptions,
host: host.compilerHost,
host,
});
const extractor = new SubgraphExtractor(
@@ -434,7 +443,7 @@ export class SubgraphExtractor {
const extract = ts.createProgram({
rootNames: [path.resolve(dirname, "./__langraph__infer.mts")],
options: compilerOptions,
host: host.compilerHost,
host,
});
const schemaGenerator = buildGenerator(extract);