langgraph-api 0.14.0.dev4__tar.gz → 0.14.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.14.0.dev4 → langgraph_api-0.14.0.dev5}/PKG-INFO +1 -1
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/Makefile +8 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/README.md +30 -1
- langgraph_api-0.14.0.dev5/benchmark/capacity-ci.js +332 -0
- langgraph_api-0.14.0.dev5/benchmark/host-v2.js +227 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/staircase.py +15 -2
- langgraph_api-0.14.0.dev5/benchmark/update-revision.js +20 -0
- langgraph_api-0.14.0.dev5/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/_checkpointer/_adapter.py +13 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/__init__.py +5 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/a2a.py +7 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/config/__init__.py +11 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/servicers/encryption.py +67 -14
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/queue_entrypoint.py +2 -3
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/server.py +4 -2
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/checkpointer.py +21 -0
- langgraph_api-0.14.0.dev5/langgraph_grpc_common/proto/checkpointer_pb2.py +87 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +56 -2
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/encryption_pb2.py +11 -7
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/encryption_pb2.pyi +61 -1
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +88 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +24 -0
- langgraph_api-0.14.0.dev4/benchmark/update-revision.js +0 -137
- langgraph_api-0.14.0.dev4/langgraph_api/__init__.py +0 -1
- langgraph_api-0.14.0.dev4/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -79
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/.gitignore +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/LICENSE +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/Makefile +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/README.md +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/.gitignore +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/assistant.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/benchmarks.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/log-failure.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/meta_workload.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/store.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/stream_write.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/thread.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/types.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/benchmark-runners/wait_write.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/clean-cli.js +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/clean.js +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/continuous/README.md +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/continuous/pyproject.toml +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/continuous/runner.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/continuous/uv.lock +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/graphs.js +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/package.json +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/ramp.js +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/reporting/dd_reporting.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/staircase_step_k6.js +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/tsconfig.json +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/weather.js +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/benchmark/yarn.lock +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/constraints.txt +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/custom_store.sql +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/forbidden.txt +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/hatch_build.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/healthcheck.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph-cloud-debugging-20260210132856.zip +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/_checkpointer/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/_checkpointer/protocol.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/_factory_utils.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/event_streaming.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/mcp/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/mcp/_constants.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/mcp/_handlers.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/mcp/_models.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/mcp/_routes.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/mcp/_sanitizers.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/profile.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/runs.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/custom.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/errors.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/cache.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/cli.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/command.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/config/_parse.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/config/schemas.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/encryption/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/encryption/aes_json.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/encryption/context.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/encryption/custom.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/encryption/middleware.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/encryption/shared.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/capabilities.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/constants.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/event_normalizers.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/namespace.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/service.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/session.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/state_normalizers.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/event_streaming/types.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/feature_flags.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/graph.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/client.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/ops/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/ops/assistants.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/ops/cache.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/ops/crons.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/ops/runs.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/ops/threads.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/server.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/servicers/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/http.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/http_metrics.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/http_metrics_utils.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/.yarnclean +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/remote.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/traceblock.mts +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/lc_security/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/lc_security/exceptions.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/lc_security/policy.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/lc_security/transport.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/metrics_collector.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/metrics_otlp.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/middleware/ensure_store.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/models/run.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/otel_context.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/release_tags.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/route.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/self_hosted_logs.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/self_hosted_metrics.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/state.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/store.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/stream_v2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/timing/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/timing/profiler.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/timing/timer.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/traceblock.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/tracing_session.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/cache.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/config.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/errors.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/extract.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/future.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/headers.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/network.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/retriable_client.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/stream_codec.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/utils/uuids.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_api/worker.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/_compat.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/checkpoint.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/config.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/durability.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/store.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/struct.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/conversion/value.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/core_api_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/core_api_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/store_pb2.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/store_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/serde.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_grpc_common/store.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/routes.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/logging.json +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/openapi.json +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/pyproject.toml +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/scripts/build_wheel.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/scripts/create_license.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/scripts/run_a2a_tck.py +0 -0
- {langgraph_api-0.14.0.dev4 → langgraph_api-0.14.0.dev5}/uv.lock +0 -0
|
@@ -19,6 +19,14 @@ benchmark-new-revision:
|
|
|
19
19
|
benchmark-staircase:
|
|
20
20
|
python staircase.py
|
|
21
21
|
|
|
22
|
+
benchmark-capacity-ci:
|
|
23
|
+
npm install
|
|
24
|
+
node capacity-ci.js
|
|
25
|
+
|
|
26
|
+
benchmark-capacity-matrix:
|
|
27
|
+
npm install
|
|
28
|
+
node capacity-ci.js --all-deployments
|
|
29
|
+
|
|
22
30
|
benchmark-staircase-reset:
|
|
23
31
|
python ../../scripts/reset_deployment.py -a $(BENCHMARK_APP_NAME) -n $(BENCHMARK_NAMESPACE) -db $(BENCHMARK_DB_INSTANCE)
|
|
24
32
|
python staircase.py
|
|
@@ -25,6 +25,14 @@ This directory contains k6 + Python/Node benchmark tooling for LangGraph API.
|
|
|
25
25
|
- `make benchmark-reset` - Cleans benchmark server state via `clean-cli.js`.
|
|
26
26
|
- `make benchmark-new-revision` - Triggers a new benchmark deployment revision.
|
|
27
27
|
|
|
28
|
+
- `make benchmark-capacity-ci` - Runs the daily capacity matrix for one deployment (`DEPLOYMENT` env). Uses `staircase.py` per cell (default 200–2000 VUs, step 100). Config lives in `capacity-ci.js`.
|
|
29
|
+
- **Example:**
|
|
30
|
+
- `DEPLOYMENT=daily-cap-benchmark-dedicated make benchmark-capacity-ci`
|
|
31
|
+
|
|
32
|
+
- `make benchmark-capacity-matrix` - Runs the full local capacity matrix for all deployments in `capacity-ci.js` (sequential).
|
|
33
|
+
|
|
34
|
+
Host API calls use [`host-v2.js`](host-v2.js) (v2 revisions + resource-tiers). [`update-revision.js`](update-revision.js) uses the same module.
|
|
35
|
+
|
|
28
36
|
## Benchmark runner types (`BENCHMARK_TYPE`)
|
|
29
37
|
|
|
30
38
|
The runner contains the actual logic each virtual user will execute during the benchmark and steps to validate the logic worked correctly. Options are:
|
|
@@ -113,11 +121,32 @@ make benchmark-clean
|
|
|
113
121
|
- `summary_<timestamp>.json`
|
|
114
122
|
- `*_chart_*.png` (when chart generation is run)
|
|
115
123
|
- Staircase:
|
|
116
|
-
- `staircase_summary.json`
|
|
124
|
+
- `staircase_summary.json` (or `SUMMARY_PATH` when set by capacity CI)
|
|
125
|
+
- `staircase_summary_<deployment>_<tier>_<runner>.json` (capacity matrix)
|
|
117
126
|
|
|
118
127
|
## CI workflows
|
|
119
128
|
|
|
120
129
|
- Daily ramp benchmark: `.github/workflows/benchmark.yml`
|
|
130
|
+
- Daily capacity matrix: `.github/workflows/benchmark-capacity-matrix.yml`
|
|
131
|
+
|
|
132
|
+
### Capacity matrix setup
|
|
133
|
+
|
|
134
|
+
1. Create staging deployments `daily-cap-benchmark-dedicated` and `daily-cap-benchmark-serverless`.
|
|
135
|
+
2. Fill in `deploymentId` and `baseUrl` in `CAPACITY_DEPLOYMENTS` at the top of [`capacity-ci.js`](capacity-ci.js).
|
|
136
|
+
3. Scheduled run: two parallel CI jobs (one per deployment), aggregate job posts Slack summary.
|
|
137
|
+
|
|
138
|
+
Local commands:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Single deployment (9 cells: 3 tiers × 3 runners)
|
|
142
|
+
DEPLOYMENT=daily-cap-benchmark-dedicated make benchmark-capacity-ci
|
|
143
|
+
|
|
144
|
+
# All deployments sequentially (18 cells)
|
|
145
|
+
make benchmark-capacity-matrix
|
|
146
|
+
|
|
147
|
+
# Aggregate downloaded CI artifacts
|
|
148
|
+
node capacity-ci.js --aggregate --summaries-dir ./artifacts --slack
|
|
149
|
+
```
|
|
121
150
|
|
|
122
151
|
## References
|
|
123
152
|
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daily capacity benchmark orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* DEPLOYMENT=daily-cap-benchmark-dedicated node capacity-ci.js
|
|
6
|
+
* node capacity-ci.js --all-deployments
|
|
7
|
+
* node capacity-ci.js --aggregate --summaries-dir ./artifacts --slack
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
|
|
15
|
+
import { requireApiKey, setResourceTiers } from "./host-v2.js";
|
|
16
|
+
|
|
17
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
|
|
19
|
+
/** @type {Array<{slug: string, deploymentId: string, baseUrl: string, tiers: string[]}>} */
|
|
20
|
+
const CAPACITY_DEPLOYMENTS = [
|
|
21
|
+
{
|
|
22
|
+
slug: "daily-cap-benchmark-dedicated",
|
|
23
|
+
deploymentId: "22a22e9d-521e-4635-9bcb-a096a22820cc",
|
|
24
|
+
baseUrl:
|
|
25
|
+
"https://daily-cap-benchmark-dedicat-9669b63626045e0681f1f1fda08ef4ce.staging.langgraph.app",
|
|
26
|
+
tiers: ["DEDICATED_L", "DEDICATED_M", "DEDICATED_S"],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
slug: "daily-cap-benchmark-serverless",
|
|
30
|
+
deploymentId: "becfa8bb-e2e3-4d96-8d08-3191b17c5d4d",
|
|
31
|
+
baseUrl:
|
|
32
|
+
"https://daily-cap-benchmark-serverl-b5dc9d9f7fa05990b279939863ae08de.staging.langgraph.app",
|
|
33
|
+
tiers: ["SERVERLESS_L", "SERVERLESS_M", "SERVERLESS_S"],
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const RUNNERS = ["wait_write", "stream_write", "threads_search_metadata"];
|
|
38
|
+
|
|
39
|
+
const RUNNER_LABELS = {
|
|
40
|
+
wait_write: "wait_write",
|
|
41
|
+
stream_write: "stream_write",
|
|
42
|
+
threads_search_metadata: "threads_search",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// 200 + 100 * (19 - 1) = 2000 VUs
|
|
46
|
+
const STAIRCASE_START_LOAD = "200";
|
|
47
|
+
const STAIRCASE_STEP_SIZE = "100";
|
|
48
|
+
const STAIRCASE_NUM_STEPS = "19";
|
|
49
|
+
|
|
50
|
+
function validateDeployment(deployment) {
|
|
51
|
+
const missing = [];
|
|
52
|
+
if (!deployment.slug) missing.push("slug");
|
|
53
|
+
if (!deployment.deploymentId) missing.push("deploymentId");
|
|
54
|
+
if (!deployment.baseUrl) missing.push("baseUrl");
|
|
55
|
+
if (!deployment.tiers?.length) missing.push("tiers");
|
|
56
|
+
if (missing.length > 0) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Deployment ${deployment.slug || "<unknown>"} is missing required fields: ${missing.join(", ")}. ` +
|
|
59
|
+
"Update CAPACITY_DEPLOYMENTS in capacity-ci.js.",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getDeployment(slug, deployments = CAPACITY_DEPLOYMENTS) {
|
|
65
|
+
const deployment = deployments.find((entry) => entry.slug === slug);
|
|
66
|
+
if (!deployment) {
|
|
67
|
+
const known = deployments.map((entry) => entry.slug).join(", ");
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Unknown deployment ${JSON.stringify(slug)}. Known deployments: ${known}`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return deployment;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function capacityVus(summary) {
|
|
76
|
+
if (!summary?.capacity) return "-";
|
|
77
|
+
return String(summary.capacity.targetVUs ?? "-");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function formatAggregateTable(deployments, summaries) {
|
|
81
|
+
/** @type {Record<string, Record<string, Record<string, object>>>} */
|
|
82
|
+
const byDeployment = Object.fromEntries(deployments.map((d) => [d.slug, {}]));
|
|
83
|
+
|
|
84
|
+
for (const summary of summaries) {
|
|
85
|
+
const config = summary.config ?? {};
|
|
86
|
+
const { deploymentSlug, computeTier, benchmarkType } = config;
|
|
87
|
+
if (deploymentSlug && computeTier && benchmarkType) {
|
|
88
|
+
byDeployment[deploymentSlug] ??= {};
|
|
89
|
+
byDeployment[deploymentSlug][computeTier] ??= {};
|
|
90
|
+
byDeployment[deploymentSlug][computeTier][benchmarkType] = summary;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const lines = ["*Daily Capacity Benchmark* (stable, default profile)", ""];
|
|
95
|
+
for (const deployment of deployments) {
|
|
96
|
+
lines.push(`*${deployment.slug}*`);
|
|
97
|
+
lines.push(
|
|
98
|
+
`${"".padEnd(16)}${RUNNERS.map((runner) => RUNNER_LABELS[runner].padEnd(16)).join("")}`,
|
|
99
|
+
);
|
|
100
|
+
for (const tier of deployment.tiers) {
|
|
101
|
+
let row = tier.padEnd(16);
|
|
102
|
+
for (const runner of RUNNERS) {
|
|
103
|
+
const summary = byDeployment[deployment.slug]?.[tier]?.[runner];
|
|
104
|
+
row += capacityVus(summary).padEnd(16);
|
|
105
|
+
}
|
|
106
|
+
lines.push(row);
|
|
107
|
+
}
|
|
108
|
+
lines.push("");
|
|
109
|
+
}
|
|
110
|
+
return lines.join("\n").trimEnd();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function summaryPathFor(deploymentSlug, tier, runner) {
|
|
114
|
+
const safeTier = tier.replaceAll("/", "-");
|
|
115
|
+
return path.join(
|
|
116
|
+
__dirname,
|
|
117
|
+
`staircase_summary_${deploymentSlug}_${safeTier}_${runner}.json`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function runCommand(command, args, env) {
|
|
122
|
+
const result = spawnSync(command, args, {
|
|
123
|
+
cwd: __dirname,
|
|
124
|
+
env: { ...process.env, ...env },
|
|
125
|
+
stdio: "inherit",
|
|
126
|
+
});
|
|
127
|
+
if (result.status !== 0) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`${command} ${args.join(" ")} failed with exit code ${result.status}`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function ensureBuild() {
|
|
135
|
+
runCommand("npm", ["run", "build"], {});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function runReset(baseUrl, apiKey) {
|
|
139
|
+
runCommand("node", ["clean-cli.js"], {
|
|
140
|
+
BASE_URL: baseUrl,
|
|
141
|
+
LANGSMITH_API_KEY: apiKey,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function runStaircase({
|
|
146
|
+
baseUrl,
|
|
147
|
+
apiKey,
|
|
148
|
+
runner,
|
|
149
|
+
deploymentSlug,
|
|
150
|
+
computeTier,
|
|
151
|
+
summaryPath,
|
|
152
|
+
}) {
|
|
153
|
+
runCommand(process.env.PYTHON || "python3", ["staircase.py"], {
|
|
154
|
+
BASE_URL: baseUrl,
|
|
155
|
+
LANGSMITH_API_KEY: apiKey,
|
|
156
|
+
BENCHMARK_TYPE: runner,
|
|
157
|
+
DEPLOYMENT_SLUG: deploymentSlug,
|
|
158
|
+
COMPUTE_TIER: computeTier,
|
|
159
|
+
SUMMARY_PATH: summaryPath,
|
|
160
|
+
START_LOAD: process.env.START_LOAD || STAIRCASE_START_LOAD,
|
|
161
|
+
STEP_SIZE: process.env.STEP_SIZE || STAIRCASE_STEP_SIZE,
|
|
162
|
+
NUM_STEPS: process.env.NUM_STEPS || STAIRCASE_NUM_STEPS,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function printDeploymentTable(deployment, summaryPaths) {
|
|
167
|
+
/** @type {Record<string, Record<string, object>>} */
|
|
168
|
+
const byKey = {};
|
|
169
|
+
for (const summaryPath of summaryPaths) {
|
|
170
|
+
const summary = JSON.parse(readFileSync(summaryPath, "utf8"));
|
|
171
|
+
const config = summary.config ?? {};
|
|
172
|
+
byKey[`${config.computeTier}:${config.benchmarkType}`] = summary;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const header =
|
|
176
|
+
"tier".padEnd(16) +
|
|
177
|
+
RUNNERS.map((runner) => RUNNER_LABELS[runner].padEnd(16)).join("");
|
|
178
|
+
console.log(
|
|
179
|
+
`\nCapacity results — ${deployment.slug} (max VUs @ SLO)\n${header}`,
|
|
180
|
+
);
|
|
181
|
+
for (const tier of deployment.tiers) {
|
|
182
|
+
let row = tier.padEnd(16);
|
|
183
|
+
for (const runner of RUNNERS) {
|
|
184
|
+
const summary = byKey[`${tier}:${runner}`];
|
|
185
|
+
row += capacityVus(summary).padEnd(16);
|
|
186
|
+
}
|
|
187
|
+
console.log(row);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function runDeploymentMatrix(deployment, apiKey) {
|
|
192
|
+
console.log(
|
|
193
|
+
`\n${"=".repeat(80)}\nCapacity matrix: ${deployment.slug}\n${"=".repeat(80)}`,
|
|
194
|
+
);
|
|
195
|
+
validateDeployment(deployment);
|
|
196
|
+
|
|
197
|
+
/** @type {string[]} */
|
|
198
|
+
const summaryPaths = [];
|
|
199
|
+
for (const tier of deployment.tiers) {
|
|
200
|
+
console.log(`\n--- Tier ${tier} ---`);
|
|
201
|
+
const databaseTier = tier.startsWith("DEDICATED_") ? tier : undefined;
|
|
202
|
+
await setResourceTiers(
|
|
203
|
+
deployment.deploymentId,
|
|
204
|
+
tier,
|
|
205
|
+
databaseTier,
|
|
206
|
+
apiKey,
|
|
207
|
+
deployment.baseUrl,
|
|
208
|
+
);
|
|
209
|
+
for (const runner of RUNNERS) {
|
|
210
|
+
const summaryPath = summaryPathFor(deployment.slug, tier, runner);
|
|
211
|
+
console.log(`\n>> ${deployment.slug} / ${tier} / ${runner}`);
|
|
212
|
+
runReset(deployment.baseUrl, apiKey);
|
|
213
|
+
runStaircase({
|
|
214
|
+
baseUrl: deployment.baseUrl,
|
|
215
|
+
apiKey,
|
|
216
|
+
runner,
|
|
217
|
+
deploymentSlug: deployment.slug,
|
|
218
|
+
computeTier: tier,
|
|
219
|
+
summaryPath,
|
|
220
|
+
});
|
|
221
|
+
summaryPaths.push(summaryPath);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
printDeploymentTable(deployment, summaryPaths);
|
|
226
|
+
return summaryPaths;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function collectSummaries(directory) {
|
|
230
|
+
const paths = readdirSync(directory)
|
|
231
|
+
.filter(
|
|
232
|
+
(name) => name.startsWith("staircase_summary_") && name.endsWith(".json"),
|
|
233
|
+
)
|
|
234
|
+
.sort()
|
|
235
|
+
.map((name) => path.join(directory, name));
|
|
236
|
+
if (paths.length === 0) {
|
|
237
|
+
throw new Error(`No staircase_summary_*.json files found in ${directory}`);
|
|
238
|
+
}
|
|
239
|
+
return paths.map((summaryPath) =>
|
|
240
|
+
JSON.parse(readFileSync(summaryPath, "utf8")),
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function postSlack(message) {
|
|
245
|
+
const token = process.env.SLACK_BOT_TOKEN;
|
|
246
|
+
const channel = process.env.SLACK_CHANNEL;
|
|
247
|
+
if (!token || !channel) {
|
|
248
|
+
console.log(
|
|
249
|
+
"SLACK_BOT_TOKEN or SLACK_CHANNEL not set; skipping Slack post",
|
|
250
|
+
);
|
|
251
|
+
console.log(message);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const response = await fetch("https://slack.com/api/chat.postMessage", {
|
|
256
|
+
method: "POST",
|
|
257
|
+
headers: {
|
|
258
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
259
|
+
Authorization: `Bearer ${token}`,
|
|
260
|
+
},
|
|
261
|
+
body: JSON.stringify({ channel, text: message }),
|
|
262
|
+
});
|
|
263
|
+
const result = await response.json();
|
|
264
|
+
if (!result.ok) {
|
|
265
|
+
throw new Error(`Slack API error: ${result.error ?? "unknown"}`);
|
|
266
|
+
}
|
|
267
|
+
console.log("Posted aggregate summary to Slack");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function runAggregate(summariesDir, { postToSlack }) {
|
|
271
|
+
const summaries = collectSummaries(summariesDir);
|
|
272
|
+
const message = formatAggregateTable(CAPACITY_DEPLOYMENTS, summaries);
|
|
273
|
+
console.log(message);
|
|
274
|
+
if (postToSlack) {
|
|
275
|
+
const artifactUrl = process.env.GITHUB_RUN_URL;
|
|
276
|
+
const slackMessage = artifactUrl
|
|
277
|
+
? `${message}\n\n<${artifactUrl}|Download artifacts>`
|
|
278
|
+
: message;
|
|
279
|
+
await postSlack(slackMessage);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function parseArgs(argv) {
|
|
284
|
+
return {
|
|
285
|
+
allDeployments: argv.includes("--all-deployments"),
|
|
286
|
+
aggregate: argv.includes("--aggregate"),
|
|
287
|
+
slack: argv.includes("--slack"),
|
|
288
|
+
summariesDir:
|
|
289
|
+
argv.includes("--summaries-dir") &&
|
|
290
|
+
argv[argv.indexOf("--summaries-dir") + 1]
|
|
291
|
+
? path.resolve(argv[argv.indexOf("--summaries-dir") + 1])
|
|
292
|
+
: __dirname,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function main() {
|
|
297
|
+
const args = parseArgs(process.argv.slice(2));
|
|
298
|
+
if (args.aggregate) {
|
|
299
|
+
await runAggregate(args.summariesDir, { postToSlack: args.slack });
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const apiKey = requireApiKey();
|
|
304
|
+
if (args.allDeployments) {
|
|
305
|
+
ensureBuild();
|
|
306
|
+
for (const deployment of CAPACITY_DEPLOYMENTS) {
|
|
307
|
+
await runDeploymentMatrix(deployment, apiKey);
|
|
308
|
+
}
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const slug = process.env.DEPLOYMENT;
|
|
313
|
+
if (!slug) {
|
|
314
|
+
console.error(
|
|
315
|
+
"Set DEPLOYMENT to a slug from CAPACITY_DEPLOYMENTS in capacity-ci.js, or pass --all-deployments",
|
|
316
|
+
);
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
ensureBuild();
|
|
321
|
+
await runDeploymentMatrix(getDeployment(slug), apiKey);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const isMain =
|
|
325
|
+
process.argv[1] &&
|
|
326
|
+
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
327
|
+
if (isMain) {
|
|
328
|
+
main().catch((error) => {
|
|
329
|
+
console.error(error.message);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangSmith Host v2 API helpers for benchmark tooling.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const STAGING_TENANT_ID = '8f32dc68-61a1-439c-81d3-33511ef55527';
|
|
6
|
+
export const HOST_V2_BASE =
|
|
7
|
+
process.env.HOST_API_V2_BASE || 'https://beta.api.host.langchain.com/v2';
|
|
8
|
+
|
|
9
|
+
export const REVISION_CONFIG = {
|
|
10
|
+
source_revision_config: {
|
|
11
|
+
langgraph_config_path: 'langgraph.json',
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const EXPECTED_REVISION_STATUSES = new Set([
|
|
16
|
+
'CREATING',
|
|
17
|
+
'QUEUED',
|
|
18
|
+
'AWAITING_BUILD',
|
|
19
|
+
'BUILDING',
|
|
20
|
+
'AWAITING_DEPLOY',
|
|
21
|
+
'DEPLOYING',
|
|
22
|
+
'DEPLOYED',
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
export const FINAL_REVISION_STATUS = 'DEPLOYED';
|
|
26
|
+
export const POLL_INTERVAL_MS = 10_000;
|
|
27
|
+
export const MAX_WAIT_MS = 30 * 60 * 1000;
|
|
28
|
+
|
|
29
|
+
export function requireApiKey() {
|
|
30
|
+
const apiKey = process.env.LANGSMITH_API_KEY;
|
|
31
|
+
if (!apiKey) {
|
|
32
|
+
throw new Error('LANGSMITH_API_KEY environment variable is required');
|
|
33
|
+
}
|
|
34
|
+
return apiKey;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function hostHeaders(apiKey) {
|
|
38
|
+
return {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'x-api-key': apiKey,
|
|
41
|
+
'X-Tenant-Id': STAGING_TENANT_ID,
|
|
42
|
+
'X-Organization-Id': STAGING_TENANT_ID,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function readErrorDetail(response) {
|
|
47
|
+
try {
|
|
48
|
+
return await response.text();
|
|
49
|
+
} catch {
|
|
50
|
+
return response.statusText;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function hostRequest(method, path, apiKey, body) {
|
|
55
|
+
const response = await fetch(`${HOST_V2_BASE}${path}`, {
|
|
56
|
+
method,
|
|
57
|
+
headers: hostHeaders(apiKey),
|
|
58
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
59
|
+
});
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const detail = await readErrorDetail(response);
|
|
62
|
+
throw new Error(`${method} ${path} failed: ${response.status} ${detail}`);
|
|
63
|
+
}
|
|
64
|
+
if (response.status === 204) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return response.json();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function listLatestRevision(deploymentId, apiKey) {
|
|
71
|
+
const result = await hostRequest(
|
|
72
|
+
'GET',
|
|
73
|
+
`/deployments/${deploymentId}/revisions?limit=1&offset=0`,
|
|
74
|
+
apiKey,
|
|
75
|
+
);
|
|
76
|
+
const revisions = result?.resources ?? [];
|
|
77
|
+
if (revisions.length === 0) {
|
|
78
|
+
throw new Error(`No revisions found for deployment ${deploymentId}`);
|
|
79
|
+
}
|
|
80
|
+
return revisions[0];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function pollRevisionDeployed(deploymentId, apiKey) {
|
|
84
|
+
const startTime = Date.now();
|
|
85
|
+
let lastStatus = null;
|
|
86
|
+
|
|
87
|
+
while (true) {
|
|
88
|
+
let revision;
|
|
89
|
+
try {
|
|
90
|
+
revision = await listLatestRevision(deploymentId, apiKey);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (Date.now() - startTime > MAX_WAIT_MS) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Deployment timeout after ${MAX_WAIT_MS / 60000} minutes. Last error: ${error.message}`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
console.error('Error polling revision (will retry):', error.message);
|
|
98
|
+
await sleep(POLL_INTERVAL_MS);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const currentStatus = revision.status;
|
|
103
|
+
if (currentStatus !== lastStatus) {
|
|
104
|
+
console.log(`[${new Date().toISOString()}] revision status: ${currentStatus}`);
|
|
105
|
+
lastStatus = currentStatus;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (currentStatus === FINAL_REVISION_STATUS) {
|
|
109
|
+
console.log(' revision deployed');
|
|
110
|
+
return revision;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!EXPECTED_REVISION_STATUSES.has(currentStatus)) {
|
|
114
|
+
throw new Error(`Deployment failed with status: ${currentStatus}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (Date.now() - startTime > MAX_WAIT_MS) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Deployment timeout after ${MAX_WAIT_MS / 60000} minutes. Last status: ${currentStatus}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await sleep(POLL_INTERVAL_MS);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function createRevision(deploymentId, apiKey) {
|
|
128
|
+
console.log(`Triggering new revision for deployment ${deploymentId}...`);
|
|
129
|
+
const response = await fetch(`${HOST_V2_BASE}/deployments/${deploymentId}/revisions`, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
headers: hostHeaders(apiKey),
|
|
132
|
+
body: JSON.stringify(REVISION_CONFIG),
|
|
133
|
+
});
|
|
134
|
+
if (response.status === 409) {
|
|
135
|
+
console.log(' revision already in progress; polling existing deployment...');
|
|
136
|
+
} else if (!response.ok) {
|
|
137
|
+
const detail = await readErrorDetail(response);
|
|
138
|
+
throw new Error(
|
|
139
|
+
`POST /deployments/${deploymentId}/revisions failed: ${response.status} ${detail}`,
|
|
140
|
+
);
|
|
141
|
+
} else {
|
|
142
|
+
const revision = await response.json();
|
|
143
|
+
console.log(` revision created: ${revision.id} (${revision.status})`);
|
|
144
|
+
}
|
|
145
|
+
return pollRevisionDeployed(deploymentId, apiKey);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function pollDeploymentHealthy(baseUrl, apiKey, { checkDb = true } = {}) {
|
|
149
|
+
const url = new URL('ok', baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`);
|
|
150
|
+
if (checkDb) {
|
|
151
|
+
url.searchParams.set('check_db', '1');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const startTime = Date.now();
|
|
155
|
+
let lastError = 'unknown';
|
|
156
|
+
|
|
157
|
+
console.log(`Polling deployment health at ${url}...`);
|
|
158
|
+
|
|
159
|
+
while (true) {
|
|
160
|
+
try {
|
|
161
|
+
const headers = { Accept: 'application/json' };
|
|
162
|
+
if (apiKey) {
|
|
163
|
+
headers['x-api-key'] = apiKey;
|
|
164
|
+
}
|
|
165
|
+
const response = await fetch(url, { headers });
|
|
166
|
+
if (response.ok) {
|
|
167
|
+
const body = await response.json();
|
|
168
|
+
if (body?.ok === true) {
|
|
169
|
+
console.log(' deployment health check passed');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
lastError = `unexpected body: ${JSON.stringify(body)}`;
|
|
173
|
+
} else {
|
|
174
|
+
const detail = await readErrorDetail(response);
|
|
175
|
+
lastError = `HTTP ${response.status} ${detail}`;
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
lastError = error.message;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (Date.now() - startTime > MAX_WAIT_MS) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Health check timeout after ${MAX_WAIT_MS / 60000} minutes. Last error: ${lastError}`,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log(` health check pending (${lastError})`);
|
|
188
|
+
await sleep(POLL_INTERVAL_MS);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function setResourceTiers(
|
|
193
|
+
deploymentId,
|
|
194
|
+
computeTier,
|
|
195
|
+
databaseTier,
|
|
196
|
+
apiKey,
|
|
197
|
+
baseUrl,
|
|
198
|
+
) {
|
|
199
|
+
/** @type {{ compute_tier?: string, database_tier?: string }} */
|
|
200
|
+
const body = {};
|
|
201
|
+
if (computeTier != null) {
|
|
202
|
+
body.compute_tier = computeTier;
|
|
203
|
+
}
|
|
204
|
+
if (databaseTier != null) {
|
|
205
|
+
body.database_tier = databaseTier;
|
|
206
|
+
}
|
|
207
|
+
if (Object.keys(body).length === 0) {
|
|
208
|
+
throw new Error('At least one of computeTier or databaseTier is required');
|
|
209
|
+
}
|
|
210
|
+
console.log(
|
|
211
|
+
`Setting resource tiers for deployment ${deploymentId}: ${JSON.stringify(body)}`,
|
|
212
|
+
);
|
|
213
|
+
await hostRequest(
|
|
214
|
+
'PATCH',
|
|
215
|
+
`/deployments/${deploymentId}/resource-tiers`,
|
|
216
|
+
apiKey,
|
|
217
|
+
body,
|
|
218
|
+
);
|
|
219
|
+
await pollRevisionDeployed(deploymentId, apiKey);
|
|
220
|
+
if (databaseTier != null && baseUrl) {
|
|
221
|
+
await pollDeploymentHealthy(baseUrl, apiKey, { checkDb: true });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function sleep(ms) {
|
|
226
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
227
|
+
}
|
|
@@ -36,6 +36,9 @@ Environment variables:
|
|
|
36
36
|
|
|
37
37
|
BENCHMARK_TYPE Benchmark runner type (default: wait_write)
|
|
38
38
|
BENCHMARK_PROFILE Optional profile override (e.g. etsy, metaview)
|
|
39
|
+
DEPLOYMENT_SLUG Deployment slug for capacity CI metadata (optional)
|
|
40
|
+
COMPUTE_TIER Compute tier for capacity CI metadata (optional)
|
|
41
|
+
SUMMARY_PATH Output path for summary JSON (default: staircase_summary.json)
|
|
39
42
|
RUN_MODE stateless (default) or stateful
|
|
40
43
|
DATA_SIZE, DELAY, EXPAND, STEPS, MODE — agent parameters
|
|
41
44
|
"""
|
|
@@ -65,6 +68,12 @@ MAX_P50_DURATION_MS = int(os.environ.get("MAX_P50_DURATION_MS", "3000"))
|
|
|
65
68
|
MAX_P95_DURATION_MS = int(os.environ.get("MAX_P95_DURATION_MS", "10000"))
|
|
66
69
|
ABORT_ERROR_RATE = float(os.environ.get("ABORT_ERROR_RATE", "10"))
|
|
67
70
|
|
|
71
|
+
BENCHMARK_TYPE = os.environ.get("BENCHMARK_TYPE", "wait_write")
|
|
72
|
+
BENCHMARK_PROFILE = os.environ.get("BENCHMARK_PROFILE", "default")
|
|
73
|
+
DEPLOYMENT_SLUG = os.environ.get("DEPLOYMENT_SLUG", "")
|
|
74
|
+
COMPUTE_TIER = os.environ.get("COMPUTE_TIER", "")
|
|
75
|
+
SUMMARY_PATH = os.environ.get("SUMMARY_PATH", "staircase_summary.json")
|
|
76
|
+
|
|
68
77
|
K6_SCRIPT = Path(__file__).parent / "staircase_step_k6.js"
|
|
69
78
|
|
|
70
79
|
|
|
@@ -302,11 +311,15 @@ def main():
|
|
|
302
311
|
"maxP95DurationMs": MAX_P95_DURATION_MS,
|
|
303
312
|
"abortErrorRate": ABORT_ERROR_RATE,
|
|
304
313
|
"baseUrl": BASE_URL,
|
|
314
|
+
"benchmarkType": BENCHMARK_TYPE,
|
|
315
|
+
"benchmarkProfile": BENCHMARK_PROFILE,
|
|
316
|
+
"deploymentSlug": DEPLOYMENT_SLUG or None,
|
|
317
|
+
"computeTier": COMPUTE_TIER or None,
|
|
305
318
|
},
|
|
306
319
|
"steps": steps,
|
|
307
320
|
}
|
|
308
|
-
Path(
|
|
309
|
-
print("\nResults written to
|
|
321
|
+
Path(SUMMARY_PATH).write_text(json.dumps(summary, indent=2))
|
|
322
|
+
print(f"\nResults written to {SUMMARY_PATH}")
|
|
310
323
|
|
|
311
324
|
|
|
312
325
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Trigger a new revision deployment and wait for it to complete.
|
|
3
|
+
* Uses Host v2 deployment APIs.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createRevision, requireApiKey } from './host-v2.js';
|
|
7
|
+
|
|
8
|
+
const DEPLOYMENT_ID =
|
|
9
|
+
process.env.DEPLOYMENT_ID || '03b7336a-73dd-4ee5-8b5e-da19c48a6cdc';
|
|
10
|
+
|
|
11
|
+
async function updateRevision() {
|
|
12
|
+
const apiKey = requireApiKey();
|
|
13
|
+
await createRevision(DEPLOYMENT_ID, apiKey);
|
|
14
|
+
console.log('\n✓ Deployment completed successfully!');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
updateRevision().catch((error) => {
|
|
18
|
+
console.error('Fatal error during revision update:', error.message);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.14.0.dev5"
|