langgraph-api 0.2.20__tar.gz → 0.2.21__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 (103) hide show
  1. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/PKG-INFO +1 -1
  2. langgraph_api-0.2.21/langgraph_api/__init__.py +1 -0
  3. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/assistants.py +134 -97
  4. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/graph.py +33 -19
  5. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/stream.py +1 -1
  6. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/pyproject.toml +1 -1
  7. langgraph_api-0.2.20/langgraph_api/__init__.py +0 -1
  8. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/LICENSE +0 -0
  9. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/README.md +0 -0
  10. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/__init__.py +0 -0
  11. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/mcp.py +0 -0
  12. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/meta.py +0 -0
  13. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/openapi.py +0 -0
  14. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/runs.py +0 -0
  15. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/store.py +0 -0
  16. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/threads.py +0 -0
  17. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/api/ui.py +0 -0
  18. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/asyncio.py +0 -0
  19. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/__init__.py +0 -0
  20. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/custom.py +0 -0
  21. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/langsmith/__init__.py +0 -0
  22. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/langsmith/backend.py +0 -0
  23. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/langsmith/client.py +0 -0
  24. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/middleware.py +0 -0
  25. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/noop.py +0 -0
  26. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/auth/studio_user.py +0 -0
  27. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/cli.py +0 -0
  28. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/command.py +0 -0
  29. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/config.py +0 -0
  30. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/cron_scheduler.py +0 -0
  31. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/errors.py +0 -0
  32. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/http.py +0 -0
  33. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/.gitignore +0 -0
  34. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/.prettierrc +0 -0
  35. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/__init__.py +0 -0
  36. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/base.py +0 -0
  37. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/build.mts +0 -0
  38. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/client.http.mts +0 -0
  39. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/client.mts +0 -0
  40. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/errors.py +0 -0
  41. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/global.d.ts +0 -0
  42. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/package.json +0 -0
  43. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/remote.py +0 -0
  44. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/schema.py +0 -0
  45. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/graph.mts +0 -0
  46. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/load.hooks.mjs +0 -0
  47. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/preload.mjs +0 -0
  48. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/utils/files.mts +0 -0
  49. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/utils/importMap.mts +0 -0
  50. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  51. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/src/utils/serde.mts +0 -0
  52. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/sse.py +0 -0
  53. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/api.test.mts +0 -0
  54. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/auth.test.mts +0 -0
  55. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/compose-postgres.auth.yml +0 -0
  56. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/compose-postgres.yml +0 -0
  57. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/.gitignore +0 -0
  58. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/agent.css +0 -0
  59. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/agent.mts +0 -0
  60. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/agent.ui.tsx +0 -0
  61. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/agent_simple.mts +0 -0
  62. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/auth.mts +0 -0
  63. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/command.mts +0 -0
  64. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/delay.mts +0 -0
  65. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/dynamic.mts +0 -0
  66. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/error.mts +0 -0
  67. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/http.mts +0 -0
  68. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/langgraph.json +0 -0
  69. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/nested.mts +0 -0
  70. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/package.json +0 -0
  71. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/weather.mts +0 -0
  72. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/graphs/yarn.lock +0 -0
  73. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tests/utils.mts +0 -0
  74. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/tsconfig.json +0 -0
  75. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/ui.py +0 -0
  76. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/js/yarn.lock +0 -0
  77. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/logging.py +0 -0
  78. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/metadata.py +0 -0
  79. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/middleware/__init__.py +0 -0
  80. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/middleware/http_logger.py +0 -0
  81. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/middleware/private_network.py +0 -0
  82. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/middleware/request_id.py +0 -0
  83. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/models/__init__.py +0 -0
  84. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/models/run.py +0 -0
  85. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/patch.py +0 -0
  86. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/queue_entrypoint.py +0 -0
  87. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/route.py +0 -0
  88. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/schema.py +0 -0
  89. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/serde.py +0 -0
  90. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/server.py +0 -0
  91. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/sse.py +0 -0
  92. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/state.py +0 -0
  93. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/thread_ttl.py +0 -0
  94. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/tunneling/cloudflare.py +0 -0
  95. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/utils.py +0 -0
  96. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/validation.py +0 -0
  97. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/webhook.py +0 -0
  98. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_api/worker.py +0 -0
  99. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_license/__init__.py +0 -0
  100. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_license/validation.py +0 -0
  101. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/langgraph_runtime/__init__.py +0 -0
  102. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/logging.json +0 -0
  103. {langgraph_api-0.2.20 → langgraph_api-0.2.21}/openapi.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langgraph-api
3
- Version: 0.2.20
3
+ Version: 0.2.21
4
4
  Summary:
5
5
  License: Elastic-2.0
6
6
  Author: Nuno Campos
@@ -0,0 +1 @@
1
+ __version__ = "0.2.21"
@@ -3,6 +3,13 @@ from uuid import uuid4
3
3
 
4
4
  import structlog
5
5
  from langchain_core.runnables.utils import create_model
6
+ from langgraph.constants import (
7
+ CONFIG_KEY_CHECKPOINT_ID,
8
+ CONFIG_KEY_CHECKPOINT_NS,
9
+ CONFIG_KEY_CHECKPOINTER,
10
+ CONFIG_KEY_STORE,
11
+ CONFIG_KEY_THREAD_ID,
12
+ )
6
13
  from langgraph.pregel import Pregel
7
14
  from pydantic import TypeAdapter
8
15
  from starlette.exceptions import HTTPException
@@ -21,13 +28,24 @@ from langgraph_api.validation import (
21
28
  AssistantVersionChange,
22
29
  AssistantVersionsSearchRequest,
23
30
  )
31
+ from langgraph_runtime.checkpoint import Checkpointer
24
32
  from langgraph_runtime.database import connect
25
33
  from langgraph_runtime.ops import Assistants
26
34
  from langgraph_runtime.retry import retry_db
35
+ from langgraph_runtime.store import Store
27
36
 
28
37
  logger = structlog.stdlib.get_logger(__name__)
29
38
 
30
39
 
40
+ EXCLUDED_CONFIG_SCHEMA = (
41
+ CONFIG_KEY_CHECKPOINTER,
42
+ CONFIG_KEY_STORE,
43
+ CONFIG_KEY_CHECKPOINT_ID,
44
+ CONFIG_KEY_CHECKPOINT_NS,
45
+ CONFIG_KEY_THREAD_ID,
46
+ )
47
+
48
+
31
49
  def _get_configurable_jsonschema(graph: Pregel) -> dict:
32
50
  """Get the JSON schema for the configurable part of the graph.
33
51
 
@@ -52,6 +70,9 @@ def _get_configurable_jsonschema(graph: Pregel) -> dict:
52
70
  if model_fields is not None and "configurable" in model_fields:
53
71
  configurable = TypeAdapter(model_fields["configurable"].annotation)
54
72
  json_schema = configurable.json_schema()
73
+ if json_schema:
74
+ for key in EXCLUDED_CONFIG_SCHEMA:
75
+ json_schema["properties"].pop(key, None)
55
76
  # The type name of the configurable type is not preserved.
56
77
  # We'll add it back to the schema if we can.
57
78
  if hasattr(graph, "config_type") and graph.config_type is not None:
@@ -174,36 +195,41 @@ async def get_assistant_graph(
174
195
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
175
196
  async with connect() as conn:
176
197
  assistant_ = await Assistants.get(conn, assistant_id)
177
- assistant = await fetchone(assistant_)
178
- config = await ajson_loads(assistant["config"])
179
- async with get_graph(assistant["graph_id"], config) as graph:
180
- xray: bool | int = False
181
- xray_query = request.query_params.get("xray")
182
- if xray_query:
183
- if xray_query in ("true", "True"):
184
- xray = True
185
- elif xray_query in ("false", "False"):
186
- xray = False
187
- else:
188
- try:
189
- xray = int(xray_query)
190
- except ValueError:
191
- raise HTTPException(422, detail="Invalid xray value") from None
192
-
193
- if xray <= 0:
194
- raise HTTPException(422, detail="Invalid xray value") from None
195
-
196
- if isinstance(graph, BaseRemotePregel):
197
- drawable_graph = await graph.fetch_graph(xray=xray)
198
- return ApiResponse(drawable_graph.to_json())
199
-
200
- try:
201
- drawable_graph = await graph.aget_graph(xray=xray)
202
- return ApiResponse(drawable_graph.to_json())
203
- except NotImplementedError:
204
- raise HTTPException(
205
- 422, detail="The graph does not support visualization"
206
- ) from None
198
+ assistant = await fetchone(assistant_)
199
+ config = await ajson_loads(assistant["config"])
200
+ async with get_graph(
201
+ assistant["graph_id"],
202
+ config,
203
+ checkpointer=Checkpointer(conn),
204
+ store=Store(),
205
+ ) as graph:
206
+ xray: bool | int = False
207
+ xray_query = request.query_params.get("xray")
208
+ if xray_query:
209
+ if xray_query in ("true", "True"):
210
+ xray = True
211
+ elif xray_query in ("false", "False"):
212
+ xray = False
213
+ else:
214
+ try:
215
+ xray = int(xray_query)
216
+ except ValueError:
217
+ raise HTTPException(422, detail="Invalid xray value") from None
218
+
219
+ if xray <= 0:
220
+ raise HTTPException(422, detail="Invalid xray value") from None
221
+
222
+ if isinstance(graph, BaseRemotePregel):
223
+ drawable_graph = await graph.fetch_graph(xray=xray)
224
+ return ApiResponse(drawable_graph.to_json())
225
+
226
+ try:
227
+ drawable_graph = await graph.aget_graph(xray=xray)
228
+ return ApiResponse(drawable_graph.to_json())
229
+ except NotImplementedError:
230
+ raise HTTPException(
231
+ 422, detail="The graph does not support visualization"
232
+ ) from None
207
233
 
208
234
 
209
235
  @retry_db
@@ -215,35 +241,40 @@ async def get_assistant_subgraphs(
215
241
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
216
242
  async with connect() as conn:
217
243
  assistant_ = await Assistants.get(conn, assistant_id)
218
- assistant = await fetchone(assistant_)
219
- config = await ajson_loads(assistant["config"])
220
- async with get_graph(assistant["graph_id"], config) as graph:
221
- namespace = request.path_params.get("namespace")
222
-
223
- if isinstance(graph, BaseRemotePregel):
224
- return ApiResponse(
225
- await graph.fetch_subgraphs(
226
- namespace=namespace,
227
- recurse=request.query_params.get("recurse", "False")
228
- in ("true", "True"),
229
- )
230
- )
231
-
232
- try:
233
- return ApiResponse(
234
- {
235
- ns: _graph_schemas(subgraph)
236
- async for ns, subgraph in graph.aget_subgraphs(
244
+ assistant = await fetchone(assistant_)
245
+ config = await ajson_loads(assistant["config"])
246
+ async with get_graph(
247
+ assistant["graph_id"],
248
+ config,
249
+ checkpointer=Checkpointer(conn),
250
+ store=Store(),
251
+ ) as graph:
252
+ namespace = request.path_params.get("namespace")
253
+
254
+ if isinstance(graph, BaseRemotePregel):
255
+ return ApiResponse(
256
+ await graph.fetch_subgraphs(
237
257
  namespace=namespace,
238
258
  recurse=request.query_params.get("recurse", "False")
239
259
  in ("true", "True"),
240
260
  )
241
- }
242
- )
243
- except NotImplementedError:
244
- raise HTTPException(
245
- 422, detail="The graph does not support visualization"
246
- ) from None
261
+ )
262
+
263
+ try:
264
+ return ApiResponse(
265
+ {
266
+ ns: _graph_schemas(subgraph)
267
+ async for ns, subgraph in graph.aget_subgraphs(
268
+ namespace=namespace,
269
+ recurse=request.query_params.get("recurse", "False")
270
+ in ("true", "True"),
271
+ )
272
+ }
273
+ )
274
+ except NotImplementedError:
275
+ raise HTTPException(
276
+ 422, detail="The graph does not support visualization"
277
+ ) from None
247
278
 
248
279
 
249
280
  @retry_db
@@ -255,54 +286,60 @@ async def get_assistant_schemas(
255
286
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
256
287
  async with connect() as conn:
257
288
  assistant_ = await Assistants.get(conn, assistant_id)
258
- assistant = await fetchone(assistant_)
259
- config = await ajson_loads(assistant["config"])
260
- async with get_graph(assistant["graph_id"], config) as graph:
261
- if isinstance(graph, BaseRemotePregel):
262
- schemas = await graph.fetch_state_schema()
289
+ # TODO Implementa cache so we can de-dent and release this connection.
290
+ assistant = await fetchone(assistant_)
291
+ config = await ajson_loads(assistant["config"])
292
+ async with get_graph(
293
+ assistant["graph_id"],
294
+ config,
295
+ checkpointer=Checkpointer(conn),
296
+ store=Store(),
297
+ ) as graph:
298
+ if isinstance(graph, BaseRemotePregel):
299
+ schemas = await graph.fetch_state_schema()
300
+ return ApiResponse(
301
+ {
302
+ "graph_id": assistant["graph_id"],
303
+ "input_schema": schemas.get("input"),
304
+ "output_schema": schemas.get("output"),
305
+ "state_schema": schemas.get("state"),
306
+ "config_schema": schemas.get("config"),
307
+ }
308
+ )
309
+
310
+ try:
311
+ input_schema = graph.get_input_jsonschema()
312
+ except Exception as e:
313
+ logger.warning(
314
+ f"Failed to get input schema for graph {graph.name} with error: `{str(e)}`"
315
+ )
316
+ input_schema = None
317
+ try:
318
+ output_schema = graph.get_output_jsonschema()
319
+ except Exception as e:
320
+ logger.warning(
321
+ f"Failed to get output schema for graph {graph.name} with error: `{str(e)}`"
322
+ )
323
+ output_schema = None
324
+
325
+ state_schema = _state_jsonschema(graph)
326
+ try:
327
+ config_schema = _get_configurable_jsonschema(graph)
328
+ except Exception as e:
329
+ config_schema = None
330
+ logger.warning(
331
+ f"Failed to get config schema for graph {graph.name} with error: `{str(e)}`"
332
+ )
263
333
  return ApiResponse(
264
334
  {
265
335
  "graph_id": assistant["graph_id"],
266
- "input_schema": schemas.get("input"),
267
- "output_schema": schemas.get("output"),
268
- "state_schema": schemas.get("state"),
269
- "config_schema": schemas.get("config"),
336
+ "input_schema": input_schema,
337
+ "output_schema": output_schema,
338
+ "state_schema": state_schema,
339
+ "config_schema": config_schema,
270
340
  }
271
341
  )
272
342
 
273
- try:
274
- input_schema = graph.get_input_jsonschema()
275
- except Exception as e:
276
- logger.warning(
277
- f"Failed to get input schema for graph {graph.name} with error: `{str(e)}`"
278
- )
279
- input_schema = None
280
- try:
281
- output_schema = graph.get_output_jsonschema()
282
- except Exception as e:
283
- logger.warning(
284
- f"Failed to get output schema for graph {graph.name} with error: `{str(e)}`"
285
- )
286
- output_schema = None
287
-
288
- state_schema = _state_jsonschema(graph)
289
- try:
290
- config_schema = _get_configurable_jsonschema(graph)
291
- except Exception as e:
292
- config_schema = None
293
- logger.warning(
294
- f"Failed to get config schema for graph {graph.name} with error: `{str(e)}`"
295
- )
296
- return ApiResponse(
297
- {
298
- "graph_id": assistant["graph_id"],
299
- "input_schema": input_schema,
300
- "output_schema": output_schema,
301
- "state_schema": state_schema,
302
- "config_schema": config_schema,
303
- }
304
- )
305
-
306
343
 
307
344
  @retry_db
308
345
  async def patch_assistant(
@@ -15,11 +15,13 @@ from typing import TYPE_CHECKING, Any, NamedTuple
15
15
  from uuid import UUID, uuid5
16
16
 
17
17
  import structlog
18
- from langchain_core.runnables.config import run_in_executor
18
+ from langchain_core.runnables.config import run_in_executor, var_child_runnable_config
19
19
  from langgraph.checkpoint.base import BaseCheckpointSaver
20
+ from langgraph.constants import CONFIG_KEY_CHECKPOINTER, CONFIG_KEY_STORE
20
21
  from langgraph.graph import Graph
21
22
  from langgraph.pregel import Pregel
22
23
  from langgraph.store.base import BaseStore
24
+ from langgraph.utils.config import ensure_config
23
25
  from starlette.exceptions import HTTPException
24
26
 
25
27
  from langgraph_api import asyncio as lg_asyncio
@@ -109,26 +111,38 @@ async def get_graph(
109
111
  """Return the runnable."""
110
112
  assert_graph_exists(graph_id)
111
113
  value = GRAPHS[graph_id]
114
+ token = None
112
115
  if graph_id in FACTORY_ACCEPTS_CONFIG:
116
+ config = ensure_config(config)
117
+ if store is not None and not config["configurable"].get(CONFIG_KEY_STORE):
118
+ config["configurable"][CONFIG_KEY_STORE] = store
119
+ if checkpointer is not None and not config["configurable"].get(
120
+ CONFIG_KEY_CHECKPOINTER
121
+ ):
122
+ config["configurable"][CONFIG_KEY_CHECKPOINTER] = checkpointer
123
+ token = var_child_runnable_config.set(config)
113
124
  value = value(config) if FACTORY_ACCEPTS_CONFIG[graph_id] else value()
114
-
115
- async with _generate_graph(value) as graph_obj:
116
- if isinstance(graph_obj, Graph):
117
- graph_obj = graph_obj.compile()
118
- if not isinstance(graph_obj, Pregel | BaseRemotePregel):
119
- raise HTTPException(
120
- status_code=424,
121
- detail=f"Graph '{graph_id}' is not valid. Review graph registration.",
122
- )
123
- update = {
124
- "checkpointer": checkpointer,
125
- "store": store,
126
- }
127
- if graph_obj.name == "LangGraph":
128
- update["name"] = graph_id
129
- if isinstance(graph_obj, BaseRemotePregel):
130
- update["config"] = config
131
- yield graph_obj.copy(update=update)
125
+ try:
126
+ async with _generate_graph(value) as graph_obj:
127
+ if isinstance(graph_obj, Graph):
128
+ graph_obj = graph_obj.compile()
129
+ if not isinstance(graph_obj, Pregel | BaseRemotePregel):
130
+ raise HTTPException(
131
+ status_code=424,
132
+ detail=f"Graph '{graph_id}' is not valid. Review graph registration.",
133
+ )
134
+ update = {
135
+ "checkpointer": checkpointer,
136
+ "store": store,
137
+ }
138
+ if graph_obj.name == "LangGraph":
139
+ update["name"] = graph_id
140
+ if isinstance(graph_obj, BaseRemotePregel):
141
+ update["config"] = config
142
+ yield graph_obj.copy(update=update)
143
+ finally:
144
+ if token is not None:
145
+ var_child_runnable_config.reset(token)
132
146
 
133
147
 
134
148
  def graph_exists(graph_id: str) -> bool:
@@ -119,7 +119,7 @@ async def astream_state(
119
119
  is_remote_pregel = isinstance(graph, BaseRemotePregel)
120
120
  if not is_remote_pregel:
121
121
  config["configurable"]["__pregel_node_finished"] = incr_nodes
122
- # TODO add node tracking for JS graphs
122
+
123
123
  # attach run_id to config
124
124
  # for attempts beyond the first, use a fresh, unique run_id
125
125
  config = {**config, "run_id": run["run_id"]} if attempt == 1 else config
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "langgraph-api"
3
- version = "0.2.20"
3
+ version = "0.2.21"
4
4
  description = ""
5
5
  authors = [
6
6
  "Nuno Campos <nuno@langchain.dev>",
@@ -1 +0,0 @@
1
- __version__ = "0.2.20"
File without changes
File without changes