langgraph-api 0.8.7__tar.gz → 0.9.0.dev1__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.
Files changed (295) hide show
  1. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/Makefile +1 -1
  2. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/PKG-INFO +8 -6
  3. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/README.md +1 -1
  4. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/continuous/uv.lock +11 -11
  5. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/ramp.js +3 -1
  6. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/constraints.txt +3 -3
  7. langgraph_api-0.9.0.dev1/langgraph_api/__init__.py +1 -0
  8. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/__init__.py +21 -1
  9. langgraph_api-0.9.0.dev1/langgraph_api/api/event_streaming.py +438 -0
  10. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/runs.py +16 -0
  11. langgraph_api-0.9.0.dev1/langgraph_api/asgi_transport.py +310 -0
  12. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/custom.py +19 -1
  13. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/middleware.py +1 -1
  14. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/config/__init__.py +27 -0
  15. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/cron_scheduler.py +1 -1
  16. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/__init__.py +1 -0
  17. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/capabilities.py +144 -0
  18. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/constants.py +43 -0
  19. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/event_normalizers.py +89 -0
  20. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/namespace.py +48 -0
  21. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/service.py +958 -0
  22. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/session.py +1786 -0
  23. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/state_normalizers.py +385 -0
  24. langgraph_api-0.9.0.dev1/langgraph_api/event_streaming/types.py +168 -0
  25. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/feature_flags.py +22 -3
  26. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/graph.py +51 -0
  27. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/ops/crons.py +39 -2
  28. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/ops/threads.py +24 -1
  29. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/package.json +1 -1
  30. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/load.hooks.mjs +1 -0
  31. langgraph_api-0.9.0.dev1/langgraph_api/js/src/preload.mjs +108 -0
  32. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/yarn.lock +639 -59
  33. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/metrics_datadog.py +19 -0
  34. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/models/run.py +19 -0
  35. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/release_tags.py +88 -30
  36. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/route.py +34 -1
  37. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/schema.py +2 -0
  38. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/stream.py +79 -10
  39. langgraph_api-0.9.0.dev1/langgraph_api/stream_v2.py +224 -0
  40. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/checkpoint.py +4 -1
  41. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/__init__.py +0 -2
  42. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +28 -3
  43. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +1 -1
  44. langgraph_api-0.9.0.dev1/langgraph_grpc_common/proto/core_api_pb2.py +274 -0
  45. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/core_api_pb2.pyi +169 -9
  46. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +44 -1
  47. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +9 -0
  48. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/encryption_pb2.pyi +13 -3
  49. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +1 -1
  50. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/engine_common_pb2.pyi +119 -3
  51. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +1 -1
  52. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +1 -1
  53. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +1 -1
  54. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +1 -1
  55. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +1 -1
  56. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +1 -1
  57. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +1 -1
  58. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +1 -1
  59. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +1 -1
  60. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +1 -1
  61. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/errors_pb2.pyi +9 -3
  62. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/errors_pb2_grpc.py +1 -1
  63. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/openapi.json +362 -0
  64. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/pyproject.toml +10 -4
  65. langgraph_api-0.9.0.dev1/uv.lock +2459 -0
  66. langgraph_api-0.8.7/langgraph_api/__init__.py +0 -1
  67. langgraph_api-0.8.7/langgraph_api/asgi_transport.py +0 -173
  68. langgraph_api-0.8.7/langgraph_api/js/src/preload.mjs +0 -29
  69. langgraph_api-0.8.7/langgraph_grpc_common/proto/core_api_pb2.py +0 -272
  70. langgraph_api-0.8.7/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2.py +0 -37
  71. langgraph_api-0.8.7/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2.pyi +0 -32
  72. langgraph_api-0.8.7/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.py +0 -24
  73. langgraph_api-0.8.7/langgraph_grpc_common/proto/enum_store_operation_entry_type_pb2_grpc.pyi +0 -20
  74. langgraph_api-0.8.7/uv.lock +0 -2268
  75. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/.gitignore +0 -0
  76. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/LICENSE +0 -0
  77. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/.gitignore +0 -0
  78. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/Makefile +0 -0
  79. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/README.md +0 -0
  80. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/assistant.ts +0 -0
  81. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
  82. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
  83. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/benchmarks.ts +0 -0
  84. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
  85. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
  86. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/log-failure.ts +0 -0
  87. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/meta_workload.ts +0 -0
  88. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/stream_write.ts +0 -0
  89. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/thread.ts +0 -0
  90. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
  91. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
  92. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/types.ts +0 -0
  93. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/benchmark-runners/wait_write.ts +0 -0
  94. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/capacity_dd_report.py +0 -0
  95. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/capacity_k6.js +0 -0
  96. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/capacity_runner.mjs +0 -0
  97. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/capacity_slack_report.py +0 -0
  98. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/capacity_urls.mjs +0 -0
  99. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/clean-cli.js +0 -0
  100. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/clean.js +0 -0
  101. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/continuous/README.md +0 -0
  102. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/continuous/pyproject.toml +0 -0
  103. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/continuous/runner.py +0 -0
  104. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/graphs.js +0 -0
  105. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/mixed_workload_k6.js +0 -0
  106. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/mixed_workload_runner.mjs +0 -0
  107. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/package.json +0 -0
  108. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/reporting/dd_reporting.py +0 -0
  109. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/reporting/slack_slowest_runs.py +0 -0
  110. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/reporting/slack_summary.py +0 -0
  111. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/run_local.sh +0 -0
  112. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/staircase.py +0 -0
  113. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/staircase_step_k6.js +0 -0
  114. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/tsconfig.json +0 -0
  115. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/update-revision.js +0 -0
  116. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/benchmark/weather.js +0 -0
  117. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/custom_store.sql +0 -0
  118. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/forbidden.txt +0 -0
  119. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/hatch_build.py +0 -0
  120. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/healthcheck.py +0 -0
  121. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph-cloud-debugging-20260210132856.zip +0 -0
  122. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/_checkpointer/__init__.py +0 -0
  123. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/_checkpointer/_adapter.py +0 -0
  124. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/_checkpointer/protocol.py +0 -0
  125. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/_factory_utils.py +0 -0
  126. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/a2a.py +0 -0
  127. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/assistants.py +0 -0
  128. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/mcp/__init__.py +0 -0
  129. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/mcp/_constants.py +0 -0
  130. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/mcp/_handlers.py +0 -0
  131. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/mcp/_models.py +0 -0
  132. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/mcp/_routes.py +0 -0
  133. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/mcp/_sanitizers.py +0 -0
  134. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/meta.py +0 -0
  135. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/openapi.py +0 -0
  136. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/profile.py +0 -0
  137. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/store.py +0 -0
  138. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/threads.py +0 -0
  139. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/api/ui.py +0 -0
  140. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/asyncio.py +0 -0
  141. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/__init__.py +0 -0
  142. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/errors.py +0 -0
  143. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/langsmith/__init__.py +0 -0
  144. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/langsmith/backend.py +0 -0
  145. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/langsmith/client.py +0 -0
  146. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/noop.py +0 -0
  147. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/auth/studio_user.py +0 -0
  148. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/cache.py +0 -0
  149. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/cli.py +0 -0
  150. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/command.py +0 -0
  151. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/config/_parse.py +0 -0
  152. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/config/schemas.py +0 -0
  153. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/encryption/__init__.py +0 -0
  154. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/encryption/aes_json.py +0 -0
  155. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/encryption/context.py +0 -0
  156. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/encryption/custom.py +0 -0
  157. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/encryption/middleware.py +0 -0
  158. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/encryption/shared.py +0 -0
  159. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/errors.py +0 -0
  160. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/__init__.py +0 -0
  161. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/client.py +0 -0
  162. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
  163. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/ops/__init__.py +0 -0
  164. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/ops/assistants.py +0 -0
  165. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/ops/cache.py +0 -0
  166. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/ops/runs.py +0 -0
  167. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/server.py +0 -0
  168. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/servicers/__init__.py +0 -0
  169. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
  170. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/grpc/servicers/encryption.py +0 -0
  171. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/http.py +0 -0
  172. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/http_metrics.py +0 -0
  173. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/http_metrics_utils.py +0 -0
  174. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/.gitignore +0 -0
  175. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/.prettierrc +0 -0
  176. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/__init__.py +0 -0
  177. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/base.py +0 -0
  178. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/build.mts +0 -0
  179. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/client.http.mts +0 -0
  180. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/client.mts +0 -0
  181. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/errors.py +0 -0
  182. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/global.d.ts +0 -0
  183. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/remote.py +0 -0
  184. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/schema.py +0 -0
  185. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/graph.mts +0 -0
  186. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
  187. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/utils/files.mts +0 -0
  188. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/utils/importMap.mts +0 -0
  189. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  190. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/src/utils/serde.mts +0 -0
  191. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/sse.py +0 -0
  192. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/traceblock.mts +0 -0
  193. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/tsconfig.json +0 -0
  194. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/js/ui.py +0 -0
  195. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/lc_security/__init__.py +0 -0
  196. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/lc_security/exceptions.py +0 -0
  197. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/lc_security/policy.py +0 -0
  198. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/lc_security/transport.py +0 -0
  199. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/logging.py +0 -0
  200. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/metadata.py +0 -0
  201. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/middleware/__init__.py +0 -0
  202. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/middleware/ensure_store.py +0 -0
  203. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/middleware/http_logger.py +0 -0
  204. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/middleware/private_network.py +0 -0
  205. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/middleware/request_id.py +0 -0
  206. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/models/__init__.py +0 -0
  207. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/otel_context.py +0 -0
  208. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/patch.py +0 -0
  209. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/queue_entrypoint.py +0 -0
  210. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/self_hosted_logs.py +0 -0
  211. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/self_hosted_metrics.py +0 -0
  212. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/serde.py +0 -0
  213. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/server.py +0 -0
  214. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/sse.py +0 -0
  215. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/state.py +0 -0
  216. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/store.py +0 -0
  217. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/timing/__init__.py +0 -0
  218. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/timing/profiler.py +0 -0
  219. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/timing/timer.py +0 -0
  220. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/traceblock.py +0 -0
  221. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/tunneling/cloudflare.py +0 -0
  222. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/__init__.py +0 -0
  223. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/cache.py +0 -0
  224. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/config.py +0 -0
  225. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/errors.py +0 -0
  226. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/extract.py +0 -0
  227. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/future.py +0 -0
  228. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/headers.py +0 -0
  229. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/network.py +0 -0
  230. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/retriable_client.py +0 -0
  231. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/stream_codec.py +0 -0
  232. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/utils/uuids.py +0 -0
  233. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/validation.py +0 -0
  234. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/webhook.py +0 -0
  235. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_api/worker.py +0 -0
  236. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/__init__.py +0 -0
  237. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/checkpointer.py +0 -0
  238. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/__init__.py +0 -0
  239. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/_compat.py +0 -0
  240. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/config.py +0 -0
  241. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/durability.py +0 -0
  242. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/struct.py +0 -0
  243. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/conversion/value.py +0 -0
  244. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
  245. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
  246. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
  247. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
  248. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
  249. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
  250. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
  251. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
  252. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
  253. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
  254. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
  255. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
  256. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
  257. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
  258. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
  259. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
  260. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
  261. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
  262. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
  263. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
  264. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
  265. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
  266. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
  267. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
  268. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
  269. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
  270. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
  271. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
  272. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
  273. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
  274. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
  275. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
  276. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
  277. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
  278. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
  279. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_grpc_common/serde.py +0 -0
  280. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_license/__init__.py +0 -0
  281. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_license/validation.py +0 -0
  282. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/__init__.py +0 -0
  283. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/checkpoint.py +0 -0
  284. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/database.py +0 -0
  285. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/lifespan.py +0 -0
  286. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/metrics.py +0 -0
  287. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/ops.py +0 -0
  288. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/queue.py +0 -0
  289. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/retry.py +0 -0
  290. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/routes.py +0 -0
  291. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/langgraph_runtime/store.py +0 -0
  292. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/logging.json +0 -0
  293. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/scripts/build_wheel.py +0 -0
  294. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/scripts/create_license.py +0 -0
  295. {langgraph_api-0.8.7 → langgraph_api-0.9.0.dev1}/scripts/run_a2a_tck.py +0 -0
@@ -1,7 +1,7 @@
1
1
  .PHONY: build release lint format test test_watch start start-inmem start-inmem-license-oss start start-js-server build-go-server start-go-server stop-go-server check-version check-base-imports test-a2a-tck test-a2a-tck-mandatory start-test-a2a-tck start-test-a2a-tck-mandatory start-test-a2a-tck-watch test-mcp-conformance start-test-mcp-conformance list-mcp-scenarios
2
2
 
3
3
  # Environment variables
4
- LANGSERVE_GRAPHS_ALL = '{"agent": {"path": "./tests/graphs/agent.py:graph", "description": "agent"}, "assistant_id_runtime": "./tests/graphs/assistant_id_runtime.py:graph", "custom_lifespan": "./tests/graphs/my_router.py:graph", "single_node": "./tests/graphs/single_node.py:graph", "benchmark": "./tests/graphs/benchmark.py:graph", "config_graph": "./tests/graphs/config_graph.py:graph", "other": "./tests/graphs/other.py:make_graph", "weather": "./tests/graphs/weather.py:mk_weather_graph", "searchy": "./tests/graphs/searchy.py:graph", "agent_simple": "./tests/graphs/agent_simple.py:graph", "simple_runtime": "./tests/graphs/simple_runtime.py:graph", "agent_interrupt": "./tests/graphs/agent_interrupt.py:graph", "agent_parallel_interrupt": "./tests/graphs/agent_parallel_interrupt.py:graph", "message_type_test": "./tests/graphs/message_type_test.py:graph", "remote_subgraph_parent": "./tests/graphs/remote_subgraph_parent.py:graph", "simple_remote": "./tests/graphs/simple_remote.py:graph", "nested_subgraphs": "./tests/graphs/nested_subgraphs.py:graph", "functional_fibonacci": "./tests/graphs/functional_fibonacci.py:fibonacci", "state_graph_fibonacci": "./tests/graphs/state_graph_fibonacci.py:fibonacci", "max_concurrency_graph": "./tests/graphs/max_concurrency_graph.py:graph", "unserializable_subgraph": "./tests/graphs/unserializable_subgraph.py:graph", "agent_interrupt_text": "./tests/graphs/agent_interrupt_text.py:graph", "agent_echo_stream": "./tests/graphs/agent_echo_stream.py:graph", "runtime_graph": "./tests/graphs/runtime_graph.py:graph", "tool_call_chunk_stream": "./tests/graphs/tool_call_chunk_stream.py:graph", "ui_tool_call_stream": "./tests/graphs/ui_tool_call_stream.py:graph"}'
4
+ LANGSERVE_GRAPHS_ALL = '{"agent": {"path": "./tests/graphs/agent.py:graph", "description": "agent"}, "assistant_id_runtime": "./tests/graphs/assistant_id_runtime.py:graph", "custom_lifespan": "./tests/graphs/my_router.py:graph", "single_node": "./tests/graphs/single_node.py:graph", "benchmark": "./tests/graphs/benchmark.py:graph", "config_graph": "./tests/graphs/config_graph.py:graph", "other": "./tests/graphs/other.py:make_graph", "weather": "./tests/graphs/weather.py:mk_weather_graph", "searchy": "./tests/graphs/searchy.py:graph", "agent_simple": "./tests/graphs/agent_simple.py:graph", "simple_runtime": "./tests/graphs/simple_runtime.py:graph", "agent_interrupt": "./tests/graphs/agent_interrupt.py:graph", "agent_parallel_interrupt": "./tests/graphs/agent_parallel_interrupt.py:graph", "message_type_test": "./tests/graphs/message_type_test.py:graph", "remote_subgraph_parent": "./tests/graphs/remote_subgraph_parent.py:graph", "simple_remote": "./tests/graphs/simple_remote.py:graph", "nested_subgraphs": "./tests/graphs/nested_subgraphs.py:graph", "functional_fibonacci": "./tests/graphs/functional_fibonacci.py:fibonacci", "state_graph_fibonacci": "./tests/graphs/state_graph_fibonacci.py:fibonacci", "max_concurrency_graph": "./tests/graphs/max_concurrency_graph.py:graph", "unserializable_subgraph": "./tests/graphs/unserializable_subgraph.py:graph", "agent_interrupt_text": "./tests/graphs/agent_interrupt_text.py:graph", "agent_echo_stream": "./tests/graphs/agent_echo_stream.py:graph", "agent_tool_stream": "./tests/graphs/agent_tool_stream.py:graph", "runtime_graph": "./tests/graphs/runtime_graph.py:graph", "tool_call_chunk_stream": "./tests/graphs/tool_call_chunk_stream.py:graph", "ui_tool_call_stream": "./tests/graphs/ui_tool_call_stream.py:graph", "agent_metrics_stream": "./tests/graphs/agent_metrics_stream.py:graph", "agent_multimodal_stream": "./tests/graphs/agent_multimodal_stream.py:graph", "agent_bedtime_story": "./tests/graphs/agent_bedtime_story.py:graph", "delta_channel": "./tests/graphs/delta_channel.py:graph", "delta_channel_freq": "./tests/graphs/delta_channel_freq.py:graph", "delta_channel_files": "./tests/graphs/delta_channel_files.py:graph", "delta_channel_files_freq": "./tests/graphs/delta_channel_files_freq.py:graph", "delta_channel_legacy": "./tests/graphs/delta_channel_migration.py:graph_legacy", "delta_channel_delta": "./tests/graphs/delta_channel_migration.py:graph_delta", "delta_channel_messages_freq": "./tests/graphs/delta_channel_messages.py:graph_freq", "delta_channel_messages": "./tests/graphs/delta_channel_messages.py:graph", "delta_channel_messages_legacy": "./tests/graphs/delta_channel_messages.py:graph_legacy", "delta_channel_messages_remove": "./tests/graphs/delta_channel_messages.py:graph_remove", "delta_channel_messages_update": "./tests/graphs/delta_channel_messages.py:graph_update", "delta_channel_messages_delta": "./tests/graphs/delta_channel_messages.py:graph_delta"}'
5
5
  LANGSERVE_GRAPHS_AUTH = '{"agent": {"path": "./tests/graphs/agent.py:graph", "description": "agent"}, "assistant_id_runtime": "./tests/graphs/assistant_id_runtime.py:graph", "config_graph": "./tests/graphs/config_graph.py:graph", "other": "./tests/graphs/other.py:make_graph", "weather": "./tests/graphs/weather.py:mk_weather_graph", "searchy": "./tests/graphs/searchy.py:graph", "agent_simple": "./tests/graphs/agent_simple.py:graph", "simple_runtime": "./tests/graphs/simple_runtime.py:graph", "agent_parallel_interrupt": "./tests/graphs/agent_parallel_interrupt.py:graph", "functional_fibonacci": "./tests/graphs/functional_fibonacci.py:fibonacci", "state_graph_fibonacci": "./tests/graphs/state_graph_fibonacci.py:fibonacci", "runtime_graph": "./tests/graphs/runtime_graph.py:graph"}'
6
6
 
7
7
  # Go server management
@@ -1,19 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.8.7
3
+ Version: 0.9.0.dev1
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<47.0,>=42.0.0
10
- Requires-Dist: grpcio-health-checking<1.79.0,>=1.78.0
11
- Requires-Dist: grpcio-tools==1.78.0
12
- Requires-Dist: grpcio<1.79.0,>=1.78.0
9
+ Requires-Dist: cryptography>=42.0.0
10
+ Requires-Dist: grpcio-health-checking<1.81.0,>=1.80.0
11
+ Requires-Dist: grpcio-tools==1.80.0
12
+ Requires-Dist: grpcio<1.81.0,>=1.80.0
13
13
  Requires-Dist: httptools>=0.5.0; platform_system != 'Windows'
14
14
  Requires-Dist: httpx>=0.25.0
15
15
  Requires-Dist: jsonschema-rs<0.45,>=0.20.0
16
16
  Requires-Dist: langchain-core>=0.3.64
17
+ Requires-Dist: langchain-protocol<0.1,>=0.0.15
17
18
  Requires-Dist: langgraph-checkpoint<5,>=3.0.1
18
19
  Requires-Dist: langgraph-runtime-inmem<0.29.0,>=0.28.0
19
20
  Requires-Dist: langgraph-sdk>=0.3.5
@@ -34,6 +35,7 @@ Requires-Dist: uuid-utils>=0.12.0
34
35
  Requires-Dist: uvicorn>=0.26.0
35
36
  Requires-Dist: uvloop>=0.18.0; platform_system != 'Windows'
36
37
  Requires-Dist: watchfiles>=0.13
38
+ Requires-Dist: websockets>=13.0
37
39
  Requires-Dist: zstandard>=0.23.0
38
40
  Description-Content-Type: text/markdown
39
41
 
@@ -48,7 +50,7 @@ For production use, see the various [deployment options](https://langchain-ai.gi
48
50
  Install the `langgraph-cli` package with the `inmem` extra. Your CLI version must be no lower than `0.1.55`.
49
51
 
50
52
  ```bash
51
- pip install -U langgraph-cli[inmem]
53
+ pip install -U "langgraph-cli[inmem]"
52
54
  ```
53
55
 
54
56
  ## Quickstart
@@ -9,7 +9,7 @@ For production use, see the various [deployment options](https://langchain-ai.gi
9
9
  Install the `langgraph-cli` package with the `inmem` extra. Your CLI version must be no lower than `0.1.55`.
10
10
 
11
11
  ```bash
12
- pip install -U langgraph-cli[inmem]
12
+ pip install -U "langgraph-cli[inmem]"
13
13
  ```
14
14
 
15
15
  ## Quickstart
@@ -25,14 +25,14 @@ wheels = [
25
25
 
26
26
  [[package]]
27
27
  name = "click"
28
- version = "8.3.2"
28
+ version = "8.3.3"
29
29
  source = { registry = "https://pypi.org/simple" }
30
30
  dependencies = [
31
31
  { name = "colorama", marker = "sys_platform == 'win32'" },
32
32
  ]
33
- sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" }
33
+ sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" }
34
34
  wheels = [
35
- { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" },
35
+ { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" },
36
36
  ]
37
37
 
38
38
  [[package]]
@@ -120,25 +120,25 @@ dependencies = [
120
120
 
121
121
  [package.metadata]
122
122
  requires-dist = [
123
- { name = "click", specifier = ">=8.3.2" },
123
+ { name = "click", specifier = ">=8.3.3" },
124
124
  { name = "datadog-api-client", specifier = ">=2.0.0" },
125
125
  { name = "httpx", specifier = ">=0.27.0" },
126
- { name = "langgraph-sdk", specifier = ">=0.2.10" },
126
+ { name = "langgraph-sdk", specifier = ">=0.3.13" },
127
127
  { name = "python-dateutil", specifier = ">=2.8.0" },
128
128
  { name = "structlog", specifier = ">=24.1.0" },
129
129
  ]
130
130
 
131
131
  [[package]]
132
132
  name = "langgraph-sdk"
133
- version = "0.3.12"
133
+ version = "0.3.14"
134
134
  source = { registry = "https://pypi.org/simple" }
135
135
  dependencies = [
136
136
  { name = "httpx" },
137
137
  { name = "orjson" },
138
138
  ]
139
- sdist = { url = "https://files.pythonhosted.org/packages/fd/a1/012f0e0f5c9fd26f92bdc9d244756ad673c428230156ef668e6ec7c18cee/langgraph_sdk-0.3.12.tar.gz", hash = "sha256:c9c9ec22b3c0fcd352e2b8f32a815164f69446b8648ca22606329f4ff4c59a71", size = 194932, upload-time = "2026-03-18T22:15:54.592Z" }
139
+ sdist = { url = "https://files.pythonhosted.org/packages/02/f1/134046c20bc4a4a15d410d1d21c9e298a3e9923777b4cc867b8669bc636b/langgraph_sdk-0.3.14.tar.gz", hash = "sha256:acd1674c538e97f3cdaa610f6dd7e34bc9bad30167f0ccc482dcd563325e81f5", size = 198162, upload-time = "2026-05-05T18:40:03.524Z" }
140
140
  wheels = [
141
- { url = "https://files.pythonhosted.org/packages/17/4d/4f796e86b03878ab20d9b30aaed1ad459eda71a5c5b67f7cfe712f3548f2/langgraph_sdk-0.3.12-py3-none-any.whl", hash = "sha256:44323804965d6ec2a07127b3cf08a0428ea6deaeb172c2d478d5cd25540e3327", size = 95834, upload-time = "2026-03-18T22:15:53.545Z" },
141
+ { url = "https://files.pythonhosted.org/packages/34/96/1c9f9fbfe756ddd850a2585e7f1949d8ebb97fdaa7a5eff8f45ed1314670/langgraph_sdk-0.3.14-py3-none-any.whl", hash = "sha256:68935bf6f4924eda92617a9e5dfb4f4281197508c648cb9d62ff083907607f9d", size = 97028, upload-time = "2026-05-05T18:40:02.099Z" },
142
142
  ]
143
143
 
144
144
  [[package]]
@@ -220,9 +220,9 @@ wheels = [
220
220
 
221
221
  [[package]]
222
222
  name = "urllib3"
223
- version = "2.6.3"
223
+ version = "2.7.0"
224
224
  source = { registry = "https://pypi.org/simple" }
225
- sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
225
+ sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
226
226
  wheels = [
227
- { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
227
+ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
228
228
  ]
@@ -1,6 +1,8 @@
1
1
  import { sleep } from 'k6';
2
2
  import { Counter, Trend } from 'k6/metrics';
3
- import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
3
+ function randomIntBetween(min, max) {
4
+ return Math.floor(Math.random() * (max - min + 1) + min);
5
+ }
4
6
  import { Benchmarks } from './benchmark-runners/dist/benchmarks.js';
5
7
  import { get_profile } from './benchmark-runners/dist/benchmark_profiles.js';
6
8
 
@@ -18,9 +18,9 @@ structlog>=24.1.0
18
18
  cloudpickle>=3.0.0
19
19
  truststore>=0.1
20
20
  protobuf>=6.32.1,<7.0.0
21
- grpcio>=1.78.0,<1.79.0
22
- grpcio-tools>=1.78.0,<1.79.0
23
- grpcio-health-checking>=1.78.0,<1.79.0
21
+ grpcio>=1.80.0,<1.81.0
22
+ grpcio-tools>=1.80.0,<1.81.0
23
+ grpcio-health-checking>=1.80.0,<1.81.0
24
24
  opentelemetry-api>=0.0.1
25
25
  opentelemetry-sdk>=0.0.1
26
26
  opentelemetry-exporter-otlp-proto-http>=0.0.1
@@ -0,0 +1 @@
1
+ __version__ = "0.9.0.dev1"
@@ -15,6 +15,7 @@ from starlette.routing import BaseRoute, Route
15
15
  from langgraph_api import timing
16
16
  from langgraph_api.api.a2a import a2a_routes
17
17
  from langgraph_api.api.assistants import assistants_routes
18
+ from langgraph_api.api.event_streaming import event_streaming_routes
18
19
  from langgraph_api.api.mcp import mcp_routes
19
20
  from langgraph_api.api.meta import meta_info, meta_metrics
20
21
  from langgraph_api.api.openapi import get_openapi_spec
@@ -30,7 +31,10 @@ from langgraph_api.config import (
30
31
  LANGGRAPH_ENCRYPTION,
31
32
  MIGRATIONS_PATH,
32
33
  )
33
- from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
34
+ from langgraph_api.feature_flags import (
35
+ FF_V2_EVENT_STREAMING,
36
+ IS_POSTGRES_OR_GRPC_BACKEND,
37
+ )
34
38
  from langgraph_api.graph import js_bg_tasks
35
39
  from langgraph_api.grpc.client import get_shared_client
36
40
  from langgraph_api.js.base import is_js_path
@@ -131,6 +135,20 @@ if HTTP_CONFIG:
131
135
  protected_routes.extend(mcp_routes)
132
136
  if not HTTP_CONFIG.get("disable_a2a"):
133
137
  protected_routes.extend(a2a_routes)
138
+ # ``disable_runs`` also gates event streaming because the v2 transport
139
+ # exposes run-creating commands (``run.start`` / ``run.cancel`` /
140
+ # ``run.attach`` over the WS, plus the ``/runs/{run_id}/protocol``
141
+ # attach route). If an operator hardens a deployment with
142
+ # ``disable_runs=true``, leaving event streaming open would be a
143
+ # backdoor that lets clients create runs anyway. ``disable_event_streaming``
144
+ # is the narrow knob (turn off just v2); ``disable_runs`` is the broad
145
+ # knob (no run-related functionality at all).
146
+ if (
147
+ FF_V2_EVENT_STREAMING
148
+ and not HTTP_CONFIG.get("disable_runs")
149
+ and not HTTP_CONFIG.get("disable_event_streaming")
150
+ ):
151
+ protected_routes.extend(event_streaming_routes)
134
152
  else:
135
153
  protected_routes.extend(assistants_routes)
136
154
  protected_routes.extend(runs_routes)
@@ -141,6 +159,8 @@ else:
141
159
  protected_routes.extend(ui_routes)
142
160
  protected_routes.extend(mcp_routes)
143
161
  protected_routes.extend(a2a_routes)
162
+ if FF_V2_EVENT_STREAMING:
163
+ protected_routes.extend(event_streaming_routes)
144
164
 
145
165
 
146
166
  def _metadata_fn(app_import: str) -> dict[str, str]:
@@ -0,0 +1,438 @@
1
+ """V2 event streaming transport routes (thread-centric).
2
+
3
+ These routes implement the v2 event streaming protocol — see
4
+ :mod:`langgraph_api.event_streaming` for the session/normalizer layer that
5
+ shapes the wire events. Connections are scoped to a thread via the URL
6
+ path; there is no server-side session state across connections.
7
+
8
+ Endpoints:
9
+
10
+ * ``POST /threads/{thread_id}/stream/events`` — SSE stream with
11
+ ``EventStreamRequest`` filter body. Each connection IS the subscription;
12
+ closing the connection unsubscribes.
13
+ * ``POST /threads/{thread_id}/commands`` — JSON command request/response.
14
+ * ``WebSocket /threads/{thread_id}/stream/events`` — full-duplex commands and events.
15
+ ``subscription.subscribe`` / ``subscription.unsubscribe`` manage
16
+ subscriptions for the lifetime of the socket.
17
+ * ``WebSocket /threads/{thread_id}/runs/{run_id}/protocol`` — compatibility
18
+ route that auto-binds to an existing run on connection.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import asyncio
24
+ import contextlib
25
+ from collections import deque
26
+ from typing import TYPE_CHECKING, Any
27
+ from uuid import uuid4
28
+
29
+ import orjson
30
+ import structlog
31
+ from starlette.responses import Response
32
+ from starlette.websockets import WebSocketDisconnect
33
+
34
+ from langgraph_api.event_streaming.service import ThreadRunManager
35
+ from langgraph_api.event_streaming.session import _is_supported_channel
36
+ from langgraph_api.event_streaming.types import Subscription
37
+ from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
38
+ from langgraph_api.route import ApiRoute, ApiWebSocketRoute
39
+ from langgraph_api.serde import json_dumpb
40
+ from langgraph_api.sse import EventSourceResponse
41
+
42
+ if TYPE_CHECKING:
43
+ from starlette.requests import Request
44
+ from starlette.websockets import WebSocket
45
+
46
+ if IS_POSTGRES_OR_GRPC_BACKEND:
47
+ from langgraph_api.grpc.ops import Runs, Threads
48
+ else:
49
+ from langgraph_runtime.ops import Runs, Threads
50
+
51
+ logger = structlog.stdlib.get_logger(__name__)
52
+
53
+
54
+ # Maximum number of recently-delivered ``event_id`` values an SSE
55
+ # connection remembers for dedup. The dedup window only needs to cover
56
+ # the brief race where a single event arrives both via the thread
57
+ # source consumer and via the session's send callback (subscription
58
+ # install handoff); after that, events flow through one path
59
+ # consistently. Cap chosen with ample headroom — a pathological
60
+ # replay storm of 2k events still fits in <50 KB of strings per
61
+ # connection, vs. the unbounded set this replaces.
62
+ _DELIVERED_DEDUP_WINDOW = 2048
63
+
64
+
65
+ def _json_response(content: Any, *, status_code: int = 200) -> Response:
66
+ """JSON response backed by the repo's orjson helper.
67
+
68
+ Starlette's default ``JSONResponse`` uses stdlib ``json`` which cannot
69
+ serialize ``UUID`` / ``datetime`` / ``bytes`` — values that regularly
70
+ appear in command responses (e.g. ``run_id`` from ``create_valid_run``).
71
+ Using ``json_dumpb`` matches the serialization used on the event
72
+ stream and keeps the two surfaces consistent.
73
+ """
74
+ return Response(
75
+ json_dumpb(content),
76
+ status_code=status_code,
77
+ media_type="application/json",
78
+ )
79
+
80
+
81
+ def _make_manager(thread_id: str, send_event: Any = None) -> ThreadRunManager:
82
+ # Auth context is propagated via ``ApiRoute``'s ``with_user`` wrapper
83
+ # — ops reads it off the context var, so we don't thread it through
84
+ # the manager explicitly.
85
+ return ThreadRunManager(
86
+ thread_id=thread_id,
87
+ runs=Runs,
88
+ threads=Threads,
89
+ send_event=send_event,
90
+ )
91
+
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # POST /threads/{thread_id}/stream/events — SSE event stream
95
+ # ---------------------------------------------------------------------------
96
+
97
+
98
+ async def _thread_events(request: Request) -> Response:
99
+ """SSE stream scoped to a thread.
100
+
101
+ Body is an ``EventStreamRequest``:
102
+
103
+ {
104
+ "channels": ["values", "messages", ...],
105
+ "namespaces": [["ns1"], ["ns2", "child"]], // optional
106
+ "depth": 2, // optional
107
+ "since": 42 // optional seq
108
+ }
109
+
110
+ On reconnect, clients pass the last ``seq`` they received as
111
+ ``since`` in the body. Buffered events with ``seq > since`` are
112
+ replayed before the stream goes live. The endpoint is POST-only, so
113
+ browser-native ``EventSource`` auto-resume (``Last-Event-ID``)
114
+ doesn't apply — clients drive resume explicitly via the body.
115
+
116
+ The filter applies for the lifetime of the connection; closing the
117
+ connection unsubscribes. No state is persisted server-side beyond the
118
+ connection.
119
+ """
120
+ thread_id = request.path_params["thread_id"]
121
+ try:
122
+ body = orjson.loads(await request.body())
123
+ except Exception:
124
+ return _json_response({"detail": "Invalid JSON body"}, status_code=400)
125
+
126
+ channels = body.get("channels") if isinstance(body, dict) else None
127
+ if not isinstance(channels, list) or not channels:
128
+ return _json_response(
129
+ {"detail": "channels is required and must be a non-empty array"},
130
+ status_code=400,
131
+ )
132
+ # Reject unknown channel names up front — otherwise the SSE stream
133
+ # would stay open indefinitely with no events flowing, confusing
134
+ # clients that expected a subscription-level error. Aligns the
135
+ # HTTP endpoint with the ``subscription.subscribe`` command which
136
+ # already short-circuits with ``invalid_argument``. ``custom:<name>``
137
+ # passes through ``_is_supported_channel`` unchanged.
138
+ bad: list[str] = []
139
+ validated: list[str] = []
140
+ for c in channels:
141
+ if not isinstance(c, str):
142
+ bad.append(repr(c))
143
+ continue
144
+ if not _is_supported_channel(c):
145
+ bad.append(c)
146
+ continue
147
+ validated.append(c)
148
+ if bad:
149
+ return _json_response(
150
+ {
151
+ "detail": (
152
+ "channels contains unsupported entries: "
153
+ + ", ".join(bad[:5])
154
+ + ". Allowed: values, updates, messages, tools, custom, "
155
+ "lifecycle, input, tasks, or any `custom:<name>`."
156
+ )
157
+ },
158
+ status_code=400,
159
+ )
160
+ channels = validated
161
+
162
+ namespaces = body.get("namespaces") if isinstance(body, dict) else None
163
+ if not isinstance(namespaces, list):
164
+ namespaces = None
165
+ else:
166
+ # only accept list[list[str]]
167
+ filtered_ns: list[list[str]] = []
168
+ for ns in namespaces:
169
+ if isinstance(ns, list) and all(isinstance(seg, str) for seg in ns):
170
+ filtered_ns.append(ns)
171
+ namespaces = filtered_ns or None
172
+
173
+ depth = body.get("depth") if isinstance(body, dict) else None
174
+ # ``bool`` is a subclass of ``int``, so a JSON ``"depth": false`` would
175
+ # otherwise fall through as ``depth=0`` ("only the exact prefix
176
+ # namespace, no deeper") and silently mute every nested-subgraph
177
+ # event. Treat any non-int (including bool) as "no depth limit".
178
+ if not isinstance(depth, int) or isinstance(depth, bool) or depth < 0:
179
+ depth = None
180
+
181
+ raw_since = body.get("since") if isinstance(body, dict) else None
182
+ # Reject ``bool`` explicitly — ``isinstance(True, int)`` is ``True``
183
+ # so a JSON ``"since": true`` would otherwise pass as ``since=1``
184
+ # and silently skip the first buffered event on reconnect.
185
+ since: int | None = (
186
+ raw_since
187
+ if isinstance(raw_since, int)
188
+ and not isinstance(raw_since, bool)
189
+ and raw_since >= 0
190
+ else None
191
+ )
192
+
193
+ # Bounded LRU dedup: ``recent_eids`` is the eviction order, ``delivered``
194
+ # is the O(1) membership view. When the deque hits its cap, the oldest
195
+ # entry rolls off; we mirror that on ``delivered`` to keep them in sync.
196
+ recent_eids: deque[str] = deque(maxlen=_DELIVERED_DEDUP_WINDOW)
197
+ delivered: set[str] = set()
198
+ pending_events: list[dict[str, Any]] = []
199
+ flush_pending = asyncio.Event()
200
+
201
+ async def on_event(event: dict[str, Any]) -> None:
202
+ eid = event.get("event_id")
203
+ if eid is None or eid in delivered:
204
+ return
205
+ # Guard against events with seq <= since slipping through (e.g.
206
+ # events delivered via the session's send callback before the
207
+ # subscription is installed with replay).
208
+ if since is not None and event.get("seq", 0) <= since:
209
+ return
210
+ if len(recent_eids) == recent_eids.maxlen:
211
+ delivered.discard(recent_eids[0])
212
+ recent_eids.append(eid)
213
+ delivered.add(eid)
214
+ pending_events.append(event)
215
+ flush_pending.set()
216
+
217
+ manager = _make_manager(thread_id, send_event=on_event)
218
+
219
+ filter_sub = Subscription(
220
+ id=str(uuid4()),
221
+ channels=set(channels),
222
+ namespaces=namespaces,
223
+ depth=depth,
224
+ active=False,
225
+ )
226
+ await logger.adebug(
227
+ "Installing event streaming subscription",
228
+ thread_id=thread_id,
229
+ subscription_id=filter_sub.id,
230
+ channels=sorted(filter_sub.channels),
231
+ depth=depth,
232
+ since=since,
233
+ )
234
+
235
+ manager.install_subscription(filter_sub)
236
+ # ``since`` is enforced by ``on_event`` above as a seq filter on
237
+ # outbound events; the thread-level reader always replays from the
238
+ # beginning so namespace-scoped projections see history. See
239
+ # ``ThreadRunManager.start_thread_stream`` for the rationale.
240
+ manager.start_thread_stream()
241
+
242
+ async def body_iter():
243
+ try:
244
+ while True:
245
+ # Race ``flush_pending`` against the thread-stream consumer
246
+ # ending. If the consumer dies (transient join_event_streaming
247
+ # error, or normal shutdown), we want this loop to exit
248
+ # rather than wedge forever waiting for events that will
249
+ # never arrive.
250
+ flush_task = asyncio.create_task(flush_pending.wait())
251
+ done_task = asyncio.create_task(manager.wait_for_thread_stream_end())
252
+ try:
253
+ done, _pending = await asyncio.wait(
254
+ {flush_task, done_task},
255
+ return_when=asyncio.FIRST_COMPLETED,
256
+ )
257
+ finally:
258
+ for p in (flush_task, done_task):
259
+ if not p.done():
260
+ p.cancel()
261
+ with contextlib.suppress(asyncio.CancelledError, Exception):
262
+ await p
263
+ stream_finished = done_task in done
264
+ # Always drain whatever was buffered before exiting so a
265
+ # final batch that arrived alongside the consumer's exit
266
+ # still reaches the client.
267
+ flush_pending.clear()
268
+ events = pending_events[:]
269
+ pending_events.clear()
270
+ for event in events:
271
+ # The wire ``event_id`` (inside the JSON body) carries
272
+ # the durable upstream Redis stream entry id used by
273
+ # the client's ``seenEventIds`` for cross-session
274
+ # dedup. The SSE ``id:`` field carries the protocol
275
+ # ``seq`` (session-local monotonic int) so server
276
+ # logs and traces can correlate against the body
277
+ # ``since`` cursor a reconnecting client sends.
278
+ sse_id = event.get("seq")
279
+ method = event.get("method", "event")
280
+ yield (
281
+ method.encode() if isinstance(method, str) else b"event",
282
+ json_dumpb(event),
283
+ str(sse_id).encode() if isinstance(sse_id, int) else None,
284
+ )
285
+ if stream_finished:
286
+ break
287
+ finally:
288
+ await manager.close()
289
+
290
+ return EventSourceResponse(body_iter())
291
+
292
+
293
+ # ---------------------------------------------------------------------------
294
+ # POST /threads/{thread_id}/commands — JSON command
295
+ # ---------------------------------------------------------------------------
296
+
297
+
298
+ async def _thread_command(request: Request) -> Response:
299
+ """Handle a single protocol command scoped to a thread.
300
+
301
+ Commands are stateless in the HTTP transport: a fresh manager is
302
+ created, the command is dispatched, and results are returned. For
303
+ ``run.start`` this creates/resumes a run; subsequent event streaming
304
+ happens over a separate ``POST .../stream`` connection.
305
+ """
306
+ thread_id = request.path_params["thread_id"]
307
+ try:
308
+ payload = orjson.loads(await request.body())
309
+ except Exception:
310
+ return _json_response({"detail": "Invalid JSON body"}, status_code=400)
311
+
312
+ if (
313
+ not isinstance(payload, dict)
314
+ or not isinstance(payload.get("id"), int)
315
+ or not isinstance(payload.get("method"), str)
316
+ ):
317
+ await logger.awarning(
318
+ "Rejected malformed event streaming command",
319
+ thread_id=thread_id,
320
+ payload_id=payload.get("id") if isinstance(payload, dict) else None,
321
+ payload_method=payload.get("method") if isinstance(payload, dict) else None,
322
+ payload_type=type(payload).__name__,
323
+ )
324
+ return _json_response(
325
+ {
326
+ "type": "error",
327
+ "id": payload.get("id") if isinstance(payload, dict) else None,
328
+ "error": "invalid_argument",
329
+ "message": "Protocol commands must include an integer id and string method.",
330
+ },
331
+ status_code=400,
332
+ )
333
+
334
+ manager = _make_manager(thread_id)
335
+ try:
336
+ resp = await manager.handle_command(payload)
337
+ return _json_response(resp)
338
+ finally:
339
+ # Commands that create runs (e.g. run.start) leave the run executing in
340
+ # the background on the worker queue. Downstream clients observe it via
341
+ # the thread-level ``POST .../stream/events`` source.
342
+ await manager.close()
343
+
344
+
345
+ # ---------------------------------------------------------------------------
346
+ # WebSocket /threads/{thread_id}/stream/events
347
+ # ---------------------------------------------------------------------------
348
+
349
+
350
+ async def _thread_websocket(websocket: WebSocket) -> None:
351
+ """Full-duplex protocol connection scoped to a thread.
352
+
353
+ Supports ``run.start``, ``input.respond``, ``subscription.subscribe``,
354
+ ``subscription.unsubscribe``, ``agent.getTree``.
355
+ """
356
+ thread_id = websocket.path_params["thread_id"]
357
+ await websocket.accept()
358
+
359
+ async def ws_send_event(event: dict[str, Any]) -> None:
360
+ await websocket.send_text(orjson.dumps(event).decode("utf-8"))
361
+
362
+ manager = _make_manager(thread_id, send_event=ws_send_event)
363
+ manager.start_thread_stream()
364
+
365
+ # Watchdog: when the thread-stream consumer ends (transient
366
+ # ``join_event_streaming`` failure or normal shutdown), close the socket so
367
+ # the client sees a clean disconnect instead of an open connection
368
+ # that will never deliver another event. ``receive_text`` below
369
+ # raises ``WebSocketDisconnect`` once the close lands, exiting the
370
+ # loop through its existing handler.
371
+ async def _stream_watchdog() -> None:
372
+ await manager.wait_for_thread_stream_end()
373
+ with contextlib.suppress(Exception):
374
+ await websocket.close(code=1011, reason="thread stream ended")
375
+
376
+ watchdog = asyncio.create_task(_stream_watchdog())
377
+
378
+ try:
379
+ while True:
380
+ raw = await websocket.receive_text()
381
+ try:
382
+ payload = orjson.loads(raw)
383
+ except Exception:
384
+ await websocket.send_json(
385
+ {
386
+ "type": "error",
387
+ "id": None,
388
+ "error": "invalid_argument",
389
+ "message": "Protocol commands must be valid JSON.",
390
+ }
391
+ )
392
+ continue
393
+
394
+ if (
395
+ not isinstance(payload, dict)
396
+ or not isinstance(payload.get("id"), int)
397
+ or not isinstance(payload.get("method"), str)
398
+ ):
399
+ await websocket.send_json(
400
+ {
401
+ "type": "error",
402
+ "id": payload.get("id") if isinstance(payload, dict) else None,
403
+ "error": "invalid_argument",
404
+ "message": "Protocol commands must include an integer id and string method.",
405
+ }
406
+ )
407
+ continue
408
+
409
+ response = await manager.handle_command(payload)
410
+ await websocket.send_text(orjson.dumps(response).decode("utf-8"))
411
+ except WebSocketDisconnect:
412
+ pass
413
+ except Exception:
414
+ logger.exception("Protocol WebSocket error")
415
+ finally:
416
+ watchdog.cancel()
417
+ with contextlib.suppress(asyncio.CancelledError, Exception):
418
+ await watchdog
419
+ await manager.close()
420
+
421
+
422
+ # ---------------------------------------------------------------------------
423
+ # Route list
424
+ # ---------------------------------------------------------------------------
425
+
426
+ event_streaming_routes: list[ApiRoute | ApiWebSocketRoute] = [
427
+ ApiRoute(
428
+ "/threads/{thread_id}/stream/events",
429
+ _thread_events,
430
+ methods=["POST"],
431
+ ),
432
+ ApiRoute(
433
+ "/threads/{thread_id}/commands",
434
+ _thread_command,
435
+ methods=["POST"],
436
+ ),
437
+ ApiWebSocketRoute("/threads/{thread_id}/stream/events", _thread_websocket),
438
+ ]