langgraph-api 0.0.48__tar.gz → 0.1.0__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 (105) hide show
  1. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/PKG-INFO +1 -1
  2. langgraph_api-0.1.0/langgraph_api/__init__.py +1 -0
  3. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/__init__.py +2 -2
  4. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/assistants.py +3 -3
  5. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/meta.py +9 -11
  6. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/runs.py +3 -3
  7. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/store.py +2 -2
  8. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/threads.py +3 -3
  9. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/cli.py +3 -1
  10. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/config.py +3 -0
  11. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/cron_scheduler.py +3 -3
  12. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/graph.py +2 -2
  13. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/remote.py +3 -3
  14. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/metadata.py +7 -0
  15. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/models/run.py +10 -1
  16. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/queue_entrypoint.py +1 -1
  17. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/server.py +2 -2
  18. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/stream.py +3 -3
  19. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/thread_ttl.py +2 -2
  20. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/worker.py +3 -3
  21. langgraph_api-0.1.0/langgraph_runtime/__init__.py +39 -0
  22. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/pyproject.toml +3 -2
  23. langgraph_api-0.0.48/langgraph_api/__init__.py +0 -1
  24. langgraph_api-0.0.48/langgraph_api/lifespan.py +0 -74
  25. langgraph_api-0.0.48/langgraph_storage/__init__.py +0 -0
  26. langgraph_api-0.0.48/langgraph_storage/checkpoint.py +0 -123
  27. langgraph_api-0.0.48/langgraph_storage/database.py +0 -200
  28. langgraph_api-0.0.48/langgraph_storage/inmem_stream.py +0 -109
  29. langgraph_api-0.0.48/langgraph_storage/ops.py +0 -2172
  30. langgraph_api-0.0.48/langgraph_storage/queue.py +0 -186
  31. langgraph_api-0.0.48/langgraph_storage/retry.py +0 -31
  32. langgraph_api-0.0.48/langgraph_storage/store.py +0 -100
  33. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/LICENSE +0 -0
  34. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/README.md +0 -0
  35. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/mcp.py +0 -0
  36. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/openapi.py +0 -0
  37. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/api/ui.py +0 -0
  38. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/asyncio.py +0 -0
  39. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/__init__.py +0 -0
  40. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/custom.py +0 -0
  41. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/langsmith/__init__.py +0 -0
  42. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/langsmith/backend.py +0 -0
  43. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/langsmith/client.py +0 -0
  44. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/middleware.py +0 -0
  45. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/noop.py +0 -0
  46. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/auth/studio_user.py +0 -0
  47. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/command.py +0 -0
  48. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/errors.py +0 -0
  49. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/http.py +0 -0
  50. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/.gitignore +0 -0
  51. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/base.py +0 -0
  52. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/build.mts +0 -0
  53. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/client.mts +0 -0
  54. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/errors.py +0 -0
  55. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/global.d.ts +0 -0
  56. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/package.json +0 -0
  57. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/schema.py +0 -0
  58. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/graph.mts +0 -0
  59. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/hooks.mjs +0 -0
  60. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/parser/parser.mts +0 -0
  61. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/parser/parser.worker.mjs +0 -0
  62. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/schema/types.mts +0 -0
  63. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/schema/types.template.mts +0 -0
  64. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/utils/importMap.mts +0 -0
  65. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  66. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/src/utils/serde.mts +0 -0
  67. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/sse.py +0 -0
  68. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/api.test.mts +0 -0
  69. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/compose-postgres.yml +0 -0
  70. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/.gitignore +0 -0
  71. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/agent.css +0 -0
  72. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/agent.mts +0 -0
  73. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/agent.ui.tsx +0 -0
  74. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/command.mts +0 -0
  75. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/delay.mts +0 -0
  76. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/dynamic.mts +0 -0
  77. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/error.mts +0 -0
  78. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/langgraph.json +0 -0
  79. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/nested.mts +0 -0
  80. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/package.json +0 -0
  81. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/weather.mts +0 -0
  82. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/graphs/yarn.lock +0 -0
  83. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/parser.test.mts +0 -0
  84. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/tests/utils.mts +0 -0
  85. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/ui.py +0 -0
  86. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/js/yarn.lock +0 -0
  87. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/logging.py +0 -0
  88. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/middleware/__init__.py +0 -0
  89. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/middleware/http_logger.py +0 -0
  90. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/middleware/private_network.py +0 -0
  91. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/models/__init__.py +0 -0
  92. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/patch.py +0 -0
  93. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/route.py +0 -0
  94. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/schema.py +0 -0
  95. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/serde.py +0 -0
  96. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/sse.py +0 -0
  97. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/state.py +0 -0
  98. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/utils.py +0 -0
  99. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/validation.py +0 -0
  100. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_api/webhook.py +0 -0
  101. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_license/__init__.py +0 -0
  102. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_license/middleware.py +0 -0
  103. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/langgraph_license/validation.py +0 -0
  104. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/logging.json +0 -0
  105. {langgraph_api-0.0.48 → langgraph_api-0.1.0}/openapi.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langgraph-api
3
- Version: 0.0.48
3
+ Version: 0.1.0
4
4
  Summary:
5
5
  License: Elastic-2.0
6
6
  Author: Nuno Campos
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -21,7 +21,7 @@ from langgraph_api.auth.middleware import auth_middleware
21
21
  from langgraph_api.config import HTTP_CONFIG, MIGRATIONS_PATH
22
22
  from langgraph_api.graph import js_bg_tasks
23
23
  from langgraph_api.validation import DOCS_HTML
24
- from langgraph_storage.database import connect, healthcheck
24
+ from langgraph_runtime.database import connect, healthcheck
25
25
 
26
26
  logger = structlog.stdlib.get_logger(__name__)
27
27
 
@@ -138,7 +138,7 @@ else:
138
138
  if "inmem" in MIGRATIONS_PATH:
139
139
 
140
140
  async def truncate(request: Request):
141
- from langgraph_storage.checkpoint import Checkpointer
141
+ from langgraph_runtime.checkpoint import Checkpointer
142
142
 
143
143
  await asyncio.to_thread(Checkpointer().clear)
144
144
  async with connect() as conn:
@@ -21,9 +21,9 @@ from langgraph_api.validation import (
21
21
  AssistantVersionChange,
22
22
  AssistantVersionsSearchRequest,
23
23
  )
24
- from langgraph_storage.database import connect
25
- from langgraph_storage.ops import Assistants
26
- from langgraph_storage.retry import retry_db
24
+ from langgraph_runtime.database import connect
25
+ from langgraph_runtime.ops import Assistants
26
+ from langgraph_runtime.retry import retry_db
27
27
 
28
28
  logger = structlog.stdlib.get_logger(__name__)
29
29
 
@@ -5,9 +5,9 @@ from starlette.responses import JSONResponse, PlainTextResponse
5
5
  from langgraph_api import config
6
6
  from langgraph_api.route import ApiRequest
7
7
  from langgraph_license.validation import plus_features_enabled
8
- from langgraph_storage.database import connect, pool_stats
9
- from langgraph_storage.ops import Runs
10
- from langgraph_storage.queue import WORKERS
8
+ from langgraph_runtime.database import connect, pool_stats
9
+ from langgraph_runtime.metrics import get_metrics
10
+ from langgraph_runtime.ops import Runs
11
11
 
12
12
  METRICS_FORMATS = {"prometheus", "json"}
13
13
 
@@ -32,20 +32,18 @@ async def meta_metrics(request: ApiRequest):
32
32
  format = "prometheus"
33
33
 
34
34
  # collect stats
35
- workers_max = config.N_JOBS_PER_WORKER
36
- workers_active = len(WORKERS)
37
- workers_available = workers_max - workers_active
35
+ metrics = get_metrics()
36
+ worker_metrics = metrics["workers"]
37
+ workers_max = worker_metrics["max"]
38
+ workers_active = worker_metrics["active"]
39
+ workers_available = worker_metrics["available"]
38
40
 
39
41
  if format == "json":
40
42
  async with connect() as conn:
41
43
  return JSONResponse(
42
44
  {
43
45
  **pool_stats(),
44
- "workers": {
45
- "max": workers_max,
46
- "active": workers_active,
47
- "available": workers_available,
48
- },
46
+ "workers": worker_metrics,
49
47
  "queue": await Runs.stats(conn),
50
48
  }
51
49
  )
@@ -22,9 +22,9 @@ from langgraph_api.validation import (
22
22
  RunsCancel,
23
23
  )
24
24
  from langgraph_license.validation import plus_features_enabled
25
- from langgraph_storage.database import connect
26
- from langgraph_storage.ops import Crons, Runs, Threads
27
- from langgraph_storage.retry import retry_db
25
+ from langgraph_runtime.database import connect
26
+ from langgraph_runtime.ops import Crons, Runs, Threads
27
+ from langgraph_runtime.retry import retry_db
28
28
 
29
29
 
30
30
  @retry_db
@@ -13,8 +13,8 @@ from langgraph_api.validation import (
13
13
  StorePutRequest,
14
14
  StoreSearchRequest,
15
15
  )
16
- from langgraph_storage.retry import retry_db
17
- from langgraph_storage.store import Store
16
+ from langgraph_runtime.retry import retry_db
17
+ from langgraph_runtime.store import Store
18
18
 
19
19
 
20
20
  def _validate_namespace(namespace: tuple[str, ...]) -> Response | None:
@@ -15,9 +15,9 @@ from langgraph_api.validation import (
15
15
  ThreadStateSearch,
16
16
  ThreadStateUpdate,
17
17
  )
18
- from langgraph_storage.database import connect
19
- from langgraph_storage.ops import Threads
20
- from langgraph_storage.retry import retry_db
18
+ from langgraph_runtime.database import connect
19
+ from langgraph_runtime.ops import Threads
20
+ from langgraph_runtime.retry import retry_db
21
21
 
22
22
 
23
23
  @retry_db
@@ -6,6 +6,7 @@ import pathlib
6
6
  import threading
7
7
  import typing
8
8
  from collections.abc import Mapping, Sequence
9
+ from typing import Literal
9
10
 
10
11
  from typing_extensions import TypedDict
11
12
 
@@ -134,6 +135,7 @@ def run_server(
134
135
  studio_url: str | None = None,
135
136
  disable_persistence: bool = False,
136
137
  allow_blocking: bool = False,
138
+ runtime_edition: Literal["inmem", "community", "postgres"] = "inmem",
137
139
  **kwargs: typing.Any,
138
140
  ):
139
141
  """Run the LangGraph API server."""
@@ -197,6 +199,7 @@ def run_server(
197
199
  LANGGRAPH_UI_BUNDLER="true",
198
200
  LANGGRAPH_API_URL=local_url,
199
201
  LANGGRAPH_DISABLE_FILE_PERSISTENCE=str(disable_persistence).lower(),
202
+ LANGGRAPH_RUNTIME_EDITION=runtime_edition,
200
203
  # If true, we will not raise on blocking IO calls (via blockbuster)
201
204
  LANGGRAPH_ALLOW_BLOCKING=str(allow_blocking).lower(),
202
205
  # See https://developer.chrome.com/blog/private-network-access-update-2024-03
@@ -274,7 +277,6 @@ For production use, please use LangGraph Cloud.
274
277
 
275
278
  """
276
279
  logger.info(welcome)
277
-
278
280
  if open_browser:
279
281
  threading.Thread(target=_open_browser, daemon=True).start()
280
282
  supported_kwargs = {
@@ -323,6 +323,9 @@ USES_INDEXING = (
323
323
  and STORE_CONFIG.get("index").get("embed")
324
324
  )
325
325
  USES_CUSTOM_APP = HTTP_CONFIG and HTTP_CONFIG.get("app")
326
+ USES_CUSTOM_AUTH = bool(LANGGRAPH_AUTH)
327
+ USES_THREAD_TTL = bool(THREAD_TTL)
328
+ USES_STORE_TTL = bool(STORE_CONFIG and STORE_CONFIG.get("ttl"))
326
329
 
327
330
  API_VARIANT = env("LANGSMITH_LANGGRAPH_API_VARIANT", cast=str, default="")
328
331
 
@@ -7,9 +7,9 @@ from langchain_core.runnables.config import run_in_executor
7
7
  from langgraph_api.models.run import create_valid_run
8
8
  from langgraph_api.utils import next_cron_date
9
9
  from langgraph_api.worker import set_auth_ctx_for_run
10
- from langgraph_storage.database import connect
11
- from langgraph_storage.ops import Crons
12
- from langgraph_storage.retry import retry_db
10
+ from langgraph_runtime.database import connect
11
+ from langgraph_runtime.ops import Crons
12
+ from langgraph_runtime.retry import retry_db
13
13
 
14
14
  logger = structlog.stdlib.get_logger(__name__)
15
15
 
@@ -50,8 +50,8 @@ async def register_graph(
50
50
  description: str | None = None,
51
51
  ) -> None:
52
52
  """Register a graph."""
53
- from langgraph_storage.database import connect
54
- from langgraph_storage.ops import Assistants
53
+ from langgraph_runtime.database import connect
54
+ from langgraph_runtime.ops import Assistants
55
55
 
56
56
  await logger.ainfo(f"Registering graph with id '{graph_id}'", graph_id=graph_id)
57
57
  GRAPHS[graph_id] = graph
@@ -365,7 +365,7 @@ async def run_js_process(paths_str: str, watch: bool = False):
365
365
 
366
366
 
367
367
  def _get_passthrough_checkpointer(conn: AsyncConnectionProto):
368
- from langgraph_storage.checkpoint import Checkpointer
368
+ from langgraph_runtime.checkpoint import Checkpointer
369
369
 
370
370
  class PassthroughSerialiser(SerializerProtocol):
371
371
  def dumps(self, obj: Any) -> bytes:
@@ -393,7 +393,7 @@ def _get_passthrough_checkpointer(conn: AsyncConnectionProto):
393
393
 
394
394
 
395
395
  def _get_passthrough_store():
396
- from langgraph_storage.store import Store
396
+ from langgraph_runtime.store import Store
397
397
 
398
398
  return Store()
399
399
 
@@ -401,7 +401,7 @@ def _get_passthrough_store():
401
401
  # Setup a HTTP server on top of CHECKPOINTER_SOCKET unix socket
402
402
  # used by `client.mts` to communicate with the Python checkpointer
403
403
  async def run_remote_checkpointer():
404
- from langgraph_storage.database import connect
404
+ from langgraph_runtime.database import connect
405
405
 
406
406
  async def checkpointer_list(payload: dict):
407
407
  """Search checkpoints"""
@@ -11,7 +11,10 @@ from langgraph_api.config import (
11
11
  LANGSMITH_API_KEY,
12
12
  LANGSMITH_AUTH_ENDPOINT,
13
13
  USES_CUSTOM_APP,
14
+ USES_CUSTOM_AUTH,
14
15
  USES_INDEXING,
16
+ USES_STORE_TTL,
17
+ USES_THREAD_TTL,
15
18
  )
16
19
  from langgraph_api.http import http_request
17
20
  from langgraph_license.validation import plus_features_enabled
@@ -95,8 +98,12 @@ async def metadata_loop() -> None:
95
98
  "langgraph.platform.variant": VARIANT,
96
99
  "langgraph.platform.host": HOST,
97
100
  "langgraph.platform.plan": PLAN,
101
+ # user app features
98
102
  "user_app.uses_indexing": USES_INDEXING,
99
103
  "user_app.uses_custom_app": USES_CUSTOM_APP,
104
+ "user_app.uses_custom_auth": USES_CUSTOM_AUTH,
105
+ "user_app.uses_thread_ttl": USES_THREAD_TTL,
106
+ "user_app.uses_store_ttl": USES_STORE_TTL,
100
107
  },
101
108
  "measures": {
102
109
  "langgraph.platform.runs": runs,
@@ -23,7 +23,7 @@ from langgraph_api.schema import (
23
23
  StreamMode,
24
24
  )
25
25
  from langgraph_api.utils import AsyncConnectionProto, get_auth_ctx
26
- from langgraph_storage.ops import Runs, logger
26
+ from langgraph_runtime.ops import Runs, logger
27
27
 
28
28
 
29
29
  class RunCreateDict(TypedDict):
@@ -177,6 +177,15 @@ async def create_valid_run(
177
177
  payload,
178
178
  run_id=run_id,
179
179
  )
180
+ if (
181
+ thread_id is None
182
+ and (command := payload.get("command"))
183
+ and command.get("resume")
184
+ ):
185
+ raise HTTPException(
186
+ status_code=400,
187
+ detail="You must provide a thread_id when resuming.",
188
+ )
180
189
  temporary = thread_id is None and payload.get("on_completion", "delete") == "delete"
181
190
  stream_mode, multitask_strategy, prevent_insert_if_inflight = assign_defaults(
182
191
  payload
@@ -8,7 +8,7 @@ import pathlib
8
8
  import structlog
9
9
  import uvloop
10
10
 
11
- from langgraph_api.lifespan import lifespan
11
+ from langgraph_runtime.lifespan import lifespan
12
12
 
13
13
  logger = structlog.stdlib.get_logger(__name__)
14
14
 
@@ -22,12 +22,12 @@ from langgraph_api.errors import (
22
22
  validation_error_handler,
23
23
  value_error_handler,
24
24
  )
25
- from langgraph_api.lifespan import lifespan
25
+ from langgraph_runtime.lifespan import lifespan
26
26
  from langgraph_api.middleware.http_logger import AccessLoggerMiddleware
27
27
  from langgraph_api.middleware.private_network import PrivateNetworkMiddleware
28
28
  from langgraph_api.utils import SchemaGenerator
29
29
  from langgraph_license.middleware import LicenseValidationMiddleware
30
- from langgraph_storage.retry import OVERLOADED_EXCEPTIONS
30
+ from langgraph_runtime.retry import OVERLOADED_EXCEPTIONS
31
31
  from langgraph_sdk.client import configure_loopback_transports
32
32
 
33
33
  logging.captureWarnings(True)
@@ -30,9 +30,9 @@ from langgraph_api.metadata import HOST, PLAN, USER_API_URL, incr_nodes
30
30
  from langgraph_api.schema import Run, StreamMode
31
31
  from langgraph_api.serde import json_dumpb
32
32
  from langgraph_api.utils import AsyncConnectionProto
33
- from langgraph_storage.checkpoint import Checkpointer
34
- from langgraph_storage.ops import Runs
35
- from langgraph_storage.store import Store
33
+ from langgraph_runtime.checkpoint import Checkpointer
34
+ from langgraph_runtime.ops import Runs
35
+ from langgraph_runtime.store import Store
36
36
 
37
37
  logger = structlog.stdlib.get_logger(__name__)
38
38
 
@@ -5,7 +5,7 @@ import asyncio
5
5
  import structlog
6
6
 
7
7
  from langgraph_api.config import THREAD_TTL
8
- from langgraph_storage.database import connect
8
+ from langgraph_runtime.database import connect
9
9
 
10
10
  logger = structlog.stdlib.get_logger(__name__)
11
11
 
@@ -30,7 +30,7 @@ async def thread_ttl_sweep_loop():
30
30
  interval_minutes=sweep_interval_minutes,
31
31
  )
32
32
 
33
- from langgraph_storage.ops import Threads
33
+ from langgraph_runtime.ops import Threads
34
34
 
35
35
  while True:
36
36
  await asyncio.sleep(sweep_interval_minutes * 60)
@@ -26,9 +26,9 @@ from langgraph_api.stream import (
26
26
  consume,
27
27
  )
28
28
  from langgraph_api.utils import set_auth_ctx, with_user
29
- from langgraph_storage.database import connect
30
- from langgraph_storage.ops import Runs, Threads
31
- from langgraph_storage.retry import RETRIABLE_EXCEPTIONS
29
+ from langgraph_runtime.database import connect
30
+ from langgraph_runtime.ops import Runs, Threads
31
+ from langgraph_runtime.retry import RETRIABLE_EXCEPTIONS
32
32
 
33
33
  try:
34
34
  from psycopg.errors import InFailedSqlTransaction
@@ -0,0 +1,39 @@
1
+ import importlib.util
2
+ import os
3
+ import sys
4
+
5
+ import structlog
6
+
7
+ logger = structlog.stdlib.get_logger(__name__)
8
+
9
+ try:
10
+ RUNTIME_EDITION = os.environ["LANGGRAPH_RUNTIME_EDITION"]
11
+ RUNTIME_PACKAGE = f"langgraph_runtime_{RUNTIME_EDITION}"
12
+ except KeyError:
13
+ raise ValueError(
14
+ "LANGGRAPH_RUNTIME_EDITION environment variable is not set."
15
+ " Expected LANGGRAPH_RUNTIME_EDITION to be set to one of:\n"
16
+ " - inmem\n"
17
+ " - postgres\n"
18
+ " - community\n"
19
+ ) from None
20
+ if importlib.util.find_spec(RUNTIME_PACKAGE):
21
+ backend = importlib.import_module(RUNTIME_PACKAGE)
22
+ logger.info(f"Using {RUNTIME_PACKAGE}")
23
+ else:
24
+ raise ImportError(
25
+ "Langgraph runtime backend not found. Please install with "
26
+ f'`pip install "langgraph-runtime[{RUNTIME_EDITION}"`'
27
+ ) from None
28
+
29
+ # All runtime backends share the same API
30
+ for module_name in (
31
+ "checkpoint",
32
+ "database",
33
+ "lifespan",
34
+ "ops",
35
+ "retry",
36
+ "store",
37
+ "metrics",
38
+ ):
39
+ sys.modules["langgraph_runtime." + module_name] = getattr(backend, module_name)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "langgraph-api"
3
- version = "0.0.48"
3
+ version = "0.1.0"
4
4
  description = ""
5
5
  authors = [
6
6
  "Nuno Campos <nuno@langchain.dev>",
@@ -9,7 +9,7 @@ authors = [
9
9
  license = "Elastic-2.0"
10
10
  packages = [
11
11
  { include = "langgraph_api" },
12
- { include = "langgraph_storage" },
12
+ { include = "langgraph_runtime" },
13
13
  { include = "langgraph_license" },
14
14
  ]
15
15
  readme = "README.md"
@@ -65,6 +65,7 @@ pytest-httpserver = "^1.1.0"
65
65
  fastapi = "^0.115.8"
66
66
  langgraph = ">=0.3.17"
67
67
  pycryptodome = "^3.22.0"
68
+ langgraph-runtime-inmem = { path = "../runtime_inmem", develop = true, python = ">=3.11,<4.0" }
68
69
 
69
70
  [tool.poetry_bumpversion.file."langgraph_api/__init__.py"]
70
71
  search = '__version__ = "{current_version}"'
@@ -1 +0,0 @@
1
- __version__ = "0.0.46"
@@ -1,74 +0,0 @@
1
- import asyncio
2
- from contextlib import asynccontextmanager
3
-
4
- import structlog
5
- from langchain_core.runnables.config import var_child_runnable_config
6
- from langgraph.constants import CONF, CONFIG_KEY_STORE
7
- from starlette.applications import Starlette
8
-
9
- import langgraph_api.config as config
10
- from langgraph_api.asyncio import SimpleTaskGroup, set_event_loop
11
- from langgraph_api.cron_scheduler import cron_scheduler
12
- from langgraph_api.graph import collect_graphs_from_env, stop_remote_graphs
13
- from langgraph_api.http import start_http_client, stop_http_client
14
- from langgraph_api.js.ui import start_ui_bundler, stop_ui_bundler
15
- from langgraph_api.metadata import metadata_loop
16
- from langgraph_api.thread_ttl import thread_ttl_sweep_loop
17
- from langgraph_license.validation import get_license_status, plus_features_enabled
18
- from langgraph_storage.database import start_pool, stop_pool
19
- from langgraph_storage.queue import queue
20
- from langgraph_storage.store import Store
21
-
22
- logger = structlog.stdlib.get_logger(__name__)
23
-
24
-
25
- @asynccontextmanager
26
- async def lifespan(
27
- app: Starlette | None = None,
28
- with_cron_scheduler: bool = True,
29
- taskset: set[asyncio.Task] | None = None,
30
- ):
31
- try:
32
- current_loop = asyncio.get_running_loop()
33
- set_event_loop(current_loop)
34
- except RuntimeError:
35
- await logger.aerror("Failed to set loop")
36
-
37
- if not await get_license_status():
38
- raise ValueError(
39
- "License verification failed. Please ensure proper configuration:\n"
40
- "- For local development, set a valid LANGSMITH_API_KEY for an account with LangGraph Cloud access "
41
- "in the environment defined in your langgraph.json file.\n"
42
- "- For production, configure the LANGGRAPH_CLOUD_LICENSE_KEY environment variable "
43
- "with your LangGraph Cloud license key.\n"
44
- "Review your configuration settings and try again. If issues persist, "
45
- "contact support for assistance."
46
- )
47
- await start_http_client()
48
- await start_pool()
49
- await collect_graphs_from_env(True)
50
- await start_ui_bundler()
51
- try:
52
- async with SimpleTaskGroup(
53
- cancel=True, taskset=taskset, taskgroup_name="Lifespan"
54
- ) as tg:
55
- tg.create_task(metadata_loop())
56
- if config.N_JOBS_PER_WORKER > 0:
57
- tg.create_task(queue())
58
- if (
59
- with_cron_scheduler
60
- and config.FF_CRONS_ENABLED
61
- and plus_features_enabled()
62
- ):
63
- tg.create_task(cron_scheduler())
64
- store = Store()
65
- tg.create_task(Store().start_ttl_sweeper())
66
- tg.create_task(thread_ttl_sweep_loop())
67
- var_child_runnable_config.set({CONF: {CONFIG_KEY_STORE: store}})
68
-
69
- yield
70
- finally:
71
- await stop_ui_bundler()
72
- await stop_remote_graphs()
73
- await stop_http_client()
74
- await stop_pool()
File without changes
@@ -1,123 +0,0 @@
1
- import logging
2
- import os
3
- import uuid
4
-
5
- from langchain_core.runnables import RunnableConfig
6
- from langgraph.checkpoint.base import (
7
- Checkpoint,
8
- CheckpointMetadata,
9
- CheckpointTuple,
10
- SerializerProtocol,
11
- )
12
- from langgraph.checkpoint.memory import MemorySaver, PersistentDict
13
-
14
- from langgraph_api.serde import Serializer
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
- _EXCLUDED_KEYS = {"checkpoint_ns", "checkpoint_id", "run_id", "thread_id"}
19
- DISABLE_FILE_PERSISTENCE = (
20
- os.getenv("LANGGRAPH_DISABLE_FILE_PERSISTENCE", "false").lower() == "true"
21
- )
22
-
23
-
24
- class InMemorySaver(MemorySaver):
25
- def __init__(
26
- self,
27
- *,
28
- serde: SerializerProtocol | None = None,
29
- ) -> None:
30
- self.filename = os.path.join(".langgraph_api", ".langgraph_checkpoint.")
31
- i = 0
32
-
33
- def factory(*args):
34
- nonlocal i
35
- i += 1
36
-
37
- thisfname = self.filename + str(i) + ".pckl"
38
- d = PersistentDict(*args, filename=thisfname)
39
- if not os.path.exists(".langgraph_api"):
40
- os.mkdir(".langgraph_api")
41
- try:
42
- d.load()
43
- except FileNotFoundError:
44
- pass
45
- except ModuleNotFoundError:
46
- logger.error(
47
- "Unable to load cached data - your code has changed in a way that's incompatible with the cache."
48
- "\nThis usually happens when you've:"
49
- "\n - Renamed or moved classes"
50
- "\n - Changed class structures"
51
- "\n - Pulled updates that modified class definitions in a way that's incompatible with the cache"
52
- "\n\nRemoving invalid cache data stored at path: .langgraph_api"
53
- )
54
- os.remove(self.filename)
55
- except Exception as e:
56
- logger.error("Failed to load cached data: %s", str(e))
57
- os.remove(self.filename)
58
- return d
59
-
60
- super().__init__(
61
- serde=serde if serde is not None else Serializer(),
62
- factory=factory if not DISABLE_FILE_PERSISTENCE else None,
63
- )
64
-
65
- def put(
66
- self,
67
- config: RunnableConfig,
68
- checkpoint: Checkpoint,
69
- metadata: CheckpointMetadata,
70
- new_versions: dict[str, str | int | float],
71
- ) -> RunnableConfig:
72
- # TODO: Should this be done in OSS as well?
73
- metadata = {
74
- **{
75
- k: v
76
- for k, v in config["configurable"].items()
77
- if not k.startswith("__") and k not in _EXCLUDED_KEYS
78
- },
79
- **config.get("metadata", {}),
80
- **metadata,
81
- }
82
- if not isinstance(checkpoint["id"], uuid.UUID):
83
- # Avoid type inconsistencies
84
- checkpoint = checkpoint.copy()
85
- checkpoint["id"] = str(checkpoint["id"])
86
- return super().put(config, checkpoint, metadata, new_versions)
87
-
88
- def get_tuple(self, config: RunnableConfig) -> CheckpointTuple | None:
89
- if isinstance(config["configurable"].get("checkpoint_id"), uuid.UUID):
90
- # Avoid type inconsistencies....
91
- config = config.copy()
92
-
93
- config["configurable"] = {
94
- **config["configurable"],
95
- "checkpoint_id": str(config["configurable"]["checkpoint_id"]),
96
- }
97
- return super().get_tuple(config)
98
-
99
- def clear(self):
100
- self.storage.clear()
101
- self.writes.clear()
102
- for suffix in ["1", "2"]:
103
- file_path = f"{self.filename}{suffix}.pckl"
104
- if os.path.exists(file_path):
105
- os.remove(file_path)
106
-
107
-
108
- MEMORY = InMemorySaver()
109
-
110
-
111
- def Checkpointer(*args, unpack_hook=None, **kwargs):
112
- if unpack_hook is not None:
113
- saver = InMemorySaver(
114
- serde=Serializer(__unpack_ext_hook__=unpack_hook), **kwargs
115
- )
116
- saver.writes = MEMORY.writes
117
- saver.blobs = MEMORY.blobs
118
- saver.storage = MEMORY.storage
119
- return saver
120
- return MEMORY
121
-
122
-
123
- __all__ = ["Checkpointer"]