langgraph-api 0.16.8__tar.gz → 0.17.0__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 (335) hide show
  1. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/LICENSE +1 -1
  2. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/Makefile +8 -2
  3. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/PKG-INFO +3 -3
  4. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/README.md +11 -20
  5. langgraph_api-0.17.0/benchmark/REPORTS.md +174 -0
  6. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/delta-turns-lib.test.js +33 -0
  7. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/delta-turns-lib.ts +41 -1
  8. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/delta_turns.ts +47 -20
  9. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/threads_search_metadata.ts +5 -4
  10. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/capacity-ci.js +88 -133
  11. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/capacity-ci.test.js +72 -34
  12. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/clean.js +0 -1
  13. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/continuous/uv.lock +7 -7
  14. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/daily-report.js +77 -99
  15. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/daily-report.test.js +111 -56
  16. langgraph_api-0.17.0/benchmark/delta-report.js +396 -0
  17. langgraph_api-0.17.0/benchmark/delta-report.test.js +196 -0
  18. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/history.js +55 -12
  19. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/history.test.js +34 -0
  20. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/multer.test.js +2 -2
  21. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/ramp.js +5 -6
  22. langgraph_api-0.17.0/benchmark/runner-descriptions.js +21 -0
  23. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/slack.js +21 -0
  24. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/update-revision.js +4 -0
  25. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/yarn.lock +3 -3
  26. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/constraints.txt +1 -1
  27. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/custom_store.sql +0 -0
  28. langgraph_api-0.17.0/langgraph_api/__init__.py +1 -0
  29. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/__init__.py +1 -1
  30. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/assistants.py +30 -75
  31. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/event_streaming.py +103 -19
  32. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/runs.py +9 -132
  33. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/store.py +17 -35
  34. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/threads.py +153 -95
  35. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/asyncio.py +29 -2
  36. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/cache.py +86 -26
  37. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/config/__init__.py +99 -5
  38. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/config/schemas.py +12 -12
  39. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/cron_scheduler.py +1 -27
  40. langgraph_api-0.17.0/langgraph_api/drain.py +164 -0
  41. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/encryption/aes_json.py +47 -6
  42. langgraph_api-0.17.0/langgraph_api/encryption/context.py +95 -0
  43. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/encryption/custom.py +14 -10
  44. langgraph_api-0.17.0/langgraph_api/encryption/middleware.py +350 -0
  45. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/encryption/shared.py +3 -30
  46. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/service.py +110 -31
  47. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/session.py +9 -6
  48. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/feature_flags.py +41 -4
  49. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/graph.py +32 -6
  50. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/ops/__init__.py +3 -4
  51. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/ops/runs.py +44 -5
  52. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/ops/threads.py +159 -72
  53. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/servicers/checkpointer.py +3 -2
  54. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/servicers/encryption.py +22 -172
  55. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/package.json +5 -5
  56. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/remote.py +2 -1
  57. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/yarn.lock +79 -80
  58. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/metrics_otlp.py +8 -0
  59. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/models/run.py +6 -28
  60. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/queue_entrypoint.py +3 -7
  61. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/schema.py +16 -110
  62. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/state.py +91 -0
  63. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/store.py +72 -1
  64. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/stream.py +50 -3
  65. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/cache.py +22 -10
  66. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/worker.py +150 -31
  67. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/worker_runtime.py +123 -3
  68. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/checkpointer.py +26 -3
  69. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/store.py +8 -6
  70. langgraph_api-0.17.0/langgraph_grpc_common/proto/checkpointer_pb2.py +99 -0
  71. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +85 -6
  72. langgraph_api-0.17.0/langgraph_grpc_common/proto/core_api_pb2.py +288 -0
  73. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/core_api_pb2.pyi +197 -7
  74. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +89 -0
  75. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +30 -0
  76. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/store_pb2.py +25 -25
  77. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/store_pb2.pyi +6 -1
  78. langgraph_api-0.17.0/langgraph_license/__init__.py +0 -0
  79. langgraph_api-0.17.0/langgraph_runtime/encryption.py +15 -0
  80. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/openapi.json +124 -4
  81. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/pyproject.toml +2 -2
  82. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/uv.lock +14 -14
  83. langgraph_api-0.16.8/benchmark/delta-report.js +0 -599
  84. langgraph_api-0.16.8/benchmark/delta-report.test.js +0 -191
  85. langgraph_api-0.16.8/benchmark/runner-descriptions.js +0 -58
  86. langgraph_api-0.16.8/langgraph_api/__init__.py +0 -1
  87. langgraph_api-0.16.8/langgraph_api/encryption/context.py +0 -35
  88. langgraph_api-0.16.8/langgraph_api/encryption/middleware.py +0 -766
  89. langgraph_api-0.16.8/langgraph_api/event_streaming/__init__.py +0 -1
  90. langgraph_api-0.16.8/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -87
  91. langgraph_api-0.16.8/langgraph_grpc_common/proto/core_api_pb2.py +0 -276
  92. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/.gitignore +0 -0
  93. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/README.md +0 -0
  94. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/.gitignore +0 -0
  95. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/Makefile +0 -0
  96. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/assistant.ts +0 -0
  97. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
  98. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
  99. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/benchmarks.ts +0 -0
  100. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
  101. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/classify-error.test.js +0 -0
  102. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/classify-error.ts +0 -0
  103. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
  104. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/interrupt_resume.ts +0 -0
  105. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/log-failure.ts +0 -0
  106. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/meta_workload.ts +0 -0
  107. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/store.ts +0 -0
  108. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/stream_write.ts +0 -0
  109. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/thread.ts +0 -0
  110. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
  111. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/types.ts +0 -0
  112. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/benchmark-runners/wait_write.ts +0 -0
  113. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/clean-cli.js +0 -0
  114. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/continuous/README.md +0 -0
  115. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/continuous/pyproject.toml +0 -0
  116. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/continuous/runner.py +0 -0
  117. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/graphs.js +0 -0
  118. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/host-v2.js +0 -0
  119. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/host-v2.test.js +0 -0
  120. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/package.json +0 -0
  121. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/reporting/dd_reporting.py +0 -0
  122. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/server-metrics.js +0 -0
  123. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/server-metrics.test.js +0 -0
  124. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/staircase.py +0 -0
  125. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/staircase_step_k6.js +0 -0
  126. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/tsconfig.json +0 -0
  127. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/benchmark/weather.js +0 -0
  128. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/forbidden.txt +0 -0
  129. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/hatch_build.py +0 -0
  130. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/healthcheck.py +0 -0
  131. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph-cloud-debugging-20260210132856.zip +0 -0
  132. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/_checkpointer/__init__.py +0 -0
  133. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/_checkpointer/_adapter.py +0 -0
  134. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/_checkpointer/protocol.py +0 -0
  135. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/_factory_utils.py +0 -0
  136. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2a.py +0 -0
  137. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2ui.py +0 -0
  138. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2ui_schemas/README.md +0 -0
  139. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2ui_schemas/client_capabilities.json +0 -0
  140. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2ui_schemas/client_data_model.json +0 -0
  141. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2ui_schemas/client_to_server.json +0 -0
  142. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/a2ui_schemas/server_to_client.json +0 -0
  143. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/mcp/__init__.py +0 -0
  144. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/mcp/_constants.py +0 -0
  145. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/mcp/_handlers.py +0 -0
  146. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/mcp/_models.py +0 -0
  147. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/mcp/_routes.py +0 -0
  148. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/mcp/_sanitizers.py +0 -0
  149. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/meta.py +0 -0
  150. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/openapi.py +0 -0
  151. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/profile.py +0 -0
  152. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/api/ui.py +0 -0
  153. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/asgi_transport.py +0 -0
  154. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/__init__.py +0 -0
  155. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/custom.py +0 -0
  156. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/errors.py +0 -0
  157. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/langsmith/__init__.py +0 -0
  158. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/langsmith/backend.py +0 -0
  159. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/langsmith/client.py +0 -0
  160. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/middleware.py +0 -0
  161. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/noop.py +0 -0
  162. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/auth/studio_user.py +0 -0
  163. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/beacon_data_plane_jwt_auth.py +0 -0
  164. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/cli.py +0 -0
  165. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/command.py +0 -0
  166. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/config/_parse.py +0 -0
  167. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/encryption/__init__.py +0 -0
  168. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/errors.py +0 -0
  169. {langgraph_api-0.16.8/langgraph_api/grpc → langgraph_api-0.17.0/langgraph_api/event_streaming}/__init__.py +0 -0
  170. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/capabilities.py +0 -0
  171. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/constants.py +0 -0
  172. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/event_normalizers.py +0 -0
  173. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/namespace.py +0 -0
  174. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/state_normalizers.py +0 -0
  175. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/event_streaming/types.py +0 -0
  176. {langgraph_api-0.16.8/langgraph_api/js → langgraph_api-0.17.0/langgraph_api/grpc}/__init__.py +0 -0
  177. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/client.py +0 -0
  178. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
  179. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/ops/assistants.py +0 -0
  180. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/ops/cache.py +0 -0
  181. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/ops/crons.py +0 -0
  182. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/server.py +0 -0
  183. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/grpc/servicers/__init__.py +0 -0
  184. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/http.py +0 -0
  185. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/http_metrics.py +0 -0
  186. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/http_metrics_utils.py +0 -0
  187. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/.gitignore +0 -0
  188. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/.prettierrc +0 -0
  189. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/.yarnclean +0 -0
  190. {langgraph_api-0.16.8/langgraph_api/middleware → langgraph_api-0.17.0/langgraph_api/js}/__init__.py +0 -0
  191. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/base.py +0 -0
  192. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/build.mts +0 -0
  193. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/client.http.mts +0 -0
  194. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/client.mts +0 -0
  195. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/errors.py +0 -0
  196. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/global.d.ts +0 -0
  197. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/schema.py +0 -0
  198. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/auth-mutations.mts +0 -0
  199. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/graph.mts +0 -0
  200. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/load.hooks.mjs +0 -0
  201. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/preload.mjs +0 -0
  202. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
  203. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/utils/files.mts +0 -0
  204. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/utils/importMap.mts +0 -0
  205. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  206. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/src/utils/serde.mts +0 -0
  207. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/sse.py +0 -0
  208. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/traceblock.mts +0 -0
  209. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/tsconfig.json +0 -0
  210. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/js/ui.py +0 -0
  211. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/lc_security/__init__.py +0 -0
  212. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/lc_security/exceptions.py +0 -0
  213. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/lc_security/policy.py +0 -0
  214. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/lc_security/transport.py +0 -0
  215. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/logging.py +0 -0
  216. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/metadata.py +0 -0
  217. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/metrics_collector.py +0 -0
  218. {langgraph_api-0.16.8/langgraph_api/models → langgraph_api-0.17.0/langgraph_api/middleware}/__init__.py +0 -0
  219. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/middleware/ensure_store.py +0 -0
  220. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/middleware/http_logger.py +0 -0
  221. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/middleware/private_network.py +0 -0
  222. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/middleware/request_id.py +0 -0
  223. {langgraph_api-0.16.8/langgraph_license → langgraph_api-0.17.0/langgraph_api/models}/__init__.py +0 -0
  224. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/otel_context.py +0 -0
  225. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/patch.py +0 -0
  226. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/release_tags.py +0 -0
  227. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/route.py +0 -0
  228. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/runner/__init__.py +0 -0
  229. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/runner/__main__.py +0 -0
  230. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/self_hosted_logs.py +0 -0
  231. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/self_hosted_metrics.py +0 -0
  232. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/serde.py +0 -0
  233. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/server.py +0 -0
  234. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/sse.py +0 -0
  235. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/stream_v2.py +0 -0
  236. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/timing/__init__.py +0 -0
  237. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/timing/profiler.py +0 -0
  238. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/timing/timer.py +0 -0
  239. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/traceblock.py +0 -0
  240. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/tracing_session.py +0 -0
  241. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/tunneling/cloudflare.py +0 -0
  242. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/__init__.py +0 -0
  243. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/config.py +0 -0
  244. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/errors.py +0 -0
  245. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/extract.py +0 -0
  246. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/future.py +0 -0
  247. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/headers.py +0 -0
  248. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/network.py +0 -0
  249. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/retriable_client.py +0 -0
  250. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/stream_codec.py +0 -0
  251. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/utils/uuids.py +0 -0
  252. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/validation.py +0 -0
  253. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_api/webhook.py +0 -0
  254. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/__init__.py +0 -0
  255. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/__init__.py +0 -0
  256. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/_compat.py +0 -0
  257. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/checkpoint.py +0 -0
  258. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/config.py +0 -0
  259. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/durability.py +0 -0
  260. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/struct.py +0 -0
  261. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/conversion/value.py +0 -0
  262. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/__init__.py +0 -0
  263. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
  264. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
  265. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
  266. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
  267. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
  268. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
  269. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
  270. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
  271. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
  272. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
  273. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
  274. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
  275. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
  276. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
  277. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
  278. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
  279. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
  280. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
  281. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
  282. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
  283. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
  284. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
  285. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
  286. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
  287. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
  288. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
  289. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
  290. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
  291. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
  292. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
  293. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
  294. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
  295. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
  296. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
  297. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
  298. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
  299. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
  300. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
  301. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
  302. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
  303. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
  304. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
  305. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
  306. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
  307. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
  308. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
  309. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
  310. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
  311. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
  312. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
  313. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/runner_pb2.py +0 -0
  314. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/runner_pb2.pyi +0 -0
  315. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/runner_pb2_grpc.py +0 -0
  316. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/runner_pb2_grpc.pyi +0 -0
  317. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
  318. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
  319. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/serde.py +0 -0
  320. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_grpc_common/store.py +0 -0
  321. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_license/validation.py +0 -0
  322. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/__init__.py +0 -0
  323. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/checkpoint.py +0 -0
  324. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/database.py +0 -0
  325. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/lifespan.py +0 -0
  326. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/metrics.py +0 -0
  327. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/ops.py +0 -0
  328. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/queue.py +0 -0
  329. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/retry.py +0 -0
  330. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/routes.py +0 -0
  331. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/langgraph_runtime/store.py +0 -0
  332. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/logging.json +0 -0
  333. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/scripts/build_wheel.py +0 -0
  334. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/scripts/create_license.py +0 -0
  335. {langgraph_api-0.16.8 → langgraph_api-0.17.0}/scripts/run_a2a_tck.py +0 -0
@@ -90,4 +90,4 @@ these terms.
90
90
 
91
91
  **use** means anything you do with the software requiring one of your licenses.
92
92
 
93
- **trademark** means trademarks, service marks, and similar rights.
93
+ **trademark** means trademarks, service marks, and similar rights.
@@ -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.16.8
3
+ Version: 0.17.0
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
@@ -17,7 +17,7 @@ Requires-Dist: jsonschema-rs<0.45,>=0.20.0
17
17
  Requires-Dist: langchain-core>=0.3.64
18
18
  Requires-Dist: langchain-protocol<0.1,>=0.0.18
19
19
  Requires-Dist: langgraph-checkpoint<5,>=3.0.1
20
- Requires-Dist: langgraph-runtime-inmem<0.37.0.dev0,>=0.36.0.dev0
20
+ Requires-Dist: langgraph-runtime-inmem<0.38.0.dev0,>=0.37.0.dev0
21
21
  Requires-Dist: langgraph-sdk>=0.4.4
22
22
  Requires-Dist: langgraph<2,>=0.4.10
23
23
  Requires-Dist: langsmith[otel]>=0.6.3
@@ -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
@@ -129,13 +129,11 @@ by replaying them. That moves cost from write to read, and the read cost grows w
129
129
  thread depth. `delta_turns` measures it: one thread per VU, one turn per iteration,
130
130
  `turn_duration` tagged by depth bucket.
131
131
 
132
- `benchmark-delta.yml` runs four cells nightly, 20 users for 25 minutes each, 1 KB appended per turn (`CHECKPOINT_SIZE`): plain channel, then
133
- delta snapshotting every 50 (`benchmark_delta_freq`, the deepagents setting), 500
134
- (`benchmark_delta_500`) and 1000 (`benchmark_delta`, the library default). `delta-report.js` posts
135
- a headline table (non-delta vs delta at 50: read, write, storage by depth) and one table per metric
136
- across the three frequencies. The messages and migration cells stay manual. Run the cells one at a time and compare `turn_duration` by depth. Both sides get slower
137
- with depth for different reasons, the control by re-writing a growing value and delta by
138
- replaying more writes, so the deliverable is which curve is worse and where they cross.
132
+ `benchmark-delta.yml` runs two cells nightly in one k6 run (`DELTA_CELLS`): every VU turns a
133
+ plain-channel thread and a `benchmark_delta_messages` thread (a message list, snapshot every 50,
134
+ the deepagents setting) in rotation, `ITERATIONS` fixed so both reach 1,400 turns.
135
+ `delta-report.js` posts turn, write, read and data at the last turn and puts the by-depth tables
136
+ in the thread; `REPORTS.md` explains the post. The cells below stay available for manual runs.
139
137
 
140
138
  | Cell | Env |
141
139
  |---|---|
@@ -143,7 +141,7 @@ replaying more writes, so the deliverable is which curve is worse and where they
143
141
  | delta, snapshot every 1000 | `GRAPH_ID=benchmark_delta` |
144
142
  | delta, snapshot every 50 | `GRAPH_ID=benchmark_delta_freq` |
145
143
  | delta, snapshot every 500 | `GRAPH_ID=benchmark_delta_500` |
146
- | delta on a message list | `GRAPH_ID=benchmark_delta_messages PAYLOAD=messages` |
144
+ | delta on a message list, snapshot every 50 | `GRAPH_ID=benchmark_delta_messages PAYLOAD=messages` |
147
145
  | migration | `GRAPH_ID=benchmark_delta MIGRATE_FROM_GRAPH_ID=benchmark MIGRATE_AFTER=200` |
148
146
 
149
147
  ```bash
@@ -175,7 +173,7 @@ At every `VERIFY_EVERY` turn it also times the cold `GET /threads/{thread_id}/st
175
173
  `state_read_duration` (the read path alone; a turn is one save plus the read before it), and
176
174
  reads `GET /threads/{thread_id}/storage` and records
177
175
  `thread_storage_bytes` tagged by depth bucket and graph, so the control and delta cells can
178
- 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.
179
177
 
180
178
  ## Outputs
181
179
 
@@ -190,9 +188,9 @@ be compared on the bytes they occupy, which is what the feature exists to reduce
190
188
 
191
189
  ## CI workflows
192
190
 
193
- - Daily ramp benchmark: `.github/workflows/benchmark.yml`
194
- - Daily capacity matrix: `.github/workflows/benchmark-capacity-matrix.yml`
195
- - Daily delta-channel cells: `.github/workflows/benchmark-delta.yml`, reported by `delta-report.js`
191
+ - Daily ramp benchmark: `.github/workflows/langgraph-api-benchmark.yml`
192
+ - Daily capacity matrix: `.github/workflows/langgraph-api-benchmark-capacity-matrix.yml`
193
+ - Daily delta-channel cells: `.github/workflows/langgraph-api-benchmark-delta.yml`, reported by `delta-report.js`
196
194
 
197
195
  The staging deployments build their graphs from
198
196
  [langgraph-server-benchmarks](https://github.com/langchain-ai/langgraph-server-benchmarks), not
@@ -209,14 +207,7 @@ Each cell also records the deployment's own view of its window (queue and API po
209
207
 
210
208
  ### Slack reports
211
209
 
212
- Every report follows one shape so the channel reads the same way each morning, on a phone as well as a desktop:
213
-
214
- - The first line is the verdict: a dot (green quiet, yellow something regressed or a bottleneck or errors, red something failed), the report name and date, `manual run` when dispatched by hand, the API version, and a clause saying what needs attention. The second line says what the benchmark is, for a reader outside the team.
215
- - Then `Failed`, `Regressed`, `Improved` and `Bottlenecks` or `Errors` lines, worst first. `Regressed` prints `none` rather than going quiet.
216
- - One table per deployment, about 40 characters wide so it fits a phone, with `▲ better` / `▼ worse` markers on cells that left their usual range.
217
- - One legend line (pass rule, arrows, dot colors), then a link to the thread, which holds the per-cell or per-run numbers and the longer *How to read*, and to the run's artifacts.
218
-
219
- Both reports compare tonight with the previous scheduled nights (`history.js`, artifacts fetched with `gh`). A figure is flagged only when it leaves that cell's own observed range, and only once five same-kind nights exist; before that the table says how many nights it has. The daily benchmark posts one digest per workflow once its last runner finishes (`daily-report.js`, fed by each runner's artifact), not one message per runner. The delta-channel report (`delta-report.js`) keeps the plain-vs-delta table in the channel and puts the snapshot-frequency sweep in the thread.
210
+ What each post means, for a reader outside the team, is in [REPORTS.md](REPORTS.md); every post links to its section. The channel message carries only the verdict, the lines that need attention and a small table per deployment (with a p95 trend on the daily ones), each fitting a phone; the numbers behind it go to the thread.
220
211
 
221
212
  Local commands:
222
213
 
@@ -0,0 +1,174 @@
1
+ # Reading the benchmark reports
2
+
3
+ The LGP Benchmark Reporter posts four benchmark reports to #test-reports-lsd.
4
+ Each post keeps to the numbers; this page explains what they mean. Every post
5
+ links to its own section below with "What is this?". The weekly image-pull post
6
+ in the same channel is separate and not covered here.
7
+
8
+ ## Reading any report
9
+
10
+ - **The dot.** 🟢 nothing to look at. 🟡 look at it: a regression, 10 or more
11
+ failed requests, a bottleneck, a correctness check or a warning line. 🔴 something failed: a
12
+ run crossed its pass bar, or never produced results.
13
+ - **The first line** is the verdict: report, date, `manual run` when someone
14
+ dispatched it by hand, the API version that was tested, and what needs
15
+ attention.
16
+ - **Failed / Errors / Regressed / Bottlenecks** lines only appear when there is
17
+ something to say, worst first.
18
+ - **Regressed / Improved.** A figure is flagged only when it leaves its own
19
+ usual range over the recent nights: the 9 before tonight for the daily and
20
+ delta reports, the last 7 for capacity, where ▲ better and ▼ worse also
21
+ mark the cell in the table. The usual range is half the spread
22
+ between the best and worst of those nights, and never less than 10%, so a
23
+ series that swings 40% night to night is not flagged for moving 15%.
24
+ Flags start once five nights of history exist; until then the post says how
25
+ many it has.
26
+ - **The thread** holds the full numbers: per-run or per-cell detail and
27
+ improvements with before and after values; the daily threads also give the
28
+ load that ran.
29
+ - **Run** opens the GitHub Actions run, with the raw k6 summaries and charts.
30
+ - `-` in a cell means there is no number: the run produced no results, nothing
31
+ succeeded, or no thread reached that depth.
32
+
33
+ ## Daily benchmark
34
+
35
+ **Question it answers:** did latency or errors change for the three core
36
+ request paths, compared with the recent nights?
37
+
38
+ **How it runs.** [k6](https://k6.io/docs/) starts virtual users (simulated
39
+ clients). Each one repeats one request path as fast as the server answers: it
40
+ sends a request, waits for the response, then sends the next (a "closed
41
+ model"). Users are added in two steps of 60 s, then held for 5 minutes. Each
42
+ path runs as its own k6 run against the benchmark staging deployment. Every
43
+ scheduled night starts from a fresh revision of that deployment; it runs the
44
+ server version staging is on, which is the API version in the first line.
45
+
46
+ | Row | Runner | What one iteration does | Users |
47
+ |---|---|---|---|
48
+ | `wait` | `wait_write` | start a run and wait for its result (`POST /runs/wait`): run execution and checkpointing | 1,000 |
49
+ | `stream` | `stream_write` | start a run and read its event stream to the end (`POST /runs/stream`) | 1,000 |
50
+ | `search` | `threads_search` | create two threads, set their metadata, then search for them by it: database and metadata search | 300 |
51
+
52
+ Tables use the one-word row names so they fit a phone; the lines above the
53
+ table use the runner names.
54
+
55
+ `threads_search` does not delete the threads it creates; the deployment's
56
+ 60-minute thread TTL removes them, so each night searches a table of about
57
+ that run's threads, not a growing history.
58
+
59
+ **The table.**
60
+
61
+ - `p95 s`: 95% of iterations finished within this many seconds tonight. When
62
+ it left its usual range, the Regressed or Improved line says so, with the
63
+ before and after.
64
+ - `last 10`: p95 over the same 10 nights the flags use, oldest on the left,
65
+ tonight on the right. Taller is slower. Each row has its own scale, so a full
66
+ bar means that runner's slowest night of the ten, not a number of seconds:
67
+ compare a row with itself, not with the row below. The bars never stretch
68
+ small noise to full height, so a real step stands out.
69
+
70
+ **Pass bar.** Request errors under 1%, p95 under 13 s, and more than 99% of
71
+ iterations succeeding. Missing any of them fails the run and turns the dot red.
72
+
73
+ **Errors line.** Failed requests by HTTP status, and how many nights in a row
74
+ that runner has had any, as `N+` when every fetched night had them, since the
75
+ streak then started before the history does. 10 or more in one night turn the dot yellow even when
76
+ the run passes.
77
+
78
+ **Thread.** Average, p95 and p95 of successful iterations only; run and
79
+ failure counts; every figure against the 9 nights before tonight, including average
80
+ latency and run count (run count follows latency under a fixed user count, so
81
+ it is shown but never flagged).
82
+
83
+ ## Scale to zero
84
+
85
+ The daily benchmark against a second deployment that scales to zero when
86
+ idle. Scheduled runs redeploy it first, so the first minute includes the cold
87
+ start; a manual run skips the redeploy unless it is asked for. 200 users per
88
+ path instead of the daily's 1,000 (300 for search), and the pass bar is p95
89
+ under 25 s to allow for the cold start. Read it like the [daily benchmark](#daily-benchmark).
90
+
91
+ ## Capacity
92
+
93
+ **Question it answers:** how much traffic can each deployment size handle
94
+ before it breaks its latency target, and what runs out first?
95
+
96
+ **How it runs.** Two staging deployments, one dedicated and one serverless,
97
+ are resized to each tier (L, M, S) in turn. For each tier and path, k6 sends a
98
+ fixed request rate regardless of how fast the server answers (an "open
99
+ model", the way real traffic arrives), and raises it every 60 s: dedicated by
100
+ 50 req/s starting at 50, serverless by 5 starting at 10.
101
+
102
+ **The table.** Each cell is the highest request rate the tier held for two
103
+ steps while staying on target: at least 99% success, p50 at most 3 s, p95 at
104
+ most 10 s. `70+` means the tier passed the last step, so its real ceiling is
105
+ higher than the test goes. `0` means no step met the target, `ERR` means the cell crashed,
106
+ `-` means it never ran. A crashed cell's error is on the `Why:` line, once per
107
+ distinct error.
108
+
109
+ **Bottlenecks.** A component (queue, api, database, redis) running at or over
110
+ 95% of its CPU request during the steps the tier passed. That is what stops
111
+ the tier going higher. Over 100% means it is bursting above its request.
112
+
113
+ **Keep in mind.** The graph is one step with no LLM call, so this measures the
114
+ server's own ceiling, not a customer workload. Every tier starts at one queue
115
+ pod and autoscales during a cell, so a capacity number is partly a pod-count
116
+ number.
117
+
118
+ **Thread.** Improvements with before and after values, then per deployment
119
+ two small tables grouped by tier: peak CPU as % of the pod's request, and pods
120
+ at the start and end of the cell. Both cover the whole cell, including steps
121
+ that failed. Last, the request rate actually served at the top step.
122
+
123
+ ## Delta channel
124
+
125
+ **Question it answers:** on a long thread, does `DeltaChannel` at the
126
+ deepagents setting (a message list, snapshot every 50 turns) save faster and
127
+ store less than a plain channel, without making reads slower?
128
+
129
+ **Background.** A plain channel saves the whole value at every checkpoint. A
130
+ `DeltaChannel` saves only what changed, plus a full snapshot every N turns,
131
+ and rebuilds the value on read by replaying the changes since the last
132
+ snapshot. That moves cost from write to read, and read cost grows with the
133
+ distance to the last snapshot.
134
+
135
+ **How it runs.** One k6 run of 20 users. Each user owns two threads, one plain
136
+ (`base`) and one delta, and takes a turn on each in rotation until both reach
137
+ 1,400 turns, so the two are always measured at the same depth seconds apart.
138
+ A turn (`POST /runs/wait`) appends one 1 KB chat message of varied text; text
139
+ repeated every turn would compress away in Postgres and make storage measure
140
+ row overhead. Each user also does a cold state read (`GET /threads/{id}/state`)
141
+ once every 50 turns, at its own offset in that interval, so the reads cover
142
+ the whole climb between two snapshots instead of the moment right after one.
143
+ Storage (`GET /threads/{id}/storage`) is read at turns 350, 700, 1050 and 1400.
144
+
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.
156
+
157
+ **Pass bar.** Request errors under 1% and success over 99%. Two correctness
158
+ checks turn the dot yellow on any failure: at turn 2 each thread confirms
159
+ delta is on (or off, for `base`), because a too-old langgraph silently
160
+ degrades a `DeltaChannel` to a plain one; and every cold read is compared with
161
+ what the run returned.
162
+
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.
166
+
167
+ ## Changing a report
168
+
169
+ The builders are `daily-report.js` (daily and scale to zero),
170
+ `capacity-ci.js --aggregate` and `delta-report.js`, all posting through
171
+ `slack.js`. The daily workflows post one digest after their last runner finishes, built from each runner's artifact. History comes from previous scheduled runs' artifacts via
172
+ `history.js`. Each has a `*.test.js` beside it (`npm test`). A dispatch of the
173
+ workflow with `post_to_slack` reproduces a post: about 30 minutes for the
174
+ daily reports, about 2 hours for delta and capacity.
@@ -1,7 +1,9 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {
4
+ parseCells,
4
5
  planTurn,
6
+ readOffset,
5
7
  deltaGuardFailure,
6
8
  digestDrift,
7
9
  stateDrift,
@@ -15,6 +17,8 @@ const BASE = {
15
17
  migrateAfter: 0,
16
18
  expectDelta: true,
17
19
  verifyEvery: 50,
20
+ readOffset: 0,
21
+ storageEvery: 0,
18
22
  bucketSize: 100,
19
23
  };
20
24
 
@@ -180,3 +184,32 @@ test('a missing digest on either side is reported, not passed', () => {
180
184
  assert.equal(digestDrift('', 'a'.repeat(64)), 'run_digest_missing');
181
185
  assert.equal(digestDrift('a'.repeat(64), null), 'cold_digest_missing');
182
186
  });
187
+
188
+ test('cold reads spread across the snapshot interval instead of all landing on it', () => {
189
+ const offsets = Array.from({ length: 20 }, (_, i) => readOffset(i + 1, 20, 50));
190
+ assert.equal(offsets[0], 0);
191
+ assert.equal(offsets.at(-1), 47);
192
+ assert.equal(new Set(offsets).size, 20, 'every VU reads at its own point');
193
+ assert.equal(planTurn(47, { ...BASE, readOffset: 3 }).verify, true);
194
+ assert.equal(planTurn(50, { ...BASE, readOffset: 3 }).verify, false);
195
+ });
196
+
197
+ test('storage is read on the cold-read turn of each bucket that ends a table row', () => {
198
+ const options = { ...BASE, bucketSize: 50, readOffset: 10, storageEvery: 350 };
199
+ assert.equal(planTurn(340, options).storage, true, 'bucket 301-350 ends on 350');
200
+ assert.equal(planTurn(290, options).storage, false, 'a cold read, but bucket 251-300 is not a row');
201
+ assert.equal(planTurn(341, options).storage, false, 'not a cold-read turn');
202
+ });
203
+
204
+ test('without a storage interval, storage is read on every cold read', () => {
205
+ assert.equal(planTurn(50, { ...BASE, storageEvery: 0 }).storage, true);
206
+ assert.equal(planTurn(51, { ...BASE, storageEvery: 0 }).storage, false);
207
+ });
208
+
209
+ test('cells parse from name:graph:expectDelta', () => {
210
+ assert.deepEqual(parseCells('control:benchmark:false, delta_50:benchmark_delta_messages:true'), [
211
+ { name: 'control', graphId: 'benchmark', expectDelta: false },
212
+ { name: 'delta_50', graphId: 'benchmark_delta_messages', expectDelta: true },
213
+ ]);
214
+ assert.deepEqual(parseCells(''), []);
215
+ });
@@ -9,9 +9,20 @@ export interface DeltaTurnsOptions {
9
9
  expectDelta: boolean;
10
10
  /** Cold re-read cadence, in turns. 0 disables. */
11
11
  verifyEvery: number;
12
+ /** Shifts this VU's cold reads off the multiples of `verifyEvery`; see readOffset. */
13
+ readOffset: number;
14
+ /** Storage is read on the cold-read turn of every bucket ending on a multiple of this. 0 reads it on every cold read. */
15
+ storageEvery: number;
12
16
  bucketSize: number;
13
17
  }
14
18
 
19
+ /** One setup the VU turns in rotation, on a thread of its own. */
20
+ export interface DeltaCell {
21
+ name: string;
22
+ graphId: string;
23
+ expectDelta: boolean;
24
+ }
25
+
15
26
  export interface TurnPlan {
16
27
  graphId: string;
17
28
  /** Cumulative on a reused thread, so turn N asks for N. */
@@ -19,6 +30,7 @@ export interface TurnPlan {
19
30
  expectDelta: boolean;
20
31
  guard: boolean;
21
32
  verify: boolean;
33
+ storage: boolean;
22
34
  depthBucket: string;
23
35
  }
24
36
 
@@ -32,16 +44,40 @@ export function unusableCheckpointSize(checkpointSize: number | undefined): bool
32
44
  export function planTurn(turn: number, options: DeltaTurnsOptions): TurnPlan {
33
45
  const migrating = options.migrateFromGraphId !== '' && options.migrateAfter > 0;
34
46
  const beforeSwitch = migrating && turn <= options.migrateAfter;
47
+ const verify = options.verifyEvery > 0 && (turn + options.readOffset) % options.verifyEvery === 0;
35
48
  return {
36
49
  graphId: beforeSwitch ? options.migrateFromGraphId : options.graphId,
37
50
  steps: turn,
38
51
  expectDelta: beforeSwitch ? false : options.expectDelta,
39
52
  guard: isGuardTurn(turn, options, migrating),
40
- verify: options.verifyEvery > 0 && turn % options.verifyEvery === 0,
53
+ verify,
54
+ storage: verify && (options.storageEvery <= 0 || bucketEnd(turn, options.bucketSize) % options.storageEvery === 0),
41
55
  depthBucket: depthBucket(turn, options.bucketSize),
42
56
  };
43
57
  }
44
58
 
59
+ /** `name:graph:expectDelta`, comma-separated. */
60
+ export function parseCells(spec: string): DeltaCell[] {
61
+ return spec
62
+ .split(',')
63
+ .map((part) => part.trim())
64
+ .filter(Boolean)
65
+ .map((part) => {
66
+ const [name, graphId, expectDelta] = part.split(':');
67
+ return { name, graphId, expectDelta: expectDelta === 'true' };
68
+ });
69
+ }
70
+
71
+ /**
72
+ * A delta snapshot lands on every multiple of its frequency, so reading every
73
+ * VU on those turns only ever measures the read right after one. Spreading the
74
+ * VUs across the interval samples the whole climb between snapshots.
75
+ */
76
+ export function readOffset(vu: number, vus: number, verifyEvery: number): number {
77
+ if (verifyEvery <= 0 || vus <= 0) return 0;
78
+ return Math.floor(((vu - 1) * verifyEvery) / vus) % verifyEvery;
79
+ }
80
+
45
81
  /**
46
82
  * Turn 1 has no counters yet, and on a snapshot point Pregel drops the counters
47
83
  * entry, so its absence there is correct rather than a fallback.
@@ -51,6 +87,10 @@ function isGuardTurn(turn: number, options: DeltaTurnsOptions, migrating: boolea
51
87
  return migrating && turn === options.migrateAfter + 2;
52
88
  }
53
89
 
90
+ function bucketEnd(turn: number, bucketSize: number): number {
91
+ return bucketSize <= 0 ? turn : Math.ceil(turn / bucketSize) * bucketSize;
92
+ }
93
+
54
94
  function depthBucket(turn: number, bucketSize: number): string {
55
95
  if (bucketSize <= 0) return String(turn);
56
96
  const floor = Math.floor((turn - 1) / bucketSize) * bucketSize;
@@ -13,9 +13,11 @@ import {
13
13
  planTurn,
14
14
  deltaGuardFailure,
15
15
  digestDrift,
16
+ parseCells,
17
+ readOffset,
16
18
  unusableCheckpointSize,
17
19
  } from './delta-turns-lib.js';
18
- import type { DeltaTurnsOptions, TurnPlan } from './delta-turns-lib.js';
20
+ import type { DeltaCell, DeltaTurnsOptions, TurnPlan } from './delta-turns-lib.js';
19
21
 
20
22
  const PAYLOAD_CHANNELS = [
21
23
  'cumulative_checkpoint',
@@ -35,20 +37,30 @@ const stateReadDuration = new Trend('state_read_duration', true);
35
37
  const checkpointSaveDuration = new Trend('checkpoint_save', true);
36
38
  const threadStorageBytes = new Trend('thread_storage_bytes', false);
37
39
 
38
- const TURN_CONFIG: Omit<DeltaTurnsOptions, 'graphId'> = {
40
+ const TURN_CONFIG: Omit<DeltaTurnsOptions, 'graphId' | 'readOffset'> = {
39
41
  migrateFromGraphId: __ENV.MIGRATE_FROM_GRAPH_ID || '',
40
42
  migrateAfter: parseInt(__ENV.MIGRATE_AFTER || '0', 10),
41
43
  expectDelta: (__ENV.EXPECT_DELTA || 'true') === 'true',
42
44
  verifyEvery: parseInt(__ENV.VERIFY_EVERY || '50', 10),
45
+ storageEvery: parseInt(__ENV.STORAGE_EVERY || '0', 10),
43
46
  // One bucket per cold read, so every row of the report is one sample per thread.
44
47
  bucketSize: parseInt(__ENV.DEPTH_BUCKET || __ENV.VERIFY_EVERY || '50', 10),
45
48
  };
46
49
 
50
+ /**
51
+ * Every VU turns these in rotation, one thread each, so the cells are measured
52
+ * at the same depth seconds apart. Empty runs GRAPH_ID alone.
53
+ */
54
+ const CELLS = parseCells(__ENV.DELTA_CELLS || '');
55
+
47
56
  // Each k6 VU runs this module in its own context, so these are per VU.
48
- let threadId: string | null = null;
49
- let turn = 0;
57
+ const threads: Record<string, { threadId: string | null; turn: number }> = {};
58
+ let iteration = 0;
50
59
 
51
60
  interface DeltaTurnsData {
61
+ cell: string;
62
+ turnMs: number;
63
+ tags: { depth: string; cell: string };
52
64
  rawResponse: ReturnType<typeof http.post>;
53
65
  plan: TurnPlan;
54
66
  guardFailure: string | null;
@@ -69,18 +81,31 @@ export class DeltaTurns extends BenchmarkRunner {
69
81
  return failResult('checkpoint_size', responses) as BenchmarkResult<DeltaTurnsData>;
70
82
  }
71
83
 
72
- if (threadId === null) {
73
- const thread = http.post(`${baseUrl}/threads`, '{}', requestParams);
84
+ const cell: DeltaCell = CELLS.length > 0
85
+ ? CELLS[iteration++ % CELLS.length]
86
+ : { name: benchmarkGraphOptions.graph_id, graphId: benchmarkGraphOptions.graph_id, expectDelta: TURN_CONFIG.expectDelta };
87
+ const own = (threads[cell.name] ??= { threadId: null, turn: 0 });
88
+ if (own.threadId === null) {
89
+ const ttlMinutes = parseInt(__ENV.THREAD_TTL_MINUTES || '0', 10);
90
+ const body = ttlMinutes > 0 ? { ttl: { strategy: 'delete', ttl: ttlMinutes } } : {};
91
+ const thread = http.post(`${baseUrl}/threads`, JSON.stringify(body), requestParams);
74
92
  addResponse(responses, 'create_thread', thread);
75
93
  if (thread.status !== 200) {
76
94
  return failResult('create_thread', responses) as BenchmarkResult<DeltaTurnsData>;
77
95
  }
78
- threadId = (thread.json() as { thread_id: string }).thread_id;
79
- turn = 0;
96
+ own.threadId = (thread.json() as { thread_id: string }).thread_id;
97
+ own.turn = 0;
80
98
  }
99
+ const threadId = own.threadId;
81
100
 
82
- turn += 1;
83
- const plan = planTurn(turn, { ...TURN_CONFIG, graphId: benchmarkGraphOptions.graph_id });
101
+ own.turn += 1;
102
+ const plan = planTurn(own.turn, {
103
+ ...TURN_CONFIG,
104
+ graphId: cell.graphId,
105
+ expectDelta: cell.expectDelta,
106
+ readOffset: readOffset(__VU, parseInt(__ENV.LOAD_SIZE || '1', 10), TURN_CONFIG.verifyEvery),
107
+ });
108
+ const tags = { depth: plan.depthBucket, cell: cell.name };
84
109
  const payload = JSON.stringify({
85
110
  assistant_id: plan.graphId,
86
111
  input: {},
@@ -97,14 +122,11 @@ export class DeltaTurns extends BenchmarkRunner {
97
122
  payload,
98
123
  requestParams
99
124
  );
100
- turnDuration.add(Date.now() - startedAt, { depth: plan.depthBucket });
125
+ const turnMs = Date.now() - startedAt;
101
126
  addResponse(responses, 'wait', response);
102
127
  const saveMs = response.status === 200 ? safeJson(response.body)?.save_ms : null;
103
128
  if (typeof saveMs === 'number' && saveMs > 0) {
104
- // Snapshots land on multiples of the bucket width, so the bucket's last
105
- // turn is where a snapshot save shows; a percentile over the bucket hides it.
106
- const rowTurn = plan.steps % TURN_CONFIG.bucketSize === 0 ? '1' : '0';
107
- checkpointSaveDuration.add(saveMs, { depth: plan.depthBucket, row_turn: rowTurn });
129
+ checkpointSaveDuration.add(saveMs, tags);
108
130
  }
109
131
 
110
132
  let guardFailure: string | null = null;
@@ -120,7 +142,7 @@ export class DeltaTurns extends BenchmarkRunner {
120
142
  // a plain-channel read cost as much as a whole turn. The turn-2 guard
121
143
  // read is at depth 2, not the bucket's end, so it is not timed.
122
144
  if (state.status === 200 && plan.verify) {
123
- stateReadDuration.add(state.timings.waiting, { depth: plan.depthBucket });
145
+ stateReadDuration.add(state.timings.waiting, tags);
124
146
  }
125
147
  addResponse(responses, 'state', state);
126
148
  const body = state.status === 200 ? safeJson(state.body) : null;
@@ -137,7 +159,7 @@ export class DeltaTurns extends BenchmarkRunner {
137
159
  drift = digestDrift(safeJson(response.body)?.payload_sha256, coldDigest(body.values));
138
160
  }
139
161
  }
140
- if (plan.verify) {
162
+ if (plan.storage) {
141
163
  // Servers before 0.16 have no storage endpoint. A 404 there is a missing
142
164
  // sample, not a failed request: without this, one 404 per 50 turns is
143
165
  // about 2% and trips the 1% error budget on every cell.
@@ -148,12 +170,12 @@ export class DeltaTurns extends BenchmarkRunner {
148
170
  addResponse(responses, 'storage', storage);
149
171
  const total = storage.status === 200 ? safeJson(storage.body)?.total_bytes : null;
150
172
  if (typeof total === 'number') {
151
- threadStorageBytes.add(total, { depth: plan.depthBucket, graph: plan.graphId });
173
+ threadStorageBytes.add(total, { ...tags, graph: plan.graphId });
152
174
  }
153
175
  }
154
176
  }
155
177
 
156
- return okResult(responses, { rawResponse: response, plan, guardFailure, drift, stateStatus });
178
+ return okResult(responses, { cell: cell.name, turnMs, tags, rawResponse: response, plan, guardFailure, drift, stateStatus });
157
179
  }
158
180
 
159
181
  static validate(
@@ -203,7 +225,12 @@ export class DeltaTurns extends BenchmarkRunner {
203
225
  );
204
226
  // The thread is now at an unknown depth, so later turns would be tagged
205
227
  // with a depth they do not have.
206
- threadId = null;
228
+ const cell = result.data?.cell;
229
+ if (cell && threads[cell]) threads[cell].threadId = null;
230
+ } else if (result.data) {
231
+ // The report counts these per bucket to tell which depth every user
232
+ // finished, so only a turn that passed every check counts.
233
+ turnDuration.add(result.data.turnMs, result.data.tags);
207
234
  }
208
235
  return success;
209
236
  }
@@ -13,11 +13,12 @@ interface ThreadsSearchMetadataData {
13
13
  }
14
14
 
15
15
  /**
16
- * Delete the threads each iteration creates, or leave them to accumulate.
16
+ * Delete the threads each iteration creates, or leave them to the deployment.
17
17
  *
18
- * Off by default: letting the table grow is how this benchmark shows whether
19
- * search degrades as thread count rises, and it is the realistic case since
20
- * deployments do not delete threads per request.
18
+ * Off by default, since deployments do not delete threads per request. The
19
+ * nightly deployments' 60-minute thread TTL (langgraph.json in
20
+ * langgraph-server-benchmarks) removes them after the run, so the table holds
21
+ * about one run's threads rather than growing night over night.
21
22
  *
22
23
  * The capacity staircase turns it on, because there the table grows *while*
23
24
  * load is ramping, so a slower step cannot be attributed to load or to size.