langgraph-api 0.18.0.dev3__tar.gz → 0.18.0.dev5__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.18.0.dev3 → langgraph_api-0.18.0.dev5}/PKG-INFO +1 -1
- langgraph_api-0.18.0.dev5/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/event_streaming.py +71 -7
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/config/__init__.py +2 -4
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/drain.py +64 -2
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/service.py +19 -3
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/session.py +9 -6
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/threads.py +54 -6
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/models/run.py +7 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/headers.py +5 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/validation.py +6 -6
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/openapi.json +25 -5
- langgraph_api-0.18.0.dev3/langgraph_api/__init__.py +0 -1
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/.gitignore +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/LICENSE +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/Makefile +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/README.md +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/.gitignore +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/Makefile +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/README.md +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/REPORTS.md +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/assistant.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/benchmarks.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/classify-error.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/classify-error.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/delta-turns-lib.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/delta-turns-lib.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/delta_turns.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/interrupt_resume.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/log-failure.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/meta_workload.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/store.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/stream_write.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/thread.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/types.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/wait_write.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/capacity-ci.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/capacity-ci.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/clean-cli.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/clean.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/README.md +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/pyproject.toml +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/runner.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/uv.lock +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/daily-report.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/daily-report.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/delta-report.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/delta-report.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/graphs.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/history.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/history.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/host-v2.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/host-v2.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/multer.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/package.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/ramp.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/reporting/dd_reporting.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/runner-descriptions.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/server-metrics.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/server-metrics.test.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/slack.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/staircase.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/staircase_step_k6.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/tsconfig.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/update-revision.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/weather.js +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/yarn.lock +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/constraints.txt +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/custom_store.sql +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/forbidden.txt +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/hatch_build.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/healthcheck.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph-cloud-debugging-20260210132856.zip +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_checkpointer/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_checkpointer/_adapter.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_checkpointer/protocol.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_factory_utils.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2a.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/README.md +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/client_capabilities.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/client_data_model.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/client_to_server.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/server_to_client.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_calls.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_constants.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_handlers.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_models.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_outcome.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_protocol.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_routes.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_sanitizers.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/profile.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/runs.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/custom.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/errors.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/beacon_data_plane_jwt_auth.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/cache.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/cli.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/command.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/config/_parse.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/config/schemas.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/aes_json.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/context.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/custom.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/middleware.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/shared.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/capabilities.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/constants.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/event_normalizers.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/namespace.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/state_normalizers.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/types.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/executor/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/executor/__main__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/feature_flags.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/graph.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/client.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/assistants.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/cache.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/crons.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/runs.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/server.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/servicers/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/servicers/encryption.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/http.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/http_metrics.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/http_metrics_utils.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/.yarnclean +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/remote.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/auth-mutations.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/traceblock.mts +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/exceptions.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/policy.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/transport.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/metrics_collector.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/metrics_otlp.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/ensure_store.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/otel_context.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/release_tags.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/route.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/self_hosted_logs.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/self_hosted_metrics.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/server.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/state.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/store.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/stream_v2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/profiler.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/startup.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/timer.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/traceblock.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/tracing_session.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/cache.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/config.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/errors.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/extract.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/future.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/network.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/retriable_client.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/stream_codec.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/uuids.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/worker.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/worker_runtime.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/checkpointer.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/_compat.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/checkpoint.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/config.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/durability.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/store.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/struct.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/value.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/serde.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/store.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/encryption.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/routes.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/logging.json +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/pyproject.toml +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/scripts/build_wheel.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/scripts/create_license.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/scripts/run_a2a_tck.py +0 -0
- {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/uv.lock +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.18.0.dev5"
|
{langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/event_streaming.py
RENAMED
|
@@ -28,6 +28,7 @@ from uuid import uuid4
|
|
|
28
28
|
|
|
29
29
|
import orjson
|
|
30
30
|
import structlog
|
|
31
|
+
from starlette.exceptions import HTTPException
|
|
31
32
|
from starlette.responses import Response
|
|
32
33
|
from starlette.websockets import WebSocketDisconnect
|
|
33
34
|
|
|
@@ -38,6 +39,7 @@ from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
|
|
|
38
39
|
from langgraph_api.route import ApiRoute, ApiWebSocketRoute
|
|
39
40
|
from langgraph_api.serde import json_dumpb
|
|
40
41
|
from langgraph_api.sse import EventSourceResponse
|
|
42
|
+
from langgraph_api.utils import validate_uuid
|
|
41
43
|
|
|
42
44
|
if TYPE_CHECKING:
|
|
43
45
|
from collections.abc import Mapping
|
|
@@ -98,6 +100,7 @@ def _make_manager(
|
|
|
98
100
|
send_event: Any = None,
|
|
99
101
|
*,
|
|
100
102
|
headers: Mapping[str, str] | None = None,
|
|
103
|
+
replay_buffer: bool = True,
|
|
101
104
|
) -> ThreadRunManager:
|
|
102
105
|
# Auth context is propagated via ``ApiRoute``'s ``with_user`` wrapper
|
|
103
106
|
# — ops reads it off the context var, so we don't thread it through
|
|
@@ -108,6 +111,7 @@ def _make_manager(
|
|
|
108
111
|
threads=Threads,
|
|
109
112
|
send_event=send_event,
|
|
110
113
|
headers=headers,
|
|
114
|
+
replay_buffer=replay_buffer,
|
|
111
115
|
)
|
|
112
116
|
|
|
113
117
|
|
|
@@ -143,8 +147,12 @@ async def _thread_events(request: Request) -> Response:
|
|
|
143
147
|
If reading the thread's event stream fails, the server ends the
|
|
144
148
|
stream with a final ``event: error`` frame carrying a protocol error
|
|
145
149
|
(``"type": "error"``, ``"id": null``, ``"error": "unknown_error"``).
|
|
150
|
+
|
|
151
|
+
A thread the caller isn't allowed to read returns 403 or 404 before
|
|
152
|
+
the stream starts, and a malformed thread ID returns 422.
|
|
146
153
|
"""
|
|
147
154
|
thread_id = request.path_params["thread_id"]
|
|
155
|
+
thread_uuid = validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
|
|
148
156
|
try:
|
|
149
157
|
body = orjson.loads(await request.body())
|
|
150
158
|
except Exception:
|
|
@@ -217,6 +225,10 @@ async def _thread_events(request: Request) -> Response:
|
|
|
217
225
|
else None
|
|
218
226
|
)
|
|
219
227
|
|
|
228
|
+
# Checked here, before the 200, because clients retry a 200 that ends in
|
|
229
|
+
# an error instead of giving up.
|
|
230
|
+
auth_filters = await Threads.Stream.check_thread_stream_auth(thread_uuid)
|
|
231
|
+
|
|
220
232
|
# Bounded LRU dedup: ``recent_eids`` is the eviction order, ``delivered``
|
|
221
233
|
# is the O(1) membership view. When the deque hits its cap, the oldest
|
|
222
234
|
# entry rolls off; we mirror that on ``delivered`` to keep them in sync.
|
|
@@ -241,7 +253,10 @@ async def _thread_events(request: Request) -> Response:
|
|
|
241
253
|
pending_events.append(event)
|
|
242
254
|
flush_pending.set()
|
|
243
255
|
|
|
244
|
-
|
|
256
|
+
# SSE never replays from the session's buffer: it has no subscribe or
|
|
257
|
+
# reconnect commands, and ``start_thread_stream`` replays from the
|
|
258
|
+
# thread's event stream.
|
|
259
|
+
manager = _make_manager(thread_id, send_event=on_event, replay_buffer=False)
|
|
245
260
|
|
|
246
261
|
filter_sub = Subscription(
|
|
247
262
|
id=str(uuid4()),
|
|
@@ -264,7 +279,7 @@ async def _thread_events(request: Request) -> Response:
|
|
|
264
279
|
# outbound events; the thread-level reader always replays from the
|
|
265
280
|
# beginning so namespace-scoped projections see history. See
|
|
266
281
|
# ``ThreadRunManager.start_thread_stream`` for the rationale.
|
|
267
|
-
manager.start_thread_stream()
|
|
282
|
+
manager.start_thread_stream(auth_filters=auth_filters)
|
|
268
283
|
|
|
269
284
|
async def body_iter():
|
|
270
285
|
try:
|
|
@@ -377,20 +392,51 @@ async def _thread_command(request: Request) -> Response:
|
|
|
377
392
|
# ---------------------------------------------------------------------------
|
|
378
393
|
|
|
379
394
|
|
|
395
|
+
async def _close_for_failed_access_check(websocket: WebSocket, exc: Exception) -> None:
|
|
396
|
+
if isinstance(exc, HTTPException) and exc.status_code < 500:
|
|
397
|
+
await websocket.close(code=4000 + exc.status_code)
|
|
398
|
+
return
|
|
399
|
+
logger.exception("Thread stream access check failed")
|
|
400
|
+
await websocket.send_text(_THREAD_STREAM_FAILED_DATA.decode())
|
|
401
|
+
await websocket.close(code=1011, reason="thread stream ended")
|
|
402
|
+
|
|
403
|
+
|
|
380
404
|
async def _thread_websocket(websocket: WebSocket) -> None:
|
|
381
405
|
"""Full-duplex protocol connection scoped to a thread.
|
|
382
406
|
|
|
383
407
|
Supports ``run.start``, ``input.respond``, ``subscription.subscribe``,
|
|
384
408
|
``subscription.unsubscribe``, ``agent.getTree``.
|
|
409
|
+
|
|
410
|
+
A 4xx from the thread's access check closes the socket with 4000 plus the
|
|
411
|
+
status (4403, 4422). A 404 can be a thread the client minted and has yet
|
|
412
|
+
to create, so the socket then waits for a ``run.start``, which checks
|
|
413
|
+
access like any run start, and closes with 4404 if another command comes
|
|
414
|
+
first. Any other failure of the check, a 5xx included, gets the stream
|
|
415
|
+
error frame and a 1011 close, as when the stream fails later.
|
|
385
416
|
"""
|
|
386
417
|
thread_id = websocket.path_params["thread_id"]
|
|
418
|
+
# Browsers report a refused upgrade only as a 1006 close, so accept first
|
|
419
|
+
# to make the close code readable.
|
|
387
420
|
await websocket.accept()
|
|
421
|
+
try:
|
|
422
|
+
thread_uuid = validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
|
|
423
|
+
except HTTPException as exc:
|
|
424
|
+
await _close_for_failed_access_check(websocket, exc)
|
|
425
|
+
return
|
|
426
|
+
awaiting_thread = False
|
|
427
|
+
auth_filters: Any = None
|
|
428
|
+
try:
|
|
429
|
+
auth_filters = await Threads.Stream.check_thread_stream_auth(thread_uuid)
|
|
430
|
+
except Exception as exc:
|
|
431
|
+
if not (isinstance(exc, HTTPException) and exc.status_code == 404):
|
|
432
|
+
await _close_for_failed_access_check(websocket, exc)
|
|
433
|
+
return
|
|
434
|
+
awaiting_thread = True
|
|
388
435
|
|
|
389
436
|
async def ws_send_event(event: dict[str, Any]) -> None:
|
|
390
437
|
await websocket.send_text(orjson.dumps(event).decode("utf-8"))
|
|
391
438
|
|
|
392
439
|
manager = _make_manager(thread_id, send_event=ws_send_event)
|
|
393
|
-
manager.start_thread_stream()
|
|
394
440
|
|
|
395
441
|
# Watchdog: when the thread-stream consumer stops, send the error frame
|
|
396
442
|
# (if it wasn't cancelled) and close the socket, instead of leaving the
|
|
@@ -405,7 +451,11 @@ async def _thread_websocket(websocket: WebSocket) -> None:
|
|
|
405
451
|
with contextlib.suppress(Exception):
|
|
406
452
|
await websocket.close(code=1011, reason="thread stream ended")
|
|
407
453
|
|
|
408
|
-
|
|
454
|
+
def start_stream(filters: Any) -> asyncio.Task[None]:
|
|
455
|
+
manager.start_thread_stream(auth_filters=filters)
|
|
456
|
+
return asyncio.create_task(_stream_watchdog())
|
|
457
|
+
|
|
458
|
+
watchdog = None if awaiting_thread else start_stream(auth_filters)
|
|
409
459
|
|
|
410
460
|
try:
|
|
411
461
|
while True:
|
|
@@ -438,16 +488,30 @@ async def _thread_websocket(websocket: WebSocket) -> None:
|
|
|
438
488
|
)
|
|
439
489
|
continue
|
|
440
490
|
|
|
491
|
+
if awaiting_thread and payload["method"] != "run.start":
|
|
492
|
+
await websocket.close(code=4404)
|
|
493
|
+
return
|
|
441
494
|
response = await manager.handle_command(payload)
|
|
442
495
|
await websocket.send_text(orjson.dumps(response).decode("utf-8"))
|
|
496
|
+
if awaiting_thread and response.get("type") == "success":
|
|
497
|
+
try:
|
|
498
|
+
auth_filters = await Threads.Stream.check_thread_stream_auth(
|
|
499
|
+
thread_uuid
|
|
500
|
+
)
|
|
501
|
+
except Exception as exc:
|
|
502
|
+
await _close_for_failed_access_check(websocket, exc)
|
|
503
|
+
return
|
|
504
|
+
watchdog = start_stream(auth_filters)
|
|
505
|
+
awaiting_thread = False
|
|
443
506
|
except WebSocketDisconnect:
|
|
444
507
|
pass
|
|
445
508
|
except Exception:
|
|
446
509
|
logger.exception("Protocol WebSocket error")
|
|
447
510
|
finally:
|
|
448
|
-
watchdog
|
|
449
|
-
|
|
450
|
-
|
|
511
|
+
if watchdog is not None:
|
|
512
|
+
watchdog.cancel()
|
|
513
|
+
with contextlib.suppress(asyncio.CancelledError, Exception):
|
|
514
|
+
await watchdog
|
|
451
515
|
await manager.close()
|
|
452
516
|
|
|
453
517
|
|
|
@@ -507,7 +507,8 @@ FF_CRONS_ENABLED = env("FF_CRONS_ENABLED", cast=bool, default=True)
|
|
|
507
507
|
FF_LOG_DROPPED_EVENTS = env("FF_LOG_DROPPED_EVENTS", cast=bool, default=False)
|
|
508
508
|
FF_LOG_QUERY_AND_PARAMS = env("FF_LOG_QUERY_AND_PARAMS", cast=bool, default=False)
|
|
509
509
|
# Opt-in handling of drained runs: the server's control signalling to the
|
|
510
|
-
# graph and its handling of drained runs, together.
|
|
510
|
+
# graph and its handling of drained runs, together. On, a Postgres-backed
|
|
511
|
+
# replica that is shutting down also drains its in-flight runs.
|
|
511
512
|
# Off: no control is created or seeded, and GraphDrained lands in the
|
|
512
513
|
# catch-all error branch.
|
|
513
514
|
FF_RESUME_DRAINED_RUNS = env("FF_RESUME_DRAINED_RUNS", cast=bool, default=False)
|
|
@@ -535,8 +536,6 @@ RESUME_DRAINED_RUNS = _resolve_resume_drained_runs(
|
|
|
535
536
|
is_postgres=IS_POSTGRES_BACKEND,
|
|
536
537
|
langgraph_supported=DRAIN_RESUME_SUPPORT,
|
|
537
538
|
)
|
|
538
|
-
# Not in public docs: internal feature flag
|
|
539
|
-
FF_USE_REDIS_QUEUE = env("FF_USE_REDIS_QUEUE", cast=bool, default=True)
|
|
540
539
|
|
|
541
540
|
|
|
542
541
|
# Internal flag intended for testing only
|
|
@@ -811,7 +810,6 @@ __all__ = [
|
|
|
811
810
|
"FF_PYSPY_PROFILING_ENABLED",
|
|
812
811
|
"FF_PYSPY_PROFILING_MAX_DURATION_SECS",
|
|
813
812
|
"FF_RESUME_DRAINED_RUNS",
|
|
814
|
-
"FF_USE_REDIS_QUEUE",
|
|
815
813
|
"GRPC_CLIENT_HTTP2_INITIAL_WINDOW_SIZE",
|
|
816
814
|
"GRPC_CLIENT_MAX_RECV_MSG_BYTES",
|
|
817
815
|
"GRPC_CLIENT_MAX_SEND_MSG_BYTES",
|
|
@@ -10,6 +10,7 @@ guarded and the placeholders below never match or instantiate anything.
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import contextvars
|
|
13
|
+
import threading
|
|
13
14
|
from typing import Any
|
|
14
15
|
|
|
15
16
|
# The control of the run whose top-level graph this context is executing. The
|
|
@@ -47,17 +48,35 @@ try:
|
|
|
47
48
|
The request is visible only where this is provably the run's top-level
|
|
48
49
|
loop: in a context the server marked for this control (see
|
|
49
50
|
mark_top_level) and outside any graph node. So the run drains only at
|
|
50
|
-
a top-level step boundary, after that step's subgraphs have finished
|
|
51
|
+
a top-level step boundary, after that step's subgraphs have finished,
|
|
52
|
+
and never before its first step.
|
|
51
53
|
Graph code inside a node, and threads a node starts, see no drain
|
|
52
54
|
(drain_requested False, drain_reason None).
|
|
53
55
|
"""
|
|
54
56
|
|
|
57
|
+
__slots__ = ("_first_check_done",)
|
|
58
|
+
|
|
59
|
+
def __init__(self) -> None:
|
|
60
|
+
super().__init__()
|
|
61
|
+
self._first_check_done = False
|
|
62
|
+
|
|
55
63
|
def _visible(self) -> bool:
|
|
56
64
|
return _TOP_LEVEL_CONTROL.get() is self and not _in_graph_node()
|
|
57
65
|
|
|
58
66
|
@property
|
|
59
67
|
def drain_requested(self) -> bool:
|
|
60
|
-
|
|
68
|
+
if not self._visible():
|
|
69
|
+
return False
|
|
70
|
+
# LangGraph checks once per top-level step boundary, before the
|
|
71
|
+
# step. Only a server drain can be pending at the first check. A
|
|
72
|
+
# run started with a Command has no checkpoint of its own until its
|
|
73
|
+
# first step ends, so if it drained there, its next claim would
|
|
74
|
+
# re-send the Command and LangGraph would apply it again. So a run
|
|
75
|
+
# always completes a step before it drains.
|
|
76
|
+
if not self._first_check_done:
|
|
77
|
+
self._first_check_done = True
|
|
78
|
+
return False
|
|
79
|
+
return RunControl.drain_requested.fget(self)
|
|
61
80
|
|
|
62
81
|
@property
|
|
63
82
|
def drain_reason(self) -> str | None:
|
|
@@ -79,6 +98,11 @@ except ImportError:
|
|
|
79
98
|
|
|
80
99
|
DRAIN_SUPPORT = False
|
|
81
100
|
|
|
101
|
+
# Reason the server passes to request_drain() when its pod is shutting down.
|
|
102
|
+
# Graph code can pass any reason (request_drain() defaults to "shutdown"), so
|
|
103
|
+
# this distinct value is what tells server drains from graph drains in logs.
|
|
104
|
+
SERVER_SHUTDOWN_DRAIN_REASON = "server_shutdown"
|
|
105
|
+
|
|
82
106
|
|
|
83
107
|
def mark_top_level(control: ServerRunControl | None) -> None:
|
|
84
108
|
"""Mark the current context as running ``control``'s top-level graph."""
|
|
@@ -92,10 +116,48 @@ def new_run_control() -> ServerRunControl | None:
|
|
|
92
116
|
return None
|
|
93
117
|
|
|
94
118
|
|
|
119
|
+
class RunControlRegistry:
|
|
120
|
+
"""Controls of the runs a queue drains at shutdown, keyed by run ID.
|
|
121
|
+
|
|
122
|
+
Workers can finish on background threads (isolated loops), so every access
|
|
123
|
+
takes a lock and ``drain_all`` works on a snapshot. Controls are registered
|
|
124
|
+
before the run starts, and removed only by the claim that registered them,
|
|
125
|
+
so a fast-finishing or superseded claim can't leave or remove the wrong
|
|
126
|
+
entry.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(self) -> None:
|
|
130
|
+
self._lock = threading.Lock()
|
|
131
|
+
self._controls: dict[str, ServerRunControl] = {}
|
|
132
|
+
|
|
133
|
+
def add(self, run_id: Any, control: ServerRunControl) -> None:
|
|
134
|
+
"""Register a run's control before the run starts."""
|
|
135
|
+
with self._lock:
|
|
136
|
+
self._controls[str(run_id)] = control
|
|
137
|
+
|
|
138
|
+
def release(self, run_id: Any, control: ServerRunControl | None) -> None:
|
|
139
|
+
"""Remove a run's control if it is still the one this claim registered."""
|
|
140
|
+
if control is None:
|
|
141
|
+
return
|
|
142
|
+
with self._lock:
|
|
143
|
+
if self._controls.get(str(run_id)) is control:
|
|
144
|
+
del self._controls[str(run_id)]
|
|
145
|
+
|
|
146
|
+
def drain_all(self, reason: str) -> int:
|
|
147
|
+
"""Request a drain from every registered run; return how many."""
|
|
148
|
+
with self._lock:
|
|
149
|
+
controls = list(self._controls.values())
|
|
150
|
+
for control in controls:
|
|
151
|
+
control.request_drain(reason)
|
|
152
|
+
return len(controls)
|
|
153
|
+
|
|
154
|
+
|
|
95
155
|
__all__ = [
|
|
96
156
|
"DRAIN_SUPPORT",
|
|
157
|
+
"SERVER_SHUTDOWN_DRAIN_REASON",
|
|
97
158
|
"GraphDrained",
|
|
98
159
|
"RunControl",
|
|
160
|
+
"RunControlRegistry",
|
|
99
161
|
"ServerRunControl",
|
|
100
162
|
"mark_top_level",
|
|
101
163
|
"new_run_control",
|
{langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/service.py
RENAMED
|
@@ -46,6 +46,7 @@ from langgraph_api.event_streaming.session import (
|
|
|
46
46
|
from langgraph_api.event_streaming.types import Subscription
|
|
47
47
|
from langgraph_api.feature_flags import FF_V2_EVENT_STREAMING, PREFER_GRPC_CHECKPOINTER
|
|
48
48
|
from langgraph_api.schema import MultitaskStrategy
|
|
49
|
+
from langgraph_api.validation import sanitize_reserved_keys
|
|
49
50
|
|
|
50
51
|
logger = structlog.stdlib.get_logger(__name__)
|
|
51
52
|
|
|
@@ -192,6 +193,9 @@ class ThreadRunManager:
|
|
|
192
193
|
One ``ThreadRunManager`` is created per connection (HTTP SSE stream or
|
|
193
194
|
WebSocket). It is not shared across connections — each observer owns
|
|
194
195
|
its own view of the thread's run stream.
|
|
196
|
+
|
|
197
|
+
``replay_buffer=False`` keeps no per-run replay buffer, for connections
|
|
198
|
+
that never replay from it.
|
|
195
199
|
"""
|
|
196
200
|
|
|
197
201
|
def __init__(
|
|
@@ -202,12 +206,14 @@ class ThreadRunManager:
|
|
|
202
206
|
threads: Any,
|
|
203
207
|
send_event: EventSink | None = None,
|
|
204
208
|
headers: Mapping[str, str] | None = None,
|
|
209
|
+
replay_buffer: bool = True,
|
|
205
210
|
) -> None:
|
|
206
211
|
self._thread_id = thread_id
|
|
207
212
|
self._runs = runs
|
|
208
213
|
self._threads = threads
|
|
209
214
|
self._send_event = send_event
|
|
210
215
|
self._headers = headers if headers is not None else {}
|
|
216
|
+
self._replay_buffer = replay_buffer
|
|
211
217
|
self._session: EventStreamingSession | None = None
|
|
212
218
|
self._current_run_id: str | None = None
|
|
213
219
|
self._queued_events: list[dict[str, Any]] = []
|
|
@@ -291,7 +297,7 @@ class ThreadRunManager:
|
|
|
291
297
|
active=True,
|
|
292
298
|
)
|
|
293
299
|
|
|
294
|
-
def start_thread_stream(self) -> None:
|
|
300
|
+
def start_thread_stream(self, *, auth_filters: Any = None) -> None:
|
|
295
301
|
"""Start consuming the thread-level stream for this connection.
|
|
296
302
|
|
|
297
303
|
Always start from the beginning of the thread's event stream
|
|
@@ -306,14 +312,19 @@ class ThreadRunManager:
|
|
|
306
312
|
produce output…". The SSE/WS sink applies the caller's ``since``
|
|
307
313
|
as a seq filter on outbound events, and the SDK dedups by
|
|
308
314
|
``event_id``, so repeat observers don't see duplicates.
|
|
315
|
+
|
|
316
|
+
``auth_filters`` is what the route's ``check_thread_stream_auth``
|
|
317
|
+
returned, passed on so the stream doesn't run the read handler again.
|
|
309
318
|
"""
|
|
310
319
|
if self._thread_source_task is not None:
|
|
311
320
|
return
|
|
312
321
|
self._thread_source_task = asyncio.create_task(
|
|
313
|
-
self._consume_thread_stream(last_event_id="-")
|
|
322
|
+
self._consume_thread_stream(last_event_id="-", auth_filters=auth_filters)
|
|
314
323
|
)
|
|
315
324
|
|
|
316
|
-
async def _consume_thread_stream(
|
|
325
|
+
async def _consume_thread_stream(
|
|
326
|
+
self, *, last_event_id: str | None, auth_filters: Any
|
|
327
|
+
) -> None:
|
|
317
328
|
try:
|
|
318
329
|
async for (
|
|
319
330
|
event,
|
|
@@ -324,6 +335,7 @@ class ThreadRunManager:
|
|
|
324
335
|
self._thread_id,
|
|
325
336
|
stream_modes=["run_modes", "lifecycle"],
|
|
326
337
|
last_event_id=last_event_id,
|
|
338
|
+
auth_filters=auth_filters,
|
|
327
339
|
):
|
|
328
340
|
if not run_id or run_id == "*":
|
|
329
341
|
continue
|
|
@@ -781,6 +793,9 @@ class ThreadRunManager:
|
|
|
781
793
|
if not capabilities.ok:
|
|
782
794
|
raise ProtocolV2UnsupportedError(capabilities)
|
|
783
795
|
|
|
796
|
+
# Drop server-owned configurable and metadata keys before the run
|
|
797
|
+
# config is built, as the REST request parser does for its bodies.
|
|
798
|
+
sanitize_reserved_keys(params)
|
|
784
799
|
config = params.get("config") if _is_record(params.get("config")) else {}
|
|
785
800
|
|
|
786
801
|
# ``input.respond`` checked its interrupts already and always resumes;
|
|
@@ -959,6 +974,7 @@ class ThreadRunManager:
|
|
|
959
974
|
get_thread_state=self._make_get_thread_state(thread_id),
|
|
960
975
|
source=None,
|
|
961
976
|
send=self._make_send(),
|
|
977
|
+
max_buffer_size=None if self._replay_buffer else 0,
|
|
962
978
|
)
|
|
963
979
|
|
|
964
980
|
self._session = session
|
{langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/session.py
RENAMED
|
@@ -228,8 +228,8 @@ class EventStreamingSession:
|
|
|
228
228
|
) -> None:
|
|
229
229
|
if max_buffer_size is None:
|
|
230
230
|
max_buffer_size = LSD_PROTOCOL_V2_BUFFER_SIZE
|
|
231
|
-
if max_buffer_size <
|
|
232
|
-
raise ValueError("max_buffer_size must be a positive integer")
|
|
231
|
+
if max_buffer_size < 0:
|
|
232
|
+
raise ValueError("max_buffer_size must be zero or a positive integer")
|
|
233
233
|
self._run_id = run_id
|
|
234
234
|
self._thread_id = thread_id
|
|
235
235
|
self._initial_run = initial_run
|
|
@@ -251,6 +251,7 @@ class EventStreamingSession:
|
|
|
251
251
|
self._buffer: list[dict[str, Any]] = []
|
|
252
252
|
self._source_task: asyncio.Task[None] | None = None
|
|
253
253
|
self._next_seq = 0
|
|
254
|
+
# 0 keeps no replay buffer, for transports that never replay from it.
|
|
254
255
|
self._max_buffer_size = max_buffer_size
|
|
255
256
|
self._root_graph_name = "root"
|
|
256
257
|
self._terminal_lifecycle_emitted = False
|
|
@@ -971,7 +972,8 @@ class EventStreamingSession:
|
|
|
971
972
|
return _synth_event_id(self._run_id, str(self._next_seq))
|
|
972
973
|
|
|
973
974
|
async def _push_event(self, event: dict[str, Any]) -> None:
|
|
974
|
-
self.
|
|
975
|
+
if self._max_buffer_size:
|
|
976
|
+
self._buffer.append(event)
|
|
975
977
|
reporter = get_otlp_metrics_reporter()
|
|
976
978
|
if len(self._buffer) > self._max_buffer_size:
|
|
977
979
|
evicted = len(self._buffer) - self._max_buffer_size
|
|
@@ -1036,9 +1038,10 @@ class EventStreamingSession:
|
|
|
1036
1038
|
callback for events with ``seq > since`` that match the filter,
|
|
1037
1039
|
then the subscription is activated so live events flow.
|
|
1038
1040
|
|
|
1039
|
-
Returns the number of events replayed. Used by
|
|
1040
|
-
``subscription.subscribe``
|
|
1041
|
-
|
|
1041
|
+
Returns the number of events replayed. Used by the WebSocket
|
|
1042
|
+
``subscription.subscribe`` and ``subscription.reconnect`` commands;
|
|
1043
|
+
``since`` resumes after a reconnect. SSE streams replay from the
|
|
1044
|
+
thread's event stream instead.
|
|
1042
1045
|
|
|
1043
1046
|
Raises :class:`ResumeGap` when *since* is older than the
|
|
1044
1047
|
session's retained buffer head. This lets callers surface a
|
|
@@ -68,6 +68,10 @@ logger = structlog.stdlib.get_logger(__name__)
|
|
|
68
68
|
# only need graph_id (from metadata) and the thread config.
|
|
69
69
|
THREAD_METADATA_READ_MASK_PATHS: list[str] = ["metadata", "config"]
|
|
70
70
|
|
|
71
|
+
# Read-mask preset for an auth/existence check that discards the thread body;
|
|
72
|
+
# Go's ``repos.ThreadExistenceCheckMask``.
|
|
73
|
+
THREAD_EXISTENCE_CHECK_READ_MASK_PATHS: list[str] = []
|
|
74
|
+
|
|
71
75
|
|
|
72
76
|
THREAD_STATUS_TO_PB = {
|
|
73
77
|
"idle": enum_thread_status.idle,
|
|
@@ -971,13 +975,20 @@ class Threads(Authenticated):
|
|
|
971
975
|
stream_modes: list[str] | None = None,
|
|
972
976
|
last_event_id: str | None = None,
|
|
973
977
|
ctx: Any = None,
|
|
978
|
+
auth_filters: list[pb.AuthFilter] | None = None,
|
|
974
979
|
):
|
|
975
|
-
"""Stream thread events with their run id for protocol demux.
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
980
|
+
"""Stream thread events with their run id for protocol demux.
|
|
981
|
+
|
|
982
|
+
``auth_filters`` comes from a ``check_thread_stream_auth`` the
|
|
983
|
+
caller already ran, so the read handler doesn't run twice. With
|
|
984
|
+
``None``, the handler runs here.
|
|
985
|
+
"""
|
|
986
|
+
if auth_filters is None:
|
|
987
|
+
auth_filters = await Threads.Stream.handle_event(
|
|
988
|
+
ctx,
|
|
989
|
+
"read",
|
|
990
|
+
Auth.types.ThreadsRead(thread_id=UUID(str(thread_id))),
|
|
991
|
+
)
|
|
981
992
|
|
|
982
993
|
stream_modes_pb = _map_thread_stream_modes(stream_modes)
|
|
983
994
|
|
|
@@ -1013,6 +1024,43 @@ class Threads(Authenticated):
|
|
|
1013
1024
|
_handle_grpc_error(e)
|
|
1014
1025
|
raise
|
|
1015
1026
|
|
|
1027
|
+
@staticmethod
|
|
1028
|
+
async def check_thread_stream_auth(
|
|
1029
|
+
thread_id: UUID,
|
|
1030
|
+
ctx: Any = None,
|
|
1031
|
+
) -> list[pb.AuthFilter]:
|
|
1032
|
+
"""Raise 403/404 before a thread stream's response starts.
|
|
1033
|
+
|
|
1034
|
+
Same check as the Go ``Stream`` RPC: the thread is looked up only
|
|
1035
|
+
when custom auth returns filters. Without filters, a thread that
|
|
1036
|
+
doesn't exist yet must stay streamable, because the Python SDK
|
|
1037
|
+
opens its lifecycle stream on ``async with client.threads.stream()``,
|
|
1038
|
+
before the ``run.start`` that creates the thread.
|
|
1039
|
+
|
|
1040
|
+
Returns the auth filters for ``join_event_streaming``.
|
|
1041
|
+
"""
|
|
1042
|
+
auth_filters = await Threads.Stream.handle_event(
|
|
1043
|
+
ctx,
|
|
1044
|
+
"read",
|
|
1045
|
+
Auth.types.ThreadsRead(thread_id=thread_id),
|
|
1046
|
+
)
|
|
1047
|
+
if not auth_filters:
|
|
1048
|
+
return auth_filters
|
|
1049
|
+
client = await get_shared_client()
|
|
1050
|
+
try:
|
|
1051
|
+
await client.threads.Get(
|
|
1052
|
+
pb.GetThreadRequest(
|
|
1053
|
+
thread_id=pb.UUID(value=_normalize_uuid(thread_id)),
|
|
1054
|
+
filters=auth_filters,
|
|
1055
|
+
read_mask=field_mask_pb2.FieldMask(
|
|
1056
|
+
paths=THREAD_EXISTENCE_CHECK_READ_MASK_PATHS
|
|
1057
|
+
),
|
|
1058
|
+
)
|
|
1059
|
+
)
|
|
1060
|
+
except AioRpcError as e:
|
|
1061
|
+
_handle_grpc_error(e)
|
|
1062
|
+
return auth_filters
|
|
1063
|
+
|
|
1016
1064
|
class State(Authenticated):
|
|
1017
1065
|
# treat this like threads resource
|
|
1018
1066
|
resource = "threads"
|
|
@@ -36,6 +36,7 @@ from langgraph_api.tracing_session import resolve_tracing_session_name
|
|
|
36
36
|
from langgraph_api.utils import AsyncConnectionProto, get_auth_ctx, get_user_id
|
|
37
37
|
from langgraph_api.utils.headers import get_configurable_headers
|
|
38
38
|
from langgraph_api.utils.uuids import uuid7
|
|
39
|
+
from langgraph_api.validation import strip_reserved
|
|
39
40
|
from langgraph_api.webhook import validate_webhook_url_or_raise
|
|
40
41
|
|
|
41
42
|
if IS_POSTGRES_OR_GRPC_BACKEND:
|
|
@@ -261,6 +262,12 @@ async def create_valid_run(
|
|
|
261
262
|
if checkpoint_id:
|
|
262
263
|
configurable["checkpoint_id"] = str(checkpoint_id)
|
|
263
264
|
if checkpoint := payload.get("checkpoint"):
|
|
265
|
+
# Cron payloads stored before requests had checkpoint stripped can still carry server-owned keys.
|
|
266
|
+
strip_reserved(
|
|
267
|
+
checkpoint,
|
|
268
|
+
"checkpoint",
|
|
269
|
+
message="Stripped reserved keys from stored checkpoint",
|
|
270
|
+
)
|
|
264
271
|
configurable.update(checkpoint)
|
|
265
272
|
configurable.update(get_configurable_headers(headers))
|
|
266
273
|
# cron_id is server-owned: drop any value merged from the request, then stamp the scheduler's.
|
|
@@ -8,6 +8,8 @@ from collections.abc import Mapping
|
|
|
8
8
|
import orjson
|
|
9
9
|
import structlog
|
|
10
10
|
|
|
11
|
+
from langgraph_api.validation import RESERVED_CONFIGURABLE_KEYS
|
|
12
|
+
|
|
11
13
|
logger = structlog.stdlib.get_logger(__name__)
|
|
12
14
|
|
|
13
15
|
LANGSMITH_METADATA = "langsmith-metadata"
|
|
@@ -146,6 +148,9 @@ def should_include_header(key: str) -> bool:
|
|
|
146
148
|
or key == "authorization"
|
|
147
149
|
):
|
|
148
150
|
return False
|
|
151
|
+
# Server-owned configurable keys are never taken from a request header.
|
|
152
|
+
if key in RESERVED_CONFIGURABLE_KEYS:
|
|
153
|
+
return False
|
|
149
154
|
|
|
150
155
|
include_patterns, exclude_patterns = get_header_patterns("configurable_headers")
|
|
151
156
|
|
|
@@ -112,7 +112,7 @@ _RESERVED_KEYS_SET = frozenset(RESERVED_CONFIGURABLE_KEYS)
|
|
|
112
112
|
_RESERVED_METADATA_KEYS_SET = frozenset(RESERVED_METADATA_KEYS)
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
def
|
|
115
|
+
def strip_reserved(
|
|
116
116
|
d: dict,
|
|
117
117
|
location: str,
|
|
118
118
|
reserved_keys: frozenset[str] = _RESERVED_KEYS_SET,
|
|
@@ -134,7 +134,7 @@ def _strip_metadata(d: dict, location: str) -> None:
|
|
|
134
134
|
"""Strip reserved keys from a ``metadata`` sub-dict if present."""
|
|
135
135
|
metadata = d.get("metadata")
|
|
136
136
|
if isinstance(metadata, dict):
|
|
137
|
-
|
|
137
|
+
strip_reserved(
|
|
138
138
|
metadata,
|
|
139
139
|
location,
|
|
140
140
|
reserved_keys=_RESERVED_METADATA_KEYS_SET,
|
|
@@ -184,22 +184,22 @@ def sanitize_reserved_keys(data: typing.Any, *, strip_metadata: bool = True) ->
|
|
|
184
184
|
if isinstance(config, dict):
|
|
185
185
|
configurable = config.get("configurable")
|
|
186
186
|
if isinstance(configurable, dict):
|
|
187
|
-
|
|
187
|
+
strip_reserved(configurable, "config.configurable")
|
|
188
188
|
|
|
189
189
|
# Config schema: top-level configurable
|
|
190
190
|
configurable = data.get("configurable")
|
|
191
191
|
if isinstance(configurable, dict):
|
|
192
|
-
|
|
192
|
+
strip_reserved(configurable, "configurable")
|
|
193
193
|
|
|
194
194
|
# write schemas: context
|
|
195
195
|
context = data.get("context")
|
|
196
196
|
if isinstance(context, dict):
|
|
197
|
-
|
|
197
|
+
strip_reserved(context, "context")
|
|
198
198
|
|
|
199
199
|
# checkpoint: merged into configurable on run create and when a cron fires
|
|
200
200
|
checkpoint = data.get("checkpoint")
|
|
201
201
|
if isinstance(checkpoint, dict):
|
|
202
|
-
|
|
202
|
+
strip_reserved(checkpoint, "checkpoint")
|
|
203
203
|
|
|
204
204
|
|
|
205
205
|
def should_strip_reserved_metadata(schema: typing.Any) -> bool:
|