langgraph-api 0.17.0.dev3__tar.gz → 0.17.0.dev4__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 (330) hide show
  1. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/LICENSE +1 -1
  2. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/Makefile +9 -5
  3. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/PKG-INFO +2 -2
  4. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/README.md +9 -11
  5. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/REPORTS.md +35 -47
  6. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/delta-turns-lib.test.js +33 -0
  7. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/delta-turns-lib.ts +41 -1
  8. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/delta_turns.ts +47 -20
  9. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/capacity-ci.js +7 -1
  10. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/capacity-ci.test.js +22 -0
  11. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/clean.js +0 -1
  12. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/continuous/uv.lock +3 -3
  13. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/daily-report.js +9 -2
  14. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/daily-report.test.js +16 -2
  15. langgraph_api-0.17.0.dev4/benchmark/delta-report.js +384 -0
  16. langgraph_api-0.17.0.dev4/benchmark/delta-report.test.js +185 -0
  17. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/history.js +36 -12
  18. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/history.test.js +25 -0
  19. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/multer.test.js +2 -2
  20. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/package.json +13 -3
  21. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/ramp.js +5 -6
  22. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/slack.js +2 -1
  23. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/update-revision.js +4 -0
  24. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/yarn.lock +154 -209
  25. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/custom_store.sql +0 -0
  26. langgraph_api-0.17.0.dev4/langgraph_api/__init__.py +1 -0
  27. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/threads.py +2 -7
  28. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/cache.py +86 -26
  29. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/config/__init__.py +45 -5
  30. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/config/schemas.py +12 -12
  31. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/cron_scheduler.py +16 -1
  32. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/feature_flags.py +35 -4
  33. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/ops/crons.py +3 -2
  34. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/ops/runs.py +3 -0
  35. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/ops/threads.py +44 -0
  36. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/package.json +1 -1
  37. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/yarn.lock +7 -7
  38. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/models/run.py +4 -0
  39. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/schema.py +3 -0
  40. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/store.py +7 -6
  41. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/cache.py +22 -10
  42. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +1 -1
  43. langgraph_api-0.17.0.dev4/langgraph_grpc_common/proto/core_api_pb2.py +286 -0
  44. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/core_api_pb2.pyi +163 -2
  45. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +47 -3
  46. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +15 -3
  47. langgraph_api-0.17.0.dev4/langgraph_license/__init__.py +0 -0
  48. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/openapi.json +8 -1
  49. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/pyproject.toml +1 -1
  50. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/uv.lock +7 -7
  51. langgraph_api-0.17.0.dev3/benchmark/delta-report.js +0 -583
  52. langgraph_api-0.17.0.dev3/benchmark/delta-report.test.js +0 -222
  53. langgraph_api-0.17.0.dev3/langgraph_api/__init__.py +0 -1
  54. langgraph_api-0.17.0.dev3/langgraph_api/event_streaming/__init__.py +0 -1
  55. langgraph_api-0.17.0.dev3/langgraph_grpc_common/proto/core_api_pb2.py +0 -274
  56. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/.gitignore +0 -0
  57. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/README.md +0 -0
  58. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/.gitignore +0 -0
  59. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/Makefile +0 -0
  60. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/assistant.ts +0 -0
  61. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
  62. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
  63. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/benchmarks.ts +0 -0
  64. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
  65. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/classify-error.test.js +0 -0
  66. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/classify-error.ts +0 -0
  67. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
  68. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/interrupt_resume.ts +0 -0
  69. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/log-failure.ts +0 -0
  70. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/meta_workload.ts +0 -0
  71. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/store.ts +0 -0
  72. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/stream_write.ts +0 -0
  73. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/thread.ts +0 -0
  74. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
  75. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
  76. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/types.ts +0 -0
  77. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/benchmark-runners/wait_write.ts +0 -0
  78. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/clean-cli.js +0 -0
  79. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/continuous/README.md +0 -0
  80. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/continuous/pyproject.toml +0 -0
  81. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/continuous/runner.py +0 -0
  82. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/graphs.js +0 -0
  83. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/host-v2.js +0 -0
  84. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/host-v2.test.js +0 -0
  85. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/reporting/dd_reporting.py +0 -0
  86. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/runner-descriptions.js +0 -0
  87. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/server-metrics.js +0 -0
  88. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/server-metrics.test.js +0 -0
  89. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/staircase.py +0 -0
  90. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/staircase_step_k6.js +0 -0
  91. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/tsconfig.json +0 -0
  92. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/benchmark/weather.js +0 -0
  93. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/constraints.txt +0 -0
  94. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/forbidden.txt +0 -0
  95. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/hatch_build.py +0 -0
  96. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/healthcheck.py +0 -0
  97. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph-cloud-debugging-20260210132856.zip +0 -0
  98. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/_checkpointer/__init__.py +0 -0
  99. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/_checkpointer/_adapter.py +0 -0
  100. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/_checkpointer/protocol.py +0 -0
  101. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/_factory_utils.py +0 -0
  102. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/__init__.py +0 -0
  103. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2a.py +0 -0
  104. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2ui.py +0 -0
  105. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2ui_schemas/README.md +0 -0
  106. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2ui_schemas/client_capabilities.json +0 -0
  107. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2ui_schemas/client_data_model.json +0 -0
  108. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2ui_schemas/client_to_server.json +0 -0
  109. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/a2ui_schemas/server_to_client.json +0 -0
  110. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/assistants.py +0 -0
  111. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/event_streaming.py +0 -0
  112. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/mcp/__init__.py +0 -0
  113. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/mcp/_constants.py +0 -0
  114. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/mcp/_handlers.py +0 -0
  115. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/mcp/_models.py +0 -0
  116. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/mcp/_routes.py +0 -0
  117. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/mcp/_sanitizers.py +0 -0
  118. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/meta.py +0 -0
  119. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/openapi.py +0 -0
  120. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/profile.py +0 -0
  121. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/runs.py +0 -0
  122. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/store.py +0 -0
  123. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/api/ui.py +0 -0
  124. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/asgi_transport.py +0 -0
  125. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/asyncio.py +0 -0
  126. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/__init__.py +0 -0
  127. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/custom.py +0 -0
  128. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/errors.py +0 -0
  129. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/langsmith/__init__.py +0 -0
  130. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/langsmith/backend.py +0 -0
  131. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/langsmith/client.py +0 -0
  132. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/middleware.py +0 -0
  133. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/noop.py +0 -0
  134. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/auth/studio_user.py +0 -0
  135. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/beacon_data_plane_jwt_auth.py +0 -0
  136. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/cli.py +0 -0
  137. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/command.py +0 -0
  138. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/config/_parse.py +0 -0
  139. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/encryption/__init__.py +0 -0
  140. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/encryption/aes_json.py +0 -0
  141. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/encryption/context.py +0 -0
  142. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/encryption/custom.py +0 -0
  143. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/encryption/middleware.py +0 -0
  144. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/encryption/shared.py +0 -0
  145. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/errors.py +0 -0
  146. {langgraph_api-0.17.0.dev3/langgraph_api/grpc → langgraph_api-0.17.0.dev4/langgraph_api/event_streaming}/__init__.py +0 -0
  147. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/capabilities.py +0 -0
  148. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/constants.py +0 -0
  149. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/event_normalizers.py +0 -0
  150. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/namespace.py +0 -0
  151. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/service.py +0 -0
  152. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/session.py +0 -0
  153. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/state_normalizers.py +0 -0
  154. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/event_streaming/types.py +0 -0
  155. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/graph.py +0 -0
  156. {langgraph_api-0.17.0.dev3/langgraph_api/js → langgraph_api-0.17.0.dev4/langgraph_api/grpc}/__init__.py +0 -0
  157. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/client.py +0 -0
  158. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
  159. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/ops/__init__.py +0 -0
  160. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/ops/assistants.py +0 -0
  161. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/ops/cache.py +0 -0
  162. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/server.py +0 -0
  163. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/servicers/__init__.py +0 -0
  164. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
  165. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/grpc/servicers/encryption.py +0 -0
  166. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/http.py +0 -0
  167. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/http_metrics.py +0 -0
  168. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/http_metrics_utils.py +0 -0
  169. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/.gitignore +0 -0
  170. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/.prettierrc +0 -0
  171. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/.yarnclean +0 -0
  172. {langgraph_api-0.17.0.dev3/langgraph_api/middleware → langgraph_api-0.17.0.dev4/langgraph_api/js}/__init__.py +0 -0
  173. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/base.py +0 -0
  174. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/build.mts +0 -0
  175. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/client.http.mts +0 -0
  176. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/client.mts +0 -0
  177. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/errors.py +0 -0
  178. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/global.d.ts +0 -0
  179. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/remote.py +0 -0
  180. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/schema.py +0 -0
  181. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/auth-mutations.mts +0 -0
  182. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/graph.mts +0 -0
  183. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/load.hooks.mjs +0 -0
  184. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/preload.mjs +0 -0
  185. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
  186. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/utils/files.mts +0 -0
  187. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/utils/importMap.mts +0 -0
  188. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  189. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/src/utils/serde.mts +0 -0
  190. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/sse.py +0 -0
  191. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/traceblock.mts +0 -0
  192. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/tsconfig.json +0 -0
  193. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/js/ui.py +0 -0
  194. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/lc_security/__init__.py +0 -0
  195. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/lc_security/exceptions.py +0 -0
  196. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/lc_security/policy.py +0 -0
  197. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/lc_security/transport.py +0 -0
  198. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/logging.py +0 -0
  199. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/metadata.py +0 -0
  200. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/metrics_collector.py +0 -0
  201. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/metrics_otlp.py +0 -0
  202. {langgraph_api-0.17.0.dev3/langgraph_api/models → langgraph_api-0.17.0.dev4/langgraph_api/middleware}/__init__.py +0 -0
  203. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/middleware/ensure_store.py +0 -0
  204. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/middleware/http_logger.py +0 -0
  205. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/middleware/private_network.py +0 -0
  206. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/middleware/request_id.py +0 -0
  207. {langgraph_api-0.17.0.dev3/langgraph_license → langgraph_api-0.17.0.dev4/langgraph_api/models}/__init__.py +0 -0
  208. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/otel_context.py +0 -0
  209. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/patch.py +0 -0
  210. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/queue_entrypoint.py +0 -0
  211. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/release_tags.py +0 -0
  212. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/route.py +0 -0
  213. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/runner/__init__.py +0 -0
  214. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/runner/__main__.py +0 -0
  215. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/self_hosted_logs.py +0 -0
  216. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/self_hosted_metrics.py +0 -0
  217. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/serde.py +0 -0
  218. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/server.py +0 -0
  219. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/sse.py +0 -0
  220. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/state.py +0 -0
  221. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/stream.py +0 -0
  222. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/stream_v2.py +0 -0
  223. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/timing/__init__.py +0 -0
  224. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/timing/profiler.py +0 -0
  225. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/timing/timer.py +0 -0
  226. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/traceblock.py +0 -0
  227. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/tracing_session.py +0 -0
  228. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/tunneling/cloudflare.py +0 -0
  229. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/__init__.py +0 -0
  230. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/config.py +0 -0
  231. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/errors.py +0 -0
  232. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/extract.py +0 -0
  233. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/future.py +0 -0
  234. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/headers.py +0 -0
  235. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/network.py +0 -0
  236. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/retriable_client.py +0 -0
  237. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/stream_codec.py +0 -0
  238. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/utils/uuids.py +0 -0
  239. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/validation.py +0 -0
  240. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/webhook.py +0 -0
  241. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/worker.py +0 -0
  242. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_api/worker_runtime.py +0 -0
  243. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/__init__.py +0 -0
  244. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/checkpointer.py +0 -0
  245. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/__init__.py +0 -0
  246. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/_compat.py +0 -0
  247. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/checkpoint.py +0 -0
  248. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/config.py +0 -0
  249. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/durability.py +0 -0
  250. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/store.py +0 -0
  251. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/struct.py +0 -0
  252. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/conversion/value.py +0 -0
  253. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/__init__.py +0 -0
  254. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
  255. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
  256. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
  257. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
  258. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
  259. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
  260. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
  261. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
  262. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
  263. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
  264. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
  265. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
  266. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
  267. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
  268. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
  269. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
  270. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
  271. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
  272. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
  273. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
  274. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
  275. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
  276. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
  277. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
  278. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
  279. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
  280. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
  281. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
  282. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
  283. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
  284. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
  285. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
  286. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
  287. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
  288. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
  289. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
  290. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
  291. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
  292. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
  293. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
  294. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
  295. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
  296. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
  297. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
  298. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
  299. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
  300. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
  301. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
  302. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
  303. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
  304. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
  305. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/runner_pb2.py +0 -0
  306. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/runner_pb2.pyi +0 -0
  307. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/runner_pb2_grpc.py +0 -0
  308. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/runner_pb2_grpc.pyi +0 -0
  309. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/store_pb2.py +0 -0
  310. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/store_pb2.pyi +0 -0
  311. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
  312. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
  313. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/serde.py +0 -0
  314. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_grpc_common/store.py +0 -0
  315. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_license/validation.py +0 -0
  316. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/__init__.py +0 -0
  317. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/checkpoint.py +0 -0
  318. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/database.py +0 -0
  319. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/encryption.py +0 -0
  320. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/lifespan.py +0 -0
  321. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/metrics.py +0 -0
  322. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/ops.py +0 -0
  323. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/queue.py +0 -0
  324. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/retry.py +0 -0
  325. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/routes.py +0 -0
  326. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/langgraph_runtime/store.py +0 -0
  327. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/logging.json +0 -0
  328. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/scripts/build_wheel.py +0 -0
  329. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/scripts/create_license.py +0 -0
  330. {langgraph_api-0.17.0.dev3 → langgraph_api-0.17.0.dev4}/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.
@@ -38,6 +38,10 @@ check-base-imports:
38
38
  # test commands
39
39
 
40
40
  TEST ?= tests/ ../runtime_inmem/tests/
41
+ # Pin rootdir/config to this package. TEST includes ../runtime_inmem/tests/,
42
+ # and in the monorepo that climbs past api/ to the root pyproject.toml which
43
+ # has no [tool.pytest] — dropping pythonpath (e.g. apply_prerelease_version).
44
+ PYTEST_ROOT_ARGS := --rootdir=. -c pyproject.toml
41
45
  PYTEST_WORKERS ?= 0
42
46
  AUTH_TEST ?= "tests/integration_tests/test_custom_auth.py"
43
47
  LANGGRAPH_HTTP ?= {"disable_mcp": false, "disable_a2a": false}
@@ -105,7 +109,7 @@ REVISION ?= $(shell git rev-parse --short HEAD)
105
109
  LANGGRAPH_ENCRYPTION ?=
106
110
 
107
111
  test-license-oss:
108
- LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_WEBHOOKS='$(LANGGRAPH_WEBHOOKS)' LANGGRAPH_HTTP='$(HTTP_CONFIG)' LANGGRAPH_STORE='$(STORE_CONFIG)' LANGGRAPH_CHECKPOINTER='$(CHECKPOINTER_CONFIG)' LANGGRAPH_ENCRYPTION='$(LANGGRAPH_ENCRYPTION)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run pytest -v $(XDIST_ARGS) $(TEST)
112
+ LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_WEBHOOKS='$(LANGGRAPH_WEBHOOKS)' LANGGRAPH_HTTP='$(HTTP_CONFIG)' LANGGRAPH_STORE='$(STORE_CONFIG)' LANGGRAPH_CHECKPOINTER='$(CHECKPOINTER_CONFIG)' LANGGRAPH_ENCRYPTION='$(LANGGRAPH_ENCRYPTION)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run pytest -v $(PYTEST_ROOT_ARGS) $(XDIST_ARGS) $(TEST)
109
113
 
110
114
  test-watch-oss:
111
115
  LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_WEBHOOKS='$(LANGGRAPH_WEBHOOKS)' LANGGRAPH_HTTP='$(HTTP_CONFIG)' LANGGRAPH_ENCRYPTION='$(LANGGRAPH_ENCRYPTION)' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run --no-sync ptw . -- -x -vv --ff --capture=no $(TEST)
@@ -113,13 +117,13 @@ test-watch-oss:
113
117
  test: test-license-oss
114
118
  test-watch: test-watch-oss
115
119
  unit-test:
116
- LANGGRAPH_RUNTIME_EDITION="inmem" DATABASE_URI="test" REDIS_URI="test" uv run pytest tests/unit_tests
120
+ LANGGRAPH_RUNTIME_EDITION="inmem" DATABASE_URI="test" REDIS_URI="test" uv run pytest $(PYTEST_ROOT_ARGS) tests/unit_tests
117
121
 
118
122
  unit-test-watch:
119
123
  LANGGRAPH_RUNTIME_EDITION="inmem" DATABASE_URI="test" REDIS_URI="test" uv run ptw . -- -x -vv --ff --capture=no tests/unit_tests
120
124
 
121
125
  test-auth:
122
- LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_AUTH='{"path": "./tests/graphs/fastapi_jwt_auth.py:auth"}' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run pytest -v $(XDIST_ARGS) $(AUTH_TEST)
126
+ LANGGRAPH_RUNTIME_EDITION=inmem LANGGRAPH_AUTH='{"path": "./tests/graphs/fastapi_jwt_auth.py:auth"}' REDIS_URI=_FAKE DATABASE_URI=:memory: MIGRATIONS_PATH=__inmem__ uv run pytest -v $(PYTEST_ROOT_ARGS) $(XDIST_ARGS) $(AUTH_TEST)
123
127
 
124
128
  test-with-server:
125
129
  @bash -euo pipefail -c '$(MAKE) $(START_TARGET) LANGGRAPH_HTTP='\''$(LANGGRAPH_HTTP)'\'' & \
@@ -146,7 +150,7 @@ define FASTAPI_JWT_AUTH_TEST
146
150
  DATABASE_URI=:memory: \
147
151
  MIGRATIONS_PATH=__inmem__ \
148
152
  LANGGRAPH_HTTP='{"app": "./tests/graphs/fastapi_jwt_middleware_ordering.py:app", "middleware_order": "$(1)", "enable_custom_route_auth": $(2)}' \
149
- uv run pytest -v $(AUTH_TEST)
153
+ uv run pytest -v $(PYTEST_ROOT_ARGS) $(AUTH_TEST)
150
154
  endef
151
155
 
152
156
  test-auth-fastapi-jwt--before-custom-middleware--no-custom-route-auth:
@@ -171,7 +175,7 @@ test-auth-langsmith-api-keys:
171
175
  REDIS_URI=_FAKE \
172
176
  DATABASE_URI=:memory: \
173
177
  MIGRATIONS_PATH=__inmem__ \
174
- uv run pytest -v tests/integration_tests/test_langsmith_parallel_auth.py
178
+ uv run pytest -v $(PYTEST_ROOT_ARGS) tests/integration_tests/test_langsmith_parallel_auth.py
175
179
 
176
180
  # dev commands
177
181
  LANGGRAPH_DISABLE_FILE_PERSISTENCE ?= true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.17.0.dev3
3
+ Version: 0.17.0.dev4
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
@@ -28,7 +28,7 @@ Requires-Dist: opentelemetry-sdk>=0.0.1
28
28
  Requires-Dist: orjson>=3.9.7
29
29
  Requires-Dist: prometheus-client>=0.0.1
30
30
  Requires-Dist: protobuf<7.0.0,>=6.32.1
31
- Requires-Dist: pyjwt>=2.13.0
31
+ Requires-Dist: pyjwt>=2.15.0
32
32
  Requires-Dist: sse-starlette<4.0.0,>=2.1.3
33
33
  Requires-Dist: starlette>=1.3.1
34
34
  Requires-Dist: structlog<26,>=24.1.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
- one row per cell (write, read and storage at the deepest turn every cell reached) and puts
136
- the by-depth tables in the thread. 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 write, read and storage 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
@@ -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
@@ -16,8 +16,8 @@ in the same channel is separate and not covered here.
16
16
  - **Failed / Errors / Regressed / Bottlenecks** lines only appear when there is
17
17
  something to say, worst first.
18
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
20
- reports, the last 7 for capacity and delta, where ▲ better and ▼ worse also
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
21
  mark the cell in the table. The usual range is half the spread
22
22
  between the best and worst of those nights, and never less than 10%, so a
23
23
  series that swings 40% night to night is not flagged for moving 15%.
@@ -101,8 +101,10 @@ model", the way real traffic arrives), and raises it every 60 s: dedicated by
101
101
 
102
102
  **The table.** Each cell is the highest request rate the tier held for two
103
103
  steps while staying on target: at least 99% success, p50 at most 3 s, p95 at
104
- most 10 s. `0` means no step met the target, `ERR` means the cell crashed,
105
- `-` means it never ran.
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.
106
108
 
107
109
  **Bottlenecks.** A component (queue, api, database, redis) running at or over
108
110
  95% of its CPU request during the steps the tier passed. That is what stops
@@ -120,9 +122,9 @@ that failed. Last, the request rate actually served at the top step.
120
122
 
121
123
  ## Delta channel
122
124
 
123
- **Question it answers:** as a thread grows to thousands of turns, does
124
- `DeltaChannel` keep reads and writes cheaper than a plain channel, and how
125
- much storage does it save?
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?
126
128
 
127
129
  **Background.** A plain channel saves the whole value at every checkpoint. A
128
130
  `DeltaChannel` saves only what changed, plus a full snapshot every N turns,
@@ -130,46 +132,32 @@ and rebuilds the value on read by replaying the changes since the last
130
132
  snapshot. That moves cost from write to read, and read cost grows with the
131
133
  distance to the last snapshot.
132
134
 
133
- **How it runs.** 20 k6 users, one thread each, for 25 minutes. Every
134
- iteration adds one turn to the user's thread (`POST /runs/wait`), appending
135
- 1 KB to its state, so threads reach about 1,500 turns. Every 50 turns each user also does a cold state read
136
- (`GET /threads/{id}/state`) and reads the thread's storage size
137
- (`GET /threads/{id}/storage`). Four cells run the same graph logic:
138
-
139
- | Row | Channel |
140
- |---|---|
141
- | `non-delta` | plain channel, the control |
142
- | `snap 50` | delta, snapshot every 50 turns (the deepagents setting) |
143
- | `snap 500` | delta, snapshot every 500 turns |
144
- | `snap 1000` | delta, snapshot every 1000 turns (the library default) |
145
-
146
- **The table.** One row per cell at the deepest turn every cell has a cold read
147
- for, named in the header (`at 1400`). A slower cell gets less deep in 25
148
- minutes, so the table stops where the slowest one did; the thread says how far
149
- each cell got. Values are seconds, except `KB`.
150
-
151
- - `write`: median checkpoint save at that turn, timed by the worker as the
152
- gap between the graph's two steps, with saves made synchronous so nothing
153
- overlaps it. `-` with a note means the deployed benchmark graph is too old
154
- to report it.
155
- - `read`: median cold state read at that turn, timed to the server's first
156
- byte, so sending the state back is not counted.
157
- - `KB`: storage the thread occupies at the deepest turn. Missing when the
158
- deployment's API predates the storage endpoint.
159
-
160
- **Pass bar.** Request errors under 1% and success over 99% per cell. Two
161
- correctness checks turn the dot yellow on any failure: at turn 2 each cell
162
- confirms delta is on (or off, for the control), because a too-old langgraph
163
- silently degrades a `DeltaChannel` to a plain one; and every cold read is
164
- compared with what the run returned.
165
-
166
- **Thread.** Per-cell turn and failure counts against past nights; the plain
167
- channel and delta-at-50 as two stacked tables every 250 turns, with the
168
- deepest turn each cell reached; and the snapshot-frequency sweep, whose
169
- columns are the snapshot interval (50, 500, 1000). The sweep shows read,
170
- write and storage at the turn before and at each snapshot, where read peaks
171
- and resets, plus the write at the row's own turn: snapshots land on those
172
- turns, so it is the full-value write the median hides.
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: `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.
151
+
152
+ **Pass bar.** Request errors under 1% and success over 99%. Two correctness
153
+ checks turn the dot yellow on any failure: at turn 2 each thread confirms
154
+ delta is on (or off, for `base`), because a too-old langgraph silently
155
+ degrades a `DeltaChannel` to a plain one; and every cold read is compared with
156
+ what the run returned.
157
+
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.
173
161
 
174
162
  ## Changing a report
175
163
 
@@ -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
  }
@@ -315,7 +315,10 @@ function moveLine(row, unit) {
315
315
  export function capacityCell(summary) {
316
316
  if (!summary) return "-";
317
317
  if (summary.error) return "ERR";
318
- return String(summary.capacity?.targetVUs ?? 0);
318
+ const vus = String(summary.capacity?.targetVUs ?? 0);
319
+ // Passing the last step says only that the server is at least this fast.
320
+ const lastStep = summary.config?.numSteps;
321
+ return lastStep != null && summary.capacity?.step === lastStep ? `${vus}+` : vus;
319
322
  }
320
323
 
321
324
  function plural(n, word) {
@@ -396,6 +399,9 @@ export function formatAggregateTable(
396
399
  if (failedParts.length > 0) {
397
400
  lines.push(`*Failed:* ${failedParts.join(" · ")} · treat the table as incomplete`);
398
401
  }
402
+ // hostRequest appends the response body, which can span lines; the detail is often on a later one.
403
+ const reasons = new Set(rows.map((row) => row.summary?.error?.replace(/\s+/g, " ").trim()).filter(Boolean));
404
+ if (reasons.size > 0) lines.push(`*Why:* ${[...reasons].join(" · ")}`);
399
405
  if (regressed.length > 0) lines.push(`*Regressed:* ${regressed.map((row) => moveLine(row, unit)).join(" · ")}`);
400
406
  if (bottlenecks.length > 0) lines.push(`*Bottlenecks:* ${bottlenecks.join(" · ")}`);
401
407
  for (const warning of allWarnings) lines.push(`:warning: ${warning}`);
@@ -80,6 +80,12 @@ test("the posted cell is the load alone; the served rate lives in the thread", (
80
80
  assert.equal(capacityCell({ capacity: { targetVUs: 900, successfulRunsPerSec: 366 } }), "900");
81
81
  });
82
82
 
83
+ test("a cell that passed the last step reads as a floor, not a ceiling", () => {
84
+ const config = { numSteps: 13 };
85
+ assert.equal(capacityCell({ config, capacity: { step: 13, targetVUs: 70 } }), "70+");
86
+ assert.equal(capacityCell({ config, capacity: { step: 12, targetVUs: 65 } }), "65");
87
+ });
88
+
83
89
  test("a failed cell renders as ERR in the posted table and is named in the Failed line", () => {
84
90
  const deployments = [
85
91
  { slug: "dep", tiers: ["TIER_A", "TIER_B"] },
@@ -130,6 +136,7 @@ test("an incomplete run says so, a clean run says all quiet", () => {
130
136
  assert.match(table, /^🔴 .* · 1 of 3 cells ran · dep TIER_A crashed, 1 never ran$/m);
131
137
  assert.match(table, /^\*Failed:\* dep TIER_A stream \(ERR\) · dep TIER_A search never ran · treat the table as incomplete$/m);
132
138
  assert.match(table.split("\n")[1], /^\*Failed:\*/, "what went wrong comes right after the verdict");
139
+ assert.match(table, /^\*Why:\* boom$/m);
133
140
 
134
141
 
135
142
  const clean = formatAggregateTable(deployments, [
@@ -418,3 +425,18 @@ test("the CPU table fits a phone even with every component reporting", () => {
418
425
  const view = formatServerView(deployments, summaries);
419
426
  assert.ok(widestCodeLine(view) <= PHONE_WIDTH, `widest table line is ${widestCodeLine(view)}`);
420
427
  });
428
+
429
+ test("tiers that crashed for the same reason name it once", () => {
430
+ const deployments = [{ slug: "dep", tiers: ["TIER_A", "TIER_B"] }];
431
+ const crash = (computeTier) =>
432
+ buildErrorSummary({ deploymentSlug: "dep", computeTier, benchmarkType: "wait_write" }, new Error("Deployment failed with status: BUILD_FAILED"));
433
+ const table = formatAggregateTable(deployments, [crash("TIER_A"), crash("TIER_B")]);
434
+ assert.match(table, /^\*Why:\* Deployment failed with status: BUILD_FAILED$/m);
435
+ });
436
+
437
+ test("a crashed cell's multi-line error keeps its detail on the Why line", () => {
438
+ const deployments = [{ slug: "dep", tiers: ["TIER_A"] }];
439
+ const error = new Error('PATCH /resource-tiers failed: 409 {\n "detail": "Unable to resize the deployment database."\n}');
440
+ const table = formatAggregateTable(deployments, [buildErrorSummary({ deploymentSlug: "dep", computeTier: "TIER_A", benchmarkType: "wait_write" }, error)]);
441
+ assert.match(table, /^\*Why:\* PATCH \/resource-tiers failed: 409 \{ "detail": "Unable to resize the deployment database\." \}$/m);
442
+ });
@@ -236,4 +236,3 @@ async function cleanThreads(baseUrl, langsmithApiKey) {
236
236
 
237
237
  console.log(`Thread cleanup completed. Total threads deleted: ${totalDeleted}`);
238
238
  }
239
-
@@ -549,11 +549,11 @@ wheels = [
549
549
 
550
550
  [[package]]
551
551
  name = "urllib3"
552
- version = "2.7.0"
552
+ version = "2.8.0"
553
553
  source = { registry = "https://pypi.org/simple" }
554
- sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
554
+ sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" }
555
555
  wheels = [
556
- { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
556
+ { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" },
557
557
  ]
558
558
 
559
559
  [[package]]
@@ -217,9 +217,15 @@ function runName(run) {
217
217
  return runnerShortName(run.benchmarkType);
218
218
  }
219
219
 
220
+ function noResults(run) {
221
+ return run.revisionError
222
+ ? `no results, the new revision failed: ${run.revisionError}`
223
+ : `no results produced, step finished as \`${run.stepOutcome}\``;
224
+ }
225
+
220
226
  function failureReason(run) {
221
227
  const metrics = run.summary?.metrics;
222
- if (!metrics) return `no results produced, step finished as \`${run.stepOutcome}\``;
228
+ if (!metrics) return noResults(run);
223
229
  const crossed = describedThresholds(run.summary.thresholds, metrics).filter((t) => t.ok === false);
224
230
  if (crossed.length > 0) return crossed.map((t) => t.breach).join(', ');
225
231
  if (!metrics.successfulRuns) return 'no run succeeded';
@@ -356,7 +362,7 @@ function perRunDetail(runs, changesByRun, improved, load) {
356
362
  for (const run of runs) {
357
363
  const metrics = run.summary?.metrics;
358
364
  if (!metrics) {
359
- lines.push(`${runName(run)}: no results, step finished as \`${run.stepOutcome}\``);
365
+ lines.push(`${runName(run)}: ${noResults(run)}`);
360
366
  continue;
361
367
  }
362
368
  const counts = `${count(metrics.totalRuns)} runs, ${count(metrics.failedRuns)} failed`;
@@ -427,6 +433,7 @@ export function collectRuns(resultsDir, historyDir) {
427
433
  return {
428
434
  benchmarkType,
429
435
  stepOutcome: context.stepOutcome ?? (dir ? 'unknown' : 'missing'),
436
+ revisionError: context.revisionError,
430
437
  summary: dir ? readSummary(findLatestSummary(dir)) : null,
431
438
  load: { loadSize: context.loadSize, levels: context.levels, plateauDuration: context.plateauDuration },
432
439
  history: historyDir ? loadDailyHistory(historyDir, `-${benchmarkType}-`) : [],