langgraph-api 0.18.0.dev3__tar.gz → 0.18.0.dev5__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 (331) hide show
  1. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/PKG-INFO +1 -1
  2. langgraph_api-0.18.0.dev5/langgraph_api/__init__.py +1 -0
  3. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/event_streaming.py +71 -7
  4. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/config/__init__.py +2 -4
  5. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/drain.py +64 -2
  6. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/service.py +19 -3
  7. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/session.py +9 -6
  8. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/threads.py +54 -6
  9. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/models/run.py +7 -0
  10. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/headers.py +5 -0
  11. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/validation.py +6 -6
  12. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/openapi.json +25 -5
  13. langgraph_api-0.18.0.dev3/langgraph_api/__init__.py +0 -1
  14. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/.gitignore +0 -0
  15. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/LICENSE +0 -0
  16. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/Makefile +0 -0
  17. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/README.md +0 -0
  18. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/.gitignore +0 -0
  19. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/Makefile +0 -0
  20. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/README.md +0 -0
  21. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/REPORTS.md +0 -0
  22. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/assistant.ts +0 -0
  23. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/benchmark-runner.ts +0 -0
  24. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/benchmark_profiles.ts +0 -0
  25. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/benchmarks.ts +0 -0
  26. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/cancel_first_second_completes.ts +0 -0
  27. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/classify-error.test.js +0 -0
  28. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/classify-error.ts +0 -0
  29. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/delta-turns-lib.test.js +0 -0
  30. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/delta-turns-lib.ts +0 -0
  31. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/delta_turns.ts +0 -0
  32. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/enqueued_runs_order.ts +0 -0
  33. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/interrupt_resume.ts +0 -0
  34. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/log-failure.ts +0 -0
  35. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/meta_workload.ts +0 -0
  36. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/store.ts +0 -0
  37. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/stream_write.ts +0 -0
  38. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/thread.ts +0 -0
  39. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/thread_runs_metadata_search.ts +0 -0
  40. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/threads_search_metadata.ts +0 -0
  41. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/types.ts +0 -0
  42. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/benchmark-runners/wait_write.ts +0 -0
  43. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/capacity-ci.js +0 -0
  44. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/capacity-ci.test.js +0 -0
  45. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/clean-cli.js +0 -0
  46. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/clean.js +0 -0
  47. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/README.md +0 -0
  48. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/pyproject.toml +0 -0
  49. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/runner.py +0 -0
  50. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/continuous/uv.lock +0 -0
  51. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/daily-report.js +0 -0
  52. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/daily-report.test.js +0 -0
  53. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/delta-report.js +0 -0
  54. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/delta-report.test.js +0 -0
  55. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/graphs.js +0 -0
  56. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/history.js +0 -0
  57. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/history.test.js +0 -0
  58. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/host-v2.js +0 -0
  59. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/host-v2.test.js +0 -0
  60. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/multer.test.js +0 -0
  61. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/package.json +0 -0
  62. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/ramp.js +0 -0
  63. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/reporting/dd_reporting.py +0 -0
  64. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/runner-descriptions.js +0 -0
  65. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/server-metrics.js +0 -0
  66. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/server-metrics.test.js +0 -0
  67. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/slack.js +0 -0
  68. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/staircase.py +0 -0
  69. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/staircase_step_k6.js +0 -0
  70. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/tsconfig.json +0 -0
  71. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/update-revision.js +0 -0
  72. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/weather.js +0 -0
  73. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/benchmark/yarn.lock +0 -0
  74. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/constraints.txt +0 -0
  75. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/custom_store.sql +0 -0
  76. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/forbidden.txt +0 -0
  77. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/hatch_build.py +0 -0
  78. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/healthcheck.py +0 -0
  79. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph-cloud-debugging-20260210132856.zip +0 -0
  80. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_checkpointer/__init__.py +0 -0
  81. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_checkpointer/_adapter.py +0 -0
  82. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_checkpointer/protocol.py +0 -0
  83. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/_factory_utils.py +0 -0
  84. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/__init__.py +0 -0
  85. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2a.py +0 -0
  86. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui.py +0 -0
  87. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/README.md +0 -0
  88. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/client_capabilities.json +0 -0
  89. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/client_data_model.json +0 -0
  90. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/client_to_server.json +0 -0
  91. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/a2ui_schemas/server_to_client.json +0 -0
  92. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/assistants.py +0 -0
  93. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/__init__.py +0 -0
  94. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_calls.py +0 -0
  95. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_constants.py +0 -0
  96. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_handlers.py +0 -0
  97. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_models.py +0 -0
  98. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_outcome.py +0 -0
  99. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_protocol.py +0 -0
  100. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_routes.py +0 -0
  101. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/mcp/_sanitizers.py +0 -0
  102. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/meta.py +0 -0
  103. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/openapi.py +0 -0
  104. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/profile.py +0 -0
  105. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/runs.py +0 -0
  106. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/store.py +0 -0
  107. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/threads.py +0 -0
  108. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/api/ui.py +0 -0
  109. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/asgi_transport.py +0 -0
  110. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/asyncio.py +0 -0
  111. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/__init__.py +0 -0
  112. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/custom.py +0 -0
  113. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/errors.py +0 -0
  114. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/langsmith/__init__.py +0 -0
  115. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/langsmith/backend.py +0 -0
  116. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/langsmith/client.py +0 -0
  117. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/middleware.py +0 -0
  118. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/noop.py +0 -0
  119. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/auth/studio_user.py +0 -0
  120. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/beacon_data_plane_jwt_auth.py +0 -0
  121. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/cache.py +0 -0
  122. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/cli.py +0 -0
  123. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/command.py +0 -0
  124. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/config/_parse.py +0 -0
  125. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/config/schemas.py +0 -0
  126. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/cron_scheduler.py +0 -0
  127. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/__init__.py +0 -0
  128. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/aes_json.py +0 -0
  129. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/context.py +0 -0
  130. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/custom.py +0 -0
  131. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/middleware.py +0 -0
  132. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/encryption/shared.py +0 -0
  133. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/errors.py +0 -0
  134. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/__init__.py +0 -0
  135. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/capabilities.py +0 -0
  136. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/constants.py +0 -0
  137. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/event_normalizers.py +0 -0
  138. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/namespace.py +0 -0
  139. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/state_normalizers.py +0 -0
  140. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/event_streaming/types.py +0 -0
  141. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/executor/__init__.py +0 -0
  142. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/executor/__main__.py +0 -0
  143. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/feature_flags.py +0 -0
  144. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/graph.py +0 -0
  145. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/__init__.py +0 -0
  146. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/client.py +0 -0
  147. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/generated/core_api_pb2.pyi +0 -0
  148. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/__init__.py +0 -0
  149. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/assistants.py +0 -0
  150. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/cache.py +0 -0
  151. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/crons.py +0 -0
  152. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/ops/runs.py +0 -0
  153. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/server.py +0 -0
  154. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/servicers/__init__.py +0 -0
  155. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/servicers/checkpointer.py +0 -0
  156. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/grpc/servicers/encryption.py +0 -0
  157. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/http.py +0 -0
  158. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/http_metrics.py +0 -0
  159. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/http_metrics_utils.py +0 -0
  160. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/.gitignore +0 -0
  161. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/.prettierrc +0 -0
  162. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/.yarnclean +0 -0
  163. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/__init__.py +0 -0
  164. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/base.py +0 -0
  165. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/build.mts +0 -0
  166. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/client.http.mts +0 -0
  167. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/client.mts +0 -0
  168. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/errors.py +0 -0
  169. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/global.d.ts +0 -0
  170. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/package.json +0 -0
  171. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/remote.py +0 -0
  172. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/schema.py +0 -0
  173. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/auth-mutations.mts +0 -0
  174. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/graph.mts +0 -0
  175. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/load.hooks.mjs +0 -0
  176. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/preload.mjs +0 -0
  177. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/experiment-tracing.mts +0 -0
  178. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/files.mts +0 -0
  179. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/importMap.mts +0 -0
  180. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  181. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/src/utils/serde.mts +0 -0
  182. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/sse.py +0 -0
  183. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/traceblock.mts +0 -0
  184. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/tsconfig.json +0 -0
  185. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/ui.py +0 -0
  186. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/js/yarn.lock +0 -0
  187. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/__init__.py +0 -0
  188. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/exceptions.py +0 -0
  189. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/policy.py +0 -0
  190. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/lc_security/transport.py +0 -0
  191. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/logging.py +0 -0
  192. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/metadata.py +0 -0
  193. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/metrics_collector.py +0 -0
  194. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/metrics_otlp.py +0 -0
  195. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/__init__.py +0 -0
  196. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/ensure_store.py +0 -0
  197. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/http_logger.py +0 -0
  198. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/private_network.py +0 -0
  199. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/middleware/request_id.py +0 -0
  200. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/models/__init__.py +0 -0
  201. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/otel_context.py +0 -0
  202. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/patch.py +0 -0
  203. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/queue_entrypoint.py +0 -0
  204. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/release_tags.py +0 -0
  205. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/route.py +0 -0
  206. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/schema.py +0 -0
  207. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/self_hosted_logs.py +0 -0
  208. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/self_hosted_metrics.py +0 -0
  209. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/serde.py +0 -0
  210. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/server.py +0 -0
  211. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/sse.py +0 -0
  212. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/state.py +0 -0
  213. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/store.py +0 -0
  214. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/stream.py +0 -0
  215. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/stream_v2.py +0 -0
  216. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/__init__.py +0 -0
  217. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/profiler.py +0 -0
  218. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/startup.py +0 -0
  219. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/timing/timer.py +0 -0
  220. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/traceblock.py +0 -0
  221. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/tracing_session.py +0 -0
  222. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/tunneling/cloudflare.py +0 -0
  223. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/__init__.py +0 -0
  224. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/cache.py +0 -0
  225. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/config.py +0 -0
  226. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/errors.py +0 -0
  227. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/extract.py +0 -0
  228. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/future.py +0 -0
  229. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/network.py +0 -0
  230. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/retriable_client.py +0 -0
  231. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/stream_codec.py +0 -0
  232. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/utils/uuids.py +0 -0
  233. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/webhook.py +0 -0
  234. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/worker.py +0 -0
  235. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_api/worker_runtime.py +0 -0
  236. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/__init__.py +0 -0
  237. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/checkpointer.py +0 -0
  238. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/__init__.py +0 -0
  239. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/_compat.py +0 -0
  240. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/checkpoint.py +0 -0
  241. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/config.py +0 -0
  242. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/durability.py +0 -0
  243. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/store.py +0 -0
  244. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/struct.py +0 -0
  245. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/conversion/value.py +0 -0
  246. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/__init__.py +0 -0
  247. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2.py +0 -0
  248. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2.pyi +0 -0
  249. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.py +0 -0
  250. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/checkpointer_pb2_grpc.pyi +0 -0
  251. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2.py +0 -0
  252. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2.pyi +0 -0
  253. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2_grpc.py +0 -0
  254. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/core_api_pb2_grpc.pyi +0 -0
  255. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2.py +0 -0
  256. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2.pyi +0 -0
  257. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2_grpc.py +0 -0
  258. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/encryption_pb2_grpc.pyi +0 -0
  259. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2.py +0 -0
  260. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2.pyi +0 -0
  261. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2_grpc.py +0 -0
  262. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/engine_common_pb2_grpc.pyi +0 -0
  263. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.py +0 -0
  264. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2.pyi +0 -0
  265. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.py +0 -0
  266. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cancel_run_action_pb2_grpc.pyi +0 -0
  267. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2.py +0 -0
  268. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2.pyi +0 -0
  269. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.py +0 -0
  270. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_control_signal_pb2_grpc.pyi +0 -0
  271. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.py +0 -0
  272. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2.pyi +0 -0
  273. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.py +0 -0
  274. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_cron_on_run_completed_pb2_grpc.pyi +0 -0
  275. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2.py +0 -0
  276. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2.pyi +0 -0
  277. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.py +0 -0
  278. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_durability_pb2_grpc.pyi +0 -0
  279. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.py +0 -0
  280. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2.pyi +0 -0
  281. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.py +0 -0
  282. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_multitask_strategy_pb2_grpc.pyi +0 -0
  283. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2.py +0 -0
  284. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2.pyi +0 -0
  285. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.py +0 -0
  286. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_run_status_pb2_grpc.pyi +0 -0
  287. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2.py +0 -0
  288. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2.pyi +0 -0
  289. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.py +0 -0
  290. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_stream_mode_pb2_grpc.pyi +0 -0
  291. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2.py +0 -0
  292. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2.pyi +0 -0
  293. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.py +0 -0
  294. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_status_pb2_grpc.pyi +0 -0
  295. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.py +0 -0
  296. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2.pyi +0 -0
  297. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.py +0 -0
  298. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/enum_thread_stream_mode_pb2_grpc.pyi +0 -0
  299. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2.py +0 -0
  300. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2.pyi +0 -0
  301. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2_grpc.py +0 -0
  302. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/errors_pb2_grpc.pyi +0 -0
  303. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2.py +0 -0
  304. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2.pyi +0 -0
  305. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2_grpc.py +0 -0
  306. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/orchestrator_pb2_grpc.pyi +0 -0
  307. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2.py +0 -0
  308. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2.pyi +0 -0
  309. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2_grpc.py +0 -0
  310. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/proto/store_pb2_grpc.pyi +0 -0
  311. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/serde.py +0 -0
  312. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_grpc_common/store.py +0 -0
  313. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_license/__init__.py +0 -0
  314. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_license/validation.py +0 -0
  315. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/__init__.py +0 -0
  316. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/checkpoint.py +0 -0
  317. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/database.py +0 -0
  318. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/encryption.py +0 -0
  319. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/lifespan.py +0 -0
  320. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/metrics.py +0 -0
  321. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/ops.py +0 -0
  322. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/queue.py +0 -0
  323. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/retry.py +0 -0
  324. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/routes.py +0 -0
  325. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/langgraph_runtime/store.py +0 -0
  326. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/logging.json +0 -0
  327. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/pyproject.toml +0 -0
  328. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/scripts/build_wheel.py +0 -0
  329. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/scripts/create_license.py +0 -0
  330. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/scripts/run_a2a_tck.py +0 -0
  331. {langgraph_api-0.18.0.dev3 → langgraph_api-0.18.0.dev5}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.18.0.dev3
3
+ Version: 0.18.0.dev5
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
@@ -0,0 +1 @@
1
+ __version__ = "0.18.0.dev5"
@@ -28,6 +28,7 @@ from uuid import uuid4
28
28
 
29
29
  import orjson
30
30
  import structlog
31
+ from starlette.exceptions import HTTPException
31
32
  from starlette.responses import Response
32
33
  from starlette.websockets import WebSocketDisconnect
33
34
 
@@ -38,6 +39,7 @@ from langgraph_api.feature_flags import IS_POSTGRES_OR_GRPC_BACKEND
38
39
  from langgraph_api.route import ApiRoute, ApiWebSocketRoute
39
40
  from langgraph_api.serde import json_dumpb
40
41
  from langgraph_api.sse import EventSourceResponse
42
+ from langgraph_api.utils import validate_uuid
41
43
 
42
44
  if TYPE_CHECKING:
43
45
  from collections.abc import Mapping
@@ -98,6 +100,7 @@ def _make_manager(
98
100
  send_event: Any = None,
99
101
  *,
100
102
  headers: Mapping[str, str] | None = None,
103
+ replay_buffer: bool = True,
101
104
  ) -> ThreadRunManager:
102
105
  # Auth context is propagated via ``ApiRoute``'s ``with_user`` wrapper
103
106
  # — ops reads it off the context var, so we don't thread it through
@@ -108,6 +111,7 @@ def _make_manager(
108
111
  threads=Threads,
109
112
  send_event=send_event,
110
113
  headers=headers,
114
+ replay_buffer=replay_buffer,
111
115
  )
112
116
 
113
117
 
@@ -143,8 +147,12 @@ async def _thread_events(request: Request) -> Response:
143
147
  If reading the thread's event stream fails, the server ends the
144
148
  stream with a final ``event: error`` frame carrying a protocol error
145
149
  (``"type": "error"``, ``"id": null``, ``"error": "unknown_error"``).
150
+
151
+ A thread the caller isn't allowed to read returns 403 or 404 before
152
+ the stream starts, and a malformed thread ID returns 422.
146
153
  """
147
154
  thread_id = request.path_params["thread_id"]
155
+ thread_uuid = validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
148
156
  try:
149
157
  body = orjson.loads(await request.body())
150
158
  except Exception:
@@ -217,6 +225,10 @@ async def _thread_events(request: Request) -> Response:
217
225
  else None
218
226
  )
219
227
 
228
+ # Checked here, before the 200, because clients retry a 200 that ends in
229
+ # an error instead of giving up.
230
+ auth_filters = await Threads.Stream.check_thread_stream_auth(thread_uuid)
231
+
220
232
  # Bounded LRU dedup: ``recent_eids`` is the eviction order, ``delivered``
221
233
  # is the O(1) membership view. When the deque hits its cap, the oldest
222
234
  # entry rolls off; we mirror that on ``delivered`` to keep them in sync.
@@ -241,7 +253,10 @@ async def _thread_events(request: Request) -> Response:
241
253
  pending_events.append(event)
242
254
  flush_pending.set()
243
255
 
244
- manager = _make_manager(thread_id, send_event=on_event)
256
+ # SSE never replays from the session's buffer: it has no subscribe or
257
+ # reconnect commands, and ``start_thread_stream`` replays from the
258
+ # thread's event stream.
259
+ manager = _make_manager(thread_id, send_event=on_event, replay_buffer=False)
245
260
 
246
261
  filter_sub = Subscription(
247
262
  id=str(uuid4()),
@@ -264,7 +279,7 @@ async def _thread_events(request: Request) -> Response:
264
279
  # outbound events; the thread-level reader always replays from the
265
280
  # beginning so namespace-scoped projections see history. See
266
281
  # ``ThreadRunManager.start_thread_stream`` for the rationale.
267
- manager.start_thread_stream()
282
+ manager.start_thread_stream(auth_filters=auth_filters)
268
283
 
269
284
  async def body_iter():
270
285
  try:
@@ -377,20 +392,51 @@ async def _thread_command(request: Request) -> Response:
377
392
  # ---------------------------------------------------------------------------
378
393
 
379
394
 
395
+ async def _close_for_failed_access_check(websocket: WebSocket, exc: Exception) -> None:
396
+ if isinstance(exc, HTTPException) and exc.status_code < 500:
397
+ await websocket.close(code=4000 + exc.status_code)
398
+ return
399
+ logger.exception("Thread stream access check failed")
400
+ await websocket.send_text(_THREAD_STREAM_FAILED_DATA.decode())
401
+ await websocket.close(code=1011, reason="thread stream ended")
402
+
403
+
380
404
  async def _thread_websocket(websocket: WebSocket) -> None:
381
405
  """Full-duplex protocol connection scoped to a thread.
382
406
 
383
407
  Supports ``run.start``, ``input.respond``, ``subscription.subscribe``,
384
408
  ``subscription.unsubscribe``, ``agent.getTree``.
409
+
410
+ A 4xx from the thread's access check closes the socket with 4000 plus the
411
+ status (4403, 4422). A 404 can be a thread the client minted and has yet
412
+ to create, so the socket then waits for a ``run.start``, which checks
413
+ access like any run start, and closes with 4404 if another command comes
414
+ first. Any other failure of the check, a 5xx included, gets the stream
415
+ error frame and a 1011 close, as when the stream fails later.
385
416
  """
386
417
  thread_id = websocket.path_params["thread_id"]
418
+ # Browsers report a refused upgrade only as a 1006 close, so accept first
419
+ # to make the close code readable.
387
420
  await websocket.accept()
421
+ try:
422
+ thread_uuid = validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
423
+ except HTTPException as exc:
424
+ await _close_for_failed_access_check(websocket, exc)
425
+ return
426
+ awaiting_thread = False
427
+ auth_filters: Any = None
428
+ try:
429
+ auth_filters = await Threads.Stream.check_thread_stream_auth(thread_uuid)
430
+ except Exception as exc:
431
+ if not (isinstance(exc, HTTPException) and exc.status_code == 404):
432
+ await _close_for_failed_access_check(websocket, exc)
433
+ return
434
+ awaiting_thread = True
388
435
 
389
436
  async def ws_send_event(event: dict[str, Any]) -> None:
390
437
  await websocket.send_text(orjson.dumps(event).decode("utf-8"))
391
438
 
392
439
  manager = _make_manager(thread_id, send_event=ws_send_event)
393
- manager.start_thread_stream()
394
440
 
395
441
  # Watchdog: when the thread-stream consumer stops, send the error frame
396
442
  # (if it wasn't cancelled) and close the socket, instead of leaving the
@@ -405,7 +451,11 @@ async def _thread_websocket(websocket: WebSocket) -> None:
405
451
  with contextlib.suppress(Exception):
406
452
  await websocket.close(code=1011, reason="thread stream ended")
407
453
 
408
- watchdog = asyncio.create_task(_stream_watchdog())
454
+ def start_stream(filters: Any) -> asyncio.Task[None]:
455
+ manager.start_thread_stream(auth_filters=filters)
456
+ return asyncio.create_task(_stream_watchdog())
457
+
458
+ watchdog = None if awaiting_thread else start_stream(auth_filters)
409
459
 
410
460
  try:
411
461
  while True:
@@ -438,16 +488,30 @@ async def _thread_websocket(websocket: WebSocket) -> None:
438
488
  )
439
489
  continue
440
490
 
491
+ if awaiting_thread and payload["method"] != "run.start":
492
+ await websocket.close(code=4404)
493
+ return
441
494
  response = await manager.handle_command(payload)
442
495
  await websocket.send_text(orjson.dumps(response).decode("utf-8"))
496
+ if awaiting_thread and response.get("type") == "success":
497
+ try:
498
+ auth_filters = await Threads.Stream.check_thread_stream_auth(
499
+ thread_uuid
500
+ )
501
+ except Exception as exc:
502
+ await _close_for_failed_access_check(websocket, exc)
503
+ return
504
+ watchdog = start_stream(auth_filters)
505
+ awaiting_thread = False
443
506
  except WebSocketDisconnect:
444
507
  pass
445
508
  except Exception:
446
509
  logger.exception("Protocol WebSocket error")
447
510
  finally:
448
- watchdog.cancel()
449
- with contextlib.suppress(asyncio.CancelledError, Exception):
450
- await watchdog
511
+ if watchdog is not None:
512
+ watchdog.cancel()
513
+ with contextlib.suppress(asyncio.CancelledError, Exception):
514
+ await watchdog
451
515
  await manager.close()
452
516
 
453
517
 
@@ -507,7 +507,8 @@ FF_CRONS_ENABLED = env("FF_CRONS_ENABLED", cast=bool, default=True)
507
507
  FF_LOG_DROPPED_EVENTS = env("FF_LOG_DROPPED_EVENTS", cast=bool, default=False)
508
508
  FF_LOG_QUERY_AND_PARAMS = env("FF_LOG_QUERY_AND_PARAMS", cast=bool, default=False)
509
509
  # Opt-in handling of drained runs: the server's control signalling to the
510
- # graph and its handling of drained runs, together.
510
+ # graph and its handling of drained runs, together. On, a Postgres-backed
511
+ # replica that is shutting down also drains its in-flight runs.
511
512
  # Off: no control is created or seeded, and GraphDrained lands in the
512
513
  # catch-all error branch.
513
514
  FF_RESUME_DRAINED_RUNS = env("FF_RESUME_DRAINED_RUNS", cast=bool, default=False)
@@ -535,8 +536,6 @@ RESUME_DRAINED_RUNS = _resolve_resume_drained_runs(
535
536
  is_postgres=IS_POSTGRES_BACKEND,
536
537
  langgraph_supported=DRAIN_RESUME_SUPPORT,
537
538
  )
538
- # Not in public docs: internal feature flag
539
- FF_USE_REDIS_QUEUE = env("FF_USE_REDIS_QUEUE", cast=bool, default=True)
540
539
 
541
540
 
542
541
  # Internal flag intended for testing only
@@ -811,7 +810,6 @@ __all__ = [
811
810
  "FF_PYSPY_PROFILING_ENABLED",
812
811
  "FF_PYSPY_PROFILING_MAX_DURATION_SECS",
813
812
  "FF_RESUME_DRAINED_RUNS",
814
- "FF_USE_REDIS_QUEUE",
815
813
  "GRPC_CLIENT_HTTP2_INITIAL_WINDOW_SIZE",
816
814
  "GRPC_CLIENT_MAX_RECV_MSG_BYTES",
817
815
  "GRPC_CLIENT_MAX_SEND_MSG_BYTES",
@@ -10,6 +10,7 @@ guarded and the placeholders below never match or instantiate anything.
10
10
  from __future__ import annotations
11
11
 
12
12
  import contextvars
13
+ import threading
13
14
  from typing import Any
14
15
 
15
16
  # The control of the run whose top-level graph this context is executing. The
@@ -47,17 +48,35 @@ try:
47
48
  The request is visible only where this is provably the run's top-level
48
49
  loop: in a context the server marked for this control (see
49
50
  mark_top_level) and outside any graph node. So the run drains only at
50
- a top-level step boundary, after that step's subgraphs have finished.
51
+ a top-level step boundary, after that step's subgraphs have finished,
52
+ and never before its first step.
51
53
  Graph code inside a node, and threads a node starts, see no drain
52
54
  (drain_requested False, drain_reason None).
53
55
  """
54
56
 
57
+ __slots__ = ("_first_check_done",)
58
+
59
+ def __init__(self) -> None:
60
+ super().__init__()
61
+ self._first_check_done = False
62
+
55
63
  def _visible(self) -> bool:
56
64
  return _TOP_LEVEL_CONTROL.get() is self and not _in_graph_node()
57
65
 
58
66
  @property
59
67
  def drain_requested(self) -> bool:
60
- return self._visible() and RunControl.drain_requested.fget(self)
68
+ if not self._visible():
69
+ return False
70
+ # LangGraph checks once per top-level step boundary, before the
71
+ # step. Only a server drain can be pending at the first check. A
72
+ # run started with a Command has no checkpoint of its own until its
73
+ # first step ends, so if it drained there, its next claim would
74
+ # re-send the Command and LangGraph would apply it again. So a run
75
+ # always completes a step before it drains.
76
+ if not self._first_check_done:
77
+ self._first_check_done = True
78
+ return False
79
+ return RunControl.drain_requested.fget(self)
61
80
 
62
81
  @property
63
82
  def drain_reason(self) -> str | None:
@@ -79,6 +98,11 @@ except ImportError:
79
98
 
80
99
  DRAIN_SUPPORT = False
81
100
 
101
+ # Reason the server passes to request_drain() when its pod is shutting down.
102
+ # Graph code can pass any reason (request_drain() defaults to "shutdown"), so
103
+ # this distinct value is what tells server drains from graph drains in logs.
104
+ SERVER_SHUTDOWN_DRAIN_REASON = "server_shutdown"
105
+
82
106
 
83
107
  def mark_top_level(control: ServerRunControl | None) -> None:
84
108
  """Mark the current context as running ``control``'s top-level graph."""
@@ -92,10 +116,48 @@ def new_run_control() -> ServerRunControl | None:
92
116
  return None
93
117
 
94
118
 
119
+ class RunControlRegistry:
120
+ """Controls of the runs a queue drains at shutdown, keyed by run ID.
121
+
122
+ Workers can finish on background threads (isolated loops), so every access
123
+ takes a lock and ``drain_all`` works on a snapshot. Controls are registered
124
+ before the run starts, and removed only by the claim that registered them,
125
+ so a fast-finishing or superseded claim can't leave or remove the wrong
126
+ entry.
127
+ """
128
+
129
+ def __init__(self) -> None:
130
+ self._lock = threading.Lock()
131
+ self._controls: dict[str, ServerRunControl] = {}
132
+
133
+ def add(self, run_id: Any, control: ServerRunControl) -> None:
134
+ """Register a run's control before the run starts."""
135
+ with self._lock:
136
+ self._controls[str(run_id)] = control
137
+
138
+ def release(self, run_id: Any, control: ServerRunControl | None) -> None:
139
+ """Remove a run's control if it is still the one this claim registered."""
140
+ if control is None:
141
+ return
142
+ with self._lock:
143
+ if self._controls.get(str(run_id)) is control:
144
+ del self._controls[str(run_id)]
145
+
146
+ def drain_all(self, reason: str) -> int:
147
+ """Request a drain from every registered run; return how many."""
148
+ with self._lock:
149
+ controls = list(self._controls.values())
150
+ for control in controls:
151
+ control.request_drain(reason)
152
+ return len(controls)
153
+
154
+
95
155
  __all__ = [
96
156
  "DRAIN_SUPPORT",
157
+ "SERVER_SHUTDOWN_DRAIN_REASON",
97
158
  "GraphDrained",
98
159
  "RunControl",
160
+ "RunControlRegistry",
99
161
  "ServerRunControl",
100
162
  "mark_top_level",
101
163
  "new_run_control",
@@ -46,6 +46,7 @@ from langgraph_api.event_streaming.session import (
46
46
  from langgraph_api.event_streaming.types import Subscription
47
47
  from langgraph_api.feature_flags import FF_V2_EVENT_STREAMING, PREFER_GRPC_CHECKPOINTER
48
48
  from langgraph_api.schema import MultitaskStrategy
49
+ from langgraph_api.validation import sanitize_reserved_keys
49
50
 
50
51
  logger = structlog.stdlib.get_logger(__name__)
51
52
 
@@ -192,6 +193,9 @@ class ThreadRunManager:
192
193
  One ``ThreadRunManager`` is created per connection (HTTP SSE stream or
193
194
  WebSocket). It is not shared across connections — each observer owns
194
195
  its own view of the thread's run stream.
196
+
197
+ ``replay_buffer=False`` keeps no per-run replay buffer, for connections
198
+ that never replay from it.
195
199
  """
196
200
 
197
201
  def __init__(
@@ -202,12 +206,14 @@ class ThreadRunManager:
202
206
  threads: Any,
203
207
  send_event: EventSink | None = None,
204
208
  headers: Mapping[str, str] | None = None,
209
+ replay_buffer: bool = True,
205
210
  ) -> None:
206
211
  self._thread_id = thread_id
207
212
  self._runs = runs
208
213
  self._threads = threads
209
214
  self._send_event = send_event
210
215
  self._headers = headers if headers is not None else {}
216
+ self._replay_buffer = replay_buffer
211
217
  self._session: EventStreamingSession | None = None
212
218
  self._current_run_id: str | None = None
213
219
  self._queued_events: list[dict[str, Any]] = []
@@ -291,7 +297,7 @@ class ThreadRunManager:
291
297
  active=True,
292
298
  )
293
299
 
294
- def start_thread_stream(self) -> None:
300
+ def start_thread_stream(self, *, auth_filters: Any = None) -> None:
295
301
  """Start consuming the thread-level stream for this connection.
296
302
 
297
303
  Always start from the beginning of the thread's event stream
@@ -306,14 +312,19 @@ class ThreadRunManager:
306
312
  produce output…". The SSE/WS sink applies the caller's ``since``
307
313
  as a seq filter on outbound events, and the SDK dedups by
308
314
  ``event_id``, so repeat observers don't see duplicates.
315
+
316
+ ``auth_filters`` is what the route's ``check_thread_stream_auth``
317
+ returned, passed on so the stream doesn't run the read handler again.
309
318
  """
310
319
  if self._thread_source_task is not None:
311
320
  return
312
321
  self._thread_source_task = asyncio.create_task(
313
- self._consume_thread_stream(last_event_id="-")
322
+ self._consume_thread_stream(last_event_id="-", auth_filters=auth_filters)
314
323
  )
315
324
 
316
- async def _consume_thread_stream(self, *, last_event_id: str | None) -> None:
325
+ async def _consume_thread_stream(
326
+ self, *, last_event_id: str | None, auth_filters: Any
327
+ ) -> None:
317
328
  try:
318
329
  async for (
319
330
  event,
@@ -324,6 +335,7 @@ class ThreadRunManager:
324
335
  self._thread_id,
325
336
  stream_modes=["run_modes", "lifecycle"],
326
337
  last_event_id=last_event_id,
338
+ auth_filters=auth_filters,
327
339
  ):
328
340
  if not run_id or run_id == "*":
329
341
  continue
@@ -781,6 +793,9 @@ class ThreadRunManager:
781
793
  if not capabilities.ok:
782
794
  raise ProtocolV2UnsupportedError(capabilities)
783
795
 
796
+ # Drop server-owned configurable and metadata keys before the run
797
+ # config is built, as the REST request parser does for its bodies.
798
+ sanitize_reserved_keys(params)
784
799
  config = params.get("config") if _is_record(params.get("config")) else {}
785
800
 
786
801
  # ``input.respond`` checked its interrupts already and always resumes;
@@ -959,6 +974,7 @@ class ThreadRunManager:
959
974
  get_thread_state=self._make_get_thread_state(thread_id),
960
975
  source=None,
961
976
  send=self._make_send(),
977
+ max_buffer_size=None if self._replay_buffer else 0,
962
978
  )
963
979
 
964
980
  self._session = session
@@ -228,8 +228,8 @@ class EventStreamingSession:
228
228
  ) -> None:
229
229
  if max_buffer_size is None:
230
230
  max_buffer_size = LSD_PROTOCOL_V2_BUFFER_SIZE
231
- if max_buffer_size < 1:
232
- raise ValueError("max_buffer_size must be a positive integer")
231
+ if max_buffer_size < 0:
232
+ raise ValueError("max_buffer_size must be zero or a positive integer")
233
233
  self._run_id = run_id
234
234
  self._thread_id = thread_id
235
235
  self._initial_run = initial_run
@@ -251,6 +251,7 @@ class EventStreamingSession:
251
251
  self._buffer: list[dict[str, Any]] = []
252
252
  self._source_task: asyncio.Task[None] | None = None
253
253
  self._next_seq = 0
254
+ # 0 keeps no replay buffer, for transports that never replay from it.
254
255
  self._max_buffer_size = max_buffer_size
255
256
  self._root_graph_name = "root"
256
257
  self._terminal_lifecycle_emitted = False
@@ -971,7 +972,8 @@ class EventStreamingSession:
971
972
  return _synth_event_id(self._run_id, str(self._next_seq))
972
973
 
973
974
  async def _push_event(self, event: dict[str, Any]) -> None:
974
- self._buffer.append(event)
975
+ if self._max_buffer_size:
976
+ self._buffer.append(event)
975
977
  reporter = get_otlp_metrics_reporter()
976
978
  if len(self._buffer) > self._max_buffer_size:
977
979
  evicted = len(self._buffer) - self._max_buffer_size
@@ -1036,9 +1038,10 @@ class EventStreamingSession:
1036
1038
  callback for events with ``seq > since`` that match the filter,
1037
1039
  then the subscription is activated so live events flow.
1038
1040
 
1039
- Returns the number of events replayed. Used by both the WebSocket
1040
- ``subscription.subscribe`` command and the SSE event stream, which
1041
- accept a body ``since`` cursor to resume after a reconnect.
1041
+ Returns the number of events replayed. Used by the WebSocket
1042
+ ``subscription.subscribe`` and ``subscription.reconnect`` commands;
1043
+ ``since`` resumes after a reconnect. SSE streams replay from the
1044
+ thread's event stream instead.
1042
1045
 
1043
1046
  Raises :class:`ResumeGap` when *since* is older than the
1044
1047
  session's retained buffer head. This lets callers surface a
@@ -68,6 +68,10 @@ logger = structlog.stdlib.get_logger(__name__)
68
68
  # only need graph_id (from metadata) and the thread config.
69
69
  THREAD_METADATA_READ_MASK_PATHS: list[str] = ["metadata", "config"]
70
70
 
71
+ # Read-mask preset for an auth/existence check that discards the thread body;
72
+ # Go's ``repos.ThreadExistenceCheckMask``.
73
+ THREAD_EXISTENCE_CHECK_READ_MASK_PATHS: list[str] = []
74
+
71
75
 
72
76
  THREAD_STATUS_TO_PB = {
73
77
  "idle": enum_thread_status.idle,
@@ -971,13 +975,20 @@ class Threads(Authenticated):
971
975
  stream_modes: list[str] | None = None,
972
976
  last_event_id: str | None = None,
973
977
  ctx: Any = None,
978
+ auth_filters: list[pb.AuthFilter] | None = None,
974
979
  ):
975
- """Stream thread events with their run id for protocol demux."""
976
- auth_filters = await Threads.Stream.handle_event(
977
- ctx,
978
- "read",
979
- Auth.types.ThreadsRead(thread_id=UUID(str(thread_id))),
980
- )
980
+ """Stream thread events with their run id for protocol demux.
981
+
982
+ ``auth_filters`` comes from a ``check_thread_stream_auth`` the
983
+ caller already ran, so the read handler doesn't run twice. With
984
+ ``None``, the handler runs here.
985
+ """
986
+ if auth_filters is None:
987
+ auth_filters = await Threads.Stream.handle_event(
988
+ ctx,
989
+ "read",
990
+ Auth.types.ThreadsRead(thread_id=UUID(str(thread_id))),
991
+ )
981
992
 
982
993
  stream_modes_pb = _map_thread_stream_modes(stream_modes)
983
994
 
@@ -1013,6 +1024,43 @@ class Threads(Authenticated):
1013
1024
  _handle_grpc_error(e)
1014
1025
  raise
1015
1026
 
1027
+ @staticmethod
1028
+ async def check_thread_stream_auth(
1029
+ thread_id: UUID,
1030
+ ctx: Any = None,
1031
+ ) -> list[pb.AuthFilter]:
1032
+ """Raise 403/404 before a thread stream's response starts.
1033
+
1034
+ Same check as the Go ``Stream`` RPC: the thread is looked up only
1035
+ when custom auth returns filters. Without filters, a thread that
1036
+ doesn't exist yet must stay streamable, because the Python SDK
1037
+ opens its lifecycle stream on ``async with client.threads.stream()``,
1038
+ before the ``run.start`` that creates the thread.
1039
+
1040
+ Returns the auth filters for ``join_event_streaming``.
1041
+ """
1042
+ auth_filters = await Threads.Stream.handle_event(
1043
+ ctx,
1044
+ "read",
1045
+ Auth.types.ThreadsRead(thread_id=thread_id),
1046
+ )
1047
+ if not auth_filters:
1048
+ return auth_filters
1049
+ client = await get_shared_client()
1050
+ try:
1051
+ await client.threads.Get(
1052
+ pb.GetThreadRequest(
1053
+ thread_id=pb.UUID(value=_normalize_uuid(thread_id)),
1054
+ filters=auth_filters,
1055
+ read_mask=field_mask_pb2.FieldMask(
1056
+ paths=THREAD_EXISTENCE_CHECK_READ_MASK_PATHS
1057
+ ),
1058
+ )
1059
+ )
1060
+ except AioRpcError as e:
1061
+ _handle_grpc_error(e)
1062
+ return auth_filters
1063
+
1016
1064
  class State(Authenticated):
1017
1065
  # treat this like threads resource
1018
1066
  resource = "threads"
@@ -36,6 +36,7 @@ from langgraph_api.tracing_session import resolve_tracing_session_name
36
36
  from langgraph_api.utils import AsyncConnectionProto, get_auth_ctx, get_user_id
37
37
  from langgraph_api.utils.headers import get_configurable_headers
38
38
  from langgraph_api.utils.uuids import uuid7
39
+ from langgraph_api.validation import strip_reserved
39
40
  from langgraph_api.webhook import validate_webhook_url_or_raise
40
41
 
41
42
  if IS_POSTGRES_OR_GRPC_BACKEND:
@@ -261,6 +262,12 @@ async def create_valid_run(
261
262
  if checkpoint_id:
262
263
  configurable["checkpoint_id"] = str(checkpoint_id)
263
264
  if checkpoint := payload.get("checkpoint"):
265
+ # Cron payloads stored before requests had checkpoint stripped can still carry server-owned keys.
266
+ strip_reserved(
267
+ checkpoint,
268
+ "checkpoint",
269
+ message="Stripped reserved keys from stored checkpoint",
270
+ )
264
271
  configurable.update(checkpoint)
265
272
  configurable.update(get_configurable_headers(headers))
266
273
  # cron_id is server-owned: drop any value merged from the request, then stamp the scheduler's.
@@ -8,6 +8,8 @@ from collections.abc import Mapping
8
8
  import orjson
9
9
  import structlog
10
10
 
11
+ from langgraph_api.validation import RESERVED_CONFIGURABLE_KEYS
12
+
11
13
  logger = structlog.stdlib.get_logger(__name__)
12
14
 
13
15
  LANGSMITH_METADATA = "langsmith-metadata"
@@ -146,6 +148,9 @@ def should_include_header(key: str) -> bool:
146
148
  or key == "authorization"
147
149
  ):
148
150
  return False
151
+ # Server-owned configurable keys are never taken from a request header.
152
+ if key in RESERVED_CONFIGURABLE_KEYS:
153
+ return False
149
154
 
150
155
  include_patterns, exclude_patterns = get_header_patterns("configurable_headers")
151
156
 
@@ -112,7 +112,7 @@ _RESERVED_KEYS_SET = frozenset(RESERVED_CONFIGURABLE_KEYS)
112
112
  _RESERVED_METADATA_KEYS_SET = frozenset(RESERVED_METADATA_KEYS)
113
113
 
114
114
 
115
- def _strip_reserved(
115
+ def strip_reserved(
116
116
  d: dict,
117
117
  location: str,
118
118
  reserved_keys: frozenset[str] = _RESERVED_KEYS_SET,
@@ -134,7 +134,7 @@ def _strip_metadata(d: dict, location: str) -> None:
134
134
  """Strip reserved keys from a ``metadata`` sub-dict if present."""
135
135
  metadata = d.get("metadata")
136
136
  if isinstance(metadata, dict):
137
- _strip_reserved(
137
+ strip_reserved(
138
138
  metadata,
139
139
  location,
140
140
  reserved_keys=_RESERVED_METADATA_KEYS_SET,
@@ -184,22 +184,22 @@ def sanitize_reserved_keys(data: typing.Any, *, strip_metadata: bool = True) ->
184
184
  if isinstance(config, dict):
185
185
  configurable = config.get("configurable")
186
186
  if isinstance(configurable, dict):
187
- _strip_reserved(configurable, "config.configurable")
187
+ strip_reserved(configurable, "config.configurable")
188
188
 
189
189
  # Config schema: top-level configurable
190
190
  configurable = data.get("configurable")
191
191
  if isinstance(configurable, dict):
192
- _strip_reserved(configurable, "configurable")
192
+ strip_reserved(configurable, "configurable")
193
193
 
194
194
  # write schemas: context
195
195
  context = data.get("context")
196
196
  if isinstance(context, dict):
197
- _strip_reserved(context, "context")
197
+ strip_reserved(context, "context")
198
198
 
199
199
  # checkpoint: merged into configurable on run create and when a cron fires
200
200
  checkpoint = data.get("checkpoint")
201
201
  if isinstance(checkpoint, dict):
202
- _strip_reserved(checkpoint, "checkpoint")
202
+ strip_reserved(checkpoint, "checkpoint")
203
203
 
204
204
 
205
205
  def should_strip_reserved_metadata(schema: typing.Any) -> bool: