@langchain/langgraph-api 0.0.15 → 0.0.17

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.
@@ -38,6 +38,7 @@ For production use, please use LangGraph Cloud.
38
38
  env: {
39
39
  ...context.env,
40
40
  NODE_ENV: "development",
41
+ LANGGRAPH_API_URL: localUrl,
41
42
  },
42
43
  });
43
44
  }
@@ -8,12 +8,45 @@ 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
  }
14
15
  export async function resolve(specifier, context, nextResolve) {
16
+ // HACK: @tailwindcss/node internally uses an ESM loader cache, which does not play nicely with `tsx`.
17
+ // Node.js crashes with "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file".
18
+ // As it already is a valid URI, we can just short-circuit the resolution and avoid `tsx`.
19
+ if (specifier.includes("@tailwindcss/node/dist/esm-cache.loader") &&
20
+ specifier.startsWith("file://")) {
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
+ });
43
+ }
15
44
  if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
16
- return await nextResolve(specifier, { ...context, parentURL });
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
+ }
17
50
  }
18
51
  return nextResolve(specifier, context);
19
52
  }
package/dist/server.mjs CHANGED
@@ -65,10 +65,6 @@ export async function startServer(options) {
65
65
  logger.info(`Registering graphs from ${options.cwd}`);
66
66
  await registerFromEnv(options.graphs, { cwd: options.cwd });
67
67
  if (options.ui) {
68
- if (process.versions.node.startsWith("18")) {
69
- // Not supported due to weird interop issues with `@tailwindcss/postcss` and `tsx`
70
- throw new Error("Built-in UI is not supported in Node.js 18.x. Please upgrade to Node.js 20.16 or later.");
71
- }
72
68
  logger.info(`Loading UI`);
73
69
  const { api, registerGraphUi } = await import("./ui/load.mjs");
74
70
  app.route("/", api);
package/dist/stream.mjs CHANGED
@@ -2,7 +2,7 @@ import { getGraph } from "./graph/load.mjs";
2
2
  import { Client as LangSmithClient } from "langsmith";
3
3
  import { Command, Send, } from "@langchain/langgraph";
4
4
  import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
5
- import { BaseMessageChunk, isBaseMessage } from "@langchain/core/messages";
5
+ import { isBaseMessage } from "@langchain/core/messages";
6
6
  const getLangGraphCommand = (command) => {
7
7
  let goto = command.goto != null && !Array.isArray(command.goto)
8
8
  ? [command.goto]
@@ -95,6 +95,7 @@ export async function* streamState(run, attempt = 1, options) {
95
95
  langgraph_version: "0.2.35",
96
96
  langgraph_plan: "developer",
97
97
  langgraph_host: "self-hosted",
98
+ langgraph_api_url: process.env.LANGGRAPH_API_URL ?? undefined,
98
99
  };
99
100
  const events = graph.streamEvents(kwargs.command != null
100
101
  ? getLangGraphCommand(kwargs.command)
@@ -1,9 +1,15 @@
1
1
  import { type BuildOptions } from "esbuild";
2
- export declare function build(agentName: string, uiUserPath: string): Promise<{
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, uiUserPath: string, onResult: (result: {
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>>;
@@ -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(uiUserPath) {
8
- const projectDir = path.dirname(uiUserPath);
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$/ }, (args) => ({
13
- path: path.resolve(projectDir, "ui.entrypoint.tsx"),
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: projectDir,
25
+ resolveDir: paths.cwd,
18
26
  contents: [
19
- `import ui from "${uiUserPath}"`,
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, uiUserPath, onResult) {
57
+ function setup(agentName, args, onResult) {
50
58
  return {
51
59
  write: false,
52
- outdir: path.resolve(path.dirname(uiUserPath), "dist"),
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, uiUserPath) {
76
+ export async function build(agentName, args) {
73
77
  let results = [];
74
- await runBuild(setup(agentName, uiUserPath, (result) => (results = result)));
78
+ await runBuild(setup(agentName, args, (result) => (results = result)));
75
79
  return results;
76
80
  }
77
- export async function watch(agentName, uiUserPath, onResult) {
78
- const ctx = await runContext(setup(agentName, uiUserPath, onResult));
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, uiUserPath]) => {
10
- const userPath = path.resolve(options.cwd, uiUserPath);
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];
@@ -26,11 +25,11 @@ api.post("/ui/:agent", zValidator("json", z.object({ name: z.string() })), async
26
25
  const messageName = JSON.stringify(message.name);
27
26
  const result = [];
28
27
  for (const css of files.filter((i) => path.extname(i.basename) === ".css")) {
29
- result.push(`<link rel="stylesheet" href="//${host}/ui/${agent}/${css.basename}" />`);
28
+ result.push(`<link rel="stylesheet" href="http://${host}/ui/${agent}/${css.basename}" />`);
30
29
  }
31
30
  const js = files.find((i) => path.extname(i.basename) === ".js");
32
31
  if (js) {
33
- result.push(`<script src="//${host}/ui/${agent}/${js.basename}" onload='__LGUI_${agent}.render(${messageName}, "{{shadowRootId}}")'></script>`);
32
+ result.push(`<script src="http://${host}/ui/${agent}/${js.basename}" onload='__LGUI_${agent}.render(${messageName}, "{{shadowRootId}}")'></script>`);
34
33
  }
35
34
  return c.text(result.join("\n"), {
36
35
  headers: { "Content-Type": "text/html" },
@@ -1,6 +1,5 @@
1
1
  import { serialiseAsDict } from "./serde.mjs";
2
2
  import { stream } from "hono/streaming";
3
- import { StreamingApi } from "hono/utils/stream";
4
3
  export function jsonExtra(c, object) {
5
4
  return new Response(serialiseAsDict(object), {
6
5
  ...c.res,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-api",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^18.19.0 || >=20.16.0"