langgraph-api 0.4.28__tar.gz → 0.4.29__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 (130) hide show
  1. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/Makefile +48 -8
  2. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/PKG-INFO +4 -1
  3. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/constraints.txt +3 -0
  4. langgraph_api-0.4.29/langgraph_api/__init__.py +1 -0
  5. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/assistants.py +12 -9
  6. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/feature_flags.py +9 -0
  7. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/graph.py +11 -12
  8. langgraph_api-0.4.29/langgraph_api/grpc_ops/client.py +80 -0
  9. langgraph_api-0.4.29/langgraph_api/grpc_ops/generated/__init__.py +5 -0
  10. langgraph_api-0.4.29/langgraph_api/grpc_ops/generated/core_api_pb2.py +274 -0
  11. langgraph_api-0.4.29/langgraph_api/grpc_ops/generated/core_api_pb2.pyi +988 -0
  12. langgraph_api-0.4.29/langgraph_api/grpc_ops/generated/core_api_pb2_grpc.py +1400 -0
  13. langgraph_api-0.4.29/langgraph_api/grpc_ops/ops.py +540 -0
  14. langgraph_api-0.4.29/langgraph_api/grpc_ops/scripts/generate_protos.sh +47 -0
  15. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/schema.py +2 -1
  16. langgraph_api-0.4.29/langgraph_license/__init__.py +0 -0
  17. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/pyproject.toml +6 -0
  18. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/uv.lock +144 -31
  19. langgraph_api-0.4.28/langgraph_api/__init__.py +0 -1
  20. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/.gitignore +0 -0
  21. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/LICENSE +0 -0
  22. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/README.md +0 -0
  23. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/.gitignore +0 -0
  24. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/Makefile +0 -0
  25. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/README.md +0 -0
  26. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/burst.js +0 -0
  27. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/clean.js +0 -0
  28. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/graphs.js +0 -0
  29. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/package.json +0 -0
  30. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/ramp.js +0 -0
  31. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/update-revision.js +0 -0
  32. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/benchmark/weather.js +0 -0
  33. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/forbidden.txt +0 -0
  34. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/healthcheck.py +0 -0
  35. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/__init__.py +0 -0
  36. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/a2a.py +0 -0
  37. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/mcp.py +0 -0
  38. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/meta.py +0 -0
  39. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/openapi.py +0 -0
  40. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/runs.py +0 -0
  41. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/store.py +0 -0
  42. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/threads.py +0 -0
  43. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/api/ui.py +0 -0
  44. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/asgi_transport.py +0 -0
  45. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/asyncio.py +0 -0
  46. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/__init__.py +0 -0
  47. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/custom.py +0 -0
  48. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/langsmith/__init__.py +0 -0
  49. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/langsmith/backend.py +0 -0
  50. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/langsmith/client.py +0 -0
  51. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/middleware.py +0 -0
  52. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/noop.py +0 -0
  53. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/auth/studio_user.py +0 -0
  54. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/cli.py +0 -0
  55. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/command.py +0 -0
  56. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/config.py +0 -0
  57. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/cron_scheduler.py +0 -0
  58. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/errors.py +0 -0
  59. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/executor_entrypoint.py +0 -0
  60. {langgraph_api-0.4.28/langgraph_api/js → langgraph_api-0.4.29/langgraph_api/grpc_ops}/__init__.py +0 -0
  61. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/http.py +0 -0
  62. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/http_metrics.py +0 -0
  63. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/.gitignore +0 -0
  64. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/.prettierrc +0 -0
  65. {langgraph_api-0.4.28/langgraph_api/middleware → langgraph_api-0.4.29/langgraph_api/js}/__init__.py +0 -0
  66. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/base.py +0 -0
  67. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/build.mts +0 -0
  68. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/client.http.mts +0 -0
  69. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/client.mts +0 -0
  70. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/errors.py +0 -0
  71. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/global.d.ts +0 -0
  72. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/package.json +0 -0
  73. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/remote.py +0 -0
  74. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/schema.py +0 -0
  75. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/graph.mts +0 -0
  76. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/load.hooks.mjs +0 -0
  77. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/preload.mjs +0 -0
  78. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/utils/files.mts +0 -0
  79. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/utils/importMap.mts +0 -0
  80. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  81. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/src/utils/serde.mts +0 -0
  82. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/sse.py +0 -0
  83. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/traceblock.mts +0 -0
  84. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/tsconfig.json +0 -0
  85. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/ui.py +0 -0
  86. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/js/yarn.lock +0 -0
  87. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/logging.py +0 -0
  88. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/metadata.py +0 -0
  89. {langgraph_api-0.4.28/langgraph_api/models → langgraph_api-0.4.29/langgraph_api/middleware}/__init__.py +0 -0
  90. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/middleware/http_logger.py +0 -0
  91. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/middleware/private_network.py +0 -0
  92. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/middleware/request_id.py +0 -0
  93. {langgraph_api-0.4.28/langgraph_license → langgraph_api-0.4.29/langgraph_api/models}/__init__.py +0 -0
  94. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/models/run.py +0 -0
  95. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/patch.py +0 -0
  96. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/queue_entrypoint.py +0 -0
  97. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/route.py +0 -0
  98. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/serde.py +0 -0
  99. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/server.py +0 -0
  100. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/sse.py +0 -0
  101. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/state.py +0 -0
  102. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/store.py +0 -0
  103. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/stream.py +0 -0
  104. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/thread_ttl.py +0 -0
  105. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/traceblock.py +0 -0
  106. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/tunneling/cloudflare.py +0 -0
  107. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/__init__.py +0 -0
  108. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/cache.py +0 -0
  109. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/config.py +0 -0
  110. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/future.py +0 -0
  111. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/headers.py +0 -0
  112. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/retriable_client.py +0 -0
  113. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/stream_codec.py +0 -0
  114. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/utils/uuids.py +0 -0
  115. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/validation.py +0 -0
  116. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/webhook.py +0 -0
  117. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_api/worker.py +0 -0
  118. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_license/validation.py +0 -0
  119. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/__init__.py +0 -0
  120. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/checkpoint.py +0 -0
  121. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/database.py +0 -0
  122. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/lifespan.py +0 -0
  123. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/metrics.py +0 -0
  124. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/ops.py +0 -0
  125. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/queue.py +0 -0
  126. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/retry.py +0 -0
  127. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/langgraph_runtime/store.py +0 -0
  128. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/logging.json +0 -0
  129. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/openapi.json +0 -0
  130. {langgraph_api-0.4.28 → langgraph_api-0.4.29}/scripts/create_license.py +0 -0
@@ -1,22 +1,39 @@
1
- .PHONY: build release lint format test test_watch start start-inmem start-inmem-license-oss start check-version check-base-imports
1
+ .PHONY: build release lint format test test_watch start start-inmem start-inmem-license-oss start start-js-server build-go-server start-go-server stop-go-server check-version check-base-imports
2
+
3
+ # Environment variables
4
+ FF_USE_CORE_API ?= false
5
+ CORE_API_LANGSERVE_GRAPHS = '{"agent": "./tests/graphs/agent.py:graph", "custom_lifespan": "./tests/graphs/my_router.py:graph", "single_node": "./tests/graphs/single_node.py:graph", "benchmark": "./tests/graphs/benchmark.py:graph", "config_graph": "./tests/graphs/config_graph.py:graph", "other": "./tests/graphs/other.py:make_graph", "weather": "./tests/graphs/weather.py:mk_weather_graph", "searchy": "./tests/graphs/searchy.py:graph", "agent_simple": "./tests/graphs/agent_simple.py:graph", "simple_runtime": "./tests/graphs/simple_runtime.py:graph", "agent_interrupt": "./tests/graphs/agent_interrupt.py:graph", "message_type_test": "./tests/graphs/message_type_test.py:graph", "remote_subgraph_parent": "./tests/graphs/remote_subgraph_parent.py:graph", "simple_remote": "./tests/graphs/simple_remote.py:graph"}'
6
+ # Go server management
7
+ build-go-server:
8
+ @echo "Building Go gRPC server..."
9
+ cd ../core/core-api/cmd/sqlite-test-server && go build -o cmd main.go
10
+
11
+ start-go-server:
12
+ @echo "Starting Go gRPC server on port 50051..."
13
+ cd ../core/core-api/cmd/sqlite-test-server && LANGSERVE_GRAPHS=$(CORE_API_LANGSERVE_GRAPHS) ./cmd &
14
+ @sleep 2
15
+
16
+ stop-go-server:
17
+ @echo "Stopping Go gRPC server on port 50051..."
18
+ @lsof -ti:50051 | xargs -r kill -9 || echo "No process found on port 50051"
2
19
 
3
20
  # lint commands
4
21
 
5
22
  lint:
6
- uv run ruff check .
7
- uv run ruff format . --diff
8
- uvx ty check --exclude "**/pb/**" --exclude "**/*_test.py" --exclude "**/test_*.py" --exclude "**/tests/**" --exclude "venv/**" --exclude ".venv/**" --exclude "build/**" --exclude "dist/**" .
23
+ uv run ruff check . --exclude "**/generated/**"
24
+ uv run ruff format . --diff --exclude "**/generated/**"
25
+ uvx ty check --exclude "**/pb/**" --exclude "**/*_test.py" --exclude "**/test_*.py" --exclude "**/tests/**" --exclude "venv/**" --exclude ".venv/**" --exclude "build/**" --exclude "dist/**" --exclude "**/generated/**" .
9
26
 
10
27
  format:
11
- uv run ruff check --fix .
12
- uv run ruff format .
28
+ uv run ruff check --fix . --exclude "**/generated/**"
29
+ uv run ruff format . --exclude "**/generated/**"
13
30
 
14
31
  check-base-imports:
15
32
  LANGGRAPH_RUNTIME_EDITION=inmem DATABASE_URI=:memory: REDIS_URI=_FAKE uv run python -c "from langgraph_api.config import *; from langgraph_runtime import *"
16
33
 
17
34
  # test commands
18
35
 
19
- TEST ?= tests/
36
+ TEST ?= tests/ ../runtime_inmem/tests/
20
37
  AUTH_TEST ?= "tests/integration_tests/test_custom_auth.py"
21
38
  LANGGRAPH_HTTP ?= {"disable_mcp": false, "disable_a2a": false}
22
39
  LANGGRAPH_AES_KEY ?= '1234567890123456'
@@ -37,7 +54,11 @@ endif
37
54
  REVISION ?= $(shell git rev-parse --short HEAD)
38
55
 
39
56
  test-license-oss:
40
- LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_HTTP='$(HTTP_CONFIG)' LANGGRAPH_STORE='$(STORE_CONFIG)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run pytest -v $(TEST)
57
+ @if [ "$(FF_USE_CORE_API)" = "true" ]; then \
58
+ LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_HTTP='$(HTTP_CONFIG)' LANGGRAPH_STORE='$(STORE_CONFIG)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ FF_USE_CORE_API=true uv run pytest -m grpc -v $(TEST); \
59
+ else \
60
+ LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_HTTP='$(HTTP_CONFIG)' LANGGRAPH_STORE='$(STORE_CONFIG)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run pytest -v $(TEST); \
61
+ fi
41
62
 
42
63
  test-watch-oss:
43
64
  LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_HTTP='$(HTTP_CONFIG)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run --no-sync ptw . -- -x -vv --ff --capture=no $(TEST)
@@ -56,6 +77,10 @@ test-auth-watch:
56
77
  # dev commands
57
78
 
58
79
  start:
80
+ @if [ "$(FF_USE_CORE_API)" = "true" ]; then \
81
+ $(MAKE) build-go-server && $(MAKE) start-go-server; \
82
+ trap '$(MAKE) stop-go-server' INT TERM EXIT; \
83
+ fi; \
59
84
  sleep 3 && \
60
85
  LANGGRAPH_HTTP='$(HTTP_CONFIG)' \
61
86
  LANGGRAPH_RUNTIME_EDITION=inmem \
@@ -65,6 +90,7 @@ start:
65
90
  LANGGRAPH_STORE='$(STORE_CONFIG)' \
66
91
  LANGGRAPH_CONFIG='{"agent": {"configurable": {"model_name": "openai"}}}' \
67
92
  LANGSMITH_LANGGRAPH_API_VARIANT=test \
93
+ FF_USE_CORE_API=$(FF_USE_CORE_API) \
68
94
  REDIS_URI=fake \
69
95
  DATABASE_URI=:memory: \
70
96
  MIGRATIONS_PATH=__inmem \
@@ -117,6 +143,20 @@ start-auth-fastapi-jwt:
117
143
  --reload-dir ../runtime_inmem \
118
144
  --no-access-log
119
145
 
146
+ start-js-server:
147
+ @echo "Building and starting Go gRPC server..."
148
+ $(MAKE) build-go-server
149
+ $(MAKE) start-go-server
150
+ @trap '$(MAKE) -C $(CURDIR) stop-go-server' INT TERM EXIT; \
151
+ echo "Installing JS server dependencies..."; \
152
+ cd ../public-api-server-js && npm install; \
153
+ echo "Building JS server..."; \
154
+ cd ../public-api-server-js && npm run build; \
155
+ echo "Starting JS server on port 9123..."; \
156
+ cd ../public-api-server-js && FF_USE_CORE_API=true \
157
+ LANGSERVE_GRAPHS=$(CORE_API_LANGSERVE_GRAPHS) \
158
+ PORT=9123 npm start
159
+
120
160
  VERSION_KIND ?= patch
121
161
 
122
162
  bump-version:
@@ -1,12 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.4.28
3
+ Version: 0.4.29
4
4
  Author-email: Nuno Campos <nuno@langchain.dev>, Will Fu-Hinthorn <will@langchain.dev>
5
5
  License: Elastic-2.0
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.11
8
8
  Requires-Dist: cloudpickle>=3.0.0
9
9
  Requires-Dist: cryptography<45.0,>=42.0.0
10
+ Requires-Dist: grpcio-tools<2.0.0,>=1.75.0
11
+ Requires-Dist: grpcio<2.0.0,>=1.75.0
10
12
  Requires-Dist: httpx>=0.25.0
11
13
  Requires-Dist: jsonschema-rs<0.30,>=0.20.0
12
14
  Requires-Dist: langchain-core>=0.3.64
@@ -16,6 +18,7 @@ Requires-Dist: langgraph-sdk>=0.2.0
16
18
  Requires-Dist: langgraph>=0.4.0
17
19
  Requires-Dist: langsmith>=0.3.45
18
20
  Requires-Dist: orjson>=3.9.7
21
+ Requires-Dist: protobuf<7.0.0,>=6.32.1
19
22
  Requires-Dist: pyjwt>=2.9.0
20
23
  Requires-Dist: sse-starlette<2.2.0,>=2.1.0
21
24
  Requires-Dist: starlette>=0.38.6
@@ -17,3 +17,6 @@ jsonschema-rs>=0.20.0
17
17
  structlog>=24.1.0
18
18
  cloudpickle>=3.0.0
19
19
  truststore>=0.1
20
+ protobuf>=6.32.1,<7.0.0
21
+ grpcio>=1.75.0,<2.0.0
22
+ grpcio-tools>=1.75.0,<2.0.0
@@ -0,0 +1 @@
1
+ __version__ = "0.4.29"
@@ -12,8 +12,9 @@ from starlette.responses import Response
12
12
  from starlette.routing import BaseRoute
13
13
 
14
14
  from langgraph_api import store as api_store
15
- from langgraph_api.feature_flags import USE_RUNTIME_CONTEXT_API
15
+ from langgraph_api.feature_flags import FF_USE_CORE_API, USE_RUNTIME_CONTEXT_API
16
16
  from langgraph_api.graph import get_assistant_id, get_graph
17
+ from langgraph_api.grpc_ops.ops import Assistants as GrpcAssistants
17
18
  from langgraph_api.js.base import BaseRemotePregel
18
19
  from langgraph_api.route import ApiRequest, ApiResponse, ApiRoute
19
20
  from langgraph_api.schema import ASSISTANT_FIELDS
@@ -40,6 +41,7 @@ from langgraph_runtime.retry import retry_db
40
41
 
41
42
  logger = structlog.stdlib.get_logger(__name__)
42
43
 
44
+ CrudAssistants = GrpcAssistants if FF_USE_CORE_API else Assistants
43
45
 
44
46
  EXCLUDED_CONFIG_SCHEMA = (
45
47
  "__pregel_checkpointer",
@@ -164,7 +166,7 @@ async def create_assistant(request: ApiRequest) -> ApiResponse:
164
166
  if assistant_id := payload.get("assistant_id"):
165
167
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
166
168
  async with connect() as conn:
167
- assistant = await Assistants.put(
169
+ assistant = await CrudAssistants.put(
168
170
  conn,
169
171
  assistant_id or str(uuid4()),
170
172
  config=payload.get("config") or {},
@@ -175,6 +177,7 @@ async def create_assistant(request: ApiRequest) -> ApiResponse:
175
177
  name=payload.get("name") or "Untitled",
176
178
  description=payload.get("description"),
177
179
  )
180
+
178
181
  return ApiResponse(await fetchone(assistant, not_found_code=409))
179
182
 
180
183
 
@@ -187,7 +190,7 @@ async def search_assistants(
187
190
  select = validate_select_columns(payload.get("select") or None, ASSISTANT_FIELDS)
188
191
  offset = int(payload.get("offset") or 0)
189
192
  async with connect() as conn:
190
- assistants_iter, next_offset = await Assistants.search(
193
+ assistants_iter, next_offset = await CrudAssistants.search(
191
194
  conn,
192
195
  graph_id=payload.get("graph_id"),
193
196
  metadata=payload.get("metadata"),
@@ -210,7 +213,7 @@ async def count_assistants(
210
213
  """Count assistants."""
211
214
  payload = await request.json(AssistantCountRequest)
212
215
  async with connect() as conn:
213
- count = await Assistants.count(
216
+ count = await CrudAssistants.count(
214
217
  conn,
215
218
  graph_id=payload.get("graph_id"),
216
219
  metadata=payload.get("metadata"),
@@ -226,7 +229,7 @@ async def get_assistant(
226
229
  """Get an assistant by ID."""
227
230
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
228
231
  async with connect() as conn:
229
- assistant = await Assistants.get(conn, assistant_id)
232
+ assistant = await CrudAssistants.get(conn, assistant_id)
230
233
  return ApiResponse(await fetchone(assistant))
231
234
 
232
235
 
@@ -386,7 +389,7 @@ async def patch_assistant(
386
389
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
387
390
  payload = await request.json(AssistantPatch)
388
391
  async with connect() as conn:
389
- assistant = await Assistants.patch(
392
+ assistant = await CrudAssistants.patch(
390
393
  conn,
391
394
  assistant_id,
392
395
  config=payload.get("config"),
@@ -405,7 +408,7 @@ async def delete_assistant(request: ApiRequest) -> Response:
405
408
  assistant_id = request.path_params["assistant_id"]
406
409
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
407
410
  async with connect() as conn:
408
- aid = await Assistants.delete(conn, assistant_id)
411
+ aid = await CrudAssistants.delete(conn, assistant_id)
409
412
  await fetchone(aid)
410
413
  return Response(status_code=204)
411
414
 
@@ -417,7 +420,7 @@ async def get_assistant_versions(request: ApiRequest) -> ApiResponse:
417
420
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
418
421
  payload = await request.json(AssistantVersionsSearchRequest)
419
422
  async with connect() as conn:
420
- assistants_iter = await Assistants.get_versions(
423
+ assistants_iter = await CrudAssistants.get_versions(
421
424
  conn,
422
425
  assistant_id,
423
426
  metadata=payload.get("metadata") or {},
@@ -439,7 +442,7 @@ async def set_latest_assistant_version(request: ApiRequest) -> ApiResponse:
439
442
  payload = await request.json(AssistantVersionChange)
440
443
  validate_uuid(assistant_id, "Invalid assistant ID: must be a UUID")
441
444
  async with connect() as conn:
442
- assistant = await Assistants.set_latest(
445
+ assistant = await CrudAssistants.set_latest(
443
446
  conn, assistant_id, payload.get("version")
444
447
  )
445
448
  return ApiResponse(await fetchone(assistant, not_found_code=404))
@@ -1,3 +1,5 @@
1
+ import os
2
+
1
3
  from langgraph.version import __version__
2
4
 
3
5
  # Only gate features on the major.minor version; Lets you ignore the rc/alpha/etc. releases anyway
@@ -7,3 +9,10 @@ OMIT_PENDING_SENDS = LANGGRAPH_PY_MINOR >= (0, 5)
7
9
  USE_RUNTIME_CONTEXT_API = LANGGRAPH_PY_MINOR >= (0, 6)
8
10
  USE_NEW_INTERRUPTS = LANGGRAPH_PY_MINOR >= (0, 6)
9
11
  USE_DURABILITY = LANGGRAPH_PY_MINOR >= (0, 6)
12
+
13
+ # Feature flag for new gRPC-based persistence layer
14
+ FF_USE_CORE_API = os.getenv("FF_USE_CORE_API", "false").lower() in (
15
+ "true",
16
+ "1",
17
+ "yes",
18
+ )
@@ -21,9 +21,8 @@ from langgraph.pregel import Pregel
21
21
  from langgraph.store.base import BaseStore
22
22
  from starlette.exceptions import HTTPException
23
23
 
24
- from langgraph_api import asyncio as lg_asyncio
25
24
  from langgraph_api import config
26
- from langgraph_api.feature_flags import USE_RUNTIME_CONTEXT_API
25
+ from langgraph_api.feature_flags import FF_USE_CORE_API, USE_RUNTIME_CONTEXT_API
27
26
  from langgraph_api.js.base import BaseRemotePregel, is_js_path
28
27
  from langgraph_api.schema import Config
29
28
  from langgraph_api.utils.config import run_in_executor, var_child_runnable_config
@@ -51,13 +50,19 @@ async def register_graph(
51
50
  description: str | None = None,
52
51
  ) -> None:
53
52
  """Register a graph."""
53
+ from langgraph_api.grpc_ops.ops import Assistants as AssistantsGrpc
54
54
  from langgraph_runtime.database import connect
55
- from langgraph_runtime.ops import Assistants
55
+ from langgraph_runtime.ops import Assistants as AssistantsRuntime
56
+
57
+ Assistants = AssistantsGrpc if FF_USE_CORE_API else AssistantsRuntime
56
58
 
57
59
  await logger.ainfo(f"Registering graph with id '{graph_id}'", graph_id=graph_id)
58
- GRAPHS[graph_id] = graph
59
- if callable(graph):
60
- FACTORY_ACCEPTS_CONFIG[graph_id] = len(inspect.signature(graph).parameters) > 0
60
+ if not FF_USE_CORE_API:
61
+ GRAPHS[graph_id] = graph
62
+ if callable(graph):
63
+ FACTORY_ACCEPTS_CONFIG[graph_id] = (
64
+ len(inspect.signature(graph).parameters) > 0
65
+ )
61
66
 
62
67
  from langgraph_runtime.retry import retry_db
63
68
 
@@ -87,12 +92,6 @@ async def register_graph(
87
92
  await register_graph_db()
88
93
 
89
94
 
90
- def register_graph_sync(
91
- graph_id: str, graph: GraphValue, config: dict | None = None
92
- ) -> None:
93
- lg_asyncio.run_coroutine_threadsafe(register_graph(graph_id, graph, config))
94
-
95
-
96
95
  @asynccontextmanager
97
96
  async def _generate_graph(value: Any) -> AsyncIterator[Any]:
98
97
  """Yield a graph object regardless of its type."""
@@ -0,0 +1,80 @@
1
+ """gRPC client wrapper for LangGraph persistence services."""
2
+
3
+ import os
4
+
5
+ import structlog
6
+ from grpc import aio # type: ignore[import]
7
+
8
+ from .generated.core_api_pb2_grpc import AdminStub, AssistantsStub
9
+
10
+ logger = structlog.stdlib.get_logger(__name__)
11
+
12
+
13
+ class GrpcClient:
14
+ """gRPC client for LangGraph persistence services."""
15
+
16
+ def __init__(
17
+ self,
18
+ server_address: str | None = None,
19
+ ):
20
+ """Initialize the gRPC client.
21
+
22
+ Args:
23
+ server_address: The gRPC server address (default: localhost:50051)
24
+ """
25
+ self.server_address = server_address or os.getenv(
26
+ "GRPC_SERVER_ADDRESS", "localhost:50051"
27
+ )
28
+ self._channel: aio.Channel | None = None
29
+ self._assistants_stub: AssistantsStub | None = None
30
+ self._admin_stub: AdminStub | None = None
31
+
32
+ async def __aenter__(self):
33
+ """Async context manager entry."""
34
+ await self.connect()
35
+ return self
36
+
37
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
38
+ """Async context manager exit."""
39
+ await self.close()
40
+
41
+ async def connect(self):
42
+ """Connect to the gRPC server."""
43
+ if self._channel is not None:
44
+ return
45
+
46
+ self._channel = aio.insecure_channel(self.server_address)
47
+
48
+ self._assistants_stub = AssistantsStub(self._channel)
49
+ self._admin_stub = AdminStub(self._channel)
50
+
51
+ await logger.adebug(
52
+ "Connected to gRPC server", server_address=self.server_address
53
+ )
54
+
55
+ async def close(self):
56
+ """Close the gRPC connection."""
57
+ if self._channel is not None:
58
+ await self._channel.close()
59
+ self._channel = None
60
+ self._assistants_stub = None
61
+ self._admin_stub = None
62
+ await logger.adebug("Closed gRPC connection")
63
+
64
+ @property
65
+ def assistants(self) -> AssistantsStub:
66
+ """Get the assistants service stub."""
67
+ if self._assistants_stub is None:
68
+ raise RuntimeError(
69
+ "Client not connected. Use async context manager or call connect() first."
70
+ )
71
+ return self._assistants_stub
72
+
73
+ @property
74
+ def admin(self) -> AdminStub:
75
+ """Get the admin service stub."""
76
+ if self._admin_stub is None:
77
+ raise RuntimeError(
78
+ "Client not connected. Use async context manager or call connect() first."
79
+ )
80
+ return self._admin_stub
@@ -0,0 +1,5 @@
1
+ # Generated protobuf files
2
+ from . import core_api_pb2
3
+ from . import core_api_pb2_grpc
4
+
5
+ __all__ = ["core_api_pb2", "core_api_pb2_grpc"]