langgraph-api 0.12.0.dev18__py3-none-any.whl → 0.12.0.dev20__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.
langgraph_api/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.12.0.dev18"
1
+ __version__ = "0.12.0.dev20"
langgraph_api/api/runs.py CHANGED
@@ -787,7 +787,9 @@ async def create_cron(request: ApiRequest):
787
787
 
788
788
  enabled = payload.get("enabled", True)
789
789
 
790
- async with connect(supports_core_api=False) as conn:
790
+ # gRPC/postgres Crons route through core-api and ignore ``conn`` (the default
791
+ # ``connect()`` yields None there); inmem uses the yielded connection.
792
+ async with connect() as conn:
791
793
  cron = await Crons.put(
792
794
  conn,
793
795
  thread_id=None,
@@ -834,7 +836,7 @@ async def create_thread_cron(request: ApiRequest):
834
836
  CRON_PAYLOAD_ENCRYPTION_SUBFIELDS,
835
837
  )
836
838
 
837
- async with connect(supports_core_api=False) as conn:
839
+ async with connect() as conn:
838
840
  cron = await Crons.put(
839
841
  conn,
840
842
  thread_id=thread_id,
@@ -890,7 +892,7 @@ async def patch_cron(request: ApiRequest):
890
892
  CRON_PAYLOAD_ENCRYPTION_SUBFIELDS,
891
893
  )
892
894
 
893
- async with connect(supports_core_api=False) as conn:
895
+ async with connect() as conn:
894
896
  cron = await Crons.update(
895
897
  conn,
896
898
  cron_id=cron_id,
@@ -917,7 +919,7 @@ async def delete_cron(request: ApiRequest):
917
919
  validate_uuid(cron_id, "Invalid cron ID: must be a UUID")
918
920
 
919
921
  try:
920
- async with connect(supports_core_api=False) as conn:
922
+ async with connect() as conn:
921
923
  cid = await Crons.delete(
922
924
  conn,
923
925
  cron_id=cron_id,
@@ -940,7 +942,7 @@ async def search_crons(request: ApiRequest):
940
942
  validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
941
943
 
942
944
  offset = int(payload.get("offset", 0))
943
- async with connect(supports_core_api=False) as conn:
945
+ async with connect() as conn:
944
946
  crons_iter, next_offset = await Crons.search(
945
947
  conn,
946
948
  assistant_id=assistant_id,
@@ -972,7 +974,7 @@ async def count_crons(request: ApiRequest):
972
974
  if thread_id := payload.get("thread_id"):
973
975
  validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
974
976
 
975
- async with connect(supports_core_api=False) as conn:
977
+ async with connect() as conn:
976
978
  count = await Crons.count(
977
979
  conn,
978
980
  assistant_id=assistant_id,
@@ -13,7 +13,10 @@ from langgraph_api.encryption.shared import (
13
13
  using_aes_encryption,
14
14
  using_custom_encryption,
15
15
  )
16
- from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
16
+ from langgraph_api.feature_flags import (
17
+ IS_POSTGRES_OR_GRPC_BACKEND,
18
+ PREFER_GRPC_CHECKPOINTER,
19
+ )
17
20
  from langgraph_api.route import ApiRequest, ApiResponse, ApiRoute
18
21
  from langgraph_api.schema import (
19
22
  THREAD_ENCRYPTION_FIELDS,
@@ -82,7 +85,7 @@ async def create_thread(
82
85
  )
83
86
  else:
84
87
  # Need connection for inmem put or gRPC State.bulk
85
- async with connect(supports_core_api=False) as conn:
88
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
86
89
  iter = await Threads.put(
87
90
  conn,
88
91
  thread_id,
@@ -226,7 +229,7 @@ async def get_thread_state(
226
229
  thread_id = request.path_params["thread_id"]
227
230
  validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
228
231
  subgraphs = request.query_params.get("subgraphs") in ("true", "True")
229
- async with connect(supports_core_api=False) as conn:
232
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
230
233
  config = {
231
234
  "configurable": {
232
235
  **get_configurable_headers(request.headers),
@@ -247,7 +250,7 @@ async def get_thread_state_at_checkpoint(
247
250
  thread_id = request.path_params["thread_id"]
248
251
  validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
249
252
  checkpoint_id = request.path_params["checkpoint_id"]
250
- async with connect(supports_core_api=False) as conn:
253
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
251
254
  config = {
252
255
  "configurable": {
253
256
  **get_configurable_headers(request.headers),
@@ -273,7 +276,7 @@ async def get_thread_state_at_checkpoint_post(
273
276
  thread_id = request.path_params["thread_id"]
274
277
  validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
275
278
  payload = await request.json(ThreadStateCheckpointRequest)
276
- async with connect(supports_core_api=False) as conn:
279
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
277
280
  config = {
278
281
  "configurable": {
279
282
  **payload["checkpoint"],
@@ -311,7 +314,7 @@ async def update_thread_state(
311
314
  pass
312
315
  config["configurable"].update(get_configurable_headers(request.headers))
313
316
  config["configurable"]["thread_id"] = thread_id
314
- async with connect(supports_core_api=False) as conn:
317
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
315
318
  inserted = await Threads.State.post(
316
319
  conn,
317
320
  config,
@@ -341,7 +344,7 @@ async def get_thread_history(
341
344
  **get_configurable_headers(request.headers),
342
345
  }
343
346
  }
344
- async with connect(supports_core_api=False) as conn:
347
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
345
348
  states = [
346
349
  state_snapshot_to_thread_state(c)
347
350
  for c in await Threads.State.list(
@@ -363,7 +366,7 @@ async def get_thread_history_post(
363
366
  config["configurable"].update(payload.get("checkpoint", {}))
364
367
  config["configurable"].update(get_configurable_headers(request.headers))
365
368
  config["configurable"]["thread_id"] = thread_id
366
- async with connect(supports_core_api=False) as conn:
369
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
367
370
  states = [
368
371
  state_snapshot_to_thread_state(c)
369
372
  for c in await Threads.State.list(
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Annotated, Literal, TypeVar, cast
4
4
 
5
5
  import structlog
6
6
  from pydantic.functional_validators import AfterValidator
7
- from starlette.config import Config, undefined
7
+ from starlette.config import Config
8
8
  from starlette.datastructures import CommaSeparatedStrings
9
9
 
10
10
  from langgraph_api import traceblock
@@ -41,7 +41,14 @@ STATS_INTERVAL_SECS = env("STATS_INTERVAL_SECS", cast=int, default=60)
41
41
  # storage
42
42
 
43
43
  # Not in public docs: infrastructure, set by platform
44
- DATABASE_URI = env("DATABASE_URI", cast=str, default=getenv("POSTGRES_URI", undefined))
44
+ # Optional: persistence can go through the Go core over gRPC, so the Python
45
+ # runtime can start without a direct DB connection string. When unset, the
46
+ # Postgres runtime skips creating a psycopg pool (see database._startup_needs /
47
+ # database.start_pool). Callers that still require a direct connection fail
48
+ # loudly via connect()'s "Postgres pool not initialized" guard.
49
+ DATABASE_URI: str | None = env(
50
+ "DATABASE_URI", cast=str, default=getenv("POSTGRES_URI", None)
51
+ )
45
52
  # Not in public docs: infrastructure, set by platform
46
53
  MIGRATIONS_PATH = env("MIGRATIONS_PATH", cast=str, default="/storage/migrations")
47
54
  POSTGRES_POOL_MAX_SIZE = env("LANGGRAPH_POSTGRES_POOL_MAX_SIZE", cast=int, default=150)
@@ -246,6 +253,10 @@ STORE_CONFIG = env(
246
253
  LANGGRAPH_STORE_BACKEND = env("LANGGRAPH_STORE_BACKEND", cast=str, default="python")
247
254
  USE_GRPC_STORE = LANGGRAPH_STORE_BACKEND == "grpc"
248
255
 
256
+ # When true, the Go core-server owns Postgres schema setup (DB migrations +
257
+ # vector index)
258
+ DB_MIGRATION_BY_CORE_API = env("DB_MIGRATION_BY_CORE_API", cast=bool, default=False)
259
+
249
260
 
250
261
  def _validate_mount_prefix(mount_prefix: str | None) -> str | None:
251
262
  if not mount_prefix:
@@ -642,6 +653,7 @@ __all__ = [
642
653
  "CRON_SCHEDULER_SLEEP_TIME",
643
654
  "DATABASE_URI",
644
655
  "DATADOG_METRICS_ENABLED",
656
+ "DB_MIGRATION_BY_CORE_API",
645
657
  "EXPOSE_INTERNAL_METRICS_PROMETHEUS",
646
658
  "FF_CRONS_ENABLED",
647
659
  "FF_LOG_DROPPED_EVENTS",
@@ -43,7 +43,7 @@ from langgraph_api.event_streaming.session import (
43
43
  _is_supported_channel,
44
44
  )
45
45
  from langgraph_api.event_streaming.types import Subscription
46
- from langgraph_api.feature_flags import FF_V2_EVENT_STREAMING
46
+ from langgraph_api.feature_flags import FF_V2_EVENT_STREAMING, PREFER_GRPC_CHECKPOINTER
47
47
  from langgraph_api.schema import MultitaskStrategy
48
48
 
49
49
  logger = structlog.stdlib.get_logger(__name__)
@@ -962,11 +962,11 @@ class ThreadRunManager:
962
962
  async def get_thread_state() -> dict[str, Any] | None:
963
963
  from langgraph_runtime.database import connect # noqa: PLC0415
964
964
 
965
- # ``supports_core_api=False`` so the postgres backend yields a
966
- # real connection. ``State.get`` uses the local checkpointer
967
- # and needs a usable ``conn`` the default flag yields None.
965
+ # When ``PREFER_GRPC_CHECKPOINTER`` is false the postgres backend
966
+ # yields a real connection for the Python checkpointer; when true
967
+ # it yields a no-op stand-in and checkpoint I/O goes through gRPC.
968
968
  try:
969
- async with connect(supports_core_api=False) as conn:
969
+ async with connect(supports_core_api=PREFER_GRPC_CHECKPOINTER) as conn:
970
970
  return await self._threads.State.get(
971
971
  conn,
972
972
  {"configurable": {"thread_id": thread_id}},
langgraph_api/worker.py CHANGED
@@ -25,7 +25,10 @@ from langgraph_api.encryption.middleware import (
25
25
  extract_blob_encryption_context,
26
26
  )
27
27
  from langgraph_api.errors import UserInterrupt, UserRollback, UserTimeout
28
- from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
28
+ from langgraph_api.feature_flags import (
29
+ IS_POSTGRES_OR_GRPC_BACKEND,
30
+ PREFER_GRPC_CHECKPOINTER,
31
+ )
29
32
  from langgraph_api.graph import restore_dd_trace_context
30
33
  from langgraph_api.js.errors import RemoteException
31
34
  from langgraph_api.metadata import incr_runs
@@ -319,9 +322,11 @@ async def worker(
319
322
  run_attempt=attempt,
320
323
  )
321
324
  try:
322
- # We actually still need a connection for the python checkpointer
323
- # This only doubles up connections for inmem which is fine
324
- async with connect(supports_core_api=False) as conn:
325
+ # Python checkpointer needs a real PG conn; gRPC checkpointer
326
+ # does not. This only doubles up connections for inmem.
327
+ async with connect(
328
+ supports_core_api=PREFER_GRPC_CHECKPOINTER
329
+ ) as conn:
325
330
  state_snapshot = await Threads.State.get(
326
331
  conn, run["kwargs"]["config"], subgraphs=False
327
332
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.12.0.dev18
3
+ Version: 0.12.0.dev20
4
4
  Author-email: Will Fu-Hinthorn <will@langchain.dev>, Josh Rogers <josh@langchain.dev>, Parker Rule <parker@langchain.dev>
5
5
  License: Elastic-2.0
6
6
  License-File: LICENSE
@@ -1,4 +1,4 @@
1
- langgraph_api/__init__.py,sha256=xTAqwHUE03gcPAzIvvqKQymgYred-UsTnKPtZxRYLq0,29
1
+ langgraph_api/__init__.py,sha256=TKIcjxx-9aUyZmSvMeXz-Ek1FK_EguTANVH7RKLIqQA,29
2
2
  langgraph_api/_factory_utils.py,sha256=5JsiJbg_YocVSryN2jwoZTg03-eyymlWMK6sKCmXwz0,5756
3
3
  langgraph_api/asgi_transport.py,sha256=XApY3lIWBZTMbbsl8dDJzl0cLGirmAGE0SifqZUnXvs,11896
4
4
  langgraph_api/asyncio.py,sha256=smqyAoO9nIyPPQRw1IVSCh85fwoZP4PEo-5dDhxGruc,10676
@@ -35,7 +35,7 @@ langgraph_api/traceblock.py,sha256=GhgAtLhAQ8Z8LHtRQq3par-rfPpRBQp2Q7WBACJq1NI,6
35
35
  langgraph_api/tracing_session.py,sha256=gmfv-BW1XRar6suVur1P4rTVKWkjElDEb2hhkBduWOs,728
36
36
  langgraph_api/validation.py,sha256=XyeKyt7jAICmIlT_b0J0mv2YbwIbNoe4m6zEmfk9gOA,14657
37
37
  langgraph_api/webhook.py,sha256=qXEtkE6orek2POeOQmPRsEarJgXIYp-LBrZB-OwITxc,9572
38
- langgraph_api/worker.py,sha256=HGirbQ1i1hxaayORoihsQ6JMVAq3VsrC8CUxAHwY9t0,21151
38
+ langgraph_api/worker.py,sha256=zWd14iZ9m9TLb9yD_QwTMxHcfM8dd3bhKtM1lz86M80,21256
39
39
  langgraph_api/_checkpointer/__init__.py,sha256=ofJTJLGy7Hsuzhj-2dpfDvrDloM0BzlhTzvZOdR9K8U,2223
40
40
  langgraph_api/_checkpointer/_adapter.py,sha256=1jJi0vXoNKeCwNP26W8bmYrwe-fOWFqepnovYFt14W0,21782
41
41
  langgraph_api/_checkpointer/protocol.py,sha256=udgYKMNtKWG_eLDwYkHXV3b2bZLZg8Rsfm3fjkhU-rU,3635
@@ -46,9 +46,9 @@ langgraph_api/api/event_streaming.py,sha256=nvoaKz4QGklX5YUmY9WQ3vSwhQ1Q81QeQWNR
46
46
  langgraph_api/api/meta.py,sha256=5s017GfMs-Ghq6Z5K6yW4UjbVFzCsmeXKn4UEJmfs98,4757
47
47
  langgraph_api/api/openapi.py,sha256=Zkdlb9mjrQyHro1TtrDIWVuaBDovxx-uGWJ1fZMOg54,12604
48
48
  langgraph_api/api/profile.py,sha256=CA1ZkHALOuP8orYTICnEhcG_JnnA2wnyjbWyeb117jA,3455
49
- langgraph_api/api/runs.py,sha256=h5droLgaz_aAyILCRJIpbj2KH1PbijCeXcggOSa3Zww,35178
49
+ langgraph_api/api/runs.py,sha256=eqaeSUXg0mKROEyGTG7ur6RdSFHKIq6hMDEiYxO2R7Q,35197
50
50
  langgraph_api/api/store.py,sha256=Y5bMwi03nljlVCiiN91TGkiZj5iUITO68uyctBdYLhE,6656
51
- langgraph_api/api/threads.py,sha256=fNFRiXckglF_HyX9poJ2h0on9QeA-YRiVpZ0g-Z9b3w,19606
51
+ langgraph_api/api/threads.py,sha256=atUJnC49tpdhx80OdyzT6NNV3J0pN1R1e4nq7qeXD6c,19778
52
52
  langgraph_api/api/ui.py,sha256=RalnZm1HArbC2X7fYCFtNeTJpSOQCzkLrdA0lcVmWQw,2695
53
53
  langgraph_api/api/mcp/__init__.py,sha256=T9W88PH9OqQtnjP7eFFa_163pFulDGU_AXk_PYBfEJA,469
54
54
  langgraph_api/api/mcp/_constants.py,sha256=jmMn_H77KdXP3c5NXIGifFk72B8tK2pNE5ufvJ7RdtY,555
@@ -65,7 +65,7 @@ langgraph_api/auth/studio_user.py,sha256=gNCicIo6cYaHmFj2sEdsvDYkKW7NWfGXGS2tTAM
65
65
  langgraph_api/auth/langsmith/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  langgraph_api/auth/langsmith/backend.py,sha256=Y6-VxD7zfV1jzGdjmQ66CgNa3SenLbo3d_375CcKZ9U,3770
67
67
  langgraph_api/auth/langsmith/client.py,sha256=79kwCVeHU64nsHsxWipfZhf44lM6vfs2nlfTxlJF6LU,4142
68
- langgraph_api/config/__init__.py,sha256=NYJWKJ-PbfeI6k5KnF3W_HWLE8EOS0rJKaQQqKTCAus,25717
68
+ langgraph_api/config/__init__.py,sha256=lSIVNfG_9LrJm2mKM1m46e1A8aaMwMqOEbGMgHcWY_Q,26300
69
69
  langgraph_api/config/_parse.py,sha256=RpfZgFAPJlRMv13AzGr3kAYbIrqHcgjzO8IgeboTw4A,3922
70
70
  langgraph_api/config/schemas.py,sha256=cHzVvepthpD7DDeWE2ytkOHah-iDNH7xRx9dSWUatQI,20864
71
71
  langgraph_api/encryption/__init__.py,sha256=gaCZ00CocSbqSqrDn6XJHaSp2CZCnC8qnrD9G4fbzyI,363
@@ -79,7 +79,7 @@ langgraph_api/event_streaming/capabilities.py,sha256=qjVbhCjl1VEQPGeiDxeJAhYGI_7
79
79
  langgraph_api/event_streaming/constants.py,sha256=eGsm-NvOlqV3gNxDO5vlr00FdngmgEQf59zuHSi_74E,1378
80
80
  langgraph_api/event_streaming/event_normalizers.py,sha256=5bVSqGPW-Uh7WX91qgTfwpK433pCSv_wchpbzW8TLi4,2794
81
81
  langgraph_api/event_streaming/namespace.py,sha256=aJDFt45Or2_bQdRpKJgdFhBgTDj6PYl7Coz5GzfbM84,1509
82
- langgraph_api/event_streaming/service.py,sha256=axQ2sDawAtsE96ZeJcBB8q8DbzS2VN-OqsdCM1rDF58,50063
82
+ langgraph_api/event_streaming/service.py,sha256=Ipm6LHwQFfEKT4BjeUex7R55bvKb97M8W9gCsKTNgmw,50119
83
83
  langgraph_api/event_streaming/session.py,sha256=8kx5nxJvJlfIu5fFzQCxEl-8UBJEtxftBLhCYgXMNwo,75947
84
84
  langgraph_api/event_streaming/state_normalizers.py,sha256=vgT4O4tJPr9VDBMn1EP994ieDGDYP43sROnOyLjkEAE,13659
85
85
  langgraph_api/event_streaming/types.py,sha256=RyZqfqgH-jmmmmAFQj5f6nH9M1rGK93zVG7nlmvqZgc,3647
@@ -236,8 +236,8 @@ langgraph_grpc_common/proto/store_pb2.py,sha256=uAYM7OcdEOK12iRcPYihC2suSeCo_Qdb
236
236
  langgraph_grpc_common/proto/store_pb2.pyi,sha256=_dcxyxV8moR6H67qU42r2h2p_Ub-PZSHs3OoS9KMdSY,27782
237
237
  langgraph_grpc_common/proto/store_pb2_grpc.py,sha256=wSD65QgFkYTkPTHcf7VhyI2FQ7UH_RgIf3vQW3VYlsM,3324
238
238
  langgraph_grpc_common/proto/store_pb2_grpc.pyi,sha256=oS1h2cDoq2OjyM8xazcmc8LwRDC5oCAD0zto2QUmPQw,2027
239
- langgraph_api-0.12.0.dev18.dist-info/METADATA,sha256=LFdiGtoAmXB1C3oFB4mUPPKkF75X2h9xvZFiT_iAbew,4631
240
- langgraph_api-0.12.0.dev18.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
241
- langgraph_api-0.12.0.dev18.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
242
- langgraph_api-0.12.0.dev18.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
243
- langgraph_api-0.12.0.dev18.dist-info/RECORD,,
239
+ langgraph_api-0.12.0.dev20.dist-info/METADATA,sha256=gj9GSR38Lrc1p1cb1u0BJKG1oXzuYvvnxSWfdI3y99I,4631
240
+ langgraph_api-0.12.0.dev20.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
241
+ langgraph_api-0.12.0.dev20.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
242
+ langgraph_api-0.12.0.dev20.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
243
+ langgraph_api-0.12.0.dev20.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.30.1
2
+ Generator: hatchling 1.31.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any