langgraph-api 0.5.4__py3-none-any.whl → 0.7.3__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.
Files changed (122) hide show
  1. langgraph_api/__init__.py +1 -1
  2. langgraph_api/api/__init__.py +93 -27
  3. langgraph_api/api/a2a.py +36 -32
  4. langgraph_api/api/assistants.py +114 -26
  5. langgraph_api/api/mcp.py +3 -3
  6. langgraph_api/api/meta.py +15 -2
  7. langgraph_api/api/openapi.py +27 -17
  8. langgraph_api/api/profile.py +108 -0
  9. langgraph_api/api/runs.py +114 -57
  10. langgraph_api/api/store.py +19 -2
  11. langgraph_api/api/threads.py +133 -10
  12. langgraph_api/asgi_transport.py +14 -9
  13. langgraph_api/auth/custom.py +23 -13
  14. langgraph_api/cli.py +86 -41
  15. langgraph_api/command.py +2 -2
  16. langgraph_api/config/__init__.py +532 -0
  17. langgraph_api/config/_parse.py +58 -0
  18. langgraph_api/config/schemas.py +431 -0
  19. langgraph_api/cron_scheduler.py +17 -1
  20. langgraph_api/encryption/__init__.py +15 -0
  21. langgraph_api/encryption/aes_json.py +158 -0
  22. langgraph_api/encryption/context.py +35 -0
  23. langgraph_api/encryption/custom.py +280 -0
  24. langgraph_api/encryption/middleware.py +632 -0
  25. langgraph_api/encryption/shared.py +63 -0
  26. langgraph_api/errors.py +12 -1
  27. langgraph_api/executor_entrypoint.py +11 -6
  28. langgraph_api/feature_flags.py +19 -0
  29. langgraph_api/graph.py +163 -64
  30. langgraph_api/{grpc_ops → grpc}/client.py +142 -12
  31. langgraph_api/{grpc_ops → grpc}/config_conversion.py +16 -10
  32. langgraph_api/grpc/generated/__init__.py +29 -0
  33. langgraph_api/grpc/generated/checkpointer_pb2.py +63 -0
  34. langgraph_api/grpc/generated/checkpointer_pb2.pyi +99 -0
  35. langgraph_api/grpc/generated/checkpointer_pb2_grpc.py +329 -0
  36. langgraph_api/grpc/generated/core_api_pb2.py +216 -0
  37. langgraph_api/{grpc_ops → grpc}/generated/core_api_pb2.pyi +292 -372
  38. langgraph_api/{grpc_ops → grpc}/generated/core_api_pb2_grpc.py +252 -31
  39. langgraph_api/grpc/generated/engine_common_pb2.py +219 -0
  40. langgraph_api/{grpc_ops → grpc}/generated/engine_common_pb2.pyi +178 -104
  41. langgraph_api/grpc/generated/enum_cancel_run_action_pb2.py +37 -0
  42. langgraph_api/grpc/generated/enum_cancel_run_action_pb2.pyi +12 -0
  43. langgraph_api/grpc/generated/enum_cancel_run_action_pb2_grpc.py +24 -0
  44. langgraph_api/grpc/generated/enum_control_signal_pb2.py +37 -0
  45. langgraph_api/grpc/generated/enum_control_signal_pb2.pyi +16 -0
  46. langgraph_api/grpc/generated/enum_control_signal_pb2_grpc.py +24 -0
  47. langgraph_api/grpc/generated/enum_durability_pb2.py +37 -0
  48. langgraph_api/grpc/generated/enum_durability_pb2.pyi +16 -0
  49. langgraph_api/grpc/generated/enum_durability_pb2_grpc.py +24 -0
  50. langgraph_api/grpc/generated/enum_multitask_strategy_pb2.py +37 -0
  51. langgraph_api/grpc/generated/enum_multitask_strategy_pb2.pyi +16 -0
  52. langgraph_api/grpc/generated/enum_multitask_strategy_pb2_grpc.py +24 -0
  53. langgraph_api/grpc/generated/enum_run_status_pb2.py +37 -0
  54. langgraph_api/grpc/generated/enum_run_status_pb2.pyi +22 -0
  55. langgraph_api/grpc/generated/enum_run_status_pb2_grpc.py +24 -0
  56. langgraph_api/grpc/generated/enum_stream_mode_pb2.py +37 -0
  57. langgraph_api/grpc/generated/enum_stream_mode_pb2.pyi +28 -0
  58. langgraph_api/grpc/generated/enum_stream_mode_pb2_grpc.py +24 -0
  59. langgraph_api/grpc/generated/enum_thread_status_pb2.py +37 -0
  60. langgraph_api/grpc/generated/enum_thread_status_pb2.pyi +16 -0
  61. langgraph_api/grpc/generated/enum_thread_status_pb2_grpc.py +24 -0
  62. langgraph_api/grpc/generated/enum_thread_stream_mode_pb2.py +37 -0
  63. langgraph_api/grpc/generated/enum_thread_stream_mode_pb2.pyi +16 -0
  64. langgraph_api/grpc/generated/enum_thread_stream_mode_pb2_grpc.py +24 -0
  65. langgraph_api/grpc/generated/errors_pb2.py +39 -0
  66. langgraph_api/grpc/generated/errors_pb2.pyi +21 -0
  67. langgraph_api/grpc/generated/errors_pb2_grpc.py +24 -0
  68. langgraph_api/grpc/ops/__init__.py +370 -0
  69. langgraph_api/grpc/ops/assistants.py +424 -0
  70. langgraph_api/grpc/ops/runs.py +792 -0
  71. langgraph_api/grpc/ops/threads.py +1013 -0
  72. langgraph_api/http.py +16 -5
  73. langgraph_api/js/client.mts +1 -4
  74. langgraph_api/js/package.json +28 -27
  75. langgraph_api/js/remote.py +39 -17
  76. langgraph_api/js/sse.py +2 -2
  77. langgraph_api/js/ui.py +1 -1
  78. langgraph_api/js/yarn.lock +1139 -869
  79. langgraph_api/metadata.py +29 -3
  80. langgraph_api/middleware/http_logger.py +1 -1
  81. langgraph_api/middleware/private_network.py +7 -7
  82. langgraph_api/models/run.py +44 -26
  83. langgraph_api/otel_context.py +205 -0
  84. langgraph_api/patch.py +2 -2
  85. langgraph_api/queue_entrypoint.py +34 -35
  86. langgraph_api/route.py +33 -1
  87. langgraph_api/schema.py +84 -9
  88. langgraph_api/self_hosted_logs.py +2 -2
  89. langgraph_api/self_hosted_metrics.py +73 -3
  90. langgraph_api/serde.py +16 -4
  91. langgraph_api/server.py +33 -31
  92. langgraph_api/state.py +3 -2
  93. langgraph_api/store.py +25 -16
  94. langgraph_api/stream.py +20 -16
  95. langgraph_api/thread_ttl.py +28 -13
  96. langgraph_api/timing/__init__.py +25 -0
  97. langgraph_api/timing/profiler.py +200 -0
  98. langgraph_api/timing/timer.py +318 -0
  99. langgraph_api/utils/__init__.py +53 -8
  100. langgraph_api/utils/config.py +2 -1
  101. langgraph_api/utils/future.py +10 -6
  102. langgraph_api/utils/uuids.py +29 -62
  103. langgraph_api/validation.py +6 -0
  104. langgraph_api/webhook.py +120 -6
  105. langgraph_api/worker.py +54 -24
  106. {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/METADATA +8 -6
  107. langgraph_api-0.7.3.dist-info/RECORD +168 -0
  108. {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/WHEEL +1 -1
  109. langgraph_runtime/__init__.py +1 -0
  110. langgraph_runtime/routes.py +11 -0
  111. logging.json +1 -3
  112. openapi.json +635 -537
  113. langgraph_api/config.py +0 -523
  114. langgraph_api/grpc_ops/generated/__init__.py +0 -5
  115. langgraph_api/grpc_ops/generated/core_api_pb2.py +0 -275
  116. langgraph_api/grpc_ops/generated/engine_common_pb2.py +0 -194
  117. langgraph_api/grpc_ops/ops.py +0 -1045
  118. langgraph_api-0.5.4.dist-info/RECORD +0 -121
  119. /langgraph_api/{grpc_ops → grpc}/__init__.py +0 -0
  120. /langgraph_api/{grpc_ops → grpc}/generated/engine_common_pb2_grpc.py +0 -0
  121. {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/entry_points.txt +0 -0
  122. {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/licenses/LICENSE +0 -0
langgraph_api/http.py CHANGED
@@ -70,11 +70,11 @@ class JsonHttpClient:
70
70
  await res.aclose()
71
71
 
72
72
 
73
- _http_client: JsonHttpClient
73
+ _http_client: JsonHttpClient | None = None
74
74
  _loopback_client: JsonHttpClient | None = None
75
75
 
76
76
 
77
- async def start_http_client() -> None:
77
+ async def start_http_client() -> JsonHttpClient:
78
78
  global _http_client
79
79
  _http_client = JsonHttpClient(
80
80
  client=httpx.AsyncClient(
@@ -86,15 +86,26 @@ async def start_http_client() -> None:
86
86
  ),
87
87
  ),
88
88
  )
89
+ return _http_client
89
90
 
90
91
 
91
92
  async def stop_http_client() -> None:
92
93
  global _http_client
94
+ if _http_client is None:
95
+ return
93
96
  await _http_client.client.aclose()
94
- del _http_client
97
+ _http_client = None
98
+
99
+
100
+ def get_http_client() -> JsonHttpClient | None:
101
+ global _http_client
102
+ return _http_client
95
103
 
96
104
 
97
- def get_http_client() -> JsonHttpClient:
105
+ async def ensure_http_client() -> JsonHttpClient:
106
+ global _http_client
107
+ if _http_client is None:
108
+ return await start_http_client()
98
109
  return _http_client
99
110
 
100
111
 
@@ -168,7 +179,7 @@ async def http_request(
168
179
  if not path.startswith(("http://", "https://", "/")):
169
180
  raise ValueError("path must start with / or http")
170
181
 
171
- client = client or get_http_client()
182
+ client = client or (await ensure_http_client())
172
183
 
173
184
  content = None
174
185
  if body is not None:
@@ -527,10 +527,7 @@ export class RemoteStore extends BaseStore {
527
527
  }
528
528
 
529
529
  async get(namespace: string[], key: string): Promise<Item | null> {
530
- return await sendRecv<Item | null>("store_get", {
531
- namespace: namespace.join("."),
532
- key,
533
- });
530
+ return await sendRecv<Item | null>("store_get", { namespace, key });
534
531
  }
535
532
 
536
533
  async search(
@@ -7,41 +7,42 @@
7
7
  "format": "prettier --write ."
8
8
  },
9
9
  "dependencies": {
10
- "@hono/node-server": "^1.12.0",
11
- "@hono/zod-validator": "^0.2.2",
12
- "@langchain/core": "^1.0.1",
13
- "@langchain/langgraph": "^1.0.0",
10
+ "@hono/node-server": "^1.19.8",
11
+ "@hono/zod-validator": "^0.7.6",
12
+ "@langchain/core": "^1.1.8",
13
+ "@langchain/langgraph": "^1.1.0",
14
14
  "@langchain/langgraph-api": "^1.0.3",
15
- "@langchain/langgraph-ui": "^1.0.3",
16
15
  "@langchain/langgraph-checkpoint": "^1.0.0",
16
+ "@langchain/langgraph-ui": "^1.1.11",
17
17
  "@types/json-schema": "^7.0.15",
18
- "@typescript/vfs": "^1.6.0",
19
- "dedent": "^1.7.0",
20
- "exit-hook": "^4.0.0",
21
- "hono": "^4.10.4",
22
- "p-queue": "^8.0.1",
23
- "p-retry": "^6.2.0",
24
- "tsx": "^4.20.6",
25
- "typescript": "^5.5.4",
26
- "undici": "^6.21.2",
27
- "uuid": "^10.0.0",
28
- "vite": "^6.4.1",
29
- "winston": "^3.17.0",
30
- "zod": "^3.25.32"
18
+ "@typescript/vfs": "^1.6.2",
19
+ "dedent": "^1.7.1",
20
+ "esbuild": "^0.27.2",
21
+ "exit-hook": "^5.0.1",
22
+ "hono": "^4.11.4",
23
+ "p-queue": "^9.0.1",
24
+ "p-retry": "^7.1.1",
25
+ "tsx": "^4.21.0",
26
+ "typescript": "^5.9.3",
27
+ "undici": "^7.18.2",
28
+ "uuid": "^13.0.0",
29
+ "vite": "^7.3.0",
30
+ "winston": "^3.19.0",
31
+ "zod": "^4.2.1"
31
32
  },
32
33
  "resolutions": {
33
34
  "esbuild": "^0.25.0",
34
35
  "vite": "^6.1.6"
35
36
  },
36
37
  "devDependencies": {
37
- "@langchain/langgraph-sdk": "^0.0.104",
38
- "@types/node": "^22.2.0",
39
- "@types/react": "^19.0.8",
40
- "@types/react-dom": "^19.0.3",
41
- "jose": "^6.0.10",
42
- "postgres": "^3.4.4",
43
- "prettier": "^3.6.2",
44
- "vitest": "^4.0.6"
38
+ "@langchain/langgraph-sdk": "^1.5.4",
39
+ "@types/node": "^25.0.9",
40
+ "@types/react": "^19.2.7",
41
+ "@types/react-dom": "^19.2.3",
42
+ "jose": "^6.1.3",
43
+ "postgres": "^3.4.7",
44
+ "prettier": "^3.7.4",
45
+ "vitest": "^4.0.16"
45
46
  },
46
47
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
47
- }
48
+ }
@@ -15,7 +15,7 @@ import httpx
15
15
  import orjson
16
16
  import structlog
17
17
  import uvicorn
18
- from langchain_core.runnables.config import RunnableConfig
18
+ from langchain_core.runnables.config import RunnableConfig, merge_configs
19
19
  from langchain_core.runnables.graph import Edge, Node
20
20
  from langchain_core.runnables.graph import Graph as DrawableGraph
21
21
  from langchain_core.runnables.schema import (
@@ -49,6 +49,7 @@ from langgraph_api.js.sse import SSEDecoder, aiter_lines_raw
49
49
  from langgraph_api.route import ApiResponse
50
50
  from langgraph_api.schema import Config
51
51
  from langgraph_api.serde import json_dumpb
52
+ from langgraph_api.utils import get_auth_ctx, get_user_id
52
53
 
53
54
  logger = structlog.stdlib.get_logger(__name__)
54
55
 
@@ -170,9 +171,9 @@ class RemotePregel(BaseRemotePregel):
170
171
  "getGraph",
171
172
  {
172
173
  "graph_id": self.graph_id,
173
- "graph_config": self.config,
174
+ "graph_config": self._inject_auth_to_config(self.config),
174
175
  "graph_name": self.name,
175
- "config": config,
176
+ "config": self._inject_auth_to_config(config),
176
177
  "xray": xray,
177
178
  },
178
179
  )
@@ -211,11 +212,11 @@ class RemotePregel(BaseRemotePregel):
211
212
  "getSubgraphs",
212
213
  {
213
214
  "graph_id": self.graph_id,
214
- "graph_config": self.config,
215
+ "graph_config": self._inject_auth_to_config(self.config),
215
216
  "graph_name": self.name,
216
217
  "namespace": namespace,
217
218
  "recurse": recurse,
218
- "config": config,
219
+ "config": self._inject_auth_to_config(config),
219
220
  },
220
221
  )
221
222
 
@@ -248,7 +249,7 @@ class RemotePregel(BaseRemotePregel):
248
249
 
249
250
  return StateSnapshot( # type: ignore[missing-argument]
250
251
  item.get("values"),
251
- cast(tuple, item.get("next", ())),
252
+ cast("tuple", item.get("next", ())),
252
253
  item.get("config"),
253
254
  item.get("metadata"),
254
255
  item.get("createdAt"),
@@ -266,9 +267,9 @@ class RemotePregel(BaseRemotePregel):
266
267
  "getState",
267
268
  {
268
269
  "graph_id": self.graph_id,
269
- "graph_config": self.config,
270
+ "graph_config": self._inject_auth_to_config(self.config),
270
271
  "graph_name": self.name,
271
- "config": config,
272
+ "config": self._inject_auth_to_config(config),
272
273
  "subgraphs": subgraphs,
273
274
  },
274
275
  )
@@ -284,9 +285,9 @@ class RemotePregel(BaseRemotePregel):
284
285
  "updateState",
285
286
  {
286
287
  "graph_id": self.graph_id,
287
- "graph_config": self.config,
288
+ "graph_config": self._inject_auth_to_config(self.config),
288
289
  "graph_name": self.name,
289
- "config": config,
290
+ "config": self._inject_auth_to_config(config),
290
291
  "values": values,
291
292
  "as_node": as_node,
292
293
  },
@@ -305,9 +306,9 @@ class RemotePregel(BaseRemotePregel):
305
306
  "getStateHistory",
306
307
  {
307
308
  "graph_id": self.graph_id,
308
- "graph_config": self.config,
309
+ "graph_config": self._inject_auth_to_config(self.config),
309
310
  "graph_name": self.name,
310
- "config": config,
311
+ "config": self._inject_auth_to_config(config),
311
312
  "limit": limit,
312
313
  "filter": filter,
313
314
  "before": before,
@@ -353,6 +354,27 @@ class RemotePregel(BaseRemotePregel):
353
354
  )
354
355
  return result["nodesExecuted"]
355
356
 
357
+ def _inject_auth_to_config(self, config: RunnableConfig | Config):
358
+ if ctx := get_auth_ctx():
359
+ user_id = get_user_id(cast("BaseUser | None", ctx.user))
360
+
361
+ # Skip if cannot serialize the user to JSON
362
+ if not hasattr(ctx.user, "model_dump"):
363
+ return config
364
+
365
+ return merge_configs(
366
+ config,
367
+ {
368
+ "configurable": {
369
+ "langgraph_auth_user": ctx.user,
370
+ "langgraph_auth_user_id": user_id,
371
+ "langgraph_auth_permissions": list(ctx.permissions),
372
+ }
373
+ },
374
+ )
375
+
376
+ return config
377
+
356
378
 
357
379
  async def run_js_process(paths_str: str | None, watch: bool = False):
358
380
  # check if tsx is available
@@ -632,13 +654,13 @@ async def run_remote_checkpointer():
632
654
 
633
655
  async def store_get(payload: dict):
634
656
  """Get store data"""
635
- namespaces_str = payload.get("namespace")
657
+ namespaces = payload.get("namespace")
636
658
  key = payload.get("key")
637
659
 
638
- if not namespaces_str or not key:
660
+ if not namespaces or not key:
639
661
  raise ValueError("Both namespaces and key are required")
640
662
 
641
- namespaces = namespaces_str.split(".")
663
+ namespaces = tuple(namespaces)
642
664
 
643
665
  store = await _get_passthrough_store()
644
666
  result = await store.aget(namespaces, key)
@@ -648,7 +670,7 @@ async def run_remote_checkpointer():
648
670
  async def store_put(payload: dict):
649
671
  """Put the new store data"""
650
672
 
651
- namespace = tuple(payload["namespace"].split("."))
673
+ namespace = tuple(payload["namespace"])
652
674
  key = payload["key"]
653
675
  value = payload["value"]
654
676
  index = payload.get("index")
@@ -958,7 +980,7 @@ async def handle_js_auth_event(
958
980
 
959
981
  raise HTTPException(status_code=status, detail=message, headers=headers)
960
982
 
961
- filters = cast(Auth.types.FilterType | None, response.get("filters"))
983
+ filters = cast("Auth.types.FilterType | None", response.get("filters"))
962
984
 
963
985
  # mutate metadata in value if applicable
964
986
  # we need to preserve the identity of the object, so cannot create a new
langgraph_api/js/sse.py CHANGED
@@ -51,7 +51,7 @@ class BytesLineDecoder:
51
51
  # Include any existing buffer in the first portion of the
52
52
  # splitlines result.
53
53
  self.buffer.extend(lines[0])
54
- lines = [self.buffer] + lines[1:]
54
+ lines = [self.buffer, *lines[1:]]
55
55
  self.buffer = bytearray()
56
56
 
57
57
  if not trailing_newline:
@@ -79,7 +79,7 @@ class SSEDecoder:
79
79
  self._retry: int | None = None
80
80
 
81
81
  def decode(self, line: bytes) -> StreamPart | None:
82
- # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501
82
+ # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
83
83
 
84
84
  if not line:
85
85
  if (
langgraph_api/js/ui.py CHANGED
@@ -66,7 +66,7 @@ async def _start_ui_bundler_process():
66
66
  "watch",
67
67
  "-o",
68
68
  UI_ROOT_DIR,
69
- env=os.environ,
69
+ env=dict(os.environ),
70
70
  )
71
71
  pid = process.pid
72
72
  logger.info("Started UI bundler process [%d]", pid)