langgraph-api 0.1.8__py3-none-any.whl → 0.1.12__py3-none-any.whl

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.

langgraph_api/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.8"
1
+ __version__ = "0.1.12"
langgraph_api/cli.py CHANGED
@@ -122,6 +122,7 @@ def run_server(
122
122
  n_jobs_per_worker: int | None = None,
123
123
  env_file: str | None = None,
124
124
  open_browser: bool = False,
125
+ tunnel: bool = False,
125
126
  debug_port: int | None = None,
126
127
  wait_for_client: bool = False,
127
128
  env: str | pathlib.Path | Mapping[str, str] | None = None,
@@ -189,9 +190,33 @@ def run_server(
189
190
  debugpy.wait_for_client()
190
191
  logger.info("Debugger attached. Starting server...")
191
192
 
192
- local_url = f"http://{host}:{port}"
193
+ # Determine local or tunneled URL
194
+ upstream_url = f"http://{host}:{port}"
193
195
  if mount_prefix:
194
- local_url += mount_prefix
196
+ upstream_url += mount_prefix
197
+ if tunnel:
198
+ logger.info("Starting Cloudflare Tunnel...")
199
+ from concurrent.futures import TimeoutError as FutureTimeoutError
200
+
201
+ from langgraph_api.tunneling.cloudflare import start_tunnel
202
+
203
+ tunnel_obj = start_tunnel(port)
204
+ try:
205
+ public_url = tunnel_obj.url.result(timeout=30)
206
+ except FutureTimeoutError:
207
+ logger.warning(
208
+ "Timed out waiting for Cloudflare Tunnel URL; using local URL %s",
209
+ upstream_url,
210
+ )
211
+ public_url = upstream_url
212
+ except Exception as e:
213
+ tunnel_obj.process.kill()
214
+ raise RuntimeError("Failed to start Cloudflare Tunnel") from e
215
+ local_url = public_url
216
+ if mount_prefix:
217
+ local_url += mount_prefix
218
+ else:
219
+ local_url = upstream_url
195
220
  to_patch = dict(
196
221
  MIGRATIONS_PATH="__inmem",
197
222
  DATABASE_URI=":memory:",
@@ -361,6 +386,11 @@ def main():
361
386
  action="store_true",
362
387
  help="Whether to break and wait for a debugger to attach",
363
388
  )
389
+ parser.add_argument(
390
+ "--tunnel",
391
+ action="store_true",
392
+ help="Expose the server via Cloudflare Tunnel",
393
+ )
364
394
 
365
395
  args = parser.parse_args()
366
396
 
@@ -378,6 +408,7 @@ def main():
378
408
  graphs,
379
409
  n_jobs_per_worker=args.n_jobs_per_worker,
380
410
  open_browser=not args.no_browser,
411
+ tunnel=args.tunnel,
381
412
  debug_port=args.debug_port,
382
413
  wait_for_client=args.wait_for_client,
383
414
  env=config_data.get("env", None),
langgraph_api/config.py CHANGED
@@ -159,6 +159,7 @@ REDIS_URI = env("REDIS_URI", cast=str)
159
159
  REDIS_CLUSTER = env("REDIS_CLUSTER", cast=bool, default=False)
160
160
  REDIS_MAX_CONNECTIONS = env("REDIS_MAX_CONNECTIONS", cast=int, default=500)
161
161
  REDIS_CONNECT_TIMEOUT = env("REDIS_CONNECT_TIMEOUT", cast=float, default=10.0)
162
+ REDIS_KEY_PREFIX = env("REDIS_KEY_PREFIX", cast=str, default="")
162
163
 
163
164
  # server
164
165
  ALLOW_PRIVATE_NETWORK = env("ALLOW_PRIVATE_NETWORK", cast=bool, default=False)
@@ -10,7 +10,7 @@
10
10
  "@hono/node-server": "^1.12.0",
11
11
  "@hono/zod-validator": "^0.2.2",
12
12
  "@langchain/core": "^0.3.44",
13
- "@langchain/langgraph": "^0.2.64",
13
+ "@langchain/langgraph": "^0.2.65",
14
14
  "@langchain/langgraph-checkpoint": "^0.0.17",
15
15
  "@types/json-schema": "^7.0.15",
16
16
  "@typescript/vfs": "^1.6.0",
@@ -2078,6 +2078,7 @@ it("custom routes - mutate request body", async () => {
2078
2078
  messages: expect.arrayContaining([
2079
2079
  expect.objectContaining({ content: "end: extra-client" }),
2080
2080
  ]),
2081
+ prompts: [],
2081
2082
  });
2082
2083
  });
2083
2084
 
@@ -2094,6 +2095,34 @@ it("custom routes - langgraph", async () => {
2094
2095
  messages: expect.arrayContaining([
2095
2096
  expect.objectContaining({ content: "input" }),
2096
2097
  ]),
2098
+ prompts: [],
2099
+ },
2100
+ });
2101
+ });
2102
+
2103
+ it("send map-reduce", async () => {
2104
+ const assistant = await client.assistants.create({ graphId: "agent_simple" });
2105
+ const thread = await client.threads.create();
2106
+
2107
+ const chunks = await gatherIterator(
2108
+ client.runs.stream(thread.thread_id, assistant.assistant_id, {
2109
+ input: { messages: [{ role: "human", content: "input" }] },
2110
+ config: { configurable: { "map-reduce": true } },
2111
+ }),
2112
+ );
2113
+
2114
+ expect(chunks.filter((i) => i.event === "error")).toEqual([]);
2115
+ expect(findLast(chunks, (i) => i.event === "values")).toMatchObject({
2116
+ data: {
2117
+ messages: [
2118
+ { type: "human", content: "input" },
2119
+ { type: "human", content: "map-reduce" },
2120
+ ],
2121
+ prompts: [
2122
+ { type: "ai", content: "first" },
2123
+ { type: "ai", content: "second" },
2124
+ { type: "ai", content: "third" },
2125
+ ],
2097
2126
  },
2098
2127
  });
2099
2128
  });
@@ -7,7 +7,7 @@ import {
7
7
  START,
8
8
  LangGraphRunnableConfig,
9
9
  } from "@langchain/langgraph";
10
- import { BaseMessage, ToolMessage } from "@langchain/core/messages";
10
+ import { AIMessage, BaseMessage, ToolMessage } from "@langchain/core/messages";
11
11
  import { FakeListChatModel } from "@langchain/core/utils/testing";
12
12
 
13
13
  const getStableModel = (() => {
@@ -25,6 +25,7 @@ const AgentState = Annotation.Root({
25
25
  key_two: Annotation<string>(),
26
26
  sleep: Annotation<number>(),
27
27
  messages: MessagesAnnotation.spec.messages,
28
+ prompts: MessagesAnnotation.spec.messages,
28
29
  });
29
30
 
30
31
  async function callModel(
@@ -47,6 +48,10 @@ async function callModel(
47
48
  };
48
49
  }
49
50
 
51
+ if (config.configurable?.["map-reduce"] != null) {
52
+ return { messages: ["map-reduce"] };
53
+ }
54
+
50
55
  const model = getStableModel(config.configurable?.thread_id ?? "$");
51
56
  const existing = await config.store?.get([userId ?? "ALL"], "key_one");
52
57
  if (!existing) {
@@ -68,15 +73,31 @@ async function callTool(
68
73
  return { messages: [response] };
69
74
  }
70
75
 
71
- function shouldContinue(state: typeof AgentState.State): typeof END | Send {
76
+ function shouldContinue(
77
+ state: typeof AgentState.State,
78
+ ): typeof END | Send | Send[] {
72
79
  const lastMessage = state.messages.at(-1);
73
80
  if ((lastMessage?.content as string).startsWith("end")) return END;
81
+ if ((lastMessage?.content as string).includes("map-reduce")) {
82
+ return [
83
+ new Send("map-reduce", { messages: [new AIMessage("first")] }),
84
+ new Send("map-reduce", { messages: [new AIMessage("second")] }),
85
+ new Send("map-reduce", { messages: [new AIMessage("third")] }),
86
+ ];
87
+ }
74
88
  return new Send("tool", lastMessage);
75
89
  }
76
90
 
91
+ function callMapReduce(state: {
92
+ messages: BaseMessage[];
93
+ }): typeof AgentState.Update {
94
+ return { prompts: state.messages.slice(-1) };
95
+ }
96
+
77
97
  const workflow = new StateGraph(AgentState)
78
98
  .addNode("agent", callModel)
79
99
  .addNode("tool", callTool)
100
+ .addNode("map-reduce", callMapReduce)
80
101
  .addEdge(START, "agent")
81
102
  .addConditionalEdges("agent", shouldContinue)
82
103
  .addEdge("tool", "agent");
@@ -256,10 +256,10 @@
256
256
  esbuild-plugin-tailwindcss "^2.0.1"
257
257
  zod "^3.23.8"
258
258
 
259
- "@langchain/langgraph@^0.2.64":
260
- version "0.2.64"
261
- resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.64.tgz#90f8c32bc34fbc3f7c1b04595f1e5165dd5a5fb4"
262
- integrity sha512-M6lh8ekDoZVCLdA10jeqIsU58LODDzXpP38aeXil5A5pg31IJp5L8O4yBfbp8mRobVX+Bbga5R5ZRyQBQl6NTg==
259
+ "@langchain/langgraph@^0.2.65":
260
+ version "0.2.65"
261
+ resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.65.tgz#f080add1c26a3eb3744af2ef23b8b53eddbf5cb2"
262
+ integrity sha512-g/Xap2KSEaEBXMJXGZTh31fd0qrdfaWA1l8NJzweJg6AkvVSf+d6DmMk9DtzGW8W1H1qQ2I6FWZ3AdP61Kkaig==
263
263
  dependencies:
264
264
  "@langchain/langgraph-checkpoint" "~0.0.17"
265
265
  "@langchain/langgraph-sdk" "~0.0.32"
langgraph_api/metadata.py CHANGED
@@ -40,7 +40,10 @@ RUN_COUNTER = 0
40
40
  NODE_COUNTER = 0
41
41
  FROM_TIMESTAMP = datetime.now(UTC).isoformat()
42
42
 
43
- if "api.smith.langchain.com" in LANGSMITH_AUTH_ENDPOINT:
43
+ if (
44
+ "api.smith.langchain.com" in LANGSMITH_AUTH_ENDPOINT
45
+ and not LANGGRAPH_CLOUD_LICENSE_KEY
46
+ ):
44
47
  METADATA_ENDPOINT = LANGSMITH_AUTH_ENDPOINT.rstrip("/") + "/v1/metadata/submit"
45
48
  else:
46
49
  METADATA_ENDPOINT = "https://api.smith.langchain.com/v1/metadata/submit"
@@ -100,20 +103,21 @@ async def metadata_loop() -> None:
100
103
  "from_timestamp": from_timestamp,
101
104
  "to_timestamp": to_timestamp,
102
105
  "tags": {
106
+ # Tag values must be strings.
103
107
  "langgraph.python.version": langgraph.version.__version__,
104
- "langgraph_api.version": __version__,
105
- "langgraph.platform.revision": REVISION,
106
- "langgraph.platform.variant": VARIANT,
108
+ "langgraph_api.version": __version__ or "",
109
+ "langgraph.platform.revision": REVISION or "",
110
+ "langgraph.platform.variant": VARIANT or "",
107
111
  "langgraph.platform.host": HOST,
108
- "langgraph.platform.tenant_id": TENANT_ID,
109
- "langgraph.platform.project_id": PROJECT_ID,
112
+ "langgraph.platform.tenant_id": TENANT_ID or "",
113
+ "langgraph.platform.project_id": PROJECT_ID or "",
110
114
  "langgraph.platform.plan": PLAN,
111
115
  # user app features
112
- "user_app.uses_indexing": USES_INDEXING,
113
- "user_app.uses_custom_app": USES_CUSTOM_APP,
114
- "user_app.uses_custom_auth": USES_CUSTOM_AUTH,
115
- "user_app.uses_thread_ttl": USES_THREAD_TTL,
116
- "user_app.uses_store_ttl": USES_STORE_TTL,
116
+ "user_app.uses_indexing": str(USES_INDEXING or ""),
117
+ "user_app.uses_custom_app": str(USES_CUSTOM_APP or ""),
118
+ "user_app.uses_custom_auth": str(USES_CUSTOM_AUTH),
119
+ "user_app.uses_thread_ttl": str(USES_THREAD_TTL),
120
+ "user_app.uses_store_ttl": str(USES_STORE_TTL),
117
121
  },
118
122
  "measures": {
119
123
  "langgraph.platform.runs": runs,
langgraph_api/server.py CHANGED
@@ -30,7 +30,6 @@ from langgraph_runtime.lifespan import lifespan
30
30
  from langgraph_api.middleware.http_logger import AccessLoggerMiddleware
31
31
  from langgraph_api.middleware.private_network import PrivateNetworkMiddleware
32
32
  from langgraph_api.utils import SchemaGenerator
33
- from langgraph_license.middleware import LicenseValidationMiddleware
34
33
  from langgraph_runtime.retry import OVERLOADED_EXCEPTIONS
35
34
  from langgraph_api.js.base import is_js_path
36
35
  from langgraph_sdk.client import configure_loopback_transports
@@ -68,7 +67,6 @@ middleware.extend(
68
67
  **config.CORS_CONFIG,
69
68
  )
70
69
  ),
71
- Middleware(LicenseValidationMiddleware),
72
70
  Middleware(AccessLoggerMiddleware, logger=logger),
73
71
  ]
74
72
  )
@@ -0,0 +1,119 @@
1
+ import atexit
2
+ import logging
3
+ import os
4
+ import platform as _platform
5
+ import re
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import tarfile
10
+ import tempfile
11
+ import threading
12
+ import urllib.request
13
+ from concurrent.futures import Future
14
+ from pathlib import Path
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ CLOUDFLARED_VERSION = os.environ.get("LANGGRAPH_CLOUDFLARED_VERSION", "2025.2.1")
19
+ CACHE_DIR = (
20
+ Path(os.path.expanduser("~"))
21
+ / ".langgraph_api"
22
+ / "cloudflared"
23
+ / CLOUDFLARED_VERSION
24
+ )
25
+
26
+
27
+ def get_platform_arch():
28
+ plat = sys.platform
29
+ if plat.startswith("darwin"):
30
+ plat = "darwin"
31
+ elif plat.startswith("linux"):
32
+ plat = "linux"
33
+ elif plat.startswith("win"):
34
+ plat = "windows"
35
+ else:
36
+ raise RuntimeError(f"Unsupported platform: {sys.platform}")
37
+ arch = _platform.machine().lower()
38
+ if arch in ("x86_64", "amd64"):
39
+ arch = "amd64"
40
+ elif arch in ("arm64", "aarch64"):
41
+ arch = "arm64"
42
+ elif arch in ("i386", "i686", "x86"):
43
+ arch = "386"
44
+ else:
45
+ raise RuntimeError(f"Unsupported architecture: {_platform.machine()}")
46
+ return plat, arch
47
+
48
+
49
+ def ensure_cloudflared() -> Path:
50
+ plat, arch = get_platform_arch()
51
+ # determine file names and if archive
52
+ if plat == "windows":
53
+ file_name = f"cloudflared-windows-{arch}.exe"
54
+ is_archive = False
55
+ elif plat == "darwin":
56
+ file_name = f"cloudflared-darwin-{arch}.tgz"
57
+ is_archive = True
58
+ else: # linux
59
+ file_name = f"cloudflared-linux-{arch}"
60
+ is_archive = False
61
+
62
+ CACHE_DIR.mkdir(parents=True, exist_ok=True)
63
+ binary_name = "cloudflared" if is_archive else file_name
64
+ target_bin = CACHE_DIR / binary_name
65
+ if not target_bin.exists():
66
+ url = f"https://github.com/cloudflare/cloudflared/releases/download/{CLOUDFLARED_VERSION}/{file_name}"
67
+ logger.info(f"Downloading cloudflared from {url}")
68
+ with urllib.request.urlopen(url) as resp:
69
+ data = resp.read()
70
+ with tempfile.TemporaryDirectory() as tmpd:
71
+ tmpd = Path(tmpd)
72
+ path = tmpd / file_name
73
+ path.write_bytes(data)
74
+ if is_archive:
75
+ with tarfile.open(path) as tf:
76
+ tf.extractall(tmpd)
77
+ src = tmpd / "cloudflared"
78
+ else:
79
+ src = path
80
+ shutil.move(str(src), str(target_bin))
81
+ target_bin.chmod(0o755)
82
+ return target_bin
83
+
84
+
85
+ class CloudflareTunnel:
86
+ def __init__(self, process: subprocess.Popen, url_future: Future[str]):
87
+ self.process = process
88
+ self.url = url_future
89
+
90
+
91
+ def start_tunnel(port: int) -> CloudflareTunnel:
92
+ bin_path = ensure_cloudflared()
93
+ cmd = [str(bin_path), "tunnel", "--url", f"http://localhost:{port}"]
94
+ proc = subprocess.Popen(
95
+ cmd,
96
+ stdout=subprocess.PIPE,
97
+ stderr=subprocess.PIPE,
98
+ text=True,
99
+ bufsize=1,
100
+ )
101
+ atexit.register(proc.kill)
102
+
103
+ url_future: Future[str] = Future()
104
+
105
+ def _reader(stream):
106
+ for line in stream:
107
+ line = line.strip()
108
+ logger.info(f"[cloudflared] {line}")
109
+ if not url_future.done():
110
+ # match any trycloudflare.com host with optional subdomains
111
+ pattern = re.compile(r"(https://[A-Za-z0-9.-]+\.trycloudflare\.com)")
112
+ m = pattern.search(line)
113
+ if m:
114
+ url_future.set_result(m.group(1))
115
+
116
+ threading.Thread(target=_reader, args=(proc.stdout,), daemon=True).start()
117
+ threading.Thread(target=_reader, args=(proc.stderr,), daemon=True).start()
118
+
119
+ return CloudflareTunnel(proc, url_future)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langgraph-api
3
- Version: 0.1.8
3
+ Version: 0.1.12
4
4
  Summary:
5
5
  License: Elastic-2.0
6
6
  Author: Nuno Campos
@@ -1,5 +1,5 @@
1
1
  LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
2
- langgraph_api/__init__.py,sha256=C69ADlbQREQlR15trneyA2sk8x0-oH4rDAX5fsv19_U,22
2
+ langgraph_api/__init__.py,sha256=LcIlFjHZFfiF9Rd4UHoakmombOFkxIYk00I181frGBM,23
3
3
  langgraph_api/api/__init__.py,sha256=IKKMrC5gCHTzjprbg8jgZDrAJRuqJfSUgEkZAgh3l-M,5771
4
4
  langgraph_api/api/assistants.py,sha256=i-nxkScUB2g8bTVGtQIp1psABXlaY1aVx9pkB_UiRH8,14353
5
5
  langgraph_api/api/mcp.py,sha256=KbR19dtFCpJEiKYj3IfepAuJij8YZVELuVp7JY_yu_o,13754
@@ -18,9 +18,9 @@ langgraph_api/auth/langsmith/client.py,sha256=eKchvAom7hdkUXauD8vHNceBDDUijrFgdT
18
18
  langgraph_api/auth/middleware.py,sha256=jDA4t41DUoAArEY_PNoXesIUBJ0nGhh85QzRdn5EPD0,1916
19
19
  langgraph_api/auth/noop.py,sha256=Bk6Nf3p8D_iMVy_OyfPlyiJp_aEwzL-sHrbxoXpCbac,586
20
20
  langgraph_api/auth/studio_user.py,sha256=FzFQRROKDlA9JjtBuwyZvk6Mbwno5M9RVYjDO6FU3F8,186
21
- langgraph_api/cli.py,sha256=NQSHyGbsr8I5xqEmbgDxADgCxbqWrcJRvT69JfGP3ms,13452
21
+ langgraph_api/cli.py,sha256=9Ou3tGDDY_VVLt5DFle8UviJdpI4ZigC5hElYvq2-To,14519
22
22
  langgraph_api/command.py,sha256=3O9v3i0OPa96ARyJ_oJbLXkfO8rPgDhLCswgO9koTFA,768
23
- langgraph_api/config.py,sha256=uvw51OP8VApy54DbqZIShNoaCJeM7M83mR-8hDgMLY8,10553
23
+ langgraph_api/config.py,sha256=GWXgIDVPtpY7MBiAQMg7iluDzl7z6VYUsX_I1payq4k,10618
24
24
  langgraph_api/cron_scheduler.py,sha256=i87j4pJrcsmsqMKeKUs69gaAjrGaSM3pM3jnXdN5JDQ,2630
25
25
  langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
26
26
  langgraph_api/graph.py,sha256=OMvYH6xO5KXwPxTSZ3e_yQZXDmT8nVsa0iqOWqKqYaw,21477
@@ -34,7 +34,7 @@ langgraph_api/js/client.http.mts,sha256=AGA-p8J85IcNh2oXZjDxHQ4PnQdJmt-LPcpZp6j0
34
34
  langgraph_api/js/client.mts,sha256=7v5BcWsR5w6wGCsxhm6xryBgI-5vfu2Or1YmT-GdKyY,28766
35
35
  langgraph_api/js/errors.py,sha256=Cm1TKWlUCwZReDC5AQ6SgNIVGD27Qov2xcgHyf8-GXo,361
36
36
  langgraph_api/js/global.d.ts,sha256=j4GhgtQSZ5_cHzjSPcHgMJ8tfBThxrH-pUOrrJGteOU,196
37
- langgraph_api/js/package.json,sha256=UiJmCaT-N5Bl8NiotYYYMNZDb9ibz4LqRKgeyMfHisc,1289
37
+ langgraph_api/js/package.json,sha256=RTeBG4ubSdvB_zp2Nh_Cp2tCDZn7eFXCcJgFEYkQ3Mk,1289
38
38
  langgraph_api/js/remote.py,sha256=pnyq3oGtMX3kGaBLU-lhMf_kKvc1a1324Z3e_KIKAD0,35117
39
39
  langgraph_api/js/schema.py,sha256=7idnv7URlYUdSNMBXQcw7E4SxaPxCq_Oxwnlml8q5ik,408
40
40
  langgraph_api/js/src/graph.mts,sha256=g86jOvbHj1B0o1jatBc2X5_JEZW2DSNwgUJ_kw1k8Cw,3569
@@ -48,7 +48,7 @@ langgraph_api/js/src/utils/importMap.mts,sha256=pX4TGOyUpuuWF82kXcxcv3-8mgusRezO
48
48
  langgraph_api/js/src/utils/pythonSchemas.mts,sha256=98IW7Z_VP7L_CHNRMb3_MsiV3BgLE2JsWQY_PQcRR3o,685
49
49
  langgraph_api/js/src/utils/serde.mts,sha256=OuyyO9btvwWd55rU_H4x91dFEJiaPxL-lL9O6Zgo908,742
50
50
  langgraph_api/js/sse.py,sha256=lsfp4nyJyA1COmlKG9e2gJnTttf_HGCB5wyH8OZBER8,4105
51
- langgraph_api/js/tests/api.test.mts,sha256=ZWOFnEPxXQgSOvQjUFNI1mof2civ7RB6980_JuWFr0E,66808
51
+ langgraph_api/js/tests/api.test.mts,sha256=Zbnbyzy6xZwcM2r-_dTV8u9tAT592QK8pJ4JdI0xO9k,67694
52
52
  langgraph_api/js/tests/auth.test.mts,sha256=A8JXfEep6S4jzduoSZeRQkqq9WsFbVE8Bvi3Hj_zx2w,21600
53
53
  langgraph_api/js/tests/compose-postgres.auth.yml,sha256=iPfJbCeYZdV6GiRLiDn_f7qgpG4TyyGaQ4lV-ZXr6Qk,1768
54
54
  langgraph_api/js/tests/compose-postgres.yml,sha256=w4B3YRS0QEnTcZH2-MY0DYvR_c5GcER0uDa1Ga_knf8,1960
@@ -56,7 +56,7 @@ langgraph_api/js/tests/graphs/.gitignore,sha256=26J8MarZNXh7snXD5eTpV3CPFTht5Znv
56
56
  langgraph_api/js/tests/graphs/agent.css,sha256=QgcOC0W7IBsrg4pSqqpull-WTgtULZfx_lF_5ZxLdag,23
57
57
  langgraph_api/js/tests/graphs/agent.mts,sha256=E9WMv0alMv0njUEECqEsqoRk9NXJUgXW7SyQJ3GOZ8k,5396
58
58
  langgraph_api/js/tests/graphs/agent.ui.tsx,sha256=JDFJdpdIS6rglkXTaROSb1Is0j1kt5wN9ML8W4cuht8,175
59
- langgraph_api/js/tests/graphs/agent_simple.mts,sha256=pfpzWEd_PQmQvzbEZTc6xT-Trd7K43_xTifh7J5gERU,2348
59
+ langgraph_api/js/tests/graphs/agent_simple.mts,sha256=EDaQXM5x73HhcHoujezOX5C27uZdGdtfMVBE9o4hleE,2998
60
60
  langgraph_api/js/tests/graphs/auth.mts,sha256=kF2TZP3n_urWigf0qgejZqTe93-341_Mhqe_qnBO_Io,3195
61
61
  langgraph_api/js/tests/graphs/command.mts,sha256=YO1_cEs_n9VsH_-IediLnI4Yc8KRlp4qrprUZXpAlwM,1163
62
62
  langgraph_api/js/tests/graphs/delay.mts,sha256=CFneKxqI4bGGK0lYjSbe80QirowPQlsRSuhDUKfydhk,703
@@ -71,9 +71,9 @@ langgraph_api/js/tests/graphs/yarn.lock,sha256=GwbaZr7inRbWzuuvrQKLHT72zYDKwteng
71
71
  langgraph_api/js/tests/parser.test.mts,sha256=dEC8KTqKygeb1u39ZvpPqCT4HtfPD947nLmITt2buxA,27883
72
72
  langgraph_api/js/tests/utils.mts,sha256=q1V9gvT63v95onlfK9W4iv3n9ZJO3h-0RD9TdDYuRyY,439
73
73
  langgraph_api/js/ui.py,sha256=XNT8iBcyT8XmbIqSQUWd-j_00HsaWB2vRTVabwFBkik,2439
74
- langgraph_api/js/yarn.lock,sha256=XYw61N9krBIAyoABfY1ROXzOCehSHHV9fFQcWBL3OT0,83379
74
+ langgraph_api/js/yarn.lock,sha256=_J3wSh92WUu6rBwTE5x2V22TZLWXGbkCSybjteB4tz0,83379
75
75
  langgraph_api/logging.py,sha256=JJIzbNIgLCN6ClQ3tA-Mm5ffuBGvpRDSZsEvnIlsuu4,3693
76
- langgraph_api/metadata.py,sha256=jibmAW9sOQZPZl6ZKOn1u6HrFsmkP0M_OQPChADnyaM,4321
76
+ langgraph_api/metadata.py,sha256=ptaxwmzdx2bUBSc1KRhqgF-Xnm-Zh2gqwSiHpl8LD9c,4482
77
77
  langgraph_api/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  langgraph_api/middleware/http_logger.py,sha256=aj4mdisRobFePkD3Iy6-w_Mujwx4TQRaEhPvSd6HgLk,3284
79
79
  langgraph_api/middleware/private_network.py,sha256=eYgdyU8AzU2XJu362i1L8aSFoQRiV7_aLBPw7_EgeqI,2111
@@ -84,23 +84,23 @@ langgraph_api/queue_entrypoint.py,sha256=gjtajZfnDXhsi7JElfmkY-p0ENBiKBDJ4Ugiw-e
84
84
  langgraph_api/route.py,sha256=fM4qYCGbmH0a3_cV8uKocb1sLklehxO6HhdRXqLK6OM,4421
85
85
  langgraph_api/schema.py,sha256=Frh_YOC3S1cDAMPUVanNi78ooSXK2WFpu9YkIVz5h14,5433
86
86
  langgraph_api/serde.py,sha256=TVsx2QQtepf8Wsgsabcku1NV4Vbugu4Oujmdnq4qMS0,3964
87
- langgraph_api/server.py,sha256=7GBwJ7W5xEp2RKLblAGQFysmjCNE-2masnPKmm0HWIc,6662
87
+ langgraph_api/server.py,sha256=gluUa9L822atoMuAOxnlgSkHuuluT5vjW_u0EV5XL2o,6544
88
88
  langgraph_api/sse.py,sha256=2wNodCOP2eg7a9mpSu0S3FQ0CHk2BBV_vv0UtIgJIcc,4034
89
89
  langgraph_api/state.py,sha256=8jx4IoTCOjTJuwzuXJKKFwo1VseHjNnw_CCq4x1SW14,2284
90
90
  langgraph_api/stream.py,sha256=SN96CLJ5QnSQ2YWRrkQb4K8XkdoSbloyFRj8N1vKcs8,11369
91
91
  langgraph_api/thread_ttl.py,sha256=4vch4nu1UOiYcqYRd7bTHsfs0Ei_lXuy9nBQ0uVJLyo,1765
92
+ langgraph_api/tunneling/cloudflare.py,sha256=iKb6tj-VWPlDchHFjuQyep2Dpb-w2NGfJKt-WJG9LH0,3650
92
93
  langgraph_api/utils.py,sha256=92mSti9GfGdMRRWyESKQW5yV-75Z9icGHnIrBYvdypU,3619
93
94
  langgraph_api/validation.py,sha256=zMuKmwUEBjBgFMwAaeLZmatwGVijKv2sOYtYg7gfRtc,4950
94
95
  langgraph_api/webhook.py,sha256=1ncwO0rIZcj-Df9sxSnFEzd1gP1bfS4okeZQS8NSRoE,1382
95
96
  langgraph_api/worker.py,sha256=DX_EZZs47cfb4_1owBkjiq-Mrr2vUoeGjotWvKY21uc,11290
96
97
  langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
- langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2GA0,612
98
- langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZoj0,203
98
+ langgraph_license/validation.py,sha256=ZKraAVJArAABKqrmHN-EN18ncoNUmRm500Yt1Sc7tUA,537
99
99
  langgraph_runtime/__init__.py,sha256=O4GgSmu33c-Pr8Xzxj_brcK5vkm70iNTcyxEjICFZxA,1075
100
100
  logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
101
101
  openapi.json,sha256=YW4ND-N3adriEoNwxw7UD9endO2xUZoodCtwVIfa2dU,132261
102
- langgraph_api-0.1.8.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
103
- langgraph_api-0.1.8.dist-info/METADATA,sha256=IViZJZV9LMWXABYkk67fTMe60QkO2SWZY7VySU5j7RY,4119
104
- langgraph_api-0.1.8.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
105
- langgraph_api-0.1.8.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
106
- langgraph_api-0.1.8.dist-info/RECORD,,
102
+ langgraph_api-0.1.12.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
103
+ langgraph_api-0.1.12.dist-info/METADATA,sha256=tHjMcJDzWDlUf_b1lDt4szCHsPsktPZey48MG7m-ZoI,4120
104
+ langgraph_api-0.1.12.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
105
+ langgraph_api-0.1.12.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
106
+ langgraph_api-0.1.12.dist-info/RECORD,,
@@ -9,3 +9,14 @@ async def get_license_status() -> bool:
9
9
  def plus_features_enabled() -> bool:
10
10
  """Always return false"""
11
11
  return False
12
+
13
+
14
+ async def check_license_periodically(_: int = 60):
15
+ """
16
+ Periodically re-verify the license.
17
+ If the license ever fails, you could decide to log,
18
+ raise an exception, or attempt a graceful shutdown.
19
+ """
20
+ raise NotImplementedError(
21
+ "This is a noop license middleware. No license check is performed."
22
+ )
@@ -1,21 +0,0 @@
1
- """Middleware for license validation."""
2
-
3
- from typing import Any
4
-
5
- from starlette.middleware.base import BaseHTTPMiddleware
6
- from starlette.requests import Request
7
- from starlette.responses import Response
8
- from starlette.types import ASGIApp
9
-
10
-
11
- class LicenseValidationMiddleware(BaseHTTPMiddleware):
12
- """Noop license middleware"""
13
-
14
- def __init__(self, app: ASGIApp):
15
- """Initialize middleware."""
16
- super().__init__(app)
17
-
18
- async def dispatch(self, request: Request, call_next: Any) -> Response:
19
- """Noop middleware."""
20
- response = await call_next(request)
21
- return response