langgraph-api 0.7.31__tar.gz → 0.7.33__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.
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/PKG-INFO +1 -1
- langgraph_api-0.7.33/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/_checkpointer/__init__.py +8 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/_checkpointer/_adapter.py +105 -41
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/_checkpointer/protocol.py +5 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/a2a.py +12 -12
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/runs.py +50 -4
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/store.py +1 -1
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/ui.py +2 -1
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/auth/custom.py +16 -4
- langgraph_api-0.7.33/langgraph_api/auth/noop.py +53 -0
- langgraph_api-0.7.33/langgraph_api/auth/studio_user.py +39 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/cli.py +4 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/cron_scheduler.py +12 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/encryption/shared.py +8 -1
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/graph.py +2 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/ops/runs.py +44 -18
- langgraph_api-0.7.33/langgraph_api/grpc/servicers/checkpointer.py +262 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/servicers/encryption.py +30 -5
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/models/run.py +6 -2
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/schema.py +3 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/serde.py +30 -1
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/sse.py +6 -2
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/worker.py +9 -3
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/checkpoint.py +42 -2
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/config.py +18 -1
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/messages.py +10 -6
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/struct.py +7 -1
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/__init__.py +2 -0
- langgraph_api-0.7.33/langgraph_grpc_common/proto/core_api_pb2.py +259 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/core_api_pb2.pyi +555 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +330 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +76 -0
- langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +37 -0
- langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +32 -0
- langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +24 -0
- langgraph_api-0.7.33/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +20 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/serde.py +4 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/scripts/run_a2a_tck.py +15 -5
- langgraph_api-0.7.31/langgraph_api/__init__.py +0 -1
- langgraph_api-0.7.31/langgraph_api/auth/noop.py +0 -22
- langgraph_api-0.7.31/langgraph_api/auth/studio_user.py +0 -15
- langgraph_api-0.7.31/langgraph_api/grpc/servicers/checkpointer.py +0 -118
- langgraph_api-0.7.31/langgraph_grpc_common/proto/core_api_pb2.py +0 -228
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/.gitignore +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/LICENSE +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/Makefile +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/README.md +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/.gitignore +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/Makefile +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/README.md +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/benchmark-runners/assistant.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/benchmark-runners/benchmark-runner.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/benchmark-runners/benchmarks.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/benchmark-runners/stream_write.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/benchmark-runners/thread.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/benchmark-runners/wait_write.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/burst.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/capacity_dd_report.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/capacity_k6.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/capacity_runner.mjs +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/capacity_slack_report.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/capacity_urls.mjs +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/clean-cli.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/clean.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/continuous/README.md +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/continuous/pyproject.toml +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/continuous/runner.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/continuous/uv.lock +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/graphs.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/mixed_workload_k6.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/mixed_workload_runner.mjs +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/package.json +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/ramp.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/reporting/dd_reporting.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/reporting/slack_slowest_runs.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/reporting/slack_summary.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/run_local.sh +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/update-revision.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/benchmark/weather.js +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/constraints.txt +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/custom_store.sql +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/forbidden.txt +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/hatch_build.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/healthcheck.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph-cloud-debugging-20260210132856.zip +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/_factory_utils.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/mcp/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/mcp/_constants.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/mcp/_handlers.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/mcp/_models.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/mcp/_routes.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/mcp/_sanitizers.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/profile.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/cache.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/command.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/config/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/config/_parse.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/config/schemas.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/encryption/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/encryption/aes_json.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/encryption/context.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/encryption/custom.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/encryption/middleware.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/executor_entrypoint.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/feature_flags.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/client.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/ops/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/ops/assistants.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/ops/cache.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/ops/threads.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/server.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/grpc/servicers/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/http.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/http_metrics.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/http_metrics_utils.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/remote.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/traceblock.mts +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/middleware/ensure_store.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/otel_context.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/route.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/self_hosted_logs.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/self_hosted_metrics.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/server.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/state.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/store.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/timing/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/timing/profiler.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/timing/timer.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/traceblock.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/cache.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/config.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/errors.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/future.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/headers.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/retriable_client.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/stream_codec.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/utils/uuids.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/_compat.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/channel.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/durability.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/exception.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/graph.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/interrupt.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/orchestrator_response.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/runopts.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/stream_mode.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/task.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/conversion/value.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_api_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_api_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_api_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_api_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
- /langgraph_api-0.7.31/langgraph_grpc_common/proto/errors_pb2_grpc.pyi → /langgraph_api-0.7.33/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/executor_api_pb2.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/executor_api_pb2.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/executor_api_pb2_grpc.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/proto/executor_api_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_grpc_common/sanitize.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/routes.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/logging.json +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/openapi.json +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/pyproject.toml +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/scripts/build_wheel.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/scripts/create_license.py +0 -0
- {langgraph_api-0.7.31 → langgraph_api-0.7.33}/uv.lock +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.33"
|
|
@@ -25,6 +25,8 @@ async def get_checkpointer(
|
|
|
25
25
|
|
|
26
26
|
async def start_checkpointer() -> None:
|
|
27
27
|
"""Start the checkpointer resources."""
|
|
28
|
+
# Load the custom checkpointer from LANGGRAPH_CHECKPOINTER env var, if configured.
|
|
29
|
+
await _adapter.collect_checkpointer_from_env()
|
|
28
30
|
# If the custom checkpointer is provided, it will be started here / enter the stack.
|
|
29
31
|
checkpointer = await get_checkpointer()
|
|
30
32
|
if not isinstance(checkpointer, (BaseCheckpointSaver, CheckpointerProtocol)):
|
|
@@ -44,8 +46,14 @@ async def exit_checkpointer() -> None:
|
|
|
44
46
|
await _adapter.exit_checkpointer()
|
|
45
47
|
|
|
46
48
|
|
|
49
|
+
def get_checkpointer_capabilities() -> _adapter.CheckpointerCapabilities | None:
|
|
50
|
+
"""Return the capabilities of the custom checkpointer, or None if not configured."""
|
|
51
|
+
return _adapter.get_checkpointer_capabilities()
|
|
52
|
+
|
|
53
|
+
|
|
47
54
|
__all__ = [
|
|
48
55
|
"exit_checkpointer",
|
|
49
56
|
"get_checkpointer",
|
|
57
|
+
"get_checkpointer_capabilities",
|
|
50
58
|
"start_checkpointer",
|
|
51
59
|
]
|
|
@@ -5,7 +5,7 @@ import importlib.util
|
|
|
5
5
|
import random
|
|
6
6
|
import sys
|
|
7
7
|
import threading
|
|
8
|
-
from collections.abc import AsyncIterator, Callable
|
|
8
|
+
from collections.abc import AsyncIterator, Callable
|
|
9
9
|
from contextlib import AsyncExitStack, asynccontextmanager
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from typing import TYPE_CHECKING, Any, Self, cast
|
|
@@ -25,7 +25,7 @@ from langgraph_api.timing import profiled_import
|
|
|
25
25
|
from langgraph_api.utils.config import run_in_executor
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
|
-
from collections.abc import AsyncIterator, Callable, Sequence
|
|
28
|
+
from collections.abc import AsyncIterator, Callable, Iterable, Sequence
|
|
29
29
|
|
|
30
30
|
from langchain_core.runnables import RunnableConfig
|
|
31
31
|
from langgraph.checkpoint.base import (
|
|
@@ -63,6 +63,9 @@ class CheckpointerCapabilities:
|
|
|
63
63
|
|
|
64
64
|
has_aget_iter: bool
|
|
65
65
|
has_adelete_thread: bool
|
|
66
|
+
has_adelete_for_runs: bool
|
|
67
|
+
has_acopy_thread: bool
|
|
68
|
+
has_aprune: bool
|
|
66
69
|
|
|
67
70
|
@classmethod
|
|
68
71
|
def from_type(cls: type[Self], inner_type: type) -> Self:
|
|
@@ -70,6 +73,9 @@ class CheckpointerCapabilities:
|
|
|
70
73
|
return cls(
|
|
71
74
|
has_aget_iter=_is_overridden(inner_type, "aget_iter"),
|
|
72
75
|
has_adelete_thread=_is_overridden(inner_type, "adelete_thread"),
|
|
76
|
+
has_adelete_for_runs=_has_method(inner_type, "adelete_for_runs"),
|
|
77
|
+
has_acopy_thread=_has_method(inner_type, "acopy_thread"),
|
|
78
|
+
has_aprune=_has_method(inner_type, "aprune"),
|
|
73
79
|
)
|
|
74
80
|
|
|
75
81
|
|
|
@@ -80,7 +86,6 @@ class _CustomCheckpointerAdapter(BaseCheckpointSaver):
|
|
|
80
86
|
_validate_required_methods(inner)
|
|
81
87
|
self._inner = inner
|
|
82
88
|
self._capabilities = capabilities
|
|
83
|
-
self.latest_iter: AsyncIterator[CheckpointTuple] | None = None
|
|
84
89
|
super().__init__(serde=getattr(inner, "serde", None))
|
|
85
90
|
|
|
86
91
|
def __getattr__(self, name: str) -> Any:
|
|
@@ -106,7 +111,7 @@ class _CustomCheckpointerAdapter(BaseCheckpointSaver):
|
|
|
106
111
|
metadata: CheckpointMetadata,
|
|
107
112
|
new_versions: ChannelVersions,
|
|
108
113
|
) -> RunnableConfig:
|
|
109
|
-
metadata =
|
|
114
|
+
metadata = _enrich_metadata(metadata, config)
|
|
110
115
|
return await self._inner.aput(config, checkpoint, metadata, new_versions)
|
|
111
116
|
|
|
112
117
|
async def aput_writes(
|
|
@@ -142,23 +147,36 @@ class _CustomCheckpointerAdapter(BaseCheckpointSaver):
|
|
|
142
147
|
"Please implement adelete_thread in your custom checkpointer to support thread deletion."
|
|
143
148
|
)
|
|
144
149
|
|
|
145
|
-
async def
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
150
|
+
async def adelete_for_runs(self, run_ids: Iterable[str]) -> None:
|
|
151
|
+
if self._capabilities.has_adelete_for_runs:
|
|
152
|
+
await self._inner.adelete_for_runs(run_ids)
|
|
153
|
+
return
|
|
154
|
+
raise RuntimeError(
|
|
155
|
+
"Please implement adelete_for_runs in your custom checkpointer "
|
|
156
|
+
"to support run deletion/rollback."
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
async def acopy_thread(self, source_thread_id: str, target_thread_id: str) -> None:
|
|
160
|
+
if self._capabilities.has_acopy_thread:
|
|
161
|
+
await self._inner.acopy_thread(source_thread_id, target_thread_id)
|
|
162
|
+
return
|
|
163
|
+
raise RuntimeError(
|
|
164
|
+
"Please implement acopy_thread in your custom checkpointer "
|
|
165
|
+
"to support thread copy."
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
async def aprune(
|
|
169
|
+
self, thread_ids: Sequence[str], *, strategy: str = "keep_latest"
|
|
170
|
+
) -> None:
|
|
171
|
+
if self._capabilities.has_aprune:
|
|
172
|
+
await self._inner.aprune(thread_ids, strategy=strategy)
|
|
173
|
+
return
|
|
174
|
+
raise RuntimeError(
|
|
175
|
+
"Please implement aprune in your custom checkpointer "
|
|
176
|
+
"to support thread pruning."
|
|
177
|
+
)
|
|
161
178
|
|
|
179
|
+
async def aget_tuple(self, config: RunnableConfig) -> CheckpointTuple | None:
|
|
162
180
|
return await self._inner.aget_tuple(config)
|
|
163
181
|
|
|
164
182
|
def get_next_version(self, current: str | None, channel: None) -> str:
|
|
@@ -180,7 +198,7 @@ async def get_checkpointer(
|
|
|
180
198
|
use_direct_connection: bool = False,
|
|
181
199
|
) -> CheckpointerProtocol:
|
|
182
200
|
global _CHECKPOINTER_CAPABILITIES
|
|
183
|
-
if CUSTOM_CHECKPOINTER:
|
|
201
|
+
if CUSTOM_CHECKPOINTER is not None:
|
|
184
202
|
# Get or create the inner checkpointer (cached per-thread)
|
|
185
203
|
if not hasattr(CHECKPOINTER_STACK, "inner"):
|
|
186
204
|
stack = AsyncExitStack()
|
|
@@ -198,7 +216,7 @@ async def get_checkpointer(
|
|
|
198
216
|
f"Using custom checkpointer: {inner}",
|
|
199
217
|
kind=str(type(inner)),
|
|
200
218
|
)
|
|
201
|
-
# Create fresh adapter each time (not cached) - each gets own latest_iter
|
|
219
|
+
# Create a fresh adapter each time (not cached) - each gets own latest_iter
|
|
202
220
|
if _CHECKPOINTER_CAPABILITIES is None:
|
|
203
221
|
raise RuntimeError("Capabilities not initialized")
|
|
204
222
|
return _CustomCheckpointerAdapter(
|
|
@@ -212,8 +230,13 @@ async def get_checkpointer(
|
|
|
212
230
|
)
|
|
213
231
|
|
|
214
232
|
|
|
233
|
+
def get_checkpointer_capabilities() -> CheckpointerCapabilities | None:
|
|
234
|
+
"""Return the capabilities of the custom checkpointer, or None if not configured."""
|
|
235
|
+
return _CHECKPOINTER_CAPABILITIES
|
|
236
|
+
|
|
237
|
+
|
|
215
238
|
async def exit_checkpointer() -> None:
|
|
216
|
-
if
|
|
239
|
+
if CUSTOM_CHECKPOINTER is None:
|
|
217
240
|
return
|
|
218
241
|
stack = cast("AsyncExitStack|None", getattr(CHECKPOINTER_STACK, "stack", None))
|
|
219
242
|
if stack is None:
|
|
@@ -231,8 +254,8 @@ async def collect_checkpointer_from_env() -> None:
|
|
|
231
254
|
|
|
232
255
|
await logger.ainfo(
|
|
233
256
|
f"Heads up! You are configuring a custom checkpointer at {checkpointer_path}\n\n"
|
|
234
|
-
"This checkpointer will be used
|
|
235
|
-
"The availability of some functionality, such as TTLs and pruning, may depend on the completion of your implementation
|
|
257
|
+
"This checkpointer will be used INSTEAD OF the default persistence backend.\n"
|
|
258
|
+
"The availability of some functionality, such as TTLs and pruning, may depend on the completion of your implementation.\n"
|
|
236
259
|
"Performance & feature support will depend on the quality of your implementation."
|
|
237
260
|
)
|
|
238
261
|
|
|
@@ -252,7 +275,7 @@ async def collect_checkpointer_from_env() -> None:
|
|
|
252
275
|
async def _yield_checkpointer(value: Any):
|
|
253
276
|
if isinstance(value, BaseCheckpointSaver):
|
|
254
277
|
yield value
|
|
255
|
-
# Async
|
|
278
|
+
# Async context manager
|
|
256
279
|
elif hasattr(value, "__aenter__") and hasattr(value, "__aexit__"):
|
|
257
280
|
async with value as ctx_value:
|
|
258
281
|
yield ctx_value
|
|
@@ -338,28 +361,64 @@ def _load_checkpointer(checkpointer_path: str) -> Any:
|
|
|
338
361
|
raise ValueError(
|
|
339
362
|
f"Could not find checkpointer '{checkpointer_path}'. "
|
|
340
363
|
f"Please check that:\n"
|
|
341
|
-
f"1. The file exports a variable named '{
|
|
364
|
+
f"1. The file exports a variable named '{function}'\n"
|
|
342
365
|
f"2. The variable name in your config matches the export name{suggestion}"
|
|
343
366
|
) from e
|
|
344
367
|
return checkpointer
|
|
345
368
|
|
|
346
369
|
|
|
347
|
-
|
|
370
|
+
# Keys from config["configurable"] that should NOT be copied into checkpoint metadata.
|
|
371
|
+
_EXCLUDED_CONFIGURABLE_KEYS = frozenset({"checkpoint_ns", "checkpoint_id"})
|
|
372
|
+
# Keys that are request-scoped and must not be persisted in checkpoints.
|
|
373
|
+
_TRANSIENT_CONFIGURABLE_KEYS = frozenset(
|
|
374
|
+
{
|
|
375
|
+
"langgraph_request_id",
|
|
376
|
+
"langgraph_auth_user",
|
|
377
|
+
"langgraph_auth_user_id",
|
|
378
|
+
"langgraph_auth_permissions",
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _enrich_metadata(
|
|
348
384
|
metadata: CheckpointMetadata, config: RunnableConfig
|
|
349
385
|
) -> CheckpointMetadata:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
386
|
+
"""Enrich checkpoint metadata with config fields.
|
|
387
|
+
|
|
388
|
+
Mirrors the metadata enrichment performed by the built-in checkpointers
|
|
389
|
+
so that downstream consumers (API, state endpoints, copy) see a
|
|
390
|
+
consistent metadata shape regardless of checkpointer implementation.
|
|
391
|
+
"""
|
|
392
|
+
configurable = config.get("configurable", {})
|
|
393
|
+
config_metadata = config.get("metadata", {})
|
|
394
|
+
enriched: dict = {
|
|
395
|
+
# 1. Non-internal configurable keys (thread_id, graph_id, etc.)
|
|
396
|
+
**{
|
|
397
|
+
k: v
|
|
398
|
+
for k, v in configurable.items()
|
|
399
|
+
if not k.startswith("__")
|
|
400
|
+
and k not in _EXCLUDED_CONFIGURABLE_KEYS
|
|
401
|
+
and k not in _TRANSIENT_CONFIGURABLE_KEYS
|
|
402
|
+
},
|
|
403
|
+
# 2. Config metadata (assistant_id, model_name, etc.)
|
|
404
|
+
**{
|
|
405
|
+
k: v
|
|
406
|
+
for k, v in config_metadata.items()
|
|
407
|
+
if k not in _TRANSIENT_CONFIGURABLE_KEYS
|
|
408
|
+
},
|
|
409
|
+
# 3. Original metadata on top (source, step, parents, etc.)
|
|
410
|
+
**{k: v for k, v in metadata.items() if k not in _TRANSIENT_CONFIGURABLE_KEYS},
|
|
411
|
+
}
|
|
412
|
+
# Ensure run_id is present when available (not always set, e.g. state updates)
|
|
413
|
+
if not enriched.get("run_id"):
|
|
414
|
+
run_id = (
|
|
415
|
+
config.get("run_id")
|
|
416
|
+
or config_metadata.get("run_id")
|
|
417
|
+
or configurable.get("run_id")
|
|
418
|
+
)
|
|
419
|
+
if run_id:
|
|
420
|
+
enriched["run_id"] = run_id
|
|
421
|
+
return enriched
|
|
363
422
|
|
|
364
423
|
|
|
365
424
|
def _validate_required_methods(inner: BaseCheckpointSaver):
|
|
@@ -381,3 +440,8 @@ def _is_overridden(inner_type: type, method: str) -> bool:
|
|
|
381
440
|
if base is None or impl is None:
|
|
382
441
|
return impl is not None
|
|
383
442
|
return impl is not base
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def _has_method(inner_type: type, method: str) -> bool:
|
|
446
|
+
"""Check if a type has a callable method (for methods not on BaseCheckpointSaver)."""
|
|
447
|
+
return callable(getattr(inner_type, method, None))
|
|
@@ -83,6 +83,11 @@ class CheckpointerProtocol(Protocol):
|
|
|
83
83
|
) -> None: ...
|
|
84
84
|
|
|
85
85
|
async def adelete_thread(self, thread_id: str) -> None: ...
|
|
86
|
+
|
|
87
|
+
# NOTE: adelete_for_runs, acopy_thread, and aprune are optional extended
|
|
88
|
+
# capabilities checked at runtime via CheckpointerCapabilities. They are
|
|
89
|
+
# NOT part of this protocol to avoid breaking isinstance checks.
|
|
90
|
+
|
|
86
91
|
async def aget_iter(
|
|
87
92
|
self, config: RunnableConfig
|
|
88
93
|
) -> AsyncIterator[CheckpointTuple]: ...
|
|
@@ -661,7 +661,7 @@ def _map_runs_create_error_to_rpc(
|
|
|
661
661
|
return {
|
|
662
662
|
"error": {
|
|
663
663
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
664
|
-
"message":
|
|
664
|
+
"message": "Internal server error",
|
|
665
665
|
}
|
|
666
666
|
}
|
|
667
667
|
|
|
@@ -717,7 +717,7 @@ def _map_runs_get_error_to_rpc(
|
|
|
717
717
|
return {
|
|
718
718
|
"error": {
|
|
719
719
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
720
|
-
"message":
|
|
720
|
+
"message": "Internal server error",
|
|
721
721
|
}
|
|
722
722
|
}
|
|
723
723
|
|
|
@@ -1287,12 +1287,12 @@ async def handle_message_send(
|
|
|
1287
1287
|
assistant_id=assistant_id,
|
|
1288
1288
|
)
|
|
1289
1289
|
|
|
1290
|
-
except Exception
|
|
1290
|
+
except Exception:
|
|
1291
1291
|
logger.exception(f"Error in message/send for assistant {assistant_id}")
|
|
1292
1292
|
return {
|
|
1293
1293
|
"error": {
|
|
1294
1294
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
1295
|
-
"message":
|
|
1295
|
+
"message": "Internal server error",
|
|
1296
1296
|
}
|
|
1297
1297
|
}
|
|
1298
1298
|
|
|
@@ -1488,7 +1488,7 @@ async def handle_tasks_get(
|
|
|
1488
1488
|
return {
|
|
1489
1489
|
"error": {
|
|
1490
1490
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
1491
|
-
"message":
|
|
1491
|
+
"message": "Internal server error",
|
|
1492
1492
|
}
|
|
1493
1493
|
}
|
|
1494
1494
|
|
|
@@ -1654,12 +1654,12 @@ async def handle_get_extended_card(
|
|
|
1654
1654
|
"message": str(e),
|
|
1655
1655
|
}
|
|
1656
1656
|
}
|
|
1657
|
-
except Exception
|
|
1657
|
+
except Exception:
|
|
1658
1658
|
logger.exception(f"Error generating extended agent card for {assistant_id}")
|
|
1659
1659
|
return {
|
|
1660
1660
|
"error": {
|
|
1661
1661
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
1662
|
-
"message":
|
|
1662
|
+
"message": "Internal server error",
|
|
1663
1663
|
}
|
|
1664
1664
|
}
|
|
1665
1665
|
|
|
@@ -1806,12 +1806,12 @@ async def handle_agent_card_endpoint(request: ApiRequest) -> Response:
|
|
|
1806
1806
|
status_code=400,
|
|
1807
1807
|
media_type="application/json",
|
|
1808
1808
|
)
|
|
1809
|
-
except Exception
|
|
1809
|
+
except Exception:
|
|
1810
1810
|
logger.exception("Failed to generate agent card")
|
|
1811
1811
|
error_response = {
|
|
1812
1812
|
"error": {
|
|
1813
1813
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
1814
|
-
"message":
|
|
1814
|
+
"message": "Internal server error",
|
|
1815
1815
|
}
|
|
1816
1816
|
}
|
|
1817
1817
|
return Response(
|
|
@@ -2209,7 +2209,7 @@ async def handle_message_stream(
|
|
|
2209
2209
|
"id": rpc_id,
|
|
2210
2210
|
"error": {
|
|
2211
2211
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
2212
|
-
"message":
|
|
2212
|
+
"message": "Internal server error",
|
|
2213
2213
|
},
|
|
2214
2214
|
},
|
|
2215
2215
|
)
|
|
@@ -2300,12 +2300,12 @@ async def handle_assistant_agent_card_endpoint(request: ApiRequest) -> Response:
|
|
|
2300
2300
|
status_code=400,
|
|
2301
2301
|
media_type="application/json",
|
|
2302
2302
|
)
|
|
2303
|
-
except Exception
|
|
2303
|
+
except Exception:
|
|
2304
2304
|
logger.exception("Failed to generate agent card")
|
|
2305
2305
|
error_response = {
|
|
2306
2306
|
"error": {
|
|
2307
2307
|
"code": ERROR_CODE_INTERNAL_ERROR,
|
|
2308
|
-
"message":
|
|
2308
|
+
"message": "Internal server error",
|
|
2309
2309
|
}
|
|
2310
2310
|
}
|
|
2311
2311
|
return Response(
|
|
@@ -10,12 +10,16 @@ from starlette.responses import Response, StreamingResponse
|
|
|
10
10
|
|
|
11
11
|
from langgraph_api import config
|
|
12
12
|
from langgraph_api.asyncio import ValueEvent
|
|
13
|
+
from langgraph_api.encryption.context import get_encryption_context
|
|
13
14
|
from langgraph_api.encryption.middleware import (
|
|
14
15
|
decrypt_response,
|
|
15
16
|
decrypt_responses,
|
|
16
17
|
encrypt_request,
|
|
17
18
|
)
|
|
18
|
-
from langgraph_api.encryption.shared import
|
|
19
|
+
from langgraph_api.encryption.shared import (
|
|
20
|
+
BLOB_ENCRYPTION_CONTEXT_KEY,
|
|
21
|
+
using_aes_encryption,
|
|
22
|
+
)
|
|
19
23
|
from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
|
|
20
24
|
from langgraph_api.graph import _validate_assistant_id
|
|
21
25
|
from langgraph_api.models.run import create_valid_run
|
|
@@ -62,6 +66,29 @@ else:
|
|
|
62
66
|
logger = structlog.stdlib.get_logger(__name__)
|
|
63
67
|
|
|
64
68
|
|
|
69
|
+
def parse_stream_mode_param(stream_mode_param: str | None) -> list[str]:
|
|
70
|
+
"""Parse stream_mode query parameter. We use this to support the query param format used by the SDK.
|
|
71
|
+
|
|
72
|
+
Supports:
|
|
73
|
+
- Single values: "values" -> ["values"]
|
|
74
|
+
- JSON arrays: '["values","messages-tuple","updates"]' -> ["values", "messages-tuple", "updates"]
|
|
75
|
+
- Empty/None: None -> []
|
|
76
|
+
"""
|
|
77
|
+
if not stream_mode_param:
|
|
78
|
+
return []
|
|
79
|
+
|
|
80
|
+
# Try to parse as JSON array first
|
|
81
|
+
if stream_mode_param.startswith("["):
|
|
82
|
+
try:
|
|
83
|
+
parsed = orjson.loads(stream_mode_param)
|
|
84
|
+
if isinstance(parsed, list):
|
|
85
|
+
return parsed
|
|
86
|
+
except (orjson.JSONDecodeError, ValueError):
|
|
87
|
+
pass
|
|
88
|
+
# Single value
|
|
89
|
+
return [stream_mode_param]
|
|
90
|
+
|
|
91
|
+
|
|
65
92
|
# Type alias for stream handlers (GrpcStreamHandler or ContextQueue).
|
|
66
93
|
# Runs is selected at runtime, and the implementations have different
|
|
67
94
|
# type signatures, so we use Any for compatibility.
|
|
@@ -539,7 +566,10 @@ async def join_run_stream(request: ApiRequest):
|
|
|
539
566
|
cancel_on_disconnect = cancel_on_disconnect_str.lower() in {"true", "yes", "1"}
|
|
540
567
|
validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
|
|
541
568
|
validate_uuid(run_id, "Invalid run ID: must be a UUID")
|
|
542
|
-
|
|
569
|
+
|
|
570
|
+
stream_mode_param = request.query_params.get("stream_mode")
|
|
571
|
+
stream_mode = parse_stream_mode_param(stream_mode_param)
|
|
572
|
+
|
|
543
573
|
last_event_id = request.headers.get("last-event-id") or None
|
|
544
574
|
|
|
545
575
|
async def body():
|
|
@@ -688,8 +718,16 @@ async def create_cron(request: ApiRequest):
|
|
|
688
718
|
await validate_webhook_url_or_raise(str(webhook))
|
|
689
719
|
_validate_assistant_id(payload.get("assistant_id"))
|
|
690
720
|
|
|
721
|
+
# Store encryption context at payload root so cron scheduler can extract it
|
|
722
|
+
# regardless of which fields (metadata, input, config, context) are present.
|
|
723
|
+
# Use a separate variable to avoid shadowing the typed payload.
|
|
724
|
+
enc_ctx = get_encryption_context()
|
|
725
|
+
payload_for_encryption: dict = (
|
|
726
|
+
{**payload, BLOB_ENCRYPTION_CONTEXT_KEY: enc_ctx} if enc_ctx else payload
|
|
727
|
+
)
|
|
728
|
+
|
|
691
729
|
encrypted_payload = await encrypt_request(
|
|
692
|
-
|
|
730
|
+
payload_for_encryption,
|
|
693
731
|
"cron",
|
|
694
732
|
CRON_PAYLOAD_ENCRYPTION_SUBFIELDS,
|
|
695
733
|
)
|
|
@@ -724,8 +762,16 @@ async def create_thread_cron(request: ApiRequest):
|
|
|
724
762
|
await validate_webhook_url_or_raise(str(webhook))
|
|
725
763
|
_validate_assistant_id(payload.get("assistant_id"))
|
|
726
764
|
|
|
765
|
+
# Store encryption context at payload root so cron scheduler can extract it
|
|
766
|
+
# regardless of which fields (metadata, input, config, context) are present.
|
|
767
|
+
# Use a separate variable to avoid shadowing the typed payload.
|
|
768
|
+
enc_ctx = get_encryption_context()
|
|
769
|
+
payload_for_encryption: dict = (
|
|
770
|
+
{**payload, BLOB_ENCRYPTION_CONTEXT_KEY: enc_ctx} if enc_ctx else payload
|
|
771
|
+
)
|
|
772
|
+
|
|
727
773
|
encrypted_payload = await encrypt_request(
|
|
728
|
-
|
|
774
|
+
payload_for_encryption,
|
|
729
775
|
"cron",
|
|
730
776
|
CRON_PAYLOAD_ENCRYPTION_SUBFIELDS,
|
|
731
777
|
)
|
|
@@ -65,7 +65,7 @@ async def put_item(request: ApiRequest):
|
|
|
65
65
|
}
|
|
66
66
|
await handle_event("put", handler_payload)
|
|
67
67
|
await (await get_store()).aput(
|
|
68
|
-
namespace, handler_payload["key"], handler_payload["value"]
|
|
68
|
+
handler_payload["namespace"], handler_payload["key"], handler_payload["value"]
|
|
69
69
|
)
|
|
70
70
|
return Response(status_code=204)
|
|
71
71
|
|
|
@@ -68,9 +68,10 @@ async def handle_ui(request: ApiRequest) -> Response:
|
|
|
68
68
|
f'<link rel="stylesheet" href="{protocol}//{host}/ui/{graph_id}/{basename}" />'
|
|
69
69
|
)
|
|
70
70
|
elif ext == ".js":
|
|
71
|
+
safe_name = json.dumps(message["name"]).replace("'", "'")
|
|
71
72
|
result.append(
|
|
72
73
|
f'<script src="{protocol}//{host}/ui/{graph_id}/{basename}" '
|
|
73
|
-
f"onload='__LGUI_{valid_js_name}.render({
|
|
74
|
+
f"onload='__LGUI_{valid_js_name}.render({safe_name}, \"{{{{shadowRootId}}}}\")'>"
|
|
74
75
|
"</script>"
|
|
75
76
|
)
|
|
76
77
|
|
|
@@ -517,10 +517,10 @@ class ProxyUser(BaseUser):
|
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
def __contains__(self, key: str) -> bool:
|
|
520
|
-
return key in self.
|
|
520
|
+
return key in self.dict()
|
|
521
521
|
|
|
522
522
|
def __getitem__(self, key):
|
|
523
|
-
return self.
|
|
523
|
+
return self.dict()[key]
|
|
524
524
|
|
|
525
525
|
def __setitem__(self, key, value):
|
|
526
526
|
self._user[key] = value
|
|
@@ -530,10 +530,22 @@ class ProxyUser(BaseUser):
|
|
|
530
530
|
return getattr(self._user, name)
|
|
531
531
|
|
|
532
532
|
def __iter__(self):
|
|
533
|
-
return iter(self.
|
|
533
|
+
return iter(self.dict())
|
|
534
534
|
|
|
535
535
|
def __len__(self):
|
|
536
|
-
return len(self.
|
|
536
|
+
return len(self.dict())
|
|
537
|
+
|
|
538
|
+
def get(self, key, /, default=None):
|
|
539
|
+
return self.dict().get(key, default)
|
|
540
|
+
|
|
541
|
+
def keys(self):
|
|
542
|
+
return self.dict().keys()
|
|
543
|
+
|
|
544
|
+
def values(self):
|
|
545
|
+
return self.dict().values()
|
|
546
|
+
|
|
547
|
+
def items(self):
|
|
548
|
+
return self.dict().items()
|
|
537
549
|
|
|
538
550
|
def __str__(self) -> str:
|
|
539
551
|
return f"{self._user}"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from starlette.authentication import (
|
|
2
|
+
AuthCredentials,
|
|
3
|
+
AuthenticationBackend,
|
|
4
|
+
BaseUser,
|
|
5
|
+
)
|
|
6
|
+
from starlette.authentication import (
|
|
7
|
+
UnauthenticatedUser as StarletteUnauthenticatedUser,
|
|
8
|
+
)
|
|
9
|
+
from starlette.requests import HTTPConnection
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UnauthenticatedUser(StarletteUnauthenticatedUser):
|
|
13
|
+
@property
|
|
14
|
+
def identity(self) -> str:
|
|
15
|
+
return ""
|
|
16
|
+
|
|
17
|
+
def dict(self):
|
|
18
|
+
return {
|
|
19
|
+
"identity": self.identity,
|
|
20
|
+
"is_authenticated": self.is_authenticated,
|
|
21
|
+
"display_name": self.display_name,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def __getitem__(self, key):
|
|
25
|
+
return self.dict()[key]
|
|
26
|
+
|
|
27
|
+
def __contains__(self, key):
|
|
28
|
+
return key in self.dict()
|
|
29
|
+
|
|
30
|
+
def __iter__(self):
|
|
31
|
+
return iter(self.dict())
|
|
32
|
+
|
|
33
|
+
def __len__(self):
|
|
34
|
+
return len(self.dict())
|
|
35
|
+
|
|
36
|
+
def get(self, key, /, default=None):
|
|
37
|
+
return self.dict().get(key, default)
|
|
38
|
+
|
|
39
|
+
def keys(self):
|
|
40
|
+
return self.dict().keys()
|
|
41
|
+
|
|
42
|
+
def values(self):
|
|
43
|
+
return self.dict().values()
|
|
44
|
+
|
|
45
|
+
def items(self):
|
|
46
|
+
return self.dict().items()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class NoopAuthBackend(AuthenticationBackend):
|
|
50
|
+
async def authenticate(
|
|
51
|
+
self, conn: HTTPConnection
|
|
52
|
+
) -> tuple[AuthCredentials, BaseUser] | None:
|
|
53
|
+
return AuthCredentials(), UnauthenticatedUser()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from langgraph_sdk.auth.types import StudioUser as StudioUserBase
|
|
2
|
+
from starlette.authentication import BaseUser
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class StudioUser(StudioUserBase, BaseUser):
|
|
6
|
+
"""StudioUser class."""
|
|
7
|
+
|
|
8
|
+
def dict(self):
|
|
9
|
+
return {
|
|
10
|
+
"kind": "StudioUser",
|
|
11
|
+
"is_authenticated": self.is_authenticated,
|
|
12
|
+
"display_name": self.display_name,
|
|
13
|
+
"identity": self.identity,
|
|
14
|
+
"permissions": self.permissions,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def __getitem__(self, key):
|
|
18
|
+
return self.dict()[key]
|
|
19
|
+
|
|
20
|
+
def __contains__(self, key):
|
|
21
|
+
return key in self.dict()
|
|
22
|
+
|
|
23
|
+
def __iter__(self):
|
|
24
|
+
return iter(self.dict())
|
|
25
|
+
|
|
26
|
+
def __len__(self):
|
|
27
|
+
return len(self.dict())
|
|
28
|
+
|
|
29
|
+
def get(self, key, /, default=None):
|
|
30
|
+
return self.dict().get(key, default)
|
|
31
|
+
|
|
32
|
+
def keys(self):
|
|
33
|
+
return self.dict().keys()
|
|
34
|
+
|
|
35
|
+
def values(self):
|
|
36
|
+
return self.dict().values()
|
|
37
|
+
|
|
38
|
+
def items(self):
|
|
39
|
+
return self.dict().items()
|
|
@@ -107,6 +107,7 @@ def run_server(
|
|
|
107
107
|
ui: dict | None = None,
|
|
108
108
|
webhooks: dict | None = None,
|
|
109
109
|
ui_config: dict | None = None,
|
|
110
|
+
checkpointer: dict | None = None,
|
|
110
111
|
studio_url: str | None = None,
|
|
111
112
|
disable_persistence: bool = False,
|
|
112
113
|
allow_blocking: bool = False,
|
|
@@ -209,6 +210,7 @@ def run_server(
|
|
|
209
210
|
LANGGRAPH_UI=json.dumps(ui) if ui else None,
|
|
210
211
|
LANGGRAPH_WEBHOOKS=json.dumps(webhooks) if webhooks else None,
|
|
211
212
|
LANGGRAPH_UI_CONFIG=json.dumps(ui_config) if ui_config else None,
|
|
213
|
+
LANGGRAPH_CHECKPOINTER=json.dumps(checkpointer) if checkpointer else None,
|
|
212
214
|
LANGGRAPH_UI_BUNDLER="true",
|
|
213
215
|
LANGGRAPH_API_URL=local_url,
|
|
214
216
|
LANGGRAPH_DISABLE_FILE_PERSISTENCE=str(disable_persistence).lower(),
|
|
@@ -411,6 +413,7 @@ def main():
|
|
|
411
413
|
ui = config_data.get("ui")
|
|
412
414
|
webhooks = config_data.get("webhooks")
|
|
413
415
|
ui_config = config_data.get("ui_config")
|
|
416
|
+
checkpointer = config_data.get("checkpointer")
|
|
414
417
|
kwargs = {}
|
|
415
418
|
if args.runtime_edition == "postgres":
|
|
416
419
|
kwargs["__redis_uri__"] = os.getenv("REDIS_URI")
|
|
@@ -433,6 +436,7 @@ def main():
|
|
|
433
436
|
ui=ui,
|
|
434
437
|
webhooks=webhooks,
|
|
435
438
|
ui_config=ui_config,
|
|
439
|
+
checkpointer=checkpointer,
|
|
436
440
|
runtime_edition=args.runtime_edition,
|
|
437
441
|
**kwargs,
|
|
438
442
|
)
|