langgraph-api 0.17.0.dev4__tar.gz → 0.17.0rc1__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 (327) hide show
  1. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/Makefile +8 -2
  2. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/PKG-INFO +2 -2
  3. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/README.md +2 -2
  4. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/REPORTS.md +14 -9
  5. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/delta-report.js +26 -14
  6. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/delta-report.test.js +35 -24
  7. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/constraints.txt +1 -1
  8. langgraph_api-0.17.0rc1/langgraph_api/__init__.py +1 -0
  9. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/event_streaming.py +31 -11
  10. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/threads.py +13 -0
  11. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/asyncio.py +29 -2
  12. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/service.py +22 -4
  13. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/graph.py +3 -0
  14. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/ops/threads.py +6 -0
  15. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/client.mts +2 -0
  16. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/remote.py +17 -7
  17. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/metrics_otlp.py +9 -0
  18. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/queue_entrypoint.py +3 -6
  19. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/stream.py +1 -0
  20. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/worker.py +2 -0
  21. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/checkpoint.py +19 -14
  22. langgraph_api-0.17.0rc1/langgraph_grpc_common/proto/core_api_pb2.py +288 -0
  23. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/core_api_pb2.pyi +54 -5
  24. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +45 -0
  25. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +18 -0
  26. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/openapi.json +37 -1
  27. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/pyproject.toml +1 -1
  28. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/uv.lock +4 -4
  29. langgraph_api-0.17.0.dev4/langgraph_api/__init__.py +0 -1
  30. langgraph_api-0.17.0.dev4/langgraph_grpc_common/proto/core_api_pb2.py +0 -286
  31. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/.gitignore +0 -0
  32. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/LICENSE +0 -0
  33. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/README.md +0 -0
  34. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/.gitignore +0 -0
  35. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/Makefile +0 -0
  36. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/assistant.ts +0 -0
  37. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
  38. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
  39. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/benchmarks.ts +0 -0
  40. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
  41. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/classify-error.test.js +0 -0
  42. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/classify-error.ts +0 -0
  43. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/delta-turns-lib.test.js +0 -0
  44. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/delta-turns-lib.ts +0 -0
  45. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/delta_turns.ts +0 -0
  46. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
  47. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/interrupt_resume.ts +0 -0
  48. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/log-failure.ts +0 -0
  49. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/meta_workload.ts +0 -0
  50. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/store.ts +0 -0
  51. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/stream_write.ts +0 -0
  52. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/thread.ts +0 -0
  53. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
  54. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
  55. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/types.ts +0 -0
  56. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/benchmark-runners/wait_write.ts +0 -0
  57. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/capacity-ci.js +0 -0
  58. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/capacity-ci.test.js +0 -0
  59. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/clean-cli.js +0 -0
  60. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/clean.js +0 -0
  61. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/continuous/README.md +0 -0
  62. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/continuous/pyproject.toml +0 -0
  63. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/continuous/runner.py +0 -0
  64. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/continuous/uv.lock +0 -0
  65. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/daily-report.js +0 -0
  66. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/daily-report.test.js +0 -0
  67. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/graphs.js +0 -0
  68. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/history.js +0 -0
  69. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/history.test.js +0 -0
  70. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/host-v2.js +0 -0
  71. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/host-v2.test.js +0 -0
  72. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/multer.test.js +0 -0
  73. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/package.json +0 -0
  74. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/ramp.js +0 -0
  75. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/reporting/dd_reporting.py +0 -0
  76. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/runner-descriptions.js +0 -0
  77. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/server-metrics.js +0 -0
  78. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/server-metrics.test.js +0 -0
  79. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/slack.js +0 -0
  80. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/staircase.py +0 -0
  81. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/staircase_step_k6.js +0 -0
  82. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/tsconfig.json +0 -0
  83. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/update-revision.js +0 -0
  84. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/weather.js +0 -0
  85. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/benchmark/yarn.lock +0 -0
  86. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/custom_store.sql +0 -0
  87. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/forbidden.txt +0 -0
  88. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/hatch_build.py +0 -0
  89. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/healthcheck.py +0 -0
  90. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph-cloud-debugging-20260210132856.zip +0 -0
  91. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/_checkpointer/__init__.py +0 -0
  92. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/_checkpointer/_adapter.py +0 -0
  93. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/_checkpointer/protocol.py +0 -0
  94. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/_factory_utils.py +0 -0
  95. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/__init__.py +0 -0
  96. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2a.py +0 -0
  97. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2ui.py +0 -0
  98. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2ui_schemas/README.md +0 -0
  99. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2ui_schemas/client_capabilities.json +0 -0
  100. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2ui_schemas/client_data_model.json +0 -0
  101. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2ui_schemas/client_to_server.json +0 -0
  102. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/a2ui_schemas/server_to_client.json +0 -0
  103. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/assistants.py +0 -0
  104. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/mcp/__init__.py +0 -0
  105. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/mcp/_constants.py +0 -0
  106. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/mcp/_handlers.py +0 -0
  107. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/mcp/_models.py +0 -0
  108. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/mcp/_routes.py +0 -0
  109. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/mcp/_sanitizers.py +0 -0
  110. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/meta.py +0 -0
  111. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/openapi.py +0 -0
  112. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/profile.py +0 -0
  113. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/runs.py +0 -0
  114. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/store.py +0 -0
  115. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/api/ui.py +0 -0
  116. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/asgi_transport.py +0 -0
  117. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/__init__.py +0 -0
  118. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/custom.py +0 -0
  119. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/errors.py +0 -0
  120. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/langsmith/__init__.py +0 -0
  121. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/langsmith/backend.py +0 -0
  122. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/langsmith/client.py +0 -0
  123. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/middleware.py +0 -0
  124. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/noop.py +0 -0
  125. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/auth/studio_user.py +0 -0
  126. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/beacon_data_plane_jwt_auth.py +0 -0
  127. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/cache.py +0 -0
  128. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/cli.py +0 -0
  129. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/command.py +0 -0
  130. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/config/__init__.py +0 -0
  131. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/config/_parse.py +0 -0
  132. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/config/schemas.py +0 -0
  133. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/cron_scheduler.py +0 -0
  134. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/encryption/__init__.py +0 -0
  135. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/encryption/aes_json.py +0 -0
  136. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/encryption/context.py +0 -0
  137. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/encryption/custom.py +0 -0
  138. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/encryption/middleware.py +0 -0
  139. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/encryption/shared.py +0 -0
  140. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/errors.py +0 -0
  141. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/__init__.py +0 -0
  142. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/capabilities.py +0 -0
  143. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/constants.py +0 -0
  144. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/event_normalizers.py +0 -0
  145. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/namespace.py +0 -0
  146. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/session.py +0 -0
  147. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/state_normalizers.py +0 -0
  148. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/event_streaming/types.py +0 -0
  149. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/feature_flags.py +0 -0
  150. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/__init__.py +0 -0
  151. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/client.py +0 -0
  152. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
  153. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/ops/__init__.py +0 -0
  154. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/ops/assistants.py +0 -0
  155. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/ops/cache.py +0 -0
  156. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/ops/crons.py +0 -0
  157. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/ops/runs.py +0 -0
  158. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/server.py +0 -0
  159. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/servicers/__init__.py +0 -0
  160. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
  161. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/grpc/servicers/encryption.py +0 -0
  162. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/http.py +0 -0
  163. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/http_metrics.py +0 -0
  164. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/http_metrics_utils.py +0 -0
  165. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/.gitignore +0 -0
  166. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/.prettierrc +0 -0
  167. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/.yarnclean +0 -0
  168. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/__init__.py +0 -0
  169. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/base.py +0 -0
  170. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/build.mts +0 -0
  171. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/client.http.mts +0 -0
  172. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/errors.py +0 -0
  173. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/global.d.ts +0 -0
  174. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/package.json +0 -0
  175. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/schema.py +0 -0
  176. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/auth-mutations.mts +0 -0
  177. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/graph.mts +0 -0
  178. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/load.hooks.mjs +0 -0
  179. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/preload.mjs +0 -0
  180. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
  181. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/utils/files.mts +0 -0
  182. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/utils/importMap.mts +0 -0
  183. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  184. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/src/utils/serde.mts +0 -0
  185. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/sse.py +0 -0
  186. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/traceblock.mts +0 -0
  187. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/tsconfig.json +0 -0
  188. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/ui.py +0 -0
  189. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/js/yarn.lock +0 -0
  190. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/lc_security/__init__.py +0 -0
  191. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/lc_security/exceptions.py +0 -0
  192. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/lc_security/policy.py +0 -0
  193. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/lc_security/transport.py +0 -0
  194. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/logging.py +0 -0
  195. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/metadata.py +0 -0
  196. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/metrics_collector.py +0 -0
  197. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/middleware/__init__.py +0 -0
  198. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/middleware/ensure_store.py +0 -0
  199. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/middleware/http_logger.py +0 -0
  200. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/middleware/private_network.py +0 -0
  201. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/middleware/request_id.py +0 -0
  202. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/models/__init__.py +0 -0
  203. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/models/run.py +0 -0
  204. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/otel_context.py +0 -0
  205. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/patch.py +0 -0
  206. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/release_tags.py +0 -0
  207. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/route.py +0 -0
  208. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/runner/__init__.py +0 -0
  209. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/runner/__main__.py +0 -0
  210. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/schema.py +0 -0
  211. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/self_hosted_logs.py +0 -0
  212. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/self_hosted_metrics.py +0 -0
  213. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/serde.py +0 -0
  214. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/server.py +0 -0
  215. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/sse.py +0 -0
  216. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/state.py +0 -0
  217. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/store.py +0 -0
  218. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/stream_v2.py +0 -0
  219. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/timing/__init__.py +0 -0
  220. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/timing/profiler.py +0 -0
  221. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/timing/timer.py +0 -0
  222. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/traceblock.py +0 -0
  223. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/tracing_session.py +0 -0
  224. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/tunneling/cloudflare.py +0 -0
  225. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/__init__.py +0 -0
  226. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/cache.py +0 -0
  227. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/config.py +0 -0
  228. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/errors.py +0 -0
  229. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/extract.py +0 -0
  230. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/future.py +0 -0
  231. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/headers.py +0 -0
  232. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/network.py +0 -0
  233. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/retriable_client.py +0 -0
  234. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/stream_codec.py +0 -0
  235. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/utils/uuids.py +0 -0
  236. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/validation.py +0 -0
  237. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/webhook.py +0 -0
  238. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_api/worker_runtime.py +0 -0
  239. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/__init__.py +0 -0
  240. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/checkpointer.py +0 -0
  241. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/__init__.py +0 -0
  242. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/_compat.py +0 -0
  243. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/config.py +0 -0
  244. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/durability.py +0 -0
  245. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/store.py +0 -0
  246. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/struct.py +0 -0
  247. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/conversion/value.py +0 -0
  248. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/__init__.py +0 -0
  249. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
  250. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +0 -0
  251. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
  252. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
  253. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
  254. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
  255. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
  256. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
  257. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
  258. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
  259. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
  260. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
  261. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
  262. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
  263. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
  264. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
  265. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
  266. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
  267. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
  268. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
  269. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
  270. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
  271. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
  272. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
  273. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
  274. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
  275. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
  276. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
  277. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
  278. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
  279. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
  280. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
  281. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
  282. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
  283. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
  284. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
  285. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
  286. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
  287. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
  288. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
  289. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
  290. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
  291. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
  292. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
  293. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
  294. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
  295. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
  296. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
  297. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
  298. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
  299. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
  300. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
  301. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/runner_pb2.py +0 -0
  302. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/runner_pb2.pyi +0 -0
  303. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/runner_pb2_grpc.py +0 -0
  304. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/runner_pb2_grpc.pyi +0 -0
  305. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/store_pb2.py +0 -0
  306. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/store_pb2.pyi +0 -0
  307. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
  308. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
  309. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/serde.py +0 -0
  310. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_grpc_common/store.py +0 -0
  311. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_license/__init__.py +0 -0
  312. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_license/validation.py +0 -0
  313. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/__init__.py +0 -0
  314. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/checkpoint.py +0 -0
  315. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/database.py +0 -0
  316. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/encryption.py +0 -0
  317. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/lifespan.py +0 -0
  318. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/metrics.py +0 -0
  319. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/ops.py +0 -0
  320. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/queue.py +0 -0
  321. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/retry.py +0 -0
  322. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/routes.py +0 -0
  323. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/langgraph_runtime/store.py +0 -0
  324. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/logging.json +0 -0
  325. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/scripts/build_wheel.py +0 -0
  326. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/scripts/create_license.py +0 -0
  327. {langgraph_api-0.17.0.dev4 → langgraph_api-0.17.0rc1}/scripts/run_a2a_tck.py +0 -0
@@ -43,7 +43,7 @@ TEST ?= tests/ ../runtime_inmem/tests/
43
43
  # has no [tool.pytest] — dropping pythonpath (e.g. apply_prerelease_version).
44
44
  PYTEST_ROOT_ARGS := --rootdir=. -c pyproject.toml
45
45
  PYTEST_WORKERS ?= 0
46
- AUTH_TEST ?= "tests/integration_tests/test_custom_auth.py"
46
+ AUTH_TEST ?= tests/integration_tests/test_custom_auth.py tests/integration_tests/test_auth_mcp.py
47
47
  LANGGRAPH_HTTP ?= {"disable_mcp": false, "disable_a2a": false}
48
48
  LANGGRAPH_AES_KEY ?= '1234567890123456'
49
49
  BG_JOB_TIMEOUT_SECS ?= 86400
@@ -128,7 +128,13 @@ test-auth:
128
128
  test-with-server:
129
129
  @bash -euo pipefail -c '$(MAKE) $(START_TARGET) LANGGRAPH_HTTP='\''$(LANGGRAPH_HTTP)'\'' & \
130
130
  pid=$$!; \
131
- cleanup() { kill $$pid >/dev/null 2>&1 || true; }; \
131
+ cleanup() { \
132
+ if [ -r /proc/$$pid/winpid ]; then \
133
+ taskkill //F //T //PID "$$(cat /proc/$$pid/winpid)" >/dev/null 2>&1 || true; \
134
+ else \
135
+ kill $$pid >/dev/null 2>&1 || true; \
136
+ fi; \
137
+ }; \
132
138
  trap cleanup EXIT; \
133
139
  for i in $$(seq 1 $(SERVER_START_TIMEOUT_SECS)); do \
134
140
  if curl -sf "$(SERVER_HEALTH_URL)" >/dev/null; then \
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.17.0.dev4
3
+ Version: 0.17.0rc1
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
@@ -35,7 +35,7 @@ Requires-Dist: structlog<26,>=24.1.0
35
35
  Requires-Dist: tenacity>=8.0.0
36
36
  Requires-Dist: truststore>=0.1
37
37
  Requires-Dist: uuid-utils>=0.16.2
38
- Requires-Dist: uvicorn>=0.26.0
38
+ Requires-Dist: uvicorn>=0.29.0
39
39
  Requires-Dist: uvloop>=0.18.0; platform_system != 'Windows'
40
40
  Requires-Dist: watchfiles>=0.13
41
41
  Requires-Dist: websockets>=13.0
@@ -132,7 +132,7 @@ thread depth. `delta_turns` measures it: one thread per VU, one turn per iterati
132
132
  `benchmark-delta.yml` runs two cells nightly in one k6 run (`DELTA_CELLS`): every VU turns a
133
133
  plain-channel thread and a `benchmark_delta_messages` thread (a message list, snapshot every 50,
134
134
  the deepagents setting) in rotation, `ITERATIONS` fixed so both reach 1,400 turns.
135
- `delta-report.js` posts write, read and storage at the last turn and puts the by-depth tables
135
+ `delta-report.js` posts turn, write, read and data at the last turn and puts the by-depth tables
136
136
  in the thread; `REPORTS.md` explains the post. The cells below stay available for manual runs.
137
137
 
138
138
  | Cell | Env |
@@ -173,7 +173,7 @@ At every `VERIFY_EVERY` turn it also times the cold `GET /threads/{thread_id}/st
173
173
  `state_read_duration` (the read path alone; a turn is one save plus the read before it), and
174
174
  reads `GET /threads/{thread_id}/storage` and records
175
175
  `thread_storage_bytes` tagged by depth bucket and graph, so the control and delta cells can
176
- be compared on the bytes they occupy, which is what the feature exists to reduce.
176
+ be compared on the bytes they store, which is what the feature exists to reduce.
177
177
 
178
178
  ## Outputs
179
179
 
@@ -142,12 +142,17 @@ once every 50 turns, at its own offset in that interval, so the reads cover
142
142
  the whole climb between two snapshots instead of the moment right after one.
143
143
  Storage (`GET /threads/{id}/storage`) is read at turns 350, 700, 1050 and 1400.
144
144
 
145
- **The table.** Both setups at turn 1400: `write` is the median checkpoint
146
- save, timed by the worker between the graph's two steps; `read` is the median
147
- cold read, timed to the server's first byte; `MB` is the thread's storage.
148
- Lower is better for all three. `last 10` is the delta value over tonight and
149
- the nine nights before it. A metric outside its usual range over five or more
150
- nights gets a ⚠️ line above the table.
145
+ **The table.** Both setups at turn 1400: `turn` is the average successful
146
+ turn (`POST /runs/wait`), what a user waits for; `write` is the average
147
+ checkpoint save, timed by the worker between the graph's two steps. Both are
148
+ averages so that a delta thread's snapshot, written on one turn in 50, counts:
149
+ a median never sees it. `read` is the median cold read, timed to the server's
150
+ first byte. `data` is the thread's stored data in MB as
151
+ `GET /threads/{id}/storage` reports it: the stored size of the checkpoint,
152
+ metadata and blob values (`pg_column_size`), without keys, row headers or
153
+ indexes, so not disk use. Lower is better for every row. `last 10` is the
154
+ delta value over tonight and the nine nights before it. A metric outside its
155
+ usual range over five or more nights gets a ⚠️ line above the table.
151
156
 
152
157
  **Pass bar.** Request errors under 1% and success over 99%. Two correctness
153
158
  checks turn the dot yellow on any failure: at turn 2 each thread confirms
@@ -155,9 +160,9 @@ delta is on (or off, for `base`), because a too-old langgraph silently
155
160
  degrades a `DeltaChannel` to a plain one; and every cold read is compared with
156
161
  what the run returned.
157
162
 
158
- **Thread.** Write, read and MB at turns 350, 700, 1050 and 1400, with `gain`:
159
- how many times better delta is (`same` within 15%, below `1.0x` when delta is
160
- worse). Then the run's size, failures and correctness checks.
163
+ **Thread.** Turn, write, read and data at turns 350, 700, 1050 and 1400, with
164
+ `gain`: how many times better delta is (`same` within 15%, below `1.0x` when
165
+ delta is worse). Then the run's size, failures and correctness checks.
161
166
 
162
167
  ## Changing a report
163
168
 
@@ -21,8 +21,8 @@ export const CELLS = [
21
21
  { cell: 'delta_50', label: 'delta' },
22
22
  ];
23
23
 
24
- /** Nights measured another way (one cell per job, a bytes channel) do not compare with these. */
25
- export const DESIGN = 'paired-messages';
24
+ /** Nights measured another way (one cell per job, a bytes channel, a median write) do not compare with these. */
25
+ export const DESIGN = 'paired-messages-mean';
26
26
 
27
27
  /** Tonight plus the nine nights before it, as in the daily report. */
28
28
  const NIGHTS = 10;
@@ -30,13 +30,19 @@ const NIGHTS = 10;
30
30
  /** The thread's growth tables, one row per this many turns. Matches STORAGE_EVERY in the workflow. */
31
31
  export const ROW_EVERY = 350;
32
32
 
33
- /** Metric key, label, printer. All three are lower-is-better. */
33
+ /** Metric key, label, printer, unit. All are lower-is-better. */
34
34
  const METRICS = [
35
- ['saveMs', 'write', (v) => (isNumber(v) ? (v / 1000).toFixed(2) : '-')],
36
- ['readP50Ms', 'read', (v) => (isNumber(v) ? (v / 1000).toFixed(2) : '-')],
37
- ['bytes', 'MB', formatMb],
35
+ ['turnMeanMs', 'turn', formatSeconds, 's'],
36
+ ['saveMeanMs', 'write', formatSeconds, 's'],
37
+ ['readP50Ms', 'read', formatSeconds, 's'],
38
+ ['bytes', 'data', formatMb, 'MB'],
38
39
  ];
39
40
 
41
+ /** From 10 s on, one decimal: five characters would fill the column and touch the one before it. */
42
+ function formatSeconds(v) {
43
+ return isNumber(v) ? (v / 1000).toFixed(v >= 10_000 ? 1 : 2) : '-';
44
+ }
45
+
40
46
  function formatMb(v) {
41
47
  if (!isNumber(v)) return '-';
42
48
  const mb = v / 1024 / 1024;
@@ -56,6 +62,10 @@ function percentile(sorted, p) {
56
62
  return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * p) - 1))];
57
63
  }
58
64
 
65
+ function mean(values) {
66
+ return values.length > 0 ? values.reduce((sum, v) => sum + v, 0) / values.length : null;
67
+ }
68
+
59
69
  export function bucketStart(bucket) {
60
70
  const n = parseInt(String(bucket).split('-')[0], 10);
61
71
  return Number.isFinite(n) ? n : Number.MAX_SAFE_INTEGER;
@@ -91,9 +101,12 @@ export function aggregateSamples(points) {
91
101
  for (const depth of new Set([...Object.keys(turns), ...Object.keys(reads), ...Object.keys(saves), ...Object.keys(bytes)])) {
92
102
  buckets[depth] = {
93
103
  turns: (turns[depth] ?? []).length,
104
+ // Averages, so a delta thread's snapshot turn counts: one write in 50
105
+ // saves the whole value, and a median never sees it.
106
+ turnMeanMs: mean(turns[depth] ?? []),
107
+ saveMeanMs: mean(saves[depth] ?? []),
94
108
  // One cold read per thread per bucket is few samples, so the median only.
95
109
  readP50Ms: percentile((reads[depth] ?? []).sort((a, b) => a - b), 0.5),
96
- saveMs: percentile((saves[depth] ?? []).sort((a, b) => a - b), 0.5),
97
110
  bytes: bytes[depth] ?? null,
98
111
  };
99
112
  }
@@ -228,11 +241,11 @@ function failureReason(run) {
228
241
  export function cellChanges(cell, depth, history) {
229
242
  const tonight = cell.buckets?.[depth];
230
243
  const changes = [];
231
- for (const [key, label, format] of METRICS) {
244
+ for (const [key, label, format, unit] of METRICS) {
232
245
  const past = history.map((night) => night[cell.cell]?.buckets?.[depth]?.[key]).filter(isNumber);
233
246
  const flagged = flaggedChange(tonight?.[key], past, { higherIsBetter: false });
234
247
  if (!flagged) continue;
235
- changes.push({ key, better: flagged.better, text: `${cell.label} ${label} ${formatMove(format(flagged.median), format(tonight[key]), flagged.deltaPct, key === 'bytes' ? 'MB' : 's')}` });
248
+ changes.push({ key, better: flagged.better, text: `${cell.label} ${label} ${formatMove(format(flagged.median), format(tonight[key]), flagged.deltaPct, unit)}` });
236
249
  }
237
250
  return changes;
238
251
  }
@@ -241,7 +254,7 @@ export function cellChanges(cell, depth, history) {
241
254
  export function gain(base, cell) {
242
255
  if (!isNumber(base) || !isNumber(cell) || base <= 0 || cell <= 0) return '-';
243
256
  const ratio = base / cell;
244
- // About the night-to-night noise on these medians; closer reads as a tie.
257
+ // About the night-to-night noise on these numbers; closer reads as a tie.
245
258
  if (ratio > 0.85 && ratio < 1.15) return 'same';
246
259
  return ratio >= 10 ? `${Math.round(ratio)}x` : `${ratio.toFixed(1)}x`;
247
260
  }
@@ -266,9 +279,8 @@ export function growthTables(cells) {
266
279
  const depths = Object.keys(base.buckets)
267
280
  .filter((d) => bucketEnd(d) % ROW_EVERY === 0 && delta.buckets[d])
268
281
  .sort(byDepth);
269
- const titles = { saveMs: 'write s', readP50Ms: 'read s', bytes: 'MB' };
270
- return METRICS.filter(([key]) => depths.some((d) => isNumber(base.buckets[d][key]))).map(([key, , format]) => {
271
- const lines = ['```', titles[key], `${'turn'.padEnd(5)}${'base'.padStart(6)}${'delta'.padStart(6)}${'gain'.padStart(6)}`];
282
+ return METRICS.filter(([key]) => depths.some((d) => isNumber(base.buckets[d][key]))).map(([key, label, format, unit]) => {
283
+ const lines = ['```', `${label} ${unit}`, `${'turn'.padEnd(5)}${'base'.padStart(6)}${'delta'.padStart(6)}${'gain'.padStart(6)}`];
272
284
  for (const d of depths) {
273
285
  const [b, x] = [base.buckets[d][key], delta.buckets[d][key]];
274
286
  lines.push(`${depthLabel(d).padEnd(5)}${format(b).padStart(6)}${format(x).padStart(6)}${gain(b, x).padStart(6)}`);
@@ -321,7 +333,7 @@ export function buildReport(run, context = {}) {
321
333
  lines.push('*No turn was finished by every user on both cells.*');
322
334
  }
323
335
  if (depth && !anyBytes(run.cells[0])) {
324
- lines.push('_No MB row: the deployment runs an API without `GET /threads/{id}/storage` yet._');
336
+ lines.push('_No data row: the deployment runs an API without `GET /threads/{id}/storage` yet._');
325
337
  }
326
338
  if (history.length < MIN_HISTORY_NIGHTS) lines.push(`_${history.length} of ${MIN_HISTORY_NIGHTS} nights of history, no change flags yet_`);
327
339
  lines.push(footer('delta-channel', artifactUrl));
@@ -9,19 +9,21 @@ import { PHONE_WIDTH, footer, widestCodeLine } from './slack.js';
9
9
  const MB = 1024 * 1024;
10
10
  const point = (metric, depth, value, cell) => ({ metric, value, tags: { depth, ...(cell ? { cell } : {}) } });
11
11
 
12
- test('aggregates cold read, write and end-of-bucket bytes per depth', () => {
12
+ test('turn and write are averages so a snapshot write counts, read is the median, bytes the largest reading', () => {
13
13
  const buckets = aggregateSamples([
14
14
  point('turn_duration', '1-50', 100),
15
15
  point('turn_duration', '1-50', 300),
16
16
  point('checkpoint_save', '1-50', 30),
17
+ point('checkpoint_save', '1-50', 30),
18
+ point('checkpoint_save', '1-50', 600),
17
19
  point('thread_storage_bytes', '1-50', 1024),
18
20
  point('thread_storage_bytes', '1-50', 4096),
19
21
  point('state_read_duration', '1-50', 50),
20
22
  point('state_read_duration', '1-50', 70),
21
23
  point('turn_duration', '51-100', 900),
22
24
  ]);
23
- assert.deepEqual(buckets['1-50'], { turns: 2, readP50Ms: 50, saveMs: 30, bytes: 4096 });
24
- assert.deepEqual(buckets['51-100'], { turns: 1, readP50Ms: null, saveMs: null, bytes: null });
25
+ assert.deepEqual(buckets['1-50'], { turns: 2, turnMeanMs: 200, saveMeanMs: 220, readP50Ms: 50, bytes: 4096 });
26
+ assert.deepEqual(buckets['51-100'], { turns: 1, turnMeanMs: 900, saveMeanMs: null, readP50Ms: null, bytes: null });
25
27
  });
26
28
 
27
29
  test('samples from one run split by the cell the runner tagged them with', () => {
@@ -31,21 +33,21 @@ test('samples from one run split by the cell the runner tagged them with', () =>
31
33
  point('checkpoint_save', '1-50', 999),
32
34
  ]);
33
35
  assert.deepEqual(Object.keys(byCell).sort(), ['control', 'delta_50']);
34
- assert.equal(byCell.control['1-50'].saveMs, 300);
35
- assert.equal(byCell.delta_50['1-50'].saveMs, 60);
36
+ assert.equal(byCell.control['1-50'].saveMeanMs, 300);
37
+ assert.equal(byCell.delta_50['1-50'].saveMeanMs, 60);
36
38
  });
37
39
 
38
- const bucket = (saveMs, readP50Ms, bytes) => ({ turns: 1000, saveMs, readP50Ms, bytes });
40
+ const bucket = (turnMeanMs, saveMeanMs, readP50Ms, bytes) => ({ turns: 1000, turnMeanMs, saveMeanMs, readP50Ms, bytes });
39
41
 
40
42
  function run({ base = {}, delta = {}, summary, stepOutcome = 'success' } = {}) {
41
- const b = { save: 310, read: 110, bytes: 980 * MB, ...base };
42
- const d = { save: 60, read: 100, bytes: 22 * MB, ...delta };
43
- const rows = (s, r, bytes) => ({
44
- '301-350': bucket(s / 4, r * 0.6, bytes / 16),
45
- '651-700': bucket(s / 2, r * 0.7, bytes / 4),
46
- '1001-1050': bucket(s * 0.75, r * 0.9, bytes / 2),
47
- '1301-1350': bucket(s, r, null),
48
- '1351-1400': bucket(s, r, bytes),
43
+ const b = { turn: 1600, save: 310, read: 110, bytes: 980 * MB, ...base };
44
+ const d = { turn: 1400, save: 60, read: 100, bytes: 22 * MB, ...delta };
45
+ const rows = (t, s, r, bytes) => ({
46
+ '301-350': bucket(t / 4, s / 4, r * 0.6, bytes / 16),
47
+ '651-700': bucket(t / 2, s / 2, r * 0.7, bytes / 4),
48
+ '1001-1050': bucket(t * 0.75, s * 0.75, r * 0.9, bytes / 2),
49
+ '1301-1350': bucket(t, s, r, null),
50
+ '1351-1400': bucket(t, s, r, bytes),
49
51
  });
50
52
  return {
51
53
  stepOutcome,
@@ -58,8 +60,8 @@ function run({ base = {}, delta = {}, summary, stepOutcome = 'success' } = {}) {
58
60
  thresholds: { http_req_failed: { 'rate<0.01': { ok: true } } },
59
61
  },
60
62
  cells: [
61
- { cell: 'control', label: 'base', buckets: rows(b.save, b.read, b.bytes) },
62
- { cell: 'delta_50', label: 'delta', buckets: rows(d.save, d.read, d.bytes) },
63
+ { cell: 'control', label: 'base', buckets: rows(b.turn, b.save, b.read, b.bytes) },
64
+ { cell: 'delta_50', label: 'delta', buckets: rows(d.turn, d.save, d.read, d.bytes) },
63
65
  ],
64
66
  };
65
67
  }
@@ -75,19 +77,27 @@ test('a clean night is the verdict, one table at the last turn, and a footer', (
75
77
  '_at turn 1400_',
76
78
  '```',
77
79
  ' base delta last 10',
80
+ 'turn 1.60 1.40 ▄▄▄▄▄▄▄▄▄▄',
78
81
  'write 0.31 0.06 ▄▄▄▄▄▄▄▄▄▄',
79
82
  'read 0.11 0.10 ▄▄▄▄▄▄▄▄▄▄',
80
- 'MB 980 22.0 ▄▄▄▄▄▄▄▄▄▄',
83
+ 'data 980 22.0 ▄▄▄▄▄▄▄▄▄▄',
81
84
  '```',
82
85
  footer('delta-channel', 'https://github.com/x/y/actions/runs/1'),
83
86
  ]);
84
87
  assert.ok(widestCodeLine(text) <= PHONE_WIDTH, 'the table fits a phone');
85
88
  });
86
89
 
90
+ test('a turn of ten seconds or more keeps a space before it', () => {
91
+ const { text } = buildReport(run({ delta: { turn: 10500 } }), base);
92
+ assert.match(text, /^turn 1\.60 10\.5 /m);
93
+ });
94
+
87
95
  test('the thread shows each metric as the threads grow, with the gain at every row', () => {
88
96
  const { thread } = buildReport(run(), base);
89
97
  assert.match(thread[0], /^\*As the thread grows\*$/m);
98
+ assert.match(thread[0], /^turn s\nturn\s+base\s+delta\s+gain\n350\s+0\.40\s+0\.35\s+same$/m, 'a whole turn gains less than its write');
90
99
  assert.match(thread[0], /^write s\nturn\s+base\s+delta\s+gain\n350\s+0\.08\s+0\.01\s+5\.2x$/m);
100
+ assert.match(thread[0], /^data MB$/m);
91
101
  assert.match(thread[0], /^1400\s+0\.11\s+0\.10\s+same$/m, 'read within 15% is a tie');
92
102
  assert.match(thread[0], /^1400\s+980\s+22\.0\s+45x$/m);
93
103
  assert.doesNotMatch(thread[0], /^1350/m, 'rows are every 350 turns only');
@@ -120,15 +130,16 @@ test('history keeps only nights measured with this design, newest first', () =>
120
130
  write('100', { design: DESIGN, cells: { control: { tag: 'older' } } });
121
131
  write('300', { design: DESIGN, cells: { control: { tag: 'newer' } } });
122
132
  write('200', { cells: { control: { tag: 'one job per cell' } } });
133
+ write('250', { design: 'paired-messages', cells: { control: { tag: 'median write' } } });
123
134
  assert.deepEqual(loadDeltaHistory(dir).map((night) => night.control.tag), ['newer', 'older']);
124
135
  });
125
136
 
126
- test('without storage readings the MB row is left out and the post says why', () => {
137
+ test('without storage readings the data row is left out and the post says why', () => {
127
138
  const r = run();
128
139
  for (const c of r.cells) for (const b of Object.values(c.buckets)) b.bytes = null;
129
140
  const { text } = buildReport(r, base);
130
- assert.doesNotMatch(text, /^MB/m);
131
- assert.match(text, /^_No MB row: the deployment runs an API without `GET \/threads\/\{id\}\/storage` yet\._$/m);
141
+ assert.doesNotMatch(text, /^data/m);
142
+ assert.match(text, /^_No data row: the deployment runs an API without `GET \/threads\/\{id\}\/storage` yet\._$/m);
132
143
  });
133
144
 
134
145
  test('a run with no results is red and says why', () => {
@@ -156,8 +167,8 @@ test('storage missing at the compared turn shows as a dash, not as an API withou
156
167
  const r = run();
157
168
  for (const c of r.cells) c.buckets['1351-1400'].bytes = null;
158
169
  const { text } = buildReport(r, base);
159
- assert.match(text, /^MB\s+-\s+- /m);
160
- assert.doesNotMatch(text, /No MB row/);
170
+ assert.match(text, /^data\s+-\s+- /m);
171
+ assert.doesNotMatch(text, /No data row/);
161
172
  });
162
173
 
163
174
  test('gain says how many times better delta is, and a tie as same', () => {
@@ -171,7 +182,7 @@ test('gain says how many times better delta is, and a tie as same', () => {
171
182
  test('growth tables skip a metric no row measured', () => {
172
183
  const r = run();
173
184
  for (const c of r.cells) for (const b of Object.values(c.buckets)) b.bytes = null;
174
- assert.equal(growthTables(r.cells).length, 2);
185
+ assert.equal(growthTables(r.cells).length, 3);
175
186
  });
176
187
 
177
188
  test('a single downloaded artifact is read from the results directory itself', async () => {
@@ -181,5 +192,5 @@ test('a single downloaded artifact is read from the results directory itself', a
181
192
  writeFileSync(path.join(dir, 'raw_data_1.json'), `${JSON.stringify(sample)}\n`);
182
193
  const run = await collectRun(dir);
183
194
  assert.equal(run.stepOutcome, 'success');
184
- assert.equal(run.cells.find((c) => c.cell === 'delta_50').buckets['1-50'].saveMs, 30);
195
+ assert.equal(run.cells.find((c) => c.cell === 'delta_50').buckets['1-50'].saveMeanMs, 30);
185
196
  });
@@ -9,7 +9,7 @@ langsmith>=0.7.31
9
9
  orjson>=3.9.7
10
10
  httpx>=0.25.0
11
11
  tenacity>=8.0.0
12
- uvicorn>=0.26.0
12
+ uvicorn>=0.29.0
13
13
  sse-starlette>=2.1.3,<4.0.0
14
14
  uvloop>=0.18.0
15
15
  httptools>=0.5.0
@@ -0,0 +1 @@
1
+ __version__ = "0.17.0rc1"
@@ -33,7 +33,7 @@ from starlette.websockets import WebSocketDisconnect
33
33
 
34
34
  from langgraph_api.event_streaming.service import ThreadRunManager
35
35
  from langgraph_api.event_streaming.session import _is_supported_channel
36
- from langgraph_api.event_streaming.types import Subscription
36
+ from langgraph_api.event_streaming.types import ErrorResponse, Subscription
37
37
  from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
38
38
  from langgraph_api.route import ApiRoute, ApiWebSocketRoute
39
39
  from langgraph_api.serde import json_dumpb
@@ -61,6 +61,19 @@ logger = structlog.stdlib.get_logger(__name__)
61
61
  # connection, vs. the unbounded set this replaces.
62
62
  _DELIVERED_DEDUP_WINDOW = 2048
63
63
 
64
+ # Final frame on SSE and WebSocket when the thread-stream consumer stops
65
+ # without being cancelled. A thread stream has no natural end, so that always
66
+ # means the read failed. The message is fixed because the exception text can
67
+ # carry raw backend errors; the consumer has already logged it.
68
+ _THREAD_STREAM_FAILED_DATA = json_dumpb(
69
+ ErrorResponse(
70
+ type="error",
71
+ id=None,
72
+ error="unknown_error",
73
+ message="Thread event stream failed.",
74
+ )
75
+ )
76
+
64
77
 
65
78
  def _json_response(content: Any, *, status_code: int = 200) -> Response:
66
79
  """JSON response backed by the repo's orjson helper.
@@ -118,6 +131,10 @@ async def _thread_events(request: Request) -> Response:
118
131
  The filter applies for the lifetime of the connection; closing the
119
132
  connection unsubscribes. No state is persisted server-side beyond the
120
133
  connection.
134
+
135
+ If reading the thread's event stream fails, the server ends the
136
+ stream with a final ``event: error`` frame carrying a protocol error
137
+ (``"type": "error"``, ``"id": null``, ``"error": "unknown_error"``).
121
138
  """
122
139
  thread_id = request.path_params["thread_id"]
123
140
  try:
@@ -245,10 +262,9 @@ async def _thread_events(request: Request) -> Response:
245
262
  try:
246
263
  while True:
247
264
  # Race ``flush_pending`` against the thread-stream consumer
248
- # ending. If the consumer dies (transient join_event_streaming
249
- # error, or normal shutdown), we want this loop to exit
250
- # rather than wedge forever waiting for events that will
251
- # never arrive.
265
+ # ending. If the consumer stops (its read failed or its
266
+ # source ended), we want this loop to exit rather than
267
+ # wedge forever waiting for events that will never arrive.
252
268
  flush_task = asyncio.create_task(flush_pending.wait())
253
269
  done_task = asyncio.create_task(manager.wait_for_thread_stream_end())
254
270
  try:
@@ -285,6 +301,8 @@ async def _thread_events(request: Request) -> Response:
285
301
  str(sse_id).encode() if isinstance(sse_id, int) else None,
286
302
  )
287
303
  if stream_finished:
304
+ if manager.thread_stream_failed:
305
+ yield (b"error", _THREAD_STREAM_FAILED_DATA)
288
306
  break
289
307
  finally:
290
308
  await manager.close()
@@ -366,14 +384,16 @@ async def _thread_websocket(websocket: WebSocket) -> None:
366
384
  manager = _make_manager(thread_id, send_event=ws_send_event)
367
385
  manager.start_thread_stream()
368
386
 
369
- # Watchdog: when the thread-stream consumer ends (transient
370
- # ``join_event_streaming`` failure or normal shutdown), close the socket so
371
- # the client sees a clean disconnect instead of an open connection
372
- # that will never deliver another event. ``receive_text`` below
373
- # raises ``WebSocketDisconnect`` once the close lands, exiting the
374
- # loop through its existing handler.
387
+ # Watchdog: when the thread-stream consumer stops, send the error frame
388
+ # (if it wasn't cancelled) and close the socket, instead of leaving the
389
+ # client on an open connection that will never deliver another event.
390
+ # ``receive_text`` below raises ``WebSocketDisconnect`` once the close
391
+ # lands, exiting the loop through its existing handler.
375
392
  async def _stream_watchdog() -> None:
376
393
  await manager.wait_for_thread_stream_end()
394
+ if manager.thread_stream_failed:
395
+ with contextlib.suppress(Exception):
396
+ await websocket.send_text(_THREAD_STREAM_FAILED_DATA.decode())
377
397
  with contextlib.suppress(Exception):
378
398
  await websocket.close(code=1011, reason="thread stream ended")
379
399
 
@@ -96,6 +96,16 @@ async def create_thread(
96
96
  return ApiResponse(thread)
97
97
 
98
98
 
99
+ def _exclude_metadata_kwargs(payload: dict) -> dict:
100
+ """Normalize `exclude_metadata` (object or list of objects) into ops kwargs."""
101
+ exclude_metadata = payload.get("exclude_metadata")
102
+ if exclude_metadata is None:
103
+ return {}
104
+ if isinstance(exclude_metadata, dict):
105
+ exclude_metadata = [exclude_metadata]
106
+ return {"exclude_metadata": exclude_metadata}
107
+
108
+
99
109
  @retry_db
100
110
  async def search_threads(
101
111
  request: ApiRequest,
@@ -133,6 +143,7 @@ async def search_threads(
133
143
  # it would extract from ciphertext (wrong) and we'll redo it anyway.
134
144
  storage_extract = None if needs_python_extract else extract
135
145
 
146
+ exclude_kwargs = _exclude_metadata_kwargs(payload)
136
147
  async with connect() as conn:
137
148
  threads_iter, next_offset = await Threads.search(
138
149
  conn,
@@ -146,6 +157,7 @@ async def search_threads(
146
157
  sort_order=payload.get("sort_order"),
147
158
  select=storage_select,
148
159
  extract=storage_extract,
160
+ **exclude_kwargs,
149
161
  )
150
162
  threads, response_headers = await get_pagination_headers(
151
163
  threads_iter, next_offset, offset
@@ -180,6 +192,7 @@ async def count_threads(
180
192
  status=payload.get("status"),
181
193
  values=payload.get("values"),
182
194
  metadata=payload.get("metadata"),
195
+ **_exclude_metadata_kwargs(payload),
183
196
  )
184
197
  return ApiResponse(count)
185
198
 
@@ -1,11 +1,17 @@
1
1
  import asyncio
2
2
  import concurrent.futures
3
- from collections.abc import AsyncIterator, Coroutine
4
- from contextlib import AbstractAsyncContextManager, asynccontextmanager, suppress
3
+ from collections.abc import AsyncIterator, Coroutine, Generator
4
+ from contextlib import (
5
+ AbstractAsyncContextManager,
6
+ asynccontextmanager,
7
+ contextmanager,
8
+ suppress,
9
+ )
5
10
  from functools import partial
6
11
  from typing import Any, Generic, TypeVar
7
12
 
8
13
  import structlog
14
+ import uvicorn
9
15
 
10
16
  T = TypeVar("T")
11
17
 
@@ -343,3 +349,24 @@ class AsyncQueue(Generic[T], asyncio.Queue[T]):
343
349
  # the call. Wake up the next in line.
344
350
  self._wakeup_next(self._getters)
345
351
  raise
352
+
353
+
354
+ class NoSignalServer(uvicorn.Server):
355
+ """uvicorn server that leaves the process signal handlers alone.
356
+
357
+ uvicorn's own SIGTERM handler exits on the first signal, which would
358
+ short-circuit the queue's graceful shutdown. This server runs until the
359
+ task awaiting ``serve()`` is cancelled.
360
+ """
361
+
362
+ @contextmanager
363
+ def capture_signals(self) -> Generator[None, None, None]:
364
+ yield
365
+
366
+ async def serve(self, sockets: list | None = None) -> None:
367
+ try:
368
+ await super().serve(sockets)
369
+ except asyncio.CancelledError:
370
+ if self.started:
371
+ await self.shutdown(sockets)
372
+ raise
@@ -194,11 +194,13 @@ class ThreadRunManager:
194
194
  self._seq: int = 0
195
195
  self._thread_source_task: asyncio.Task[None] | None = None
196
196
  # Set by ``_consume_thread_stream`` when the background task
197
- # exits — success, cancellation, or unexpected failure all
198
- # transition this. Route handlers (SSE body_iter, WS watchdog)
199
- # await this so a transient ``join_event_streaming`` failure can no
200
- # longer leave the connection wedged with no events flowing.
197
+ # exits for any reason, including cancellation. Route handlers
198
+ # (SSE body_iter, WS watchdog) await this so a transient
199
+ # ``join_event_streaming`` failure can no longer leave the
200
+ # connection wedged with no events flowing.
201
201
  self._thread_stream_done: asyncio.Event = asyncio.Event()
202
+ # Set when the consumer stops for any reason other than cancellation.
203
+ self._thread_stream_failed: bool = False
202
204
  # WebSocket clients typically call ``subscription.subscribe``
203
205
  # before ``run.start`` — natural ordering since they want to
204
206
  # observe before firing. Buffer those subscriptions here and
@@ -224,6 +226,15 @@ class ThreadRunManager:
224
226
  def seq(self) -> int:
225
227
  return self._seq
226
228
 
229
+ @property
230
+ def thread_stream_failed(self) -> bool:
231
+ """Whether the thread-stream consumer stopped without being cancelled.
232
+
233
+ A thread stream has no natural end, so the consumer stopping on its
234
+ own, by raising or by its source finishing, means the read failed.
235
+ """
236
+ return self._thread_stream_failed
237
+
227
238
  async def attach_event_sink(self, send_event: EventSink) -> None:
228
239
  """Attach a live transport consumer and flush buffered events."""
229
240
  self._send_event = send_event
@@ -307,12 +318,19 @@ class ThreadRunManager:
307
318
  except asyncio.CancelledError:
308
319
  raise
309
320
  except Exception as exc:
321
+ self._thread_stream_failed = True
310
322
  await logger.aexception(
311
323
  "protocol thread stream failed",
312
324
  thread_id=str(self._thread_id),
313
325
  error=str(exc),
314
326
  error_type=type(exc).__name__,
315
327
  )
328
+ else:
329
+ self._thread_stream_failed = True
330
+ await logger.awarning(
331
+ "protocol thread stream ended unexpectedly",
332
+ thread_id=str(self._thread_id),
333
+ )
316
334
  finally:
317
335
  # Wake up SSE body_iter / WS watchdog so the connection can
318
336
  # be torn down. Without this, a transient ``join_event_streaming``
@@ -676,6 +676,9 @@ async def collect_graphs_from_env(
676
676
 
677
677
 
678
678
  def _handle_exception(task: asyncio.Task) -> None:
679
+ if task.cancelled():
680
+ # Intentional stop (stop_remote_graphs); let lifespan teardown finish.
681
+ return
679
682
  try:
680
683
  task.result()
681
684
  except (asyncio.CancelledError, SystemExit):
@@ -334,6 +334,7 @@ class Threads(Authenticated):
334
334
  sort_order: str | None = None,
335
335
  select: list[ThreadSelectField] | None = None,
336
336
  extract: dict[str, str] | None = None,
337
+ exclude_metadata: list[dict[str, Any]] | None = None,
337
338
  ctx: Any = None,
338
339
  ) -> tuple[AsyncIterator[Thread], int | None]:
339
340
  metadata = metadata or {}
@@ -360,6 +361,8 @@ class Threads(Authenticated):
360
361
  "sort_by": _map_threads_sort_by(sort_by),
361
362
  "sort_order": _map_sort_order(sort_order),
362
363
  }
364
+ if exclude_metadata:
365
+ request_kwargs["exclude_metadata_json"] = json_dumpb(exclude_metadata)
363
366
 
364
367
  if status:
365
368
  mapped_status = _map_thread_status(status)
@@ -402,6 +405,7 @@ class Threads(Authenticated):
402
405
  metadata: MetadataInput,
403
406
  values: MetadataInput,
404
407
  status: ThreadStatus | None,
408
+ exclude_metadata: list[dict[str, Any]] | None = None,
405
409
  ctx: Any = None,
406
410
  ) -> int:
407
411
  metadata = metadata or {}
@@ -422,6 +426,8 @@ class Threads(Authenticated):
422
426
  "metadata_json": json_dumpb_optional(metadata),
423
427
  "values_json": json_dumpb_optional(values),
424
428
  }
429
+ if exclude_metadata:
430
+ request_kwargs["exclude_metadata_json"] = json_dumpb(exclude_metadata)
425
431
  if status:
426
432
  mapped_status = _map_thread_status(status)
427
433
  if mapped_status is None:
@@ -475,11 +475,13 @@ class RemoteCheckpointer extends BaseCheckpointSaver<number | string> {
475
475
  config: RunnableConfig,
476
476
  writes: [string, unknown][],
477
477
  taskId: string,
478
+ taskPath?: string,
478
479
  ): Promise<void> {
479
480
  await sendRecv("checkpointer_put_writes", {
480
481
  config: stripConfigCallbacks(config),
481
482
  writes,
482
483
  taskId,
484
+ taskPath,
483
485
  });
484
486
  }
485
487