langgraph-api 0.1.16__tar.gz → 0.1.18__tar.gz

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.

Potentially problematic release.


This version of langgraph-api might be problematic. Click here for more details.

Files changed (108) hide show
  1. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/PKG-INFO +8 -8
  2. langgraph_api-0.1.18/langgraph_api/__init__.py +1 -0
  3. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/ui.py +2 -2
  4. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/config.py +6 -0
  5. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/graph.py +1 -1
  6. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/build.mts +28 -5
  7. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/package.json +2 -2
  8. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/remote.py +16 -3
  9. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/graph.mts +0 -3
  10. langgraph_api-0.1.18/langgraph_api/js/src/load.hooks.mjs +61 -0
  11. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/parser/parser.mts +77 -51
  12. langgraph_api-0.1.18/langgraph_api/js/src/preload.mjs +21 -0
  13. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/api.test.mts +6 -3
  14. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/package.json +1 -1
  15. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/yarn.lock +9 -9
  16. langgraph_api-0.1.18/langgraph_api/js/tsconfig.json +15 -0
  17. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/yarn.lock +15 -9
  18. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/models/run.py +78 -22
  19. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/thread_ttl.py +1 -1
  20. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/pyproject.toml +13 -13
  21. langgraph_api-0.1.16/langgraph_api/__init__.py +0 -1
  22. langgraph_api-0.1.16/langgraph_api/js/src/hooks.mjs +0 -17
  23. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/LICENSE +0 -0
  24. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/README.md +0 -0
  25. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/__init__.py +0 -0
  26. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/assistants.py +0 -0
  27. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/mcp.py +0 -0
  28. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/meta.py +0 -0
  29. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/openapi.py +0 -0
  30. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/runs.py +0 -0
  31. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/store.py +0 -0
  32. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/api/threads.py +0 -0
  33. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/asyncio.py +0 -0
  34. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/__init__.py +0 -0
  35. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/custom.py +0 -0
  36. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/langsmith/__init__.py +0 -0
  37. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/langsmith/backend.py +0 -0
  38. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/langsmith/client.py +0 -0
  39. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/middleware.py +0 -0
  40. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/noop.py +0 -0
  41. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/auth/studio_user.py +0 -0
  42. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/cli.py +0 -0
  43. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/command.py +0 -0
  44. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/cron_scheduler.py +0 -0
  45. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/errors.py +0 -0
  46. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/http.py +0 -0
  47. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/.gitignore +0 -0
  48. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/.prettierrc +0 -0
  49. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/__init__.py +0 -0
  50. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/base.py +0 -0
  51. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/client.http.mts +0 -0
  52. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/client.mts +0 -0
  53. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/errors.py +0 -0
  54. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/global.d.ts +0 -0
  55. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/schema.py +0 -0
  56. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/parser/parser.worker.mjs +0 -0
  57. {langgraph_api-0.1.16/langgraph_api/js/src → langgraph_api-0.1.18/langgraph_api/js/src/parser}/schema/types.mts +0 -0
  58. {langgraph_api-0.1.16/langgraph_api/js/src → langgraph_api-0.1.18/langgraph_api/js/src/parser}/schema/types.template.mts +0 -0
  59. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/utils/files.mts +0 -0
  60. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/utils/importMap.mts +0 -0
  61. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  62. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/src/utils/serde.mts +0 -0
  63. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/sse.py +0 -0
  64. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/auth.test.mts +0 -0
  65. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/compose-postgres.auth.yml +0 -0
  66. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/compose-postgres.yml +0 -0
  67. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/.gitignore +0 -0
  68. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/agent.css +0 -0
  69. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/agent.mts +0 -0
  70. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/agent.ui.tsx +0 -0
  71. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/agent_simple.mts +0 -0
  72. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/auth.mts +0 -0
  73. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/command.mts +0 -0
  74. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/delay.mts +0 -0
  75. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/dynamic.mts +0 -0
  76. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/error.mts +0 -0
  77. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/http.mts +0 -0
  78. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/langgraph.json +0 -0
  79. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/nested.mts +0 -0
  80. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/graphs/weather.mts +0 -0
  81. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/parser.test.mts +0 -0
  82. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/tests/utils.mts +0 -0
  83. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/js/ui.py +0 -0
  84. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/logging.py +0 -0
  85. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/metadata.py +0 -0
  86. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/middleware/__init__.py +0 -0
  87. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/middleware/http_logger.py +0 -0
  88. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/middleware/private_network.py +0 -0
  89. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/models/__init__.py +0 -0
  90. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/patch.py +0 -0
  91. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/queue_entrypoint.py +0 -0
  92. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/route.py +0 -0
  93. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/schema.py +0 -0
  94. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/serde.py +0 -0
  95. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/server.py +0 -0
  96. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/sse.py +0 -0
  97. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/state.py +0 -0
  98. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/stream.py +0 -0
  99. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/tunneling/cloudflare.py +0 -0
  100. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/utils.py +0 -0
  101. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/validation.py +0 -0
  102. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/webhook.py +0 -0
  103. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_api/worker.py +0 -0
  104. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_license/__init__.py +0 -0
  105. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_license/validation.py +0 -0
  106. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/langgraph_runtime/__init__.py +0 -0
  107. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/logging.json +0 -0
  108. {langgraph_api-0.1.16 → langgraph_api-0.1.18}/openapi.json +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langgraph-api
3
- Version: 0.1.16
3
+ Version: 0.1.18
4
4
  Summary:
5
5
  License: Elastic-2.0
6
6
  Author: Nuno Campos
7
7
  Author-email: nuno@langchain.dev
8
- Requires-Python: >=3.11.0,<4.0
8
+ Requires-Python: >=3.11
9
9
  Classifier: License :: Other/Proprietary License
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.11
@@ -15,12 +15,12 @@ Requires-Dist: cloudpickle (>=3.0.0,<4.0.0)
15
15
  Requires-Dist: cryptography (>=42.0.0,<45.0)
16
16
  Requires-Dist: httpx (>=0.25.0)
17
17
  Requires-Dist: jsonschema-rs (>=0.20.0,<0.30)
18
- Requires-Dist: langchain-core (>=0.2.38,<0.4.0)
19
- Requires-Dist: langgraph (>=0.2.56,<0.4.0)
20
- Requires-Dist: langgraph-checkpoint (>=2.0.23,<3.0)
21
- Requires-Dist: langgraph-runtime-inmem (>=0.0.6)
22
- Requires-Dist: langgraph-sdk (>=0.1.63,<0.2.0)
23
- Requires-Dist: langsmith (>=0.1.63,<0.4.0)
18
+ Requires-Dist: langchain-core (>=0.2.38) ; python_version < "4.0"
19
+ Requires-Dist: langgraph (>=0.2.56) ; python_version < "4.0"
20
+ Requires-Dist: langgraph-checkpoint (>=2.0.23) ; python_version < "4.0"
21
+ Requires-Dist: langgraph-runtime-inmem (>=0.0.7)
22
+ Requires-Dist: langgraph-sdk (>=0.1.63,<0.2.0) ; python_version < "4.0"
23
+ Requires-Dist: langsmith (>=0.1.63)
24
24
  Requires-Dist: orjson (>=3.9.7)
25
25
  Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
26
26
  Requires-Dist: sse-starlette (>=2.1.0,<2.2.0)
@@ -0,0 +1 @@
1
+ __version__ = "0.1.18"
@@ -60,8 +60,8 @@ async def handle_ui(request: ApiRequest) -> Response:
60
60
  elif ext == ".js":
61
61
  result.append(
62
62
  f'<script src="//{host}/ui/{graph_id}/{basename}" '
63
- f'onload=\'__LGUI_{graph_id}.render({json.dumps(message["name"])}, "{{{{shadowRootId}}}}")\'>'
64
- '</script>'
63
+ f"onload='__LGUI_{graph_id}.render({json.dumps(message['name'])}, \"{{{{shadowRootId}}}}\")'>"
64
+ "</script>"
65
65
  )
66
66
 
67
67
  return Response(content="\n".join(result), headers={"Content-Type": "text/html"})
@@ -18,6 +18,11 @@ class CorsConfig(TypedDict, total=False):
18
18
  max_age: int
19
19
 
20
20
 
21
+ class ConfigurableHeaders(TypedDict):
22
+ includes: list[str] | None
23
+ excludes: list[str] | None
24
+
25
+
21
26
  class HttpConfig(TypedDict, total=False):
22
27
  app: str
23
28
  """Import path for a custom Starlette/FastAPI app to mount"""
@@ -39,6 +44,7 @@ class HttpConfig(TypedDict, total=False):
39
44
  """Disable /mcp routes"""
40
45
  mount_prefix: str
41
46
  """Prefix for mounted routes. E.g., "/my-deployment/api"."""
47
+ configurable_headers: ConfigurableHeaders | None
42
48
 
43
49
 
44
50
  class ThreadTTLConfig(TypedDict, total=False):
@@ -487,7 +487,7 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
487
487
  return graph
488
488
 
489
489
 
490
- @functools.lru_cache
490
+ @functools.lru_cache(maxsize=1)
491
491
  def _get_init_embeddings() -> Callable[[str, ...], "Embeddings"] | None:
492
492
  try:
493
493
  from langchain.embeddings import init_embeddings
@@ -1,26 +1,49 @@
1
1
  /// <reference types="./global.d.ts" />
2
+ import "./src/preload.mjs";
2
3
 
3
4
  import { z } from "zod";
4
5
  import * as fs from "node:fs/promises";
5
6
  import * as path from "node:path";
6
7
  import {
7
- GraphSchema,
8
+ type GraphSchema,
8
9
  resolveGraph,
9
10
  runGraphSchemaWorker,
10
11
  } from "./src/graph.mts";
11
12
  import { build } from "@langchain/langgraph-ui";
13
+ import { checkLangGraphSemver } from "@langchain/langgraph-api/semver";
12
14
  import { filterValidExportPath } from "./src/utils/files.mts";
13
15
 
14
16
  const __dirname = new URL(".", import.meta.url).pathname;
15
17
 
16
18
  async function main() {
17
19
  const specs = Object.entries(
18
- z.record(z.string()).parse(JSON.parse(process.env.LANGSERVE_GRAPHS))
20
+ z.record(z.string()).parse(JSON.parse(process.env.LANGSERVE_GRAPHS)),
19
21
  ).filter(([_, spec]) => filterValidExportPath(spec));
20
22
 
21
23
  const GRAPH_SCHEMAS: Record<string, Record<string, GraphSchema> | false> = {};
22
- let failed = false;
23
24
 
25
+ const semver = await checkLangGraphSemver();
26
+ const invalidPackages = semver.filter(
27
+ (s) => !s.satisfies && s.version !== "0.0.0",
28
+ );
29
+ if (invalidPackages.length > 0) {
30
+ console.error(
31
+ `Some LangGraph.js dependencies required by the LangGraph API server are not up to date. \n` +
32
+ `Please make sure to upgrade them to the required version:\n` +
33
+ invalidPackages
34
+ .map(
35
+ (i) =>
36
+ `- ${i.name}@${i.version} is not up to date. Required: ${i.required}`,
37
+ )
38
+ .join("\n") +
39
+ "\n" +
40
+ "Visit https://langchain-ai.github.io/langgraphjs/cloud/deployment/setup_javascript/ for more information.",
41
+ );
42
+
43
+ process.exit(1);
44
+ }
45
+
46
+ let failed = false;
24
47
  try {
25
48
  await Promise.all(
26
49
  specs.map(async ([graphId, rawSpec]) => {
@@ -38,13 +61,13 @@ async function main() {
38
61
  console.error(`[${graphId}]: Error extracting schema: ${error}`);
39
62
  GRAPH_SCHEMAS[graphId] = false;
40
63
  }
41
- })
64
+ }),
42
65
  );
43
66
 
44
67
  await fs.writeFile(
45
68
  path.resolve(__dirname, "client.schemas.json"),
46
69
  JSON.stringify(GRAPH_SCHEMAS),
47
- { encoding: "utf-8" }
70
+ { encoding: "utf-8" },
48
71
  );
49
72
  } catch (error) {
50
73
  console.error(`Error resolving graphs: ${error}`);
@@ -24,8 +24,8 @@
24
24
  "undici": "^6.21.1",
25
25
  "uuid": "^10.0.0",
26
26
  "winston": "^3.17.0",
27
- "@langchain/langgraph-api": "~0.0.21",
28
- "@langchain/langgraph-ui": "~0.0.21",
27
+ "@langchain/langgraph-api": "~0.0.29",
28
+ "@langchain/langgraph-ui": "~0.0.29",
29
29
  "zod": "^3.23.8"
30
30
  },
31
31
  "resolutions": {
@@ -350,9 +350,22 @@ async def run_js_process(paths_str: str, watch: bool = False):
350
350
  attempt = 0
351
351
  while not asyncio.current_task().cancelled():
352
352
  client_file = os.path.join(os.path.dirname(__file__), "client.mts")
353
- args = ("tsx", client_file)
354
- if watch:
355
- args = ("tsx", "watch", client_file, "--skip-schema-cache")
353
+ client_preload_file = os.path.join(
354
+ os.path.dirname(__file__), "src", "preload.mjs"
355
+ )
356
+
357
+ args = (
358
+ (
359
+ "tsx",
360
+ "watch",
361
+ "--import",
362
+ client_preload_file,
363
+ client_file,
364
+ "--skip-schema-cache",
365
+ )
366
+ if watch
367
+ else ("tsx", "--import", client_preload_file, client_file)
368
+ )
356
369
  try:
357
370
  process = await asyncio.create_subprocess_exec(
358
371
  *args,
@@ -5,9 +5,6 @@ import type { CompiledGraph, Graph } from "@langchain/langgraph";
5
5
  import * as path from "node:path";
6
6
  import type { JSONSchema7 } from "json-schema";
7
7
 
8
- // enforce API @langchain/langgraph precedence
9
- register("./hooks.mjs", import.meta.url);
10
-
11
8
  export interface GraphSchema {
12
9
  state: JSONSchema7 | undefined;
13
10
  input: JSONSchema7 | undefined;
@@ -0,0 +1,61 @@
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
+ const OVERRIDE_RESOLVE = [
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(\/.+)?$`),
9
+ ];
10
+
11
+ let parentURL;
12
+ let langgraphPackageURL;
13
+
14
+ export async function initialize(args) {
15
+ parentURL = args.parentURL;
16
+ }
17
+
18
+ export async function resolve(specifier, context, nextResolve) {
19
+ // HACK: @tailwindcss/node internally uses an ESM loader cache, which does not play nicely with `tsx`.
20
+ // Node.js crashes with "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file".
21
+ // As it already is a valid URI, we can just short-circuit the resolution and avoid `tsx`.
22
+ if (
23
+ specifier.includes("@tailwindcss/node/dist/esm-cache.loader") &&
24
+ specifier.startsWith("file://")
25
+ ) {
26
+ return {
27
+ shortCircuit: true,
28
+ // Node 18.x will for some reason attempt to load `.mts` instead of `.mjs`
29
+ url: specifier.replace(".mts", ".mjs"),
30
+ format: "module",
31
+ };
32
+ }
33
+
34
+ if (specifier === "@langchain/langgraph-checkpoint") {
35
+ // resolve relative to @langchain/langgraph package instead
36
+ // This is done to avoid adding a direct dependency on @langchain/langgraph-checkpoint
37
+ // in project, which if not present will cause `pnpm` to not find the package.
38
+ if (!langgraphPackageURL) {
39
+ const main = await nextResolve("@langchain/langgraph", {
40
+ ...context,
41
+ parentURL,
42
+ });
43
+ langgraphPackageURL = main.url.toString();
44
+ }
45
+
46
+ return await nextResolve(specifier, {
47
+ ...context,
48
+ parentURL: langgraphPackageURL,
49
+ });
50
+ }
51
+
52
+ if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
53
+ const resolved = await nextResolve(specifier, { ...context, parentURL });
54
+
55
+ // If @langchain/langgraph is resolved first, cache it!
56
+ if (specifier === "@langchain/langgraph" && !langgraphPackageURL) {
57
+ langgraphPackageURL = resolved.url.toString();
58
+ }
59
+ }
60
+ return nextResolve(specifier, context);
61
+ }
@@ -2,9 +2,17 @@ import * as ts from "typescript";
2
2
  import * as vfs from "@typescript/vfs";
3
3
  import * as path from "node:path";
4
4
  import dedent from "dedent";
5
- import { buildGenerator } from "../schema/types.mts";
5
+ import { buildGenerator } from "./schema/types.mjs";
6
+ import { fileURLToPath } from "node:url";
6
7
 
7
- const __dirname = new URL(".", import.meta.url).pathname;
8
+ const __dirname = fileURLToPath(new URL(".", import.meta.url));
9
+
10
+ const OVERRIDE_RESOLVE = [
11
+ // Override `@langchain/langgraph` or `@langchain/langgraph/prebuilt`,
12
+ // but not `@langchain/langgraph-sdk`
13
+ new RegExp(`^@langchain\/langgraph(\/.+)?$`),
14
+ new RegExp(`^@langchain\/langgraph-checkpoint(\/.+)?$`),
15
+ ];
8
16
 
9
17
  const compilerOptions = {
10
18
  noEmit: true,
@@ -27,7 +35,7 @@ export class SubgraphExtractor {
27
35
  program: ts.Program,
28
36
  sourceFile: ts.SourceFile,
29
37
  inferFile: ts.SourceFile,
30
- options?: { strict?: boolean }
38
+ options?: { strict?: boolean },
31
39
  ) {
32
40
  this.program = program;
33
41
  this.sourceFile = sourceFile;
@@ -64,7 +72,7 @@ export class SubgraphExtractor {
64
72
 
65
73
  private find = (
66
74
  root: ts.Node,
67
- predicate: (node: ts.Node) => boolean
75
+ predicate: (node: ts.Node) => boolean,
68
76
  ): ts.Node | undefined => {
69
77
  let result: ts.Node | undefined = undefined;
70
78
 
@@ -83,7 +91,7 @@ export class SubgraphExtractor {
83
91
 
84
92
  protected findSubgraphs = (
85
93
  node: ts.Node,
86
- namespace: string[] = []
94
+ namespace: string[] = [],
87
95
  ): {
88
96
  node: string;
89
97
  namespace: string[];
@@ -95,7 +103,7 @@ export class SubgraphExtractor {
95
103
  namespace: string[];
96
104
  subgraph: { name: string; node: ts.Node };
97
105
  }[],
98
- node: ts.Node
106
+ node: ts.Node,
99
107
  ) => {
100
108
  if (ts.isCallExpression(node)) {
101
109
  const firstChild = node.getChildAt(0);
@@ -127,7 +135,7 @@ export class SubgraphExtractor {
127
135
  variables = this.reduceChildren(
128
136
  callArg,
129
137
  this.findSubgraphIdentifiers,
130
- []
138
+ [],
131
139
  );
132
140
  } else if (ts.isIdentifier(callArg)) {
133
141
  variables = this.findSubgraphIdentifiers([], callArg);
@@ -165,13 +173,13 @@ export class SubgraphExtractor {
165
173
  type InternalFlowNode = ts.Node & { flowNode?: { node: ts.Node } };
166
174
  const candidate = this.find(
167
175
  node,
168
- (node: any) => node && "flowNode" in node && node.flowNode
176
+ (node: any) => node && "flowNode" in node && node.flowNode,
169
177
  ) as InternalFlowNode | undefined;
170
178
 
171
179
  if (
172
180
  candidate?.flowNode &&
173
181
  this.isGraphOrPregelType(
174
- this.checker.getTypeAtLocation(candidate.flowNode.node)
182
+ this.checker.getTypeAtLocation(candidate.flowNode.node),
175
183
  )
176
184
  ) {
177
185
  subgraphs = this.findSubgraphs(candidate.flowNode.node, namespace);
@@ -183,7 +191,7 @@ export class SubgraphExtractor {
183
191
  return [
184
192
  ...subgraphs,
185
193
  ...subgraphs.map(({ subgraph, node }) =>
186
- this.findSubgraphs(subgraph.node, [...namespace, node])
194
+ this.findSubgraphs(subgraph.node, [...namespace, node]),
187
195
  ),
188
196
  ].flat();
189
197
  }
@@ -198,7 +206,7 @@ export class SubgraphExtractor {
198
206
  const targetExport = exports.find((item) => item.name === name);
199
207
  if (!targetExport) throw new Error(`Failed to find export "${name}"`);
200
208
  const varDecls = (targetExport.declarations ?? []).filter(
201
- ts.isVariableDeclaration
209
+ ts.isVariableDeclaration,
202
210
  );
203
211
 
204
212
  return varDecls.flatMap((varDecl) => {
@@ -208,7 +216,7 @@ export class SubgraphExtractor {
208
216
  };
209
217
 
210
218
  public getAugmentedSourceFile = (
211
- name: string
219
+ name: string,
212
220
  ): {
213
221
  files: [filePath: string, contents: string][];
214
222
  exports: { typeName: string; valueName: string; graphName: string }[];
@@ -237,7 +245,7 @@ export class SubgraphExtractor {
237
245
  this.getText(this.sourceFile),
238
246
  ...typeExports.map(
239
247
  ({ typeName, valueName }) =>
240
- `export type ${typeName} = typeof ${valueName}`
248
+ `export type ${typeName} = typeof ${valueName}`,
241
249
  ),
242
250
  ].join("\n\n");
243
251
 
@@ -245,7 +253,7 @@ export class SubgraphExtractor {
245
253
  const inferContents = [
246
254
  ...typeExports.map(
247
255
  ({ typeName }) =>
248
- `import type { ${typeName}} from "./__langgraph__source.mts"`
256
+ `import type { ${typeName}} from "./__langgraph__source.mts"`,
249
257
  ),
250
258
  this.inferFile.getText(this.inferFile),
251
259
 
@@ -276,7 +284,7 @@ export class SubgraphExtractor {
276
284
 
277
285
  protected findSubgraphIdentifiers = (
278
286
  acc: { node: ts.Node; name: string }[],
279
- node: ts.Node
287
+ node: ts.Node,
280
288
  ) => {
281
289
  if (ts.isIdentifier(node)) {
282
290
  const smb = this.checker.getSymbolAtLocation(node);
@@ -321,11 +329,12 @@ export class SubgraphExtractor {
321
329
  protected reduceChildren<Acc>(
322
330
  node: ts.Node,
323
331
  fn: (acc: Acc, node: ts.Node) => Acc,
324
- initial: Acc
332
+ initial: Acc,
325
333
  ): Acc {
326
334
  let acc = initial;
327
335
  function it(node: ts.Node) {
328
336
  acc = fn(acc, node);
337
+ // @ts-expect-error
329
338
  ts.forEachChild(node, it.bind(this));
330
339
  }
331
340
 
@@ -341,19 +350,27 @@ export class SubgraphExtractor {
341
350
  files?: [fileName: string, contents: string][];
342
351
  },
343
352
  name: string,
344
- options?: { strict?: boolean }
353
+ options?: { strict?: boolean },
345
354
  ) {
346
355
  const dirname =
347
356
  typeof target === "string" ? path.dirname(target) : __dirname;
348
357
 
358
+ // This API is not well made for Windows, ensure that the paths are UNIX slashes
349
359
  const fsMap = new Map<string, string>();
350
360
  const system = vfs.createFSBackedSystem(fsMap, dirname, ts);
351
361
 
352
362
  // TODO: investigate if we should create a PR in @typescript/vfs
353
363
  const oldReadFile = system.readFile.bind(system);
354
- system.readFile = (fileName) => oldReadFile(fileName) ?? "// Non-existent file";
364
+ system.readFile = (fileName) =>
365
+ oldReadFile(fileName) ?? "// Non-existent file";
366
+
367
+ const vfsPath = (inputPath: string) => {
368
+ if (process.platform === "win32") return inputPath.replace(/\\/g, "/");
369
+ return inputPath;
370
+ };
355
371
 
356
- const host = vfs.createVirtualCompilerHost(system, compilerOptions, ts);
372
+ const vfsHost = vfs.createVirtualCompilerHost(system, compilerOptions, ts);
373
+ const host = vfsHost.compilerHost;
357
374
 
358
375
  const targetPath =
359
376
  typeof target === "string"
@@ -362,65 +379,71 @@ export class SubgraphExtractor {
362
379
 
363
380
  const inferTemplatePath = path.resolve(
364
381
  __dirname,
365
- "../schema/types.template.mts"
382
+ "./schema/types.template.mts",
366
383
  );
367
384
 
368
385
  if (typeof target !== "string") {
369
- fsMap.set(targetPath, target.contents);
386
+ fsMap.set(vfsPath(targetPath), target.contents);
370
387
  for (const [name, contents] of target.files ?? []) {
371
- fsMap.set(path.resolve(dirname, name), contents);
388
+ fsMap.set(vfsPath(path.resolve(dirname, name)), contents);
372
389
  }
373
390
  }
374
391
 
375
- host.compilerHost.resolveModuleNames = (moduleNames, containingFile) => {
376
- const resolvedModules: (ts.ResolvedModule | undefined)[] = [];
377
- for (const moduleName of moduleNames) {
378
- let target = containingFile;
379
- const relative = path.relative(dirname, containingFile);
380
- if (
381
- moduleName.startsWith("@langchain/langgraph") &&
382
- relative &&
383
- !relative.startsWith("..") &&
384
- !path.isAbsolute(relative)
385
- ) {
386
- target = path.resolve(__dirname, relative);
392
+ const moduleCache = ts.createModuleResolutionCache(dirname, (x) => x);
393
+ host.resolveModuleNameLiterals = (
394
+ entries,
395
+ containingFile,
396
+ redirectedReference,
397
+ options,
398
+ ) =>
399
+ entries.flatMap((entry) => {
400
+ const specifier = entry.text;
401
+
402
+ // Force module resolution to use @langchain/langgraph from the local project
403
+ // rather than from API/CLI.
404
+ let targetFile = containingFile;
405
+ if (OVERRIDE_RESOLVE.some((regex) => regex.test(specifier))) {
406
+ // check if we're not already importing from node_modules
407
+ if (!containingFile.split(path.sep).includes("node_modules")) {
408
+ // Doesn't matter if the file exists, only used to nudge `ts.resolveModuleName`
409
+ targetFile = path.resolve(dirname, "__langgraph__resolve.mts");
410
+ }
387
411
  }
388
412
 
389
- resolvedModules.push(
413
+ return [
390
414
  ts.resolveModuleName(
391
- moduleName,
392
- target,
393
- compilerOptions,
394
- host.compilerHost
395
- ).resolvedModule
396
- );
397
- }
398
-
399
- return resolvedModules;
400
- };
415
+ specifier,
416
+ targetFile,
417
+ options,
418
+ host,
419
+ moduleCache,
420
+ redirectedReference,
421
+ ),
422
+ ];
423
+ });
401
424
 
402
425
  const research = ts.createProgram({
403
426
  rootNames: [inferTemplatePath, targetPath],
404
427
  options: compilerOptions,
405
- host: host.compilerHost,
428
+ host,
406
429
  });
407
430
 
408
431
  const extractor = new SubgraphExtractor(
409
432
  research,
410
433
  research.getSourceFile(targetPath)!,
411
434
  research.getSourceFile(inferTemplatePath)!,
412
- options
435
+ options,
413
436
  );
414
437
 
415
438
  const { files, exports } = extractor.getAugmentedSourceFile(name);
416
439
  for (const [name, source] of files) {
417
- system.writeFile(path.resolve(dirname, name), source);
440
+ system.writeFile(vfsPath(path.resolve(dirname, name)), source);
418
441
  }
419
442
 
420
443
  const extract = ts.createProgram({
421
444
  rootNames: [path.resolve(dirname, "./__langraph__infer.mts")],
422
445
  options: compilerOptions,
423
- host: host.compilerHost,
446
+ host,
424
447
  });
425
448
 
426
449
  const schemaGenerator = buildGenerator(extract);
@@ -428,7 +451,10 @@ export class SubgraphExtractor {
428
451
  try {
429
452
  return schema?.getSchemaForSymbol(symbol) ?? undefined;
430
453
  } catch (e) {
431
- console.warn(`Failed to obtain symbol "${symbol}":`, e?.message);
454
+ console.warn(
455
+ `Failed to obtain symbol "${symbol}":`,
456
+ (e as Error)?.message,
457
+ );
432
458
  }
433
459
  return undefined;
434
460
  };
@@ -442,7 +468,7 @@ export class SubgraphExtractor {
442
468
  state: trySymbol(schemaGenerator, `${typeName}__update`),
443
469
  config: trySymbol(schemaGenerator, `${typeName}__config`),
444
470
  },
445
- ])
471
+ ]),
446
472
  );
447
473
  }
448
474
  }
@@ -0,0 +1,21 @@
1
+ import { register } from "node:module";
2
+ import { pathToFileURL } from "node:url";
3
+ import { join } from "node:path";
4
+
5
+ // we only care about the payload, which contains the server definition
6
+ const graphs = JSON.parse(process.env.LANGSERVE_GRAPHS || "{}");
7
+ const cwd = process.cwd();
8
+
9
+ // find the first file, as `parentURL` needs to be a valid file URL
10
+ // if no graph found, just assume a dummy default file, which should
11
+ // be working fine as well.
12
+ const firstGraphFile =
13
+ Object.values(graphs)
14
+ .flatMap((i) => i.split(":").at(0))
15
+ .at(0) || "index.mts";
16
+
17
+ // enforce API @langchain/langgraph resolution
18
+ register("./load.hooks.mjs", import.meta.url, {
19
+ parentURL: "data:",
20
+ data: { parentURL: pathToFileURL(join(cwd, firstGraphFile)).toString() },
21
+ });
@@ -488,7 +488,7 @@ describe("runs", () => {
488
488
  expect(runs.length).toBe(1);
489
489
  });
490
490
 
491
- it.concurrent("stream values", async () => {
491
+ it.concurrent("stream values", { retry: 3 }, async () => {
492
492
  const assistant = await client.assistants.create({ graphId: "agent" });
493
493
  const thread = await client.threads.create();
494
494
  const input = {
@@ -1991,8 +1991,11 @@ it("dynamic graph", async () => {
1991
1991
 
1992
1992
  it("generative ui", async () => {
1993
1993
  const ui = await client["~ui"].getComponent("agent", "weather-component");
1994
- expect(ui).toEqual(
1995
- `<script src="//localhost:9123/ui/agent/entrypoint.js" onload='__LGUI_agent.render("weather-component", "{{shadowRootId}}")'></script>\n<link rel="stylesheet" href="//localhost:9123/ui/agent/entrypoint.css" />`,
1994
+ expect(ui).toContain(
1995
+ `<link rel="stylesheet" href="//localhost:9123/ui/agent/entrypoint.css" />`,
1996
+ );
1997
+ expect(ui).toContain(
1998
+ `<script src="//localhost:9123/ui/agent/entrypoint.js" onload='__LGUI_agent.render("weather-component", "{{shadowRootId}}")'></script>`,
1996
1999
  );
1997
2000
 
1998
2001
  const match = /src="(?<src>[^"]+)"/.exec(ui);
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "dependencies": {
4
4
  "@langchain/core": "^0.3.40",
5
- "@langchain/langgraph": "^0.2.49",
5
+ "@langchain/langgraph": "0.2.65",
6
6
  "@langchain/langgraph-sdk": "^0.0.67",
7
7
  "jose": "^6.0.10",
8
8
  "hono": "^4.5.4"
@@ -25,10 +25,10 @@
25
25
  zod "^3.22.4"
26
26
  zod-to-json-schema "^3.22.3"
27
27
 
28
- "@langchain/langgraph-checkpoint@~0.0.16":
29
- version "0.0.16"
30
- resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.16.tgz#e996f31d5da8ce67b2a9bf3dc64c4c0e05f01d72"
31
- integrity sha512-B50l7w9o9353drHsdsD01vhQrCJw0eqvYeXid7oKeoj1Yye+qY90r97xuhiflaYCZHM5VEo2oaizs8oknerZsQ==
28
+ "@langchain/langgraph-checkpoint@~0.0.17":
29
+ version "0.0.17"
30
+ resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.17.tgz#d0a8824eb0769567da54262adebe65db4ee6d58f"
31
+ integrity sha512-6b3CuVVYx+7x0uWLG+7YXz9j2iBa+tn2AXvkLxzEvaAsLE6Sij++8PPbS2BZzC+S/FPJdWsz6I5bsrqL0BYrCA==
32
32
  dependencies:
33
33
  uuid "^10.0.0"
34
34
 
@@ -42,12 +42,12 @@
42
42
  p-retry "4"
43
43
  uuid "^9.0.0"
44
44
 
45
- "@langchain/langgraph@^0.2.49":
46
- version "0.2.54"
47
- resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.54.tgz#f57a9b471808c122ee5ae4506ed05cc75f1578bd"
48
- integrity sha512-+P2rU0Qz6bBCNPXOSV8WeUpLRTvhu8fQuzMYR2MqWsbbfmZrfmLxqtVWPHkmr5khx/txxFy1vOBAy+KwZ94mrg==
45
+ "@langchain/langgraph@0.2.65":
46
+ version "0.2.65"
47
+ resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.65.tgz#f080add1c26a3eb3744af2ef23b8b53eddbf5cb2"
48
+ integrity sha512-g/Xap2KSEaEBXMJXGZTh31fd0qrdfaWA1l8NJzweJg6AkvVSf+d6DmMk9DtzGW8W1H1qQ2I6FWZ3AdP61Kkaig==
49
49
  dependencies:
50
- "@langchain/langgraph-checkpoint" "~0.0.16"
50
+ "@langchain/langgraph-checkpoint" "~0.0.17"
51
51
  "@langchain/langgraph-sdk" "~0.0.32"
52
52
  uuid "^10.0.0"
53
53
  zod "^3.23.8"
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "NodeNext",
4
+ "jsx": "react-jsx",
5
+ "noEmit": true,
6
+ "strict": true,
7
+ "allowJs": true,
8
+ "skipLibCheck": true,
9
+ "noUnusedLocals": true,
10
+ "esModuleInterop": true,
11
+ "resolveJsonModule": true,
12
+ "allowImportingTsExtensions": true,
13
+ "forceConsistentCasingInFileNames": true
14
+ }
15
+ }