langgraph-api 0.14.0.dev1__tar.gz → 0.14.0.dev2__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.dev1 → langgraph_api-0.14.0.dev2}/PKG-INFO +2 -2
- langgraph_api-0.14.0.dev2/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/a2a.py +261 -34
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/assistants.py +39 -4
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/assistants.py +4 -1
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/package.json +1 -1
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/yarn.lock +4 -4
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/metrics_otlp.py +1 -1
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/checkpoint.py +1 -2
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/value.py +1 -2
- langgraph_api-0.14.0.dev2/langgraph_grpc_common/proto/core_api_pb2.py +274 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/core_api_pb2.pyi +10 -2
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/pyproject.toml +1 -1
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/uv.lock +49 -49
- langgraph_api-0.14.0.dev1/langgraph_api/__init__.py +0 -1
- langgraph_api-0.14.0.dev1/langgraph_grpc_common/proto/core_api_pb2.py +0 -274
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/.gitignore +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/LICENSE +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/Makefile +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/README.md +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/.gitignore +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/Makefile +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/README.md +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/assistant.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/benchmarks.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/log-failure.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/meta_workload.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/store.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/stream_write.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/thread.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/types.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/benchmark-runners/wait_write.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/clean-cli.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/clean.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/continuous/README.md +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/continuous/pyproject.toml +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/continuous/runner.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/continuous/uv.lock +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/graphs.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/package.json +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/ramp.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/reporting/dd_reporting.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/staircase.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/staircase_step_k6.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/tsconfig.json +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/update-revision.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/weather.js +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/benchmark/yarn.lock +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/constraints.txt +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/custom_store.sql +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/forbidden.txt +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/hatch_build.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/healthcheck.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph-cloud-debugging-20260210132856.zip +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/_checkpointer/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/_checkpointer/_adapter.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/_checkpointer/protocol.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/_factory_utils.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/event_streaming.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/mcp/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/mcp/_constants.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/mcp/_handlers.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/mcp/_models.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/mcp/_routes.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/mcp/_sanitizers.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/profile.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/runs.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/custom.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/errors.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/cache.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/cli.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/command.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/config/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/config/_parse.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/config/schemas.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/encryption/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/encryption/aes_json.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/encryption/context.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/encryption/custom.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/encryption/middleware.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/encryption/shared.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/capabilities.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/constants.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/event_normalizers.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/namespace.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/service.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/session.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/state_normalizers.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/event_streaming/types.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/feature_flags.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/graph.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/client.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/cache.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/crons.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/runs.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/threads.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/server.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/servicers/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/servicers/encryption.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/http.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/http_metrics.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/http_metrics_utils.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/.yarnclean +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/remote.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/traceblock.mts +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/lc_security/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/lc_security/exceptions.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/lc_security/policy.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/lc_security/transport.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/metrics_collector.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/middleware/ensure_store.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/models/run.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/otel_context.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/release_tags.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/route.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/self_hosted_logs.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/self_hosted_metrics.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/server.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/state.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/store.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/stream_v2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/timing/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/timing/profiler.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/timing/timer.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/traceblock.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/tracing_session.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/cache.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/config.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/errors.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/extract.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/future.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/headers.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/network.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/retriable_client.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/stream_codec.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/utils/uuids.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/worker.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/checkpointer.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/_compat.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/config.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/durability.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/store.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/conversion/struct.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/store_pb2.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/store_pb2.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/serde.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_grpc_common/store.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/routes.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/logging.json +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/openapi.json +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/scripts/build_wheel.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/scripts/create_license.py +0 -0
- {langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/scripts/run_a2a_tck.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.14.0.
|
|
3
|
+
Version: 0.14.0.dev2
|
|
4
4
|
Author-email: Will Fu-Hinthorn <will@langchain.dev>, Josh Rogers <josh@langchain.dev>, Parker Rule <parker@langchain.dev>
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
8
|
Requires-Dist: cloudpickle>=3.0.0
|
|
9
|
-
Requires-Dist: cryptography>=
|
|
9
|
+
Requires-Dist: cryptography>=50.0.0
|
|
10
10
|
Requires-Dist: grpcio-health-checking<1.82.0,>=1.81.0
|
|
11
11
|
Requires-Dist: grpcio-tools==1.81.1
|
|
12
12
|
Requires-Dist: grpcio<1.82.0,>=1.81.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.14.0.dev2"
|
|
@@ -11,6 +11,8 @@ Push notifications are not implemented.
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
import asyncio
|
|
14
|
+
import base64
|
|
15
|
+
import binascii
|
|
14
16
|
import functools
|
|
15
17
|
import os
|
|
16
18
|
import uuid
|
|
@@ -92,6 +94,13 @@ ERROR_CODE_INVALID_AGENT_RESPONSE = -32006
|
|
|
92
94
|
# ============================================================================
|
|
93
95
|
|
|
94
96
|
A2A_PROTOCOL_VERSION = "1.0"
|
|
97
|
+
_DEFAULT_A2A_INPUT_MODES = ("application/json", "text/plain")
|
|
98
|
+
_DEFAULT_A2A_OUTPUT_MODES = ("application/json", "text/plain")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class InvalidAgentResponseError(ValueError):
|
|
102
|
+
"""Raised when public agent output cannot be represented as an A2A part."""
|
|
103
|
+
|
|
95
104
|
|
|
96
105
|
# ============================================================================
|
|
97
106
|
# Legacy (v0.x) format helpers
|
|
@@ -592,6 +601,7 @@ _AGENT_MESSAGE_TYPES = {"ai", "aimessage", "aimessagechunk"}
|
|
|
592
601
|
_ROLE_DEFINED_MESSAGE_TYPES = {"chat", "chatmessage", "chatmessagechunk"}
|
|
593
602
|
_USER_MESSAGE_ROLES = {"human", "user"}
|
|
594
603
|
_AGENT_MESSAGE_ROLES = {"agent", "assistant"}
|
|
604
|
+
_MEDIA_CONTENT_BLOCK_TYPES = {"audio", "file", "image", "video"}
|
|
595
605
|
|
|
596
606
|
|
|
597
607
|
def _normalize_message_label(value: Any) -> str:
|
|
@@ -630,6 +640,117 @@ def _a2a_role_for_message(
|
|
|
630
640
|
return type_role or role_role
|
|
631
641
|
|
|
632
642
|
|
|
643
|
+
def _content_block_to_a2a_file_part(block: dict[str, Any]) -> dict[str, Any]:
|
|
644
|
+
"""Convert one canonical LangChain media block to an A2A FilePart."""
|
|
645
|
+
|
|
646
|
+
source = next(
|
|
647
|
+
(key for key in ("base64", "data", "url") if block.get(key) is not None),
|
|
648
|
+
None,
|
|
649
|
+
)
|
|
650
|
+
if source is None:
|
|
651
|
+
raise InvalidAgentResponseError(
|
|
652
|
+
"Media content blocks must contain 'base64', 'data', or 'url'."
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
value = block[source]
|
|
656
|
+
file_obj: dict[str, Any] = {}
|
|
657
|
+
if source == "url":
|
|
658
|
+
if not isinstance(value, str) or not value:
|
|
659
|
+
raise InvalidAgentResponseError(
|
|
660
|
+
"Media content block 'url' must be a non-empty string."
|
|
661
|
+
)
|
|
662
|
+
file_obj["uri"] = value
|
|
663
|
+
else:
|
|
664
|
+
if source == "data" and isinstance(value, (bytes, bytearray)):
|
|
665
|
+
value = base64.b64encode(value).decode("ascii")
|
|
666
|
+
if not isinstance(value, str):
|
|
667
|
+
raise InvalidAgentResponseError(
|
|
668
|
+
f"Media content block '{source}' must be base64-encoded text or bytes."
|
|
669
|
+
)
|
|
670
|
+
compact_value = "".join(value.split())
|
|
671
|
+
padded_value = compact_value + ("=" * (-len(compact_value) % 4))
|
|
672
|
+
try:
|
|
673
|
+
decoded = base64.b64decode(
|
|
674
|
+
padded_value,
|
|
675
|
+
altchars=b"-_",
|
|
676
|
+
validate=True,
|
|
677
|
+
)
|
|
678
|
+
except (binascii.Error, ValueError) as e:
|
|
679
|
+
raise InvalidAgentResponseError(
|
|
680
|
+
f"Media content block '{source}' must contain valid base64 data."
|
|
681
|
+
) from e
|
|
682
|
+
file_obj["bytes"] = base64.b64encode(decoded).decode("ascii")
|
|
683
|
+
|
|
684
|
+
mime_type = block.get("mime_type")
|
|
685
|
+
if mime_type is not None:
|
|
686
|
+
if not isinstance(mime_type, str):
|
|
687
|
+
raise InvalidAgentResponseError(
|
|
688
|
+
"Media content block 'mime_type' must be a string."
|
|
689
|
+
)
|
|
690
|
+
if mime_type:
|
|
691
|
+
file_obj["mimeType"] = mime_type
|
|
692
|
+
|
|
693
|
+
filename = block.get("filename")
|
|
694
|
+
if filename is None:
|
|
695
|
+
extras = block.get("extras")
|
|
696
|
+
if isinstance(extras, dict):
|
|
697
|
+
filename = extras.get("filename")
|
|
698
|
+
if filename is not None:
|
|
699
|
+
if not isinstance(filename, str):
|
|
700
|
+
raise InvalidAgentResponseError(
|
|
701
|
+
"Media content block filename must be a string."
|
|
702
|
+
)
|
|
703
|
+
if filename:
|
|
704
|
+
file_obj["name"] = filename
|
|
705
|
+
|
|
706
|
+
return {"kind": "file", "file": file_obj}
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
def _content_to_a2a_parts(content: Any) -> list[dict[str, Any]]:
|
|
710
|
+
"""Convert public LangChain message content to ordered A2A parts."""
|
|
711
|
+
|
|
712
|
+
if isinstance(content, str):
|
|
713
|
+
return [{"kind": "text", "text": content}]
|
|
714
|
+
if content is None:
|
|
715
|
+
return []
|
|
716
|
+
if not isinstance(content, list):
|
|
717
|
+
return [{"kind": "text", "text": str(content)}]
|
|
718
|
+
|
|
719
|
+
parts: list[dict[str, Any]] = []
|
|
720
|
+
text_parts: list[str] = []
|
|
721
|
+
|
|
722
|
+
def flush_text() -> None:
|
|
723
|
+
if text_parts:
|
|
724
|
+
parts.append({"kind": "text", "text": "".join(text_parts)})
|
|
725
|
+
text_parts.clear()
|
|
726
|
+
|
|
727
|
+
for block in content:
|
|
728
|
+
if isinstance(block, str):
|
|
729
|
+
text_parts.append(block)
|
|
730
|
+
elif isinstance(block, dict) and block.get("type") == "text":
|
|
731
|
+
text = block.get("text")
|
|
732
|
+
if isinstance(text, str):
|
|
733
|
+
text_parts.append(text)
|
|
734
|
+
elif (
|
|
735
|
+
isinstance(block, dict) and block.get("type") in _MEDIA_CONTENT_BLOCK_TYPES
|
|
736
|
+
):
|
|
737
|
+
flush_text()
|
|
738
|
+
parts.append(_content_block_to_a2a_file_part(block))
|
|
739
|
+
|
|
740
|
+
flush_text()
|
|
741
|
+
return parts
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
def _a2a_parts_have_content(parts: list[dict[str, Any]]) -> bool:
|
|
745
|
+
"""Return whether converted parts contain public text or file content."""
|
|
746
|
+
|
|
747
|
+
return any(
|
|
748
|
+
part.get("kind") == "file"
|
|
749
|
+
or (part.get("kind") == "text" and bool(part.get("text")))
|
|
750
|
+
for part in parts
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
|
|
633
754
|
def _content_to_text(content: Any) -> str:
|
|
634
755
|
"""Convert public LangChain message content to A2A text."""
|
|
635
756
|
|
|
@@ -650,41 +771,41 @@ def _content_to_text(content: Any) -> str:
|
|
|
650
771
|
return str(content)
|
|
651
772
|
|
|
652
773
|
|
|
653
|
-
def _extract_a2a_response(result: dict[str, Any]) -> str:
|
|
654
|
-
"""Extract
|
|
774
|
+
def _extract_a2a_response(result: dict[str, Any]) -> list[dict[str, Any]]:
|
|
775
|
+
"""Extract public A2A parts from the last assistant response.
|
|
655
776
|
|
|
656
777
|
Args:
|
|
657
778
|
result: Graph execution result
|
|
658
779
|
|
|
659
780
|
Returns:
|
|
660
|
-
|
|
781
|
+
Ordered public parts from the last assistant message
|
|
661
782
|
|
|
662
783
|
Raises:
|
|
663
784
|
ValueError: If result doesn't contain messages or is invalid
|
|
664
785
|
"""
|
|
665
786
|
if "__error__" in result:
|
|
666
787
|
# Let the caller handle errors
|
|
667
|
-
return str(result)
|
|
788
|
+
return [{"kind": "text", "text": str(result)}]
|
|
668
789
|
|
|
669
790
|
if "messages" not in result:
|
|
670
791
|
# Fallback to the full result if no messages schema. It is not optimal to do A2A on assistants without
|
|
671
792
|
# a messages key, but it is not a hard requirement.
|
|
672
|
-
return str(result)
|
|
793
|
+
return [{"kind": "text", "text": str(result)}]
|
|
673
794
|
|
|
674
795
|
messages = result["messages"]
|
|
675
796
|
if not isinstance(messages, list) or not messages:
|
|
676
|
-
return str(result)
|
|
797
|
+
return [{"kind": "text", "text": str(result)}]
|
|
677
798
|
|
|
678
799
|
# Find the last assistant message
|
|
679
800
|
for message in reversed(messages):
|
|
680
801
|
if not isinstance(message, dict):
|
|
681
802
|
continue
|
|
682
803
|
if _a2a_role_for_message(message) == "ROLE_AGENT" and "content" in message:
|
|
683
|
-
|
|
684
|
-
if
|
|
685
|
-
return
|
|
804
|
+
parts = _content_to_a2a_parts(message["content"])
|
|
805
|
+
if _a2a_parts_have_content(parts):
|
|
806
|
+
return parts
|
|
686
807
|
|
|
687
|
-
return ""
|
|
808
|
+
return [{"kind": "text", "text": ""}]
|
|
688
809
|
|
|
689
810
|
|
|
690
811
|
def _create_interrupt_artifact(interrupts: list[dict[str, Any]]) -> dict[str, Any]:
|
|
@@ -714,25 +835,27 @@ def _create_interrupt_artifact(interrupts: list[dict[str, Any]]) -> dict[str, An
|
|
|
714
835
|
}
|
|
715
836
|
|
|
716
837
|
|
|
717
|
-
def _create_response_artifact(
|
|
718
|
-
|
|
838
|
+
def _create_response_artifact(
|
|
839
|
+
parts: list[dict[str, Any]], assistant_id: str
|
|
840
|
+
) -> dict[str, Any]:
|
|
841
|
+
"""Create an A2A artifact carrying the agent's final response parts.
|
|
719
842
|
|
|
720
843
|
Shared by ``message/send`` and ``message/stream`` so both paths return the
|
|
721
844
|
same first-class Artifact shape. Per A2A spec section 3.7, task outputs
|
|
722
845
|
SHOULD be returned via Artifacts rather than embedded in a status Message.
|
|
723
846
|
|
|
724
847
|
Args:
|
|
725
|
-
|
|
848
|
+
parts: The final response parts (from ``_extract_a2a_response``).
|
|
726
849
|
assistant_id: The assistant ID, used only for the description.
|
|
727
850
|
|
|
728
851
|
Returns:
|
|
729
|
-
A2A artifact dict
|
|
852
|
+
A2A artifact dict containing the ordered public response parts.
|
|
730
853
|
"""
|
|
731
854
|
return {
|
|
732
855
|
"artifactId": str(uuid.uuid4()),
|
|
733
856
|
"name": "Assistant Response",
|
|
734
857
|
"description": f"Response from assistant {assistant_id}",
|
|
735
|
-
"parts":
|
|
858
|
+
"parts": parts,
|
|
736
859
|
}
|
|
737
860
|
|
|
738
861
|
|
|
@@ -740,7 +863,7 @@ def _create_response_artifact_update(
|
|
|
740
863
|
*,
|
|
741
864
|
task_id: str,
|
|
742
865
|
context_id: str,
|
|
743
|
-
|
|
866
|
+
parts: list[dict[str, Any]],
|
|
744
867
|
assistant_id: str,
|
|
745
868
|
) -> dict[str, Any]:
|
|
746
869
|
"""Create a final streaming update containing the response artifact."""
|
|
@@ -749,7 +872,7 @@ def _create_response_artifact_update(
|
|
|
749
872
|
"taskId": task_id,
|
|
750
873
|
"contextId": context_id,
|
|
751
874
|
"kind": "artifact-update",
|
|
752
|
-
"artifact": _create_response_artifact(
|
|
875
|
+
"artifact": _create_response_artifact(parts, assistant_id),
|
|
753
876
|
"append": False,
|
|
754
877
|
"lastChunk": True,
|
|
755
878
|
}
|
|
@@ -985,14 +1108,16 @@ def _convert_messages_to_a2a_format(
|
|
|
985
1108
|
|
|
986
1109
|
content = msg.get("content", "")
|
|
987
1110
|
id = msg.get("id") or str(uuid7())
|
|
988
|
-
|
|
989
|
-
if a2a_role == "ROLE_AGENT" and not
|
|
1111
|
+
parts = _content_to_a2a_parts(content)
|
|
1112
|
+
if a2a_role == "ROLE_AGENT" and not _a2a_parts_have_content(parts):
|
|
990
1113
|
continue
|
|
1114
|
+
if not parts:
|
|
1115
|
+
parts = [{"kind": "text", "text": ""}]
|
|
991
1116
|
|
|
992
1117
|
a2a_message = {
|
|
993
1118
|
"kind": "message",
|
|
994
1119
|
"role": a2a_role,
|
|
995
|
-
"parts":
|
|
1120
|
+
"parts": parts,
|
|
996
1121
|
"messageId": id,
|
|
997
1122
|
"taskId": task_id,
|
|
998
1123
|
"contextId": context_id,
|
|
@@ -1556,6 +1681,13 @@ async def handle_message_send(
|
|
|
1556
1681
|
history_length=history_length,
|
|
1557
1682
|
)
|
|
1558
1683
|
|
|
1684
|
+
except InvalidAgentResponseError as e:
|
|
1685
|
+
return {
|
|
1686
|
+
"error": {
|
|
1687
|
+
"code": ERROR_CODE_INVALID_AGENT_RESPONSE,
|
|
1688
|
+
"message": str(e),
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1559
1691
|
except Exception:
|
|
1560
1692
|
logger.exception(f"Error in message/send for assistant {assistant_id}")
|
|
1561
1693
|
return {
|
|
@@ -1704,6 +1836,13 @@ async def handle_tasks_get(
|
|
|
1704
1836
|
context_id,
|
|
1705
1837
|
history_length=history_length,
|
|
1706
1838
|
)
|
|
1839
|
+
except InvalidAgentResponseError as e:
|
|
1840
|
+
return {
|
|
1841
|
+
"error": {
|
|
1842
|
+
"code": ERROR_CODE_INVALID_AGENT_RESPONSE,
|
|
1843
|
+
"message": str(e),
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1707
1846
|
except Exception as e:
|
|
1708
1847
|
await logger.aexception(
|
|
1709
1848
|
f"Failed to get thread state for tasks/get: {e}"
|
|
@@ -2106,6 +2245,13 @@ async def handle_list_tasks(
|
|
|
2106
2245
|
}
|
|
2107
2246
|
}
|
|
2108
2247
|
|
|
2248
|
+
except InvalidAgentResponseError as e:
|
|
2249
|
+
return {
|
|
2250
|
+
"error": {
|
|
2251
|
+
"code": ERROR_CODE_INVALID_AGENT_RESPONSE,
|
|
2252
|
+
"message": str(e),
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2109
2255
|
except Exception:
|
|
2110
2256
|
logger.exception("Error in ListTasks")
|
|
2111
2257
|
return {
|
|
@@ -2156,6 +2302,60 @@ async def handle_get_extended_card(
|
|
|
2156
2302
|
# ============================================================================
|
|
2157
2303
|
|
|
2158
2304
|
|
|
2305
|
+
def _validate_agent_card_modes(
|
|
2306
|
+
value: Any,
|
|
2307
|
+
*,
|
|
2308
|
+
field: str,
|
|
2309
|
+
default: tuple[str, ...],
|
|
2310
|
+
) -> list[str]:
|
|
2311
|
+
"""Validate one optional assistant A2A media-mode override."""
|
|
2312
|
+
|
|
2313
|
+
if value is None:
|
|
2314
|
+
return list(default)
|
|
2315
|
+
if not isinstance(value, list) or not value:
|
|
2316
|
+
raise ValueError(
|
|
2317
|
+
f"Assistant metadata.a2a.{field} must be a non-empty array of strings."
|
|
2318
|
+
)
|
|
2319
|
+
|
|
2320
|
+
modes: list[str] = []
|
|
2321
|
+
for mode in value:
|
|
2322
|
+
if not isinstance(mode, str) or not mode.strip():
|
|
2323
|
+
raise ValueError(
|
|
2324
|
+
f"Assistant metadata.a2a.{field} must be a non-empty array of strings."
|
|
2325
|
+
)
|
|
2326
|
+
modes.append(mode.strip())
|
|
2327
|
+
return modes
|
|
2328
|
+
|
|
2329
|
+
|
|
2330
|
+
def _resolve_agent_card_modes(
|
|
2331
|
+
assistant: dict[str, Any],
|
|
2332
|
+
) -> tuple[list[str], list[str]]:
|
|
2333
|
+
"""Resolve per-assistant A2A modes with backward-compatible defaults."""
|
|
2334
|
+
|
|
2335
|
+
metadata = assistant.get("metadata") or {}
|
|
2336
|
+
if not isinstance(metadata, dict):
|
|
2337
|
+
raise ValueError("Assistant metadata must be an object.")
|
|
2338
|
+
|
|
2339
|
+
a2a_metadata = metadata.get("a2a")
|
|
2340
|
+
if a2a_metadata is None:
|
|
2341
|
+
return list(_DEFAULT_A2A_INPUT_MODES), list(_DEFAULT_A2A_OUTPUT_MODES)
|
|
2342
|
+
if not isinstance(a2a_metadata, dict):
|
|
2343
|
+
raise ValueError("Assistant metadata.a2a must be an object.")
|
|
2344
|
+
|
|
2345
|
+
return (
|
|
2346
|
+
_validate_agent_card_modes(
|
|
2347
|
+
a2a_metadata.get("input_modes"),
|
|
2348
|
+
field="input_modes",
|
|
2349
|
+
default=_DEFAULT_A2A_INPUT_MODES,
|
|
2350
|
+
),
|
|
2351
|
+
_validate_agent_card_modes(
|
|
2352
|
+
a2a_metadata.get("output_modes"),
|
|
2353
|
+
field="output_modes",
|
|
2354
|
+
default=_DEFAULT_A2A_OUTPUT_MODES,
|
|
2355
|
+
),
|
|
2356
|
+
)
|
|
2357
|
+
|
|
2358
|
+
|
|
2159
2359
|
async def generate_agent_card(request: ApiRequest, assistant_id: str) -> dict[str, Any]:
|
|
2160
2360
|
"""Generate A2A Agent Card for a specific assistant.
|
|
2161
2361
|
|
|
@@ -2183,6 +2383,7 @@ async def generate_agent_card(request: ApiRequest, assistant_id: str) -> dict[st
|
|
|
2183
2383
|
assistant_description = (
|
|
2184
2384
|
assistant.get("description") or f"{assistant_name} assistant"
|
|
2185
2385
|
)
|
|
2386
|
+
input_modes, output_modes = _resolve_agent_card_modes(assistant)
|
|
2186
2387
|
|
|
2187
2388
|
# For now, each assistant has one main skill - itself
|
|
2188
2389
|
skills = [
|
|
@@ -2192,8 +2393,8 @@ async def generate_agent_card(request: ApiRequest, assistant_id: str) -> dict[st
|
|
|
2192
2393
|
"description": assistant_description,
|
|
2193
2394
|
"tags": ["assistant", "langgraph"],
|
|
2194
2395
|
"examples": [],
|
|
2195
|
-
"inputModes":
|
|
2196
|
-
"outputModes":
|
|
2396
|
+
"inputModes": input_modes,
|
|
2397
|
+
"outputModes": output_modes,
|
|
2197
2398
|
"metadata": {
|
|
2198
2399
|
"inputSchema": {
|
|
2199
2400
|
"required": required,
|
|
@@ -2242,8 +2443,8 @@ async def generate_agent_card(request: ApiRequest, assistant_id: str) -> dict[st
|
|
|
2242
2443
|
"pushNotifications": False, # Not implemented yet
|
|
2243
2444
|
"stateTransitionHistory": False,
|
|
2244
2445
|
},
|
|
2245
|
-
"defaultInputModes":
|
|
2246
|
-
"defaultOutputModes":
|
|
2446
|
+
"defaultInputModes": input_modes,
|
|
2447
|
+
"defaultOutputModes": output_modes,
|
|
2247
2448
|
"skills": skills,
|
|
2248
2449
|
"version": __version__,
|
|
2249
2450
|
}
|
|
@@ -2558,19 +2759,32 @@ async def handle_message_stream(
|
|
|
2558
2759
|
is_interrupt = (
|
|
2559
2760
|
isinstance(result, dict) and "__interrupt__" in result
|
|
2560
2761
|
)
|
|
2561
|
-
# Extract the final response
|
|
2762
|
+
# Extract the final response parts (shared by both
|
|
2562
2763
|
# the completed and interrupt paths).
|
|
2563
|
-
|
|
2764
|
+
final_parts: list[dict[str, Any]] | None = None
|
|
2564
2765
|
if isinstance(result, dict):
|
|
2565
2766
|
try:
|
|
2566
|
-
|
|
2767
|
+
final_parts = _extract_a2a_response(result)
|
|
2768
|
+
except InvalidAgentResponseError as e:
|
|
2769
|
+
yield (
|
|
2770
|
+
b"message",
|
|
2771
|
+
{
|
|
2772
|
+
"jsonrpc": "2.0",
|
|
2773
|
+
"id": rpc_id,
|
|
2774
|
+
"error": {
|
|
2775
|
+
"code": ERROR_CODE_INVALID_AGENT_RESPONSE,
|
|
2776
|
+
"message": str(e),
|
|
2777
|
+
},
|
|
2778
|
+
},
|
|
2779
|
+
)
|
|
2780
|
+
return
|
|
2567
2781
|
except Exception:
|
|
2568
2782
|
await logger.aexception(
|
|
2569
2783
|
"Failed to extract final message from result",
|
|
2570
2784
|
result=result,
|
|
2571
2785
|
)
|
|
2572
|
-
if
|
|
2573
|
-
|
|
2786
|
+
if final_parts is None:
|
|
2787
|
+
final_parts = [{"kind": "text", "text": str(result)}]
|
|
2574
2788
|
|
|
2575
2789
|
if is_interrupt:
|
|
2576
2790
|
# Interrupt path is unchanged: emit the interrupt
|
|
@@ -2579,7 +2793,7 @@ async def handle_message_stream(
|
|
|
2579
2793
|
final_message = {
|
|
2580
2794
|
"kind": "message",
|
|
2581
2795
|
"role": "ROLE_AGENT",
|
|
2582
|
-
"parts":
|
|
2796
|
+
"parts": final_parts,
|
|
2583
2797
|
"messageId": str(uuid.uuid4()),
|
|
2584
2798
|
"taskId": task_id,
|
|
2585
2799
|
"contextId": context_id,
|
|
@@ -2634,7 +2848,7 @@ async def handle_message_stream(
|
|
|
2634
2848
|
"result": _create_response_artifact_update(
|
|
2635
2849
|
task_id=task_id,
|
|
2636
2850
|
context_id=context_id,
|
|
2637
|
-
|
|
2851
|
+
parts=final_parts,
|
|
2638
2852
|
assistant_id=assistant_id,
|
|
2639
2853
|
),
|
|
2640
2854
|
},
|
|
@@ -2756,13 +2970,26 @@ async def handle_message_stream(
|
|
|
2756
2970
|
# its plain terminal status-update.
|
|
2757
2971
|
if fallback_state == "TASK_STATE_COMPLETED" and isinstance(result, dict):
|
|
2758
2972
|
try:
|
|
2759
|
-
|
|
2973
|
+
fallback_parts = _extract_a2a_response(result)
|
|
2974
|
+
except InvalidAgentResponseError as e:
|
|
2975
|
+
yield (
|
|
2976
|
+
b"message",
|
|
2977
|
+
{
|
|
2978
|
+
"jsonrpc": "2.0",
|
|
2979
|
+
"id": rpc_id,
|
|
2980
|
+
"error": {
|
|
2981
|
+
"code": ERROR_CODE_INVALID_AGENT_RESPONSE,
|
|
2982
|
+
"message": str(e),
|
|
2983
|
+
},
|
|
2984
|
+
},
|
|
2985
|
+
)
|
|
2986
|
+
return
|
|
2760
2987
|
except Exception:
|
|
2761
2988
|
await logger.aexception(
|
|
2762
2989
|
"Failed to extract final message from result",
|
|
2763
2990
|
result=result,
|
|
2764
2991
|
)
|
|
2765
|
-
|
|
2992
|
+
fallback_parts = [{"kind": "text", "text": str(result)}]
|
|
2766
2993
|
yield (
|
|
2767
2994
|
b"message",
|
|
2768
2995
|
{
|
|
@@ -2771,7 +2998,7 @@ async def handle_message_stream(
|
|
|
2771
2998
|
"result": _create_response_artifact_update(
|
|
2772
2999
|
task_id=task_id,
|
|
2773
3000
|
context_id=context_id,
|
|
2774
|
-
|
|
3001
|
+
parts=fallback_parts,
|
|
2775
3002
|
assistant_id=assistant_id,
|
|
2776
3003
|
),
|
|
2777
3004
|
},
|
|
@@ -27,7 +27,13 @@ from langgraph_api.feature_flags import (
|
|
|
27
27
|
IS_POSTGRES_OR_GRPC_BACKEND,
|
|
28
28
|
USE_RUNTIME_CONTEXT_API,
|
|
29
29
|
)
|
|
30
|
-
from langgraph_api.graph import
|
|
30
|
+
from langgraph_api.graph import (
|
|
31
|
+
GRAPHS,
|
|
32
|
+
assert_graph_exists,
|
|
33
|
+
get_assistant_id,
|
|
34
|
+
get_graph,
|
|
35
|
+
graph_exists,
|
|
36
|
+
)
|
|
31
37
|
from langgraph_api.js.base import BaseRemotePregel
|
|
32
38
|
from langgraph_api.route import ApiRequest, ApiResponse, ApiRoute
|
|
33
39
|
from langgraph_api.schema import ASSISTANT_ENCRYPTION_FIELDS, ASSISTANT_FIELDS
|
|
@@ -58,6 +64,14 @@ if IS_POSTGRES_OR_GRPC_BACKEND:
|
|
|
58
64
|
else:
|
|
59
65
|
from langgraph_runtime.ops import Assistants
|
|
60
66
|
|
|
67
|
+
|
|
68
|
+
def graph_scope() -> dict[str, list[str]]:
|
|
69
|
+
"""Restrict assistant reads to the graphs this server has registered."""
|
|
70
|
+
if not IS_POSTGRES_OR_GRPC_BACKEND:
|
|
71
|
+
return {}
|
|
72
|
+
return {"graph_id_allowlist": sorted(GRAPHS)}
|
|
73
|
+
|
|
74
|
+
|
|
61
75
|
EXCLUDED_CONFIG_SCHEMA = (
|
|
62
76
|
"__pregel_checkpointer",
|
|
63
77
|
"__pregel_store",
|
|
@@ -187,6 +201,8 @@ async def create_assistant(request: ApiRequest) -> ApiResponse:
|
|
|
187
201
|
except jsonschema_rs.ValidationError as e:
|
|
188
202
|
raise HTTPException(status_code=422, detail=str(e)) from e
|
|
189
203
|
|
|
204
|
+
assert_graph_exists(payload["graph_id"])
|
|
205
|
+
|
|
190
206
|
if IS_POSTGRES_OR_GRPC_BACKEND and using_custom_encryption():
|
|
191
207
|
effective_payload = payload
|
|
192
208
|
else:
|
|
@@ -227,6 +243,9 @@ async def search_assistants(
|
|
|
227
243
|
payload = await request.json(AssistantSearchRequest)
|
|
228
244
|
select = validate_select_columns(payload.get("select") or None, ASSISTANT_FIELDS)
|
|
229
245
|
offset = int(payload.get("offset") or 0)
|
|
246
|
+
graph_id = payload.get("graph_id")
|
|
247
|
+
if graph_id is not None:
|
|
248
|
+
assert_graph_exists(graph_id)
|
|
230
249
|
config = payload.get("config")
|
|
231
250
|
if config:
|
|
232
251
|
try:
|
|
@@ -236,7 +255,7 @@ async def search_assistants(
|
|
|
236
255
|
async with connect() as conn:
|
|
237
256
|
assistants_iter, next_offset = await Assistants.search(
|
|
238
257
|
conn,
|
|
239
|
-
graph_id=
|
|
258
|
+
graph_id=graph_id,
|
|
240
259
|
name=payload.get("name"),
|
|
241
260
|
metadata=payload.get("metadata"),
|
|
242
261
|
limit=int(payload.get("limit") or 10),
|
|
@@ -244,6 +263,7 @@ async def search_assistants(
|
|
|
244
263
|
sort_by=payload.get("sort_by"),
|
|
245
264
|
sort_order=payload.get("sort_order"),
|
|
246
265
|
select=select,
|
|
266
|
+
**graph_scope(),
|
|
247
267
|
)
|
|
248
268
|
assistants, response_headers = await get_pagination_headers(
|
|
249
269
|
assistants_iter, next_offset, offset
|
|
@@ -267,12 +287,16 @@ async def count_assistants(
|
|
|
267
287
|
) -> ApiResponse:
|
|
268
288
|
"""Count assistants."""
|
|
269
289
|
payload = await request.json(AssistantCountRequest)
|
|
290
|
+
graph_id = payload.get("graph_id")
|
|
291
|
+
if graph_id is not None:
|
|
292
|
+
assert_graph_exists(graph_id)
|
|
270
293
|
async with connect() as conn:
|
|
271
294
|
count = await Assistants.count(
|
|
272
295
|
conn,
|
|
273
|
-
graph_id=
|
|
296
|
+
graph_id=graph_id,
|
|
274
297
|
name=payload.get("name"),
|
|
275
298
|
metadata=payload.get("metadata"),
|
|
299
|
+
**graph_scope(),
|
|
276
300
|
)
|
|
277
301
|
return ApiResponse(count)
|
|
278
302
|
|
|
@@ -288,6 +312,12 @@ async def get_assistant(
|
|
|
288
312
|
assistant = await Assistants.get(conn, assistant_id)
|
|
289
313
|
|
|
290
314
|
assistant_data = await fetchone(assistant)
|
|
315
|
+
# Assistants outside this server's registry are hidden rather than reported,
|
|
316
|
+
# matching the filter graph_scope() applies to search and count.
|
|
317
|
+
if not graph_exists(assistant_data["graph_id"]):
|
|
318
|
+
raise HTTPException(
|
|
319
|
+
status_code=404, detail=f"assistant {assistant_id} not found"
|
|
320
|
+
)
|
|
291
321
|
if not IS_POSTGRES_OR_GRPC_BACKEND or using_aes_encryption():
|
|
292
322
|
assistant_data = await decrypt_response(
|
|
293
323
|
assistant_data,
|
|
@@ -464,6 +494,11 @@ async def patch_assistant(
|
|
|
464
494
|
except jsonschema_rs.ValidationError as e:
|
|
465
495
|
raise HTTPException(status_code=422, detail=str(e)) from e
|
|
466
496
|
|
|
497
|
+
# A patch that leaves graph_id alone needs no check.
|
|
498
|
+
graph_id = payload.get("graph_id")
|
|
499
|
+
if graph_id is not None:
|
|
500
|
+
assert_graph_exists(graph_id)
|
|
501
|
+
|
|
467
502
|
if IS_POSTGRES_OR_GRPC_BACKEND and using_custom_encryption():
|
|
468
503
|
effective_payload = payload
|
|
469
504
|
else:
|
|
@@ -479,7 +514,7 @@ async def patch_assistant(
|
|
|
479
514
|
assistant_id,
|
|
480
515
|
config=effective_payload.get("config"),
|
|
481
516
|
context=effective_payload.get("context"),
|
|
482
|
-
graph_id=
|
|
517
|
+
graph_id=graph_id,
|
|
483
518
|
metadata=effective_payload.get("metadata"),
|
|
484
519
|
name=payload.get("name"),
|
|
485
520
|
description=payload.get("description"),
|
{langgraph_api-0.14.0.dev1 → langgraph_api-0.14.0.dev2}/langgraph_api/grpc/ops/assistants.py
RENAMED
|
@@ -86,10 +86,10 @@ class Assistants(Authenticated):
|
|
|
86
86
|
sort_by: str | None = None,
|
|
87
87
|
sort_order: str | None = None,
|
|
88
88
|
select: list[AssistantSelectField] | None = None,
|
|
89
|
+
graph_id_allowlist: list[str] | None = None,
|
|
89
90
|
ctx: Any = None,
|
|
90
91
|
) -> tuple[AsyncIterator[Assistant], int | None]:
|
|
91
92
|
"""Search assistants via gRPC."""
|
|
92
|
-
# Handle auth filters
|
|
93
93
|
auth_filters = await Assistants.handle_event(
|
|
94
94
|
ctx,
|
|
95
95
|
"search",
|
|
@@ -112,6 +112,7 @@ class Assistants(Authenticated):
|
|
|
112
112
|
sort_order=_map_sort_order(sort_order),
|
|
113
113
|
select=select,
|
|
114
114
|
name=name,
|
|
115
|
+
graph_id_allowlist=graph_id_allowlist,
|
|
115
116
|
)
|
|
116
117
|
|
|
117
118
|
client = await get_shared_client()
|
|
@@ -411,6 +412,7 @@ class Assistants(Authenticated):
|
|
|
411
412
|
graph_id: str | None = None,
|
|
412
413
|
name: str | None = None,
|
|
413
414
|
metadata: MetadataInput = None,
|
|
415
|
+
graph_id_allowlist: list[str] | None = None,
|
|
414
416
|
ctx: Any = None,
|
|
415
417
|
) -> int:
|
|
416
418
|
"""Count assistants via gRPC."""
|
|
@@ -425,6 +427,7 @@ class Assistants(Authenticated):
|
|
|
425
427
|
graph_id=graph_id,
|
|
426
428
|
name=name,
|
|
427
429
|
metadata_json=json_dumpb_optional(metadata),
|
|
430
|
+
graph_id_allowlist=graph_id_allowlist,
|
|
428
431
|
)
|
|
429
432
|
|
|
430
433
|
client = await get_shared_client()
|