langgraph-api 0.7.78__tar.gz → 0.7.80__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.78 → langgraph_api-0.7.80}/PKG-INFO +2 -2
- langgraph_api-0.7.80/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/_checkpointer/_adapter.py +2 -2
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/custom.py +2 -2
- langgraph_api-0.7.80/langgraph_api/cache.py +418 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/cli.py +3 -3
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/command.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/cron_scheduler.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/encryption/context.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/encryption/middleware.py +4 -4
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/graph.py +3 -3
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/client.py +2 -2
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/ops/assistants.py +8 -8
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/ops/crons.py +6 -6
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/ops/runs.py +8 -8
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/ops/threads.py +9 -9
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/servicers/checkpointer.py +4 -4
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/servicers/encryption.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/http.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/remote.py +4 -4
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/sse.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/logging.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/metadata.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/models/run.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/patch.py +3 -3
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/schema.py +4 -4
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/server.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/state.py +9 -9
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/store.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/stream.py +8 -8
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/timing/profiler.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/timing/timer.py +5 -5
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/traceblock.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/__init__.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/config.py +4 -4
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/future.py +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/core_api_pb2.pyi +10 -10
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_api_pb2.pyi +5 -5
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_api_pb2_grpc.pyi +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_common_pb2.pyi +3 -3
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/executor_api_pb2.pyi +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/executor_api_pb2_grpc.pyi +2 -2
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/pyproject.toml +1 -1
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/uv.lock +140 -123
- langgraph_api-0.7.78/langgraph_api/__init__.py +0 -1
- langgraph_api-0.7.78/langgraph_api/cache.py +0 -51
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/.gitignore +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/LICENSE +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/Makefile +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/README.md +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/.gitignore +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/Makefile +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/README.md +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/benchmark-runners/assistant.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/benchmark-runners/benchmark-runner.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/benchmark-runners/benchmarks.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/benchmark-runners/stream_write.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/benchmark-runners/thread.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/benchmark-runners/wait_write.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/burst.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/capacity_dd_report.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/capacity_k6.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/capacity_runner.mjs +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/capacity_slack_report.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/capacity_urls.mjs +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/clean-cli.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/clean.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/continuous/README.md +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/continuous/pyproject.toml +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/continuous/runner.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/continuous/uv.lock +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/graphs.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/mixed_workload_k6.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/mixed_workload_runner.mjs +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/package.json +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/ramp.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/reporting/dd_reporting.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/reporting/slack_slowest_runs.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/reporting/slack_summary.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/run_local.sh +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/staircase.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/staircase_step_k6.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/update-revision.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/benchmark/weather.js +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/constraints.txt +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/custom_store.sql +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/forbidden.txt +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/hatch_build.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/healthcheck.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph-cloud-debugging-20260210132856.zip +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/_checkpointer/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/_checkpointer/protocol.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/_factory_utils.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/a2a.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/mcp/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/mcp/_constants.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/mcp/_handlers.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/mcp/_models.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/mcp/_routes.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/mcp/_sanitizers.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/profile.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/runs.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/errors.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/config/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/config/_parse.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/config/schemas.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/encryption/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/encryption/aes_json.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/encryption/custom.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/encryption/shared.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/executor_entrypoint.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/feature_flags.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/ops/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/ops/cache.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/server.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/grpc/servicers/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/http_metrics.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/http_metrics_utils.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/traceblock.mts +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/middleware/ensure_store.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/otel_context.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/route.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/self_hosted_logs.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/self_hosted_metrics.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/timing/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/cache.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/errors.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/extract.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/headers.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/retriable_client.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/stream_codec.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/utils/uuids.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_api/worker.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/checkpointer.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/_compat.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/channel.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/checkpoint.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/config.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/durability.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/exception.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/graph.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/interrupt.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/messages.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/orchestrator_response.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/runopts.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/stream_mode.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/struct.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/task.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/conversion/value.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/core_api_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_api_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_api_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/executor_api_pb2.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/proto/executor_api_pb2_grpc.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/sanitize.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_grpc_common/serde.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/routes.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/logging.json +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/openapi.json +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/scripts/build_wheel.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/scripts/create_license.py +0 -0
- {langgraph_api-0.7.78 → langgraph_api-0.7.80}/scripts/run_a2a_tck.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.80
|
|
4
4
|
Author-email: Will Fu-Hinthorn <will@langchain.dev>, Josh Rogers <josh@langchain.dev>, Parker Rule <parker@langchain.dev>
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -24,7 +24,7 @@ Requires-Dist: opentelemetry-sdk>=1.37.0
|
|
|
24
24
|
Requires-Dist: orjson>=3.9.7
|
|
25
25
|
Requires-Dist: protobuf<7.0.0,>=6.32.1
|
|
26
26
|
Requires-Dist: pyjwt>=2.9.0
|
|
27
|
-
Requires-Dist: sse-starlette<3.4.0,>=
|
|
27
|
+
Requires-Dist: sse-starlette<3.4.0,>=2.1.3
|
|
28
28
|
Requires-Dist: starlette>=0.38.6
|
|
29
29
|
Requires-Dist: structlog<26,>=24.1.0
|
|
30
30
|
Requires-Dist: tenacity>=8.0.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.80"
|
|
@@ -309,7 +309,7 @@ async def get_checkpointer(
|
|
|
309
309
|
# Create a fresh adapter each time (not cached) - each gets own latest_iter
|
|
310
310
|
if _CHECKPOINTER_CAPABILITIES is None:
|
|
311
311
|
raise RuntimeError("Capabilities not initialized")
|
|
312
|
-
return _CustomCheckpointerAdapter(
|
|
312
|
+
return _CustomCheckpointerAdapter(
|
|
313
313
|
inner=CHECKPOINTER_STACK.inner, capabilities=_CHECKPOINTER_CAPABILITIES
|
|
314
314
|
)
|
|
315
315
|
|
|
@@ -431,7 +431,7 @@ def _load_checkpointer(checkpointer_path: str) -> Any:
|
|
|
431
431
|
raise ValueError(f"Could not find checkpointer file: {path_name}")
|
|
432
432
|
module = importlib.util.module_from_spec(modspec)
|
|
433
433
|
sys.modules[modname] = module
|
|
434
|
-
modspec.loader.exec_module(module)
|
|
434
|
+
modspec.loader.exec_module(module)
|
|
435
435
|
else:
|
|
436
436
|
path_name, function = checkpointer_path.rsplit(".", 1)
|
|
437
437
|
module = importlib.import_module(path_name)
|
|
@@ -251,7 +251,7 @@ def _get_auth_instance(path: str | None = None) -> Auth | Literal["js"] | None:
|
|
|
251
251
|
deps := _get_dependencies(auth_instance._authenticate_handler)
|
|
252
252
|
):
|
|
253
253
|
auth_instance._authenticate_handler = _solve_fastapi_dependencies(
|
|
254
|
-
auth_instance._authenticate_handler,
|
|
254
|
+
auth_instance._authenticate_handler,
|
|
255
255
|
deps,
|
|
256
256
|
)
|
|
257
257
|
logger.info(f"Loaded auth instance from path {path}: {auth_instance}")
|
|
@@ -631,7 +631,7 @@ def _load_auth_obj(path: str) -> Auth | Literal["js"]:
|
|
|
631
631
|
raise ValueError(f"Could not load file: {module_name}")
|
|
632
632
|
module = importlib.util.module_from_spec(modspec)
|
|
633
633
|
sys.modules[modname] = module
|
|
634
|
-
modspec.loader.exec_module(module)
|
|
634
|
+
modspec.loader.exec_module(module)
|
|
635
635
|
else:
|
|
636
636
|
# Load from Python module
|
|
637
637
|
module = importlib.import_module(module_name)
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"""Basic distributed key/value cache for internal use."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import time
|
|
6
|
+
from collections.abc import Awaitable, Callable
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from datetime import timedelta
|
|
9
|
+
from typing import Any, Generic, Literal, TypedDict, TypeVar, cast
|
|
10
|
+
|
|
11
|
+
import orjson
|
|
12
|
+
|
|
13
|
+
from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
|
|
14
|
+
from langgraph_api.utils.cache import LRUCache
|
|
15
|
+
|
|
16
|
+
MAX_CACHE_TTL = timedelta(hours=24)
|
|
17
|
+
|
|
18
|
+
if IS_POSTGRES_OR_GRPC_BACKEND:
|
|
19
|
+
from langgraph_api.grpc.ops.cache import cache_get as _cache_get
|
|
20
|
+
from langgraph_api.grpc.ops.cache import cache_set as _cache_set
|
|
21
|
+
else:
|
|
22
|
+
_CACHE: LRUCache[bytes] = LRUCache(ttl=MAX_CACHE_TTL.total_seconds())
|
|
23
|
+
|
|
24
|
+
async def _cache_get(key: str) -> bytes | None:
|
|
25
|
+
return await _CACHE.get(key)
|
|
26
|
+
|
|
27
|
+
async def _cache_set(key: str, value: bytes, ttl: timedelta | None = None) -> None:
|
|
28
|
+
ttl = _clamp_ttl(ttl)
|
|
29
|
+
_CACHE.set(key, value)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
_SWR_KEY_PREFIX = "__lg_swr__:"
|
|
35
|
+
_SWR_SCHEMA_VERSION = 1
|
|
36
|
+
_DELTA_ZERO = timedelta(0)
|
|
37
|
+
_UNSET: Any = object()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
JsonValue = dict[str, Any] | list[Any] | str | int | float | bool | None
|
|
41
|
+
|
|
42
|
+
CacheStatus = Literal["miss", "fresh", "stale", "expired"]
|
|
43
|
+
|
|
44
|
+
T = TypeVar("T")
|
|
45
|
+
|
|
46
|
+
__all__ = ["CacheStatus", "JsonValue", "SWRResult", "cache_get", "cache_set", "swr"]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SWRResult(Generic[T]):
|
|
50
|
+
"""Result wrapper returned by :func:`swr`.
|
|
51
|
+
|
|
52
|
+
Attributes:
|
|
53
|
+
value: The cached (or freshly loaded) value.
|
|
54
|
+
status: How the value was resolved: ``"miss"``, ``"fresh"``,
|
|
55
|
+
``"stale"``, or ``"expired"``.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
__slots__ = ("_cache_key", "_loader", "_max_age", "_model", "status", "value")
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
value: T,
|
|
63
|
+
*,
|
|
64
|
+
cache_key: str,
|
|
65
|
+
loader: Callable[[], Awaitable[Any]],
|
|
66
|
+
max_age: timedelta,
|
|
67
|
+
status: CacheStatus,
|
|
68
|
+
model: type[T] | None = None,
|
|
69
|
+
) -> None:
|
|
70
|
+
self.value = value
|
|
71
|
+
self._cache_key = cache_key
|
|
72
|
+
self._loader = loader
|
|
73
|
+
self._max_age = max_age
|
|
74
|
+
self._model = model
|
|
75
|
+
self.status: CacheStatus = status
|
|
76
|
+
|
|
77
|
+
async def mutate(self, value: T = _UNSET) -> T: # ty: ignore[invalid-parameter-default]
|
|
78
|
+
"""Update or revalidate the cached value.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
value: If provided, optimistically write this value into the cache.
|
|
82
|
+
If omitted, re-run the original loader to revalidate.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
The new cached value.
|
|
86
|
+
"""
|
|
87
|
+
if value is _UNSET:
|
|
88
|
+
raw = await _await_swr_load(self._cache_key, self._loader, self._max_age)
|
|
89
|
+
result = (
|
|
90
|
+
cast("T", self._model.model_validate(raw))
|
|
91
|
+
if self._model is not None
|
|
92
|
+
else cast("T", raw)
|
|
93
|
+
)
|
|
94
|
+
else:
|
|
95
|
+
raw = value.model_dump(mode="json") if self._model is not None else value
|
|
96
|
+
await _write_swr_value(self._cache_key, raw, self._max_age)
|
|
97
|
+
result = value
|
|
98
|
+
self.value = result
|
|
99
|
+
return result
|
|
100
|
+
|
|
101
|
+
def __repr__(self) -> str:
|
|
102
|
+
return f"SWRResult(value={self.value!r}, status={self.status!r})"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
async def cache_get(key: str) -> Any | None:
|
|
106
|
+
"""Get a value from the cache."""
|
|
107
|
+
val = await _cache_get(key)
|
|
108
|
+
return orjson.loads(val) if val is not None else None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
async def cache_set(key: str, value: Any, ttl: timedelta | None = None) -> None:
|
|
112
|
+
"""Set a value in the cache.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
key: The cache key.
|
|
116
|
+
value: The value to cache (must be serializable to JSON).
|
|
117
|
+
ttl: Optional time-to-live. Capped at MAX_CACHE_TTL (24 hours by default);
|
|
118
|
+
`None` or zero defaults to MAX_CACHE_TTL.
|
|
119
|
+
"""
|
|
120
|
+
ttl = _clamp_ttl(ttl)
|
|
121
|
+
await _cache_set(key, orjson.dumps(value), ttl)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class _SWREntry(TypedDict):
|
|
125
|
+
v: int
|
|
126
|
+
value: Any
|
|
127
|
+
stored_at_ms: int
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass(slots=True)
|
|
131
|
+
class _SWRState:
|
|
132
|
+
task: asyncio.Task[Any] | None = None
|
|
133
|
+
write_epoch: int = 0
|
|
134
|
+
write_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
|
|
135
|
+
users: int = 0
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
_SWR_STATES: dict[str, _SWRState] = {}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
async def swr(
|
|
142
|
+
key: str,
|
|
143
|
+
loader: Callable[[], Awaitable[T]],
|
|
144
|
+
*,
|
|
145
|
+
fresh_for: timedelta = _DELTA_ZERO,
|
|
146
|
+
max_age: timedelta | None = None,
|
|
147
|
+
model: type[T] | None = None,
|
|
148
|
+
) -> SWRResult[T]:
|
|
149
|
+
"""Load a cached value using stale-while-revalidate semantics.
|
|
150
|
+
|
|
151
|
+
This helper is server-side only and is intended for caching internal async
|
|
152
|
+
dependencies such as auth or metadata lookups.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
key: Cache key.
|
|
156
|
+
loader: Async callable that fetches the value on miss/revalidation.
|
|
157
|
+
fresh_for: How long a cached value is considered fresh (no revalidation).
|
|
158
|
+
Defaults to ``timedelta(0)`` so every access triggers a background
|
|
159
|
+
revalidate while still returning the cached value instantly. Values
|
|
160
|
+
above :data:`MAX_CACHE_TTL` are clamped to the backend maximum.
|
|
161
|
+
max_age: Total lifetime of a cached entry. After this, the next access
|
|
162
|
+
blocks on the loader. Defaults to :data:`MAX_CACHE_TTL` (24 h by
|
|
163
|
+
default). Values above :data:`MAX_CACHE_TTL` are clamped to the
|
|
164
|
+
backend maximum.
|
|
165
|
+
model: Optional Pydantic model class. When provided, values are
|
|
166
|
+
serialized via ``model_dump(mode="json")`` before storage and
|
|
167
|
+
deserialized via ``model.model_validate()`` on read.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
An :class:`SWRResult` with ``.value``, ``.status``, and an async
|
|
171
|
+
``.mutate()`` method.
|
|
172
|
+
|
|
173
|
+
Semantics:
|
|
174
|
+
- cache miss: await ``loader()``, store the value, return it
|
|
175
|
+
- fresh hit (age < fresh_for): return the cached value
|
|
176
|
+
- stale hit (fresh_for <= age < max_age): return the cached value
|
|
177
|
+
immediately and trigger a best-effort background refresh
|
|
178
|
+
- expired (age >= max_age): await ``loader()``, store the value, return it
|
|
179
|
+
"""
|
|
180
|
+
resolved_fresh_for = min(fresh_for, MAX_CACHE_TTL)
|
|
181
|
+
resolved_max_age = _resolve_swr_max_age(max_age)
|
|
182
|
+
fresh_for_ms, max_age_ms, resolved_max_age = _validate_swr_windows(
|
|
183
|
+
resolved_fresh_for, resolved_max_age
|
|
184
|
+
)
|
|
185
|
+
cache_key = _swr_cache_key(key)
|
|
186
|
+
|
|
187
|
+
# When a pydantic model is provided, wrap the loader to serialize before
|
|
188
|
+
# storage and deserialize after reads. The internal helpers always deal
|
|
189
|
+
# with plain JSON-compatible values.
|
|
190
|
+
if model is not None and hasattr(model, "model_validate"):
|
|
191
|
+
_original_loader = loader
|
|
192
|
+
|
|
193
|
+
async def _json_loader() -> Any:
|
|
194
|
+
val = await _original_loader()
|
|
195
|
+
return val.model_dump(mode="json")
|
|
196
|
+
|
|
197
|
+
json_loader: Callable[[], Awaitable[Any]] = _json_loader
|
|
198
|
+
|
|
199
|
+
def _deserialize(raw: Any) -> T:
|
|
200
|
+
return cast("T", model.model_validate(raw)) # ty: ignore[call-non-callable]
|
|
201
|
+
else:
|
|
202
|
+
json_loader = loader
|
|
203
|
+
|
|
204
|
+
def _deserialize(raw: Any) -> T:
|
|
205
|
+
return cast("T", raw)
|
|
206
|
+
|
|
207
|
+
def _result(value: T, status: CacheStatus) -> SWRResult[T]:
|
|
208
|
+
return SWRResult(
|
|
209
|
+
value,
|
|
210
|
+
cache_key=cache_key,
|
|
211
|
+
loader=json_loader,
|
|
212
|
+
max_age=resolved_max_age,
|
|
213
|
+
status=status,
|
|
214
|
+
model=model,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
entry = _parse_swr_entry(await cache_get(cache_key))
|
|
218
|
+
if entry is None:
|
|
219
|
+
raw = await _await_swr_load(cache_key, json_loader, resolved_max_age)
|
|
220
|
+
return _result(_deserialize(raw), "miss")
|
|
221
|
+
|
|
222
|
+
age_ms = max(0, _now_ms() - entry["stored_at_ms"])
|
|
223
|
+
cached_value = _deserialize(entry["value"])
|
|
224
|
+
|
|
225
|
+
if age_ms < fresh_for_ms:
|
|
226
|
+
return _result(cached_value, "fresh")
|
|
227
|
+
|
|
228
|
+
if age_ms < max_age_ms:
|
|
229
|
+
_start_swr_refresh(cache_key, json_loader, resolved_max_age)
|
|
230
|
+
return _result(cached_value, "stale")
|
|
231
|
+
|
|
232
|
+
raw = await _await_swr_load(cache_key, json_loader, resolved_max_age)
|
|
233
|
+
return _result(_deserialize(raw), "expired")
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _clamp_ttl(ttl: timedelta | None) -> timedelta:
|
|
237
|
+
"""Normalise caller-supplied TTL: None/0 -> MAX, >MAX -> MAX."""
|
|
238
|
+
if ttl is None or ttl <= timedelta(0):
|
|
239
|
+
return MAX_CACHE_TTL
|
|
240
|
+
return min(ttl, MAX_CACHE_TTL)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _resolve_swr_max_age(max_age: timedelta | None) -> timedelta:
|
|
244
|
+
if max_age is None:
|
|
245
|
+
return MAX_CACHE_TTL
|
|
246
|
+
if max_age <= _DELTA_ZERO:
|
|
247
|
+
return max_age
|
|
248
|
+
return min(max_age, MAX_CACHE_TTL)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _swr_cache_key(key: str) -> str:
|
|
252
|
+
return f"{_SWR_KEY_PREFIX}{key}"
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _validate_swr_windows(
|
|
256
|
+
fresh_for: timedelta, max_age: timedelta
|
|
257
|
+
) -> tuple[int, int, timedelta]:
|
|
258
|
+
if fresh_for < _DELTA_ZERO:
|
|
259
|
+
raise ValueError("fresh_for must be >= 0")
|
|
260
|
+
if max_age <= _DELTA_ZERO:
|
|
261
|
+
raise ValueError("max_age must be > 0")
|
|
262
|
+
if fresh_for > max_age:
|
|
263
|
+
raise ValueError("fresh_for must be <= max_age")
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
int(fresh_for.total_seconds() * 1000),
|
|
267
|
+
int(max_age.total_seconds() * 1000),
|
|
268
|
+
max_age,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _now_ms() -> int:
|
|
273
|
+
return time.time_ns() // 1_000_000
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _parse_swr_entry(value: Any) -> _SWREntry | None:
|
|
277
|
+
if not isinstance(value, dict):
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
version = value.get("v")
|
|
281
|
+
stored_at_ms = value.get("stored_at_ms")
|
|
282
|
+
if version != _SWR_SCHEMA_VERSION or not isinstance(stored_at_ms, int):
|
|
283
|
+
return None
|
|
284
|
+
if "value" not in value:
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
"v": _SWR_SCHEMA_VERSION,
|
|
289
|
+
"value": value["value"],
|
|
290
|
+
"stored_at_ms": stored_at_ms,
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _acquire_swr_state(cache_key: str) -> _SWRState:
|
|
295
|
+
state = _SWR_STATES.get(cache_key)
|
|
296
|
+
if state is None:
|
|
297
|
+
state = _SWRState()
|
|
298
|
+
_SWR_STATES[cache_key] = state
|
|
299
|
+
state.users += 1
|
|
300
|
+
return state
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _release_swr_state(cache_key: str, state: _SWRState) -> None:
|
|
304
|
+
state.users -= 1
|
|
305
|
+
_maybe_cleanup_swr_state(cache_key, state)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _maybe_cleanup_swr_state(cache_key: str, state: _SWRState) -> None:
|
|
309
|
+
if (
|
|
310
|
+
state.users == 0
|
|
311
|
+
and state.task is None
|
|
312
|
+
and not state.write_lock.locked()
|
|
313
|
+
and _SWR_STATES.get(cache_key) is state
|
|
314
|
+
):
|
|
315
|
+
_SWR_STATES.pop(cache_key, None)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
async def _cache_swr_entry(cache_key: str, value: Any, ttl: timedelta) -> None:
|
|
319
|
+
entry: _SWREntry = {
|
|
320
|
+
"v": _SWR_SCHEMA_VERSION,
|
|
321
|
+
"value": value,
|
|
322
|
+
"stored_at_ms": _now_ms(),
|
|
323
|
+
}
|
|
324
|
+
await cache_set(cache_key, entry, ttl=ttl)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
async def _write_swr_value(cache_key: str, value: Any, ttl: timedelta) -> None:
|
|
328
|
+
state = _acquire_swr_state(cache_key)
|
|
329
|
+
try:
|
|
330
|
+
async with state.write_lock:
|
|
331
|
+
state.write_epoch += 1
|
|
332
|
+
await _cache_swr_entry(cache_key, value, ttl)
|
|
333
|
+
finally:
|
|
334
|
+
_release_swr_state(cache_key, state)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
async def _store_loaded_swr_value(
|
|
338
|
+
cache_key: str, value: Any, ttl: timedelta, *, start_epoch: int
|
|
339
|
+
) -> bool:
|
|
340
|
+
state = _acquire_swr_state(cache_key)
|
|
341
|
+
try:
|
|
342
|
+
async with state.write_lock:
|
|
343
|
+
if start_epoch != state.write_epoch:
|
|
344
|
+
return False
|
|
345
|
+
await _cache_swr_entry(cache_key, value, ttl)
|
|
346
|
+
return True
|
|
347
|
+
finally:
|
|
348
|
+
_release_swr_state(cache_key, state)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
async def _load_and_store_swr_value(
|
|
352
|
+
cache_key: str,
|
|
353
|
+
loader: Callable[[], Awaitable[T]],
|
|
354
|
+
ttl: timedelta,
|
|
355
|
+
*,
|
|
356
|
+
start_epoch: int,
|
|
357
|
+
) -> T:
|
|
358
|
+
value = await loader()
|
|
359
|
+
if await _store_loaded_swr_value(cache_key, value, ttl, start_epoch=start_epoch):
|
|
360
|
+
return value
|
|
361
|
+
|
|
362
|
+
entry = _parse_swr_entry(await cache_get(cache_key))
|
|
363
|
+
if entry is not None:
|
|
364
|
+
return cast("T", entry["value"])
|
|
365
|
+
return value
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _ensure_swr_load_task(
|
|
369
|
+
cache_key: str,
|
|
370
|
+
loader: Callable[[], Awaitable[T]],
|
|
371
|
+
ttl: timedelta,
|
|
372
|
+
*,
|
|
373
|
+
log_errors: bool,
|
|
374
|
+
) -> asyncio.Task[T]:
|
|
375
|
+
state = _acquire_swr_state(cache_key)
|
|
376
|
+
try:
|
|
377
|
+
existing = state.task
|
|
378
|
+
if existing is not None and not existing.done():
|
|
379
|
+
return cast("asyncio.Task[T]", existing)
|
|
380
|
+
|
|
381
|
+
task = asyncio.create_task(
|
|
382
|
+
_load_and_store_swr_value(
|
|
383
|
+
cache_key, loader, ttl, start_epoch=state.write_epoch
|
|
384
|
+
)
|
|
385
|
+
)
|
|
386
|
+
state.task = task
|
|
387
|
+
|
|
388
|
+
def _cleanup(done: asyncio.Task[Any]) -> None:
|
|
389
|
+
cleanup_state = _SWR_STATES.get(cache_key)
|
|
390
|
+
if cleanup_state is not None and cleanup_state.task is done:
|
|
391
|
+
cleanup_state.task = None
|
|
392
|
+
_maybe_cleanup_swr_state(cache_key, cleanup_state)
|
|
393
|
+
try:
|
|
394
|
+
done.result()
|
|
395
|
+
except Exception:
|
|
396
|
+
if log_errors:
|
|
397
|
+
logger.debug(
|
|
398
|
+
"Background swr refresh failed for %s",
|
|
399
|
+
cache_key,
|
|
400
|
+
exc_info=True,
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
task.add_done_callback(_cleanup)
|
|
404
|
+
return task
|
|
405
|
+
finally:
|
|
406
|
+
_release_swr_state(cache_key, state)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
async def _await_swr_load(
|
|
410
|
+
cache_key: str, loader: Callable[[], Awaitable[T]], ttl: timedelta
|
|
411
|
+
) -> T:
|
|
412
|
+
return await _ensure_swr_load_task(cache_key, loader, ttl, log_errors=False)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _start_swr_refresh(
|
|
416
|
+
cache_key: str, loader: Callable[[], Awaitable[Any]], ttl: timedelta
|
|
417
|
+
) -> None:
|
|
418
|
+
_ensure_swr_load_task(cache_key, loader, ttl, log_errors=True)
|
|
@@ -135,7 +135,7 @@ def run_server(
|
|
|
135
135
|
mount_prefix = os.environ.get("LANGGRAPH_MOUNT_PREFIX")
|
|
136
136
|
if isinstance(env, str | pathlib.Path):
|
|
137
137
|
try:
|
|
138
|
-
from dotenv.main import ( #
|
|
138
|
+
from dotenv.main import ( # noqa: PLC0415
|
|
139
139
|
DotEnv,
|
|
140
140
|
)
|
|
141
141
|
|
|
@@ -149,7 +149,7 @@ def run_server(
|
|
|
149
149
|
|
|
150
150
|
if debug_port is not None:
|
|
151
151
|
try:
|
|
152
|
-
import debugpy #
|
|
152
|
+
import debugpy # noqa: PLC0415 # ty: ignore[unresolved-import]
|
|
153
153
|
except ImportError:
|
|
154
154
|
logger.warning("debugpy is not installed. Debugging will not be available.")
|
|
155
155
|
logger.info("To enable debugging, install debugpy: pip install debugpy")
|
|
@@ -226,7 +226,7 @@ def run_server(
|
|
|
226
226
|
if k in to_patch:
|
|
227
227
|
logger.debug(f"Skipping loaded env var {k}={v}")
|
|
228
228
|
continue
|
|
229
|
-
to_patch[k] = v
|
|
229
|
+
to_patch[k] = v
|
|
230
230
|
with patch_environment(
|
|
231
231
|
**to_patch,
|
|
232
232
|
):
|
|
@@ -21,7 +21,7 @@ def map_cmd(cmd: RunCommand) -> Command:
|
|
|
21
21
|
update=update,
|
|
22
22
|
goto=(
|
|
23
23
|
[
|
|
24
|
-
it if isinstance(it, str) else Send(it["node"], it["input"])
|
|
24
|
+
it if isinstance(it, str) else Send(it["node"], it["input"])
|
|
25
25
|
for it in goto
|
|
26
26
|
]
|
|
27
27
|
if goto
|
|
@@ -87,7 +87,7 @@ async def cron_scheduler():
|
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
if on_run_completed == "keep":
|
|
90
|
-
run_payload.setdefault("on_completion", "keep")
|
|
90
|
+
run_payload.setdefault("on_completion", "keep")
|
|
91
91
|
|
|
92
92
|
run_payload["metadata"] = get_metadata_from_payload(
|
|
93
93
|
cron, run_payload
|
|
@@ -11,7 +11,7 @@ from typing import Any
|
|
|
11
11
|
# Request-scoped encryption context
|
|
12
12
|
# Set by API middleware when X-Encryption-Context header is present
|
|
13
13
|
# Accessed by serializers during checkpoint encryption/decryption
|
|
14
|
-
encryption_context: ContextVar[dict[str, Any] | None] = ContextVar(
|
|
14
|
+
encryption_context: ContextVar[dict[str, Any] | None] = ContextVar(
|
|
15
15
|
"encryption_context", default=None
|
|
16
16
|
)
|
|
17
17
|
|
|
@@ -539,7 +539,7 @@ async def decrypt_response(
|
|
|
539
539
|
)
|
|
540
540
|
result["error"] = json_loads(error_bytes)
|
|
541
541
|
return result
|
|
542
|
-
return obj
|
|
542
|
+
return obj
|
|
543
543
|
|
|
544
544
|
result = dict(obj)
|
|
545
545
|
await _decrypt_object(result, model_type, fields, encryption_instance)
|
|
@@ -595,9 +595,9 @@ async def decrypt_responses(
|
|
|
595
595
|
result["error"] = json_loads(error_bytes)
|
|
596
596
|
results.append(result)
|
|
597
597
|
else:
|
|
598
|
-
results.append(obj)
|
|
598
|
+
results.append(obj)
|
|
599
599
|
return results
|
|
600
|
-
return objects
|
|
600
|
+
return objects
|
|
601
601
|
|
|
602
602
|
results = [dict(obj) for obj in objects]
|
|
603
603
|
await asyncio.gather(
|
|
@@ -728,7 +728,7 @@ async def encrypt_request(
|
|
|
728
728
|
"""
|
|
729
729
|
encryption_instance = get_encryption()
|
|
730
730
|
if encryption_instance is None:
|
|
731
|
-
return data
|
|
731
|
+
return data
|
|
732
732
|
|
|
733
733
|
result = dict(data)
|
|
734
734
|
encrypted_fields = await asyncio.gather(
|
|
@@ -557,7 +557,7 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
|
|
|
557
557
|
raise ValueError(f"Could not find python file for graph: {spec}")
|
|
558
558
|
module = importlib.util.module_from_spec(modspec)
|
|
559
559
|
sys.modules[modname] = module
|
|
560
|
-
modspec.loader.exec_module(module)
|
|
560
|
+
modspec.loader.exec_module(module)
|
|
561
561
|
except ImportError as e:
|
|
562
562
|
e.add_note(f"Could not import python module for graph:\n{spec}")
|
|
563
563
|
if lg_api_config.API_VARIANT == "local_dev":
|
|
@@ -665,7 +665,7 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
|
|
|
665
665
|
@functools.lru_cache(maxsize=1)
|
|
666
666
|
def _get_init_embeddings() -> Callable[[str, ...], "Embeddings"] | None:
|
|
667
667
|
try:
|
|
668
|
-
from langchain.embeddings import ( #
|
|
668
|
+
from langchain.embeddings import ( # noqa: PLC0415 # ty: ignore[unresolved-import]
|
|
669
669
|
init_embeddings,
|
|
670
670
|
)
|
|
671
671
|
|
|
@@ -730,7 +730,7 @@ def resolve_embeddings(index_config: dict) -> "Embeddings":
|
|
|
730
730
|
)
|
|
731
731
|
module = importlib.util.module_from_spec(modspec)
|
|
732
732
|
sys.modules[modname] = module
|
|
733
|
-
modspec.loader.exec_module(module)
|
|
733
|
+
modspec.loader.exec_module(module)
|
|
734
734
|
else:
|
|
735
735
|
# Load from Python module
|
|
736
736
|
module = importlib.import_module(module_name)
|
|
@@ -6,8 +6,8 @@ import threading
|
|
|
6
6
|
import time
|
|
7
7
|
|
|
8
8
|
import structlog
|
|
9
|
-
from grpc import aio
|
|
10
|
-
from grpc_health.v1 import health_pb2, health_pb2_grpc
|
|
9
|
+
from grpc import aio
|
|
10
|
+
from grpc_health.v1 import health_pb2, health_pb2_grpc
|
|
11
11
|
from langgraph_grpc_common.proto.checkpointer_pb2_grpc import CheckpointerStub
|
|
12
12
|
from langgraph_grpc_common.proto.core_api_pb2_grpc import (
|
|
13
13
|
AdminStub,
|
|
@@ -87,7 +87,7 @@ class Assistants(Authenticated):
|
|
|
87
87
|
sort_order: str | None = None,
|
|
88
88
|
select: list[AssistantSelectField] | None = None,
|
|
89
89
|
ctx: Any = None,
|
|
90
|
-
) -> tuple[AsyncIterator[Assistant], int | None]:
|
|
90
|
+
) -> tuple[AsyncIterator[Assistant], int | None]:
|
|
91
91
|
"""Search assistants via gRPC."""
|
|
92
92
|
# Handle auth filters
|
|
93
93
|
auth_filters = await Assistants.handle_event(
|
|
@@ -139,7 +139,7 @@ class Assistants(Authenticated):
|
|
|
139
139
|
conn, # Not used in gRPC implementation
|
|
140
140
|
assistant_id: UUID | str,
|
|
141
141
|
ctx: Any = None,
|
|
142
|
-
) -> AsyncIterator[Assistant]:
|
|
142
|
+
) -> AsyncIterator[Assistant]:
|
|
143
143
|
"""Get assistant by ID via gRPC."""
|
|
144
144
|
# Handle auth filters
|
|
145
145
|
auth_filters = await Assistants.handle_event(
|
|
@@ -177,7 +177,7 @@ class Assistants(Authenticated):
|
|
|
177
177
|
description: str | None = None,
|
|
178
178
|
ctx: Any = None,
|
|
179
179
|
system: bool = False,
|
|
180
|
-
) -> AsyncIterator[Assistant]:
|
|
180
|
+
) -> AsyncIterator[Assistant]:
|
|
181
181
|
"""Create/update assistant via gRPC."""
|
|
182
182
|
metadata = metadata if metadata is not None else {}
|
|
183
183
|
config = config if config is not None else Config()
|
|
@@ -240,7 +240,7 @@ class Assistants(Authenticated):
|
|
|
240
240
|
name: str | None = None,
|
|
241
241
|
description: str | None = None,
|
|
242
242
|
ctx: Any = None,
|
|
243
|
-
) -> AsyncIterator[Assistant]:
|
|
243
|
+
) -> AsyncIterator[Assistant]:
|
|
244
244
|
"""Update assistant via gRPC."""
|
|
245
245
|
metadata = metadata if metadata is not None else {}
|
|
246
246
|
config = config if config is not None else Config()
|
|
@@ -295,7 +295,7 @@ class Assistants(Authenticated):
|
|
|
295
295
|
ctx: Any = None,
|
|
296
296
|
*,
|
|
297
297
|
delete_threads: bool = False,
|
|
298
|
-
) -> AsyncIterator[UUID]:
|
|
298
|
+
) -> AsyncIterator[UUID]:
|
|
299
299
|
"""Delete assistant via gRPC."""
|
|
300
300
|
# Handle auth filters
|
|
301
301
|
auth_filters = await Assistants.handle_event(
|
|
@@ -324,7 +324,7 @@ class Assistants(Authenticated):
|
|
|
324
324
|
assistant_id: UUID | str,
|
|
325
325
|
version: int,
|
|
326
326
|
ctx: Any = None,
|
|
327
|
-
) -> AsyncIterator[Assistant]:
|
|
327
|
+
) -> AsyncIterator[Assistant]:
|
|
328
328
|
"""Set latest version of assistant via gRPC."""
|
|
329
329
|
# Handle auth filters
|
|
330
330
|
auth_filters = await Assistants.handle_event(
|
|
@@ -362,7 +362,7 @@ class Assistants(Authenticated):
|
|
|
362
362
|
limit: int,
|
|
363
363
|
offset: int,
|
|
364
364
|
ctx: Any = None,
|
|
365
|
-
) -> AsyncIterator[Assistant]:
|
|
365
|
+
) -> AsyncIterator[Assistant]:
|
|
366
366
|
"""Get all versions of assistant via gRPC."""
|
|
367
367
|
# Handle auth filters
|
|
368
368
|
auth_filters = await Assistants.handle_event(
|
|
@@ -412,7 +412,7 @@ class Assistants(Authenticated):
|
|
|
412
412
|
name: str | None = None,
|
|
413
413
|
metadata: MetadataInput = None,
|
|
414
414
|
ctx: Any = None,
|
|
415
|
-
) -> int:
|
|
415
|
+
) -> int:
|
|
416
416
|
"""Count assistants via gRPC."""
|
|
417
417
|
# Handle auth filters
|
|
418
418
|
auth_filters = await Assistants.handle_event(
|