by-framework 0.2.2.dev9__tar.gz → 0.2.2.dev11__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 (290) hide show
  1. by_framework-0.2.2.dev11/.codex/hooks.json +14 -0
  2. by_framework-0.2.2.dev11/.github/workflows/deploy-smoke-test.yml +66 -0
  3. by_framework-0.2.2.dev11/.github/workflows/verify.yml +16 -0
  4. by_framework-0.2.2.dev11/AGENTS.md +1 -0
  5. by_framework-0.2.2.dev11/CLAUDE.md +205 -0
  6. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/PKG-INFO +26 -3
  7. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/README.md +25 -2
  8. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/README_zh.md +22 -1
  9. by_framework-0.2.2.dev11/deploy/Dockerfile +61 -0
  10. by_framework-0.2.2.dev11/deploy/docker-compose.yml +70 -0
  11. by_framework-0.2.2.dev11/deploy/entrypoint.sh +13 -0
  12. by_framework-0.2.2.dev11/deploy/kubernetes/worker-deployment.yaml +62 -0
  13. by_framework-0.2.2.dev11/docs/architecture/GUARD_AUTHORING.md +62 -0
  14. by_framework-0.2.2.dev11/docs/architecture/KEY_FILES.md +186 -0
  15. by_framework-0.2.2.dev11/docs/architecture/production-deployment.md +142 -0
  16. by_framework-0.2.2.dev11/docs/architecture/redis-cluster-mode.md +85 -0
  17. by_framework-0.2.2.dev11/docs/architecture/worker-readiness-endpoint.md +240 -0
  18. by_framework-0.2.2.dev11/examples/echo_worker.py +24 -0
  19. by_framework-0.2.2.dev11/examples/send_and_verify.py +98 -0
  20. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/pyproject.toml +1 -1
  21. by_framework-0.2.2.dev11/scripts/.map.conf +9 -0
  22. by_framework-0.2.2.dev11/scripts/check-doc-discipline.sh +75 -0
  23. by_framework-0.2.2.dev11/scripts/check-entry-freshness.sh +113 -0
  24. by_framework-0.2.2.dev11/scripts/check-map-territory.sh +34 -0
  25. by_framework-0.2.2.dev11/scripts/map-stop-hook.sh +29 -0
  26. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/scripts/python_quality.sh +2 -1
  27. by_framework-0.2.2.dev11/scripts/test-growth-ladder.sh +103 -0
  28. by_framework-0.2.2.dev11/scripts/verify.sh +76 -0
  29. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/__init__.py +2 -0
  30. by_framework-0.2.2.dev11/src/by_framework/__main__.py +165 -0
  31. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/admin/cli.py +6 -5
  32. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/client/client.py +124 -3
  33. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/config.py +4 -2
  34. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/emitter.py +16 -0
  35. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/__init__.py +2 -0
  36. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/__init__.py +2 -0
  37. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/content_type.py +1 -0
  38. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/responses.py +11 -0
  39. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/registry.py +2 -1
  40. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/app.py +68 -24
  41. by_framework-0.2.2.dev11/src/by_framework/worker/health_server.py +169 -0
  42. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/runner.py +43 -0
  43. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/admin/test_cli.py +30 -0
  44. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/client/test_client.py +345 -0
  45. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/common/test_config.py +56 -0
  46. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/common/test_constants.py +6 -0
  47. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/test_registry.py +32 -0
  48. by_framework-0.2.2.dev11/tests/test_main.py +180 -0
  49. by_framework-0.2.2.dev11/tests/worker/__init__.py +0 -0
  50. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_app.py +179 -0
  51. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_emitter.py +41 -1
  52. by_framework-0.2.2.dev11/tests/worker/test_health_server.py +256 -0
  53. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_runner.py +279 -0
  54. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/uv.lock +1 -1
  55. by_framework-0.2.2.dev9/AGENTS.md +0 -96
  56. by_framework-0.2.2.dev9/CLAUDE.md +0 -98
  57. by_framework-0.2.2.dev9/src/by_framework/__main__.py +0 -86
  58. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.dockerignore +0 -0
  59. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  60. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  61. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  62. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/RELEASING.md +0 -0
  63. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/workflows/ci.yml +0 -0
  64. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/workflows/publish.yml +0 -0
  65. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.github/workflows/stale.yml +0 -0
  66. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.gitignore +0 -0
  67. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/.pre-commit-config.yaml +0 -0
  68. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/CHANGELOG.md +0 -0
  69. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/CODE_OF_CONDUCT.md +0 -0
  70. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/CONTRIBUTING.md +0 -0
  71. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/LICENSE +0 -0
  72. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/Makefile +0 -0
  73. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/SECURITY.md +0 -0
  74. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/assets/img/architecture_en.png +0 -0
  75. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/assets/img/architecture_zh.png +0 -0
  76. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/autoformat.sh +0 -0
  77. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/docs/README.md +0 -0
  78. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/docs/by-framework-trace-change-usage.html +0 -0
  79. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/docs/by-framework-trace-complete-guide.html +0 -0
  80. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/docs/plans/2026-05-15-worker-task-state-stats.md +0 -0
  81. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/docs/plans/2026-06-10-trace-metrics-correlation.md +0 -0
  82. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/docs/worker_management.html +0 -0
  83. {by_framework-0.2.2.dev9/src/by_framework/util → by_framework-0.2.2.dev11/examples}/__init__.py +0 -0
  84. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/README.md +0 -0
  85. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/pyproject.toml +0 -0
  86. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/src/by_framework_adk/__init__.py +0 -0
  87. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/src/by_framework_adk/_utils.py +0 -0
  88. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/src/by_framework_adk/adapter.py +0 -0
  89. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/src/by_framework_adk/worker.py +0 -0
  90. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-adk/tests/test_worker.py +0 -0
  91. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/Dockerfile +0 -0
  92. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/README.md +0 -0
  93. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/frontend/index.html +0 -0
  94. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/frontend/package-lock.json +0 -0
  95. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/frontend/package.json +0 -0
  96. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/frontend/src/main.jsx +0 -0
  97. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/frontend/src/styles.css +0 -0
  98. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/frontend/vite.config.js +0 -0
  99. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/pyproject.toml +0 -0
  100. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/__init__.py +0 -0
  101. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/adapters.py +0 -0
  102. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/dashboard.py +0 -0
  103. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/static/__init__.py +0 -0
  104. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/static/app.js +0 -0
  105. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/static/index.html +0 -0
  106. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/src/by_framework_dashboard/static/styles.css +0 -0
  107. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-dashboard/tests/test_dashboard_server.py +0 -0
  108. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-byclaw/README.md +0 -0
  109. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-byclaw/pyproject.toml +0 -0
  110. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-byclaw/src/by_framework_history_byclaw/__init__.py +0 -0
  111. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-byclaw/src/by_framework_history_byclaw/byclaw_history.py +0 -0
  112. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-byclaw/tests/test_byclaw_history.py +0 -0
  113. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-postgres/README.md +0 -0
  114. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-postgres/pyproject.toml +0 -0
  115. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-postgres/src/by_framework_history_postgres/__init__.py +0 -0
  116. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-postgres/src/by_framework_history_postgres/postgres.py +0 -0
  117. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-history-postgres/tests/test_postgres_history_storage.py +0 -0
  118. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/README.md +0 -0
  119. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/pyproject.toml +0 -0
  120. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/src/by_framework_langgraph/__init__.py +0 -0
  121. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/src/by_framework_langgraph/_utils.py +0 -0
  122. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/src/by_framework_langgraph/adapter.py +0 -0
  123. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/src/by_framework_langgraph/tools.py +0 -0
  124. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/src/by_framework_langgraph/worker.py +0 -0
  125. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/tests/test_adapter.py +0 -0
  126. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/tests/test_tools.py +0 -0
  127. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-langgraph/tests/test_utils.py +0 -0
  128. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-langfuse/README.md +0 -0
  129. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-langfuse/pyproject.toml +0 -0
  130. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/__init__.py +0 -0
  131. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/langfuse.py +0 -0
  132. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-langfuse/tests/test_langfuse_import.py +0 -0
  133. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-phoenix/README.md +0 -0
  134. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-phoenix/pyproject.toml +0 -0
  135. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-phoenix/src/by_framework_trace_phoenix/__init__.py +0 -0
  136. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-phoenix/src/by_framework_trace_phoenix/phoenix.py +0 -0
  137. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-phoenix/tests/test_phoenix_import.py +0 -0
  138. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-phoenix/tests/test_phoenix_plugin.py +0 -0
  139. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/pyproject.toml +0 -0
  140. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/src/by_framework_trace_query/__init__.py +0 -0
  141. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/src/by_framework_trace_query/client.py +0 -0
  142. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/src/by_framework_trace_query/merger.py +0 -0
  143. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/src/by_framework_trace_query/models.py +0 -0
  144. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/src/by_framework_trace_query/redis_source.py +0 -0
  145. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/libs/by-framework-trace-query/tests/test_trace_query_sdk.py +0 -0
  146. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/pylintrc +0 -0
  147. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/admin/__init__.py +0 -0
  148. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/admin/worker_manager.py +0 -0
  149. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/client/__init__.py +0 -0
  150. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/client/byai_client.py +0 -0
  151. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/__init__.py +0 -0
  152. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/constants.py +0 -0
  153. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/exceptions.py +0 -0
  154. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/logger.py +0 -0
  155. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/common/redis_client.py +0 -0
  156. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/availability.py +0 -0
  157. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/delivery_gate.py +0 -0
  158. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/discovery.py +0 -0
  159. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/extensions/__init__.py +0 -0
  160. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/extensions/agent_config.py +0 -0
  161. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/extensions/agent_config_audit.py +0 -0
  162. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/extensions/plugin.py +0 -0
  163. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/extensions/registry.py +0 -0
  164. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/extensions/trace_provider.py +0 -0
  165. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/action_type.py +0 -0
  166. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/agent_state.py +0 -0
  167. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/byai_codec.py +0 -0
  168. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/byai_command.py +0 -0
  169. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/byai_types.py +0 -0
  170. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/commands.py +0 -0
  171. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/content_codec.py +0 -0
  172. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/data_message.py +0 -0
  173. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/data_shapes.py +0 -0
  174. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/event_type.py +0 -0
  175. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/events.py +0 -0
  176. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/message.py +0 -0
  177. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/message_header.py +0 -0
  178. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/protocol/results.py +0 -0
  179. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/__init__.py +0 -0
  180. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/agent_config_manager.py +0 -0
  181. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/agent_runtime_state.py +0 -0
  182. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/file_manager.py +0 -0
  183. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/file_paths.py +0 -0
  184. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/file_permissions.py +0 -0
  185. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/filestore/__init__.py +0 -0
  186. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/filestore/base.py +0 -0
  187. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/filestore/local.py +0 -0
  188. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/history/__init__.py +0 -0
  189. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/history/base.py +0 -0
  190. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/history/history_manager.py +0 -0
  191. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/history/in_memory.py +0 -0
  192. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/runtime/session_manager.py +0 -0
  193. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/wakeup_controller.py +0 -0
  194. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/core/workspace.py +0 -0
  195. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/__init__.py +0 -0
  196. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/base.py +0 -0
  197. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/common.py +0 -0
  198. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/execution.py +0 -0
  199. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/http.py +0 -0
  200. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/protocol.py +0 -0
  201. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/errors/registry.py +0 -0
  202. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/metrics/__init__.py +0 -0
  203. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/metrics/catalog.py +0 -0
  204. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/metrics/collector.py +0 -0
  205. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/metrics/read_client.py +0 -0
  206. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/metrics/snapshot.py +0 -0
  207. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/trace/__init__.py +0 -0
  208. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/trace/external_trace.py +0 -0
  209. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/trace/span_recorder.py +0 -0
  210. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/trace/trace_schema.py +0 -0
  211. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/trace/trace_writer.py +0 -0
  212. {by_framework-0.2.2.dev9/src/by_framework/worker/sandbox → by_framework-0.2.2.dev11/src/by_framework/util}/__init__.py +0 -0
  213. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/util/discovery_http_client.py +0 -0
  214. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/util/generate_message_id.py +0 -0
  215. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/util/http_client.py +0 -0
  216. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/__init__.py +0 -0
  217. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/_control_handling.py +0 -0
  218. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/_execution_tracking.py +0 -0
  219. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/_message_processing.py +0 -0
  220. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/byai_context.py +0 -0
  221. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/byai_worker.py +0 -0
  222. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/context.py +0 -0
  223. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/heartbeat.py +0 -0
  224. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/processor.py +0 -0
  225. {by_framework-0.2.2.dev9/tests/admin → by_framework-0.2.2.dev11/src/by_framework/worker/sandbox}/__init__.py +0 -0
  226. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/sandbox/hook_sandbox.py +0 -0
  227. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/src/by_framework/worker/worker.py +0 -0
  228. {by_framework-0.2.2.dev9/tests/client → by_framework-0.2.2.dev11/tests/admin}/__init__.py +0 -0
  229. {by_framework-0.2.2.dev9/tests/common → by_framework-0.2.2.dev11/tests/client}/__init__.py +0 -0
  230. {by_framework-0.2.2.dev9/tests/core → by_framework-0.2.2.dev11/tests/common}/__init__.py +0 -0
  231. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/common/test_exceptions.py +0 -0
  232. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/common/test_logger.py +0 -0
  233. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/common/test_redis_client.py +0 -0
  234. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/conftest.py +0 -0
  235. {by_framework-0.2.2.dev9/tests/core/protocol → by_framework-0.2.2.dev11/tests/core}/__init__.py +0 -0
  236. {by_framework-0.2.2.dev9/tests/core/runtime/history → by_framework-0.2.2.dev11/tests/core/protocol}/__init__.py +0 -0
  237. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/protocol/test_byai_codec.py +0 -0
  238. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/protocol/test_command_wire.py +0 -0
  239. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/protocol/test_protocol.py +0 -0
  240. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/protocol/test_results.py +0 -0
  241. {by_framework-0.2.2.dev9/tests/integration → by_framework-0.2.2.dev11/tests/core/runtime/history}/__init__.py +0 -0
  242. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/history/test_history_persistence.py +0 -0
  243. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_file_access_context.py +0 -0
  244. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_file_manager_default_storage.py +0 -0
  245. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_file_paths.py +0 -0
  246. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_file_permissions.py +0 -0
  247. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_filestore_local_collection.py +0 -0
  248. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_filestore_local_mutation.py +0 -0
  249. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_filestore_local_read.py +0 -0
  250. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/runtime/test_filestore_local_search.py +0 -0
  251. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/test_agent_config_audit.py +0 -0
  252. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/test_availability.py +0 -0
  253. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/test_discovery.py +0 -0
  254. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/core/test_worker_manager.py +0 -0
  255. {by_framework-0.2.2.dev9/tests/plugin → by_framework-0.2.2.dev11/tests/integration}/__init__.py +0 -0
  256. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/integration/test_ask_user_flow.py +0 -0
  257. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/integration/test_callback_flow.py +0 -0
  258. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/integration/test_logger_integration.py +0 -0
  259. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/integration/test_scatter_gather.py +0 -0
  260. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/metrics/test_catalog.py +0 -0
  261. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/metrics/test_collector.py +0 -0
  262. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/metrics/test_metrics.py +0 -0
  263. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/metrics/test_read_client.py +0 -0
  264. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/metrics/test_snapshot.py +0 -0
  265. {by_framework-0.2.2.dev9/tests/worker → by_framework-0.2.2.dev11/tests/plugin}/__init__.py +0 -0
  266. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/plugin/test_langfuse_plugin.py +0 -0
  267. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/plugin/test_plugin_discovery.py +0 -0
  268. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/plugin/test_plugin_improvements.py +0 -0
  269. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/plugin/test_plugin_registry.py +0 -0
  270. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/plugin/test_plugin_system.py +0 -0
  271. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/trace/test_external_trace.py +0 -0
  272. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/trace/test_logger_correlation.py +0 -0
  273. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/trace/test_otel_exporter.py +0 -0
  274. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/trace/test_span_recorder.py +0 -0
  275. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/trace/test_trace_writer.py +0 -0
  276. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/util/test_discovery_http_client.py +0 -0
  277. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/util/test_discovery_http_client_download.py +0 -0
  278. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/util/test_discovery_http_client_upload.py +0 -0
  279. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/util/test_http_client.py +0 -0
  280. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_admin_control_handling.py +0 -0
  281. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_byai_worker.py +0 -0
  282. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_context.py +0 -0
  283. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_control_handling.py +0 -0
  284. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_fetch_messages.py +0 -0
  285. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_gateway_worker.py +0 -0
  286. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_heartbeat.py +0 -0
  287. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_message_processing.py +0 -0
  288. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_processor.py +0 -0
  289. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_sandbox.py +0 -0
  290. {by_framework-0.2.2.dev9 → by_framework-0.2.2.dev11}/tests/worker/test_workspace.py +0 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "hooks": {
3
+ "Stop": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "bash scripts/map-stop-hook.sh"
9
+ }
10
+ ]
11
+ }
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1,66 @@
1
+ name: Deploy Smoke Test
2
+
3
+ # Validates deploy/'s Dockerfile + docker-compose.yml actually deliver a
4
+ # message through the full pipeline - client sends -> Redis control stream
5
+ # -> Worker consumes -> Worker replies -> Redis data stream -> client reads
6
+ # - using examples/echo_worker.py, built from THIS commit's source (not the
7
+ # last PyPI release; see deploy/Dockerfile's BY_FRAMEWORK_SOURCE=local mode).
8
+ # See docs/architecture/production-deployment.md.
9
+
10
+ on:
11
+ pull_request:
12
+ paths:
13
+ - "deploy/**"
14
+ - "examples/**"
15
+ - "src/by_framework/**"
16
+ - "pyproject.toml"
17
+ - "uv.lock"
18
+ - ".github/workflows/deploy-smoke-test.yml"
19
+ push:
20
+ branches:
21
+ - main
22
+ - master
23
+ paths:
24
+ - "deploy/**"
25
+ - "examples/**"
26
+ - "src/by_framework/**"
27
+ workflow_dispatch:
28
+
29
+ jobs:
30
+ smoke-test:
31
+ runs-on: ubuntu-latest
32
+ env:
33
+ BY_FRAMEWORK_SOURCE: local
34
+ WORKER_CLASS: examples.echo_worker.EchoWorker
35
+ REDIS_HOST: localhost
36
+ REDIS_PORT: "6379"
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ - uses: actions/setup-python@v5
40
+ with:
41
+ python-version: "3.12"
42
+ - uses: astral-sh/setup-uv@v5
43
+
44
+ - name: Install by-framework (for the verify client script below)
45
+ run: uv sync
46
+
47
+ # --wait blocks until every service with a healthcheck (redis, and now
48
+ # worker's own /readyz-backed HEALTHCHECK - see
49
+ # docs/architecture/worker-readiness-endpoint.md) reports healthy, and
50
+ # fails the step if that doesn't happen in time. This is the actual
51
+ # verification that the readiness endpoint works end to end in a real
52
+ # container - not just that the Python contract tests pass.
53
+ - name: Build and start Redis + Worker via deploy/docker-compose.yml
54
+ run: |
55
+ docker compose -f deploy/docker-compose.yml up --build -d --wait --wait-timeout 60
56
+
57
+ - name: Send a message and verify the Worker echoes it back
58
+ run: uv run python examples/send_and_verify.py
59
+
60
+ - name: Worker logs
61
+ if: always()
62
+ run: docker compose -f deploy/docker-compose.yml logs worker
63
+
64
+ - name: Tear down
65
+ if: always()
66
+ run: docker compose -f deploy/docker-compose.yml down -v
@@ -0,0 +1,16 @@
1
+ name: verify
2
+ on: [push, pull_request]
3
+ jobs:
4
+ verify:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - uses: actions/checkout@v4
8
+ with: { fetch-depth: 0 }
9
+ - name: resolve map base ref
10
+ run: |
11
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
12
+ echo "MAP_BASE_REF=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_ENV"
13
+ elif git cat-file -e "${{ github.event.before }}" 2>/dev/null; then
14
+ echo "MAP_BASE_REF=${{ github.event.before }}" >> "$GITHUB_ENV"
15
+ fi
16
+ - run: bash scripts/verify.sh
@@ -0,0 +1 @@
1
+ CLAUDE.md
@@ -0,0 +1,205 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) and Codex when working with code in this repository. (`AGENTS.md` is a symlink to this file — one copy, no drift between agent ecosystems.)
4
+
5
+ ## North Star
6
+
7
+ `by-framework-python` lets agent workloads scale horizontally across Redis
8
+ Streams without losing execution identity or silently corrupting shared
9
+ state under partial failure — a worker restart, Cluster-mode operation, a
10
+ misconfigured plugin, or a delayed `ask_user` reply. When a trade-off isn't
11
+ covered by an explicit rule, prefer a change that fails loudly (raise,
12
+ warn-log) or degrades safely (no-op, skip) over one that could silently
13
+ drop, duplicate, orphan, or misroute an execution, a message, or a
14
+ heartbeat — this repo's fix-commit history is dominated by exactly that
15
+ failure shape.
16
+
17
+ ## Core mental model
18
+
19
+ 1. **Control plane vs. data plane are separate Redis Streams, never
20
+ conflated.** Commands travel on per-agent-type control streams
21
+ (competitive consume via consumer groups); output travels on
22
+ session-scoped data streams. Misrouting one onto the other silently
23
+ breaks delivery.
24
+ 2. **An execution's identity must survive suspend/resume, not just
25
+ request/response.** A task can suspend (`ask_user`, or a `call_agent`
26
+ hop) and later resume via a `RESUME` dispatch that must reattach to the
27
+ *original* `execution_id` via the registry lookup — treating every
28
+ dispatch as "mint a new execution" silently orphans the suspended one.
29
+ This was the single most-recurring bug class in this repo's history (fix
30
+ 90764e1, closing #75/#76/#77).
31
+
32
+ ## Project Overview
33
+
34
+ `by-framework` is a distributed, high-performance Agent scheduling engine built on Redis Streams. It provides a framework for building AI agents with self-driven orchestration and sandbox isolation capabilities.
35
+
36
+ ## Build Commands
37
+
38
+ ```bash
39
+ # Install dependencies
40
+ make install
41
+
42
+ # Format code (isort + ruff + pyink)
43
+ make format
44
+
45
+ # Lint code (pylint + ruff)
46
+ make lint
47
+
48
+ # Run all tests
49
+ make test
50
+
51
+ # Run a single test file
52
+ uv run pytest tests/worker/test_gateway_worker.py
53
+
54
+ # Run tests matching a pattern
55
+ uv run pytest -k "test_name_pattern"
56
+ ```
57
+
58
+ ## Architecture
59
+
60
+ ### Core Data Flow
61
+
62
+ ```
63
+ Client → Redis Input MQ (queue:ctrl:{agent_type}) → GatewayWorker
64
+
65
+ Redis Data MQ (queue:data:stream)
66
+
67
+ WebSocket Backend
68
+ ```
69
+
70
+ ### Key Components
71
+
72
+ | Component | Location | Purpose |
73
+ |-----------|----------|---------|
74
+ | `GatewayWorker` | `src/by_framework/worker/worker.py` | Abstract base class for workers; implement `get_capabilities()` and `process_command()` |
75
+ | `AgentContext` | `src/by_framework/worker/context.py` | Runtime context for task execution; emits chunks, states, artifacts; calls other agents |
76
+ | `run_worker()` | `src/by_framework/worker/app.py` | Main entry point for starting a worker |
77
+ | `GatewayClient` | `src/by_framework/client/client.py` | Sends commands to Redis Streams |
78
+ | `ByaiGatewayClient` | `src/by_framework/client/byai_client.py` | GatewayClient with ByaiMessageInterceptor |
79
+ | `Plugin` | `src/by_framework/core/extensions/plugin.py` | Abstract base for extensible plugins with lifecycle hooks |
80
+ | `PluginRegistry` | `src/by_framework/core/extensions/registry.py` | Manages plugin registration and discovery |
81
+
82
+ ### Protocol System
83
+
84
+ Commands and events are defined in `src/by_framework/core/protocol/`:
85
+ - `commands.py` - `AskAgentCommand`, `CancelTaskCommand`, `ResumeCommand`
86
+ - `events.py` - `StreamChunkEvent`, `StateChangeEvent`, `ArtifactEvent`
87
+ - `message_header.py` - `MessageHeader` with session_id, trace_id, message_id
88
+
89
+ ### Plugin Lifecycle Hooks
90
+
91
+ Plugins can implement: `on_worker_startup`, `on_worker_shutdown`, `on_task_start`, `on_task_complete`, `on_task_error`, `on_task_cancel`
92
+
93
+ ### Redis Key Patterns
94
+
95
+ - `byai_gateway:ctrl:agent_type:{agent_type}` — Control stream; competitive consume per agent type
96
+ - `byai_gateway:ctrl:worker:{worker_id}` — Direct per-worker routing
97
+ - `byai_gateway:session:{session_id}:data_stream` — Session-scoped output events
98
+ - `byai_gateway:registry:worker:online:{worker_id}` — Heartbeat TTL key
99
+ - `byai_gateway:task_group:{group_id}` — Scatter-gather group tracker
100
+
101
+ Connection precedence and Cluster-mode/key-schema-versioning details: see
102
+ the Reference map below, not repeated here.
103
+
104
+ ## Test Structure
105
+
106
+ Tests are organized by module in `tests/`:
107
+ - `tests/common/` - Logger, redis client, config, exceptions
108
+ - `tests/core/` - Registry, protocol, history
109
+ - `tests/worker/` - Worker, context, processor, sandbox
110
+ - `tests/client/` - Client functionality
111
+ - `tests/plugin/` - Plugin system and discovery
112
+ - `tests/integration/` - Cross-component flows (scatter-gather, callbacks, ask_user)
113
+
114
+ ## Code Style
115
+
116
+ - **Import sorting**: isort
117
+ - **Formatting**: ruff-format + pyink
118
+ - **Linting**: pylint (with `pylintrc`) + ruff
119
+ - **Testing**: pytest with pytest-asyncio
120
+
121
+ Pre-commit hooks are configured in `.pre-commit-config.yaml` and run isort, ruff, pylint, pyink, and general checks.
122
+
123
+ ## Development Notes
124
+
125
+ - Package is at `src/by_framework/` (configured in `pyproject.toml`)
126
+ - `pythonpath = ["src"]` is set in pytest config
127
+ - Redis 7.0+ is required for Streams functionality
128
+ - Worker capabilities are declared via `get_capabilities()` and used for task routing
129
+
130
+ ## Cross-cutting invariants
131
+
132
+ - **An explicitly-passed kwarg must never be silently discarded because a
133
+ config object's corresponding field defaults to `None`/"unset."** Incident:
134
+ fix 6ec070c — `redis_client.init_redis()` let `config.max_connections`
135
+ (default `None`, meaning "not specified") unconditionally override an
136
+ explicitly-passed `max_connections` kwarg, discarding
137
+ `worker/app.py`'s `max_concurrency`-derived pool size. Correct form:
138
+ `if config.<field> is not None: value = config.<field>` — only let the
139
+ config object win when it was actually set. No dedicated guard yet;
140
+ applies to any new `Optional[...] = None` config field.
141
+
142
+ - **Plugin/trace hook code must fail soft (log + return/`None`), never raise
143
+ into the primary task-execution or worker-startup path.** Incident: fix
144
+ 8b5bf93 — `LangfusePlugin._build_default_tracer()` used to `raise
145
+ RuntimeError` when Langfuse env vars were unset, which would have broken
146
+ worker startup for anyone with the plugin auto-discovered but
147
+ unconfigured; changed to log + return `None`, with every call site guarded.
148
+ Reinforced by `core/extensions/registry.py`'s `_execute_hook()`, which
149
+ wraps every plugin lifecycle hook in try/except + timeout handling so no
150
+ hook exception ever propagates to the caller. Correct form: any new
151
+ plugin/trace integration point must degrade to a no-op (logged) rather
152
+ than raising.
153
+
154
+ ## Iron rules
155
+
156
+ <!-- No process rules (test invocation, release steps) have caused an
157
+ incident yet — entries land here only via a real trigger (see
158
+ "Maintaining this map" below), never invented up front. -->
159
+
160
+ ## Reference map
161
+
162
+ | When you're working on... | Read first |
163
+ |---|---|
164
+ | any source file | `docs/architecture/KEY_FILES.md` — find the file's entry |
165
+ | Redis connection setup, cluster-mode, or key-schema versioning (`RedisConfig`, `RedisKeys`, `_get_redis()`, admin-index writes) | `docs/architecture/redis-cluster-mode.md` |
166
+ | Worker deployment/production-readiness — README's 部署 section, `__main__.py` CLI flags, `run_worker()`'s signature, or shutdown/signal handling | `docs/architecture/production-deployment.md` |
167
+ | Worker readiness/health-check endpoint (`WorkerHealthServer`, `/readyz`, `--health-port`) — building it, or touching anything that changes what "ready" means | `docs/architecture/worker-readiness-endpoint.md` |
168
+
169
+ ## Maintaining this map
170
+
171
+ The map grows only on triggers — never speculatively:
172
+
173
+ 1. **After an incident** — write the postmortem in `docs/incidents/`
174
+ (append-only is legal there), then ask "what grep would have prevented
175
+ this" → a new guard, or an append to an existing one.
176
+ 2. **After editing a load-bearing file** — rewrite its KEY_FILES entry in
177
+ place. Behaviour changed means the entry changes; never append history.
178
+ 3. **Same mistake twice** — triage into exactly one layer:
179
+ machine-checkable → guard in `scripts/verify.sh`'s CHECKS;
180
+ cross-cutting → quad bullet above;
181
+ domain detail → docs/ file + a Reference-map row.
182
+ 4. **Explored a subsystem to do a task and no doc held it** — diarize it into
183
+ `docs/architecture/<x>.md` + a Reference-map row while the understanding is
184
+ hot. Don't make the next agent re-read the same files to learn the same
185
+ thing.
186
+ 5. **A rule is already known — no incident needed** — someone states a
187
+ requirement up front (deployment steps, a naming convention, whatever).
188
+ Don't wait for it to bite twice: triage it right now, same three-way
189
+ split as every other find. Machine can check it → write a guard per
190
+ `docs/architecture/GUARD_AUTHORING.md`, register it in `verify.sh`'s
191
+ `CHECKS`. Only judgement can check it → a quad-bullet above — **unless
192
+ two or more existing bullets already cover the same concern** (e.g.
193
+ several deployment steps), in which case lift the whole cluster into a
194
+ `docs/` file + Reference-map row instead of adding a third bullet. Same
195
+ move as "Diarize a subsystem" for file entries: one doc per concern
196
+ beats a pile of bullets that only gets noticed at the next size-cap
197
+ surgery. Domain detail from the start → a `docs/` file + a Reference-map
198
+ row, no waiting to accumulate.
199
+
200
+ Guards: `bash scripts/verify.sh` before every push (kept under 30s).
201
+ Growth enforcement: `check-entry-freshness.sh` warns in verify on stale
202
+ entries, unindexed new source files, and untriaged fix commits; the Stop
203
+ hook (`scripts/map-stop-hook.sh`, wired into `.claude/settings.json` and
204
+ `.codex/hooks.json`) blocks session end once until stale entries are
205
+ rewritten or declared unchanged.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: by-framework
3
- Version: 0.2.2.dev9
3
+ Version: 0.2.2.dev11
4
4
  Summary: 分布式 Agent 调度框架
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -250,6 +250,13 @@ async def main():
250
250
  asyncio.run(main())
251
251
  ```
252
252
 
253
+ A runnable version of this pair lives at
254
+ [`examples/echo_worker.py`](examples/echo_worker.py) (Worker) and
255
+ [`examples/send_and_verify.py`](examples/send_and_verify.py) (client — blocks
256
+ until it sees the echoed reply) — the same pair `deploy/`'s CI smoke test
257
+ drives end to end, see
258
+ [`docs/architecture/production-deployment.md`](docs/architecture/production-deployment.md).
259
+
253
260
  ---
254
261
 
255
262
  ## Core Concepts
@@ -602,7 +609,7 @@ Tests are organized by module under `tests/`:
602
609
 
603
610
  ```bash
604
611
  # 1. Start Redis
605
- docker run -d --name by-redis -p 6379:6379 registry:7-alpine
612
+ docker run -d --name by-redis -p 6379:6379 redis:7-alpine
606
613
 
607
614
  # 2. Start a Worker
608
615
  python -m by_framework \
@@ -621,11 +628,27 @@ python -m by_framework --worker-class my_agent.MyAgent --worker-id worker-02 &
621
628
  python -m by_framework --worker-class my_agent.MyAgent --worker-id worker-03 &
622
629
  ```
623
630
 
631
+ `&` is fine for a quick local check but isn't real process supervision — for
632
+ an actual deployment, use the reference Dockerfile, Compose file, and
633
+ Kubernetes Deployment under [`deploy/`](deploy/):
634
+
635
+ ```bash
636
+ # Docker Compose — N supervised replicas, distinct worker ids, restart policy
637
+ docker compose -f deploy/docker-compose.yml up --build --scale worker=3
638
+
639
+ # Kubernetes — same idea as a Deployment
640
+ kubectl apply -f deploy/kubernetes/worker-deployment.yaml
641
+ ```
642
+
643
+ The CLI also exposes `--redis-password`, `--redis-username`, `--redis-mode`,
644
+ and `--redis-cluster-nodes` (all mirrored by the `REDIS_*` env vars used in
645
+ the Compose/Kubernetes examples above) — see `python -m by_framework --help`.
646
+
624
647
  ### Reliability
625
648
 
626
649
  - **Message persistence:** Messages are stored in Redis Streams until explicitly acknowledged (`XACK`). Unacknowledged messages are redelivered on Worker restart.
627
650
  - **Durable config:** Agent config snapshots are persisted to Redis, so a restarted Worker recovers the last-known plugin configuration.
628
- - **Gradual shutdown:** `WorkerRunner` drains in-flight tasks before shutting down, acknowledging completed work.
651
+ - **Graceful shutdown:** `WorkerRunner` drains in-flight tasks before shutting down, acknowledging completed work. This is wired to both `SIGINT` (Ctrl+C) and `SIGTERM` — the signal `docker stop`/Kubernetes pod termination actually send — so it fires under real container orchestration, not just an interactive terminal. Give it enough `stop_grace_period`/`terminationGracePeriodSeconds` to cover your longest task (see the `deploy/` examples), since a hard `SIGKILL` after the grace period skips the drain entirely.
629
652
  - **Separate data path:** Data output goes to session-scoped streams independently of control, so backend consumers are decoupled from Worker scaling.
630
653
 
631
654
  ### Logging
@@ -221,6 +221,13 @@ async def main():
221
221
  asyncio.run(main())
222
222
  ```
223
223
 
224
+ A runnable version of this pair lives at
225
+ [`examples/echo_worker.py`](examples/echo_worker.py) (Worker) and
226
+ [`examples/send_and_verify.py`](examples/send_and_verify.py) (client — blocks
227
+ until it sees the echoed reply) — the same pair `deploy/`'s CI smoke test
228
+ drives end to end, see
229
+ [`docs/architecture/production-deployment.md`](docs/architecture/production-deployment.md).
230
+
224
231
  ---
225
232
 
226
233
  ## Core Concepts
@@ -573,7 +580,7 @@ Tests are organized by module under `tests/`:
573
580
 
574
581
  ```bash
575
582
  # 1. Start Redis
576
- docker run -d --name by-redis -p 6379:6379 registry:7-alpine
583
+ docker run -d --name by-redis -p 6379:6379 redis:7-alpine
577
584
 
578
585
  # 2. Start a Worker
579
586
  python -m by_framework \
@@ -592,11 +599,27 @@ python -m by_framework --worker-class my_agent.MyAgent --worker-id worker-02 &
592
599
  python -m by_framework --worker-class my_agent.MyAgent --worker-id worker-03 &
593
600
  ```
594
601
 
602
+ `&` is fine for a quick local check but isn't real process supervision — for
603
+ an actual deployment, use the reference Dockerfile, Compose file, and
604
+ Kubernetes Deployment under [`deploy/`](deploy/):
605
+
606
+ ```bash
607
+ # Docker Compose — N supervised replicas, distinct worker ids, restart policy
608
+ docker compose -f deploy/docker-compose.yml up --build --scale worker=3
609
+
610
+ # Kubernetes — same idea as a Deployment
611
+ kubectl apply -f deploy/kubernetes/worker-deployment.yaml
612
+ ```
613
+
614
+ The CLI also exposes `--redis-password`, `--redis-username`, `--redis-mode`,
615
+ and `--redis-cluster-nodes` (all mirrored by the `REDIS_*` env vars used in
616
+ the Compose/Kubernetes examples above) — see `python -m by_framework --help`.
617
+
595
618
  ### Reliability
596
619
 
597
620
  - **Message persistence:** Messages are stored in Redis Streams until explicitly acknowledged (`XACK`). Unacknowledged messages are redelivered on Worker restart.
598
621
  - **Durable config:** Agent config snapshots are persisted to Redis, so a restarted Worker recovers the last-known plugin configuration.
599
- - **Gradual shutdown:** `WorkerRunner` drains in-flight tasks before shutting down, acknowledging completed work.
622
+ - **Graceful shutdown:** `WorkerRunner` drains in-flight tasks before shutting down, acknowledging completed work. This is wired to both `SIGINT` (Ctrl+C) and `SIGTERM` — the signal `docker stop`/Kubernetes pod termination actually send — so it fires under real container orchestration, not just an interactive terminal. Give it enough `stop_grace_period`/`terminationGracePeriodSeconds` to cover your longest task (see the `deploy/` examples), since a hard `SIGKILL` after the grace period skips the drain entirely.
600
623
  - **Separate data path:** Data output goes to session-scoped streams independently of control, so backend consumers are decoupled from Worker scaling.
601
624
 
602
625
  ### Logging
@@ -221,6 +221,11 @@ async def main():
221
221
  asyncio.run(main())
222
222
  ```
223
223
 
224
+ 可运行的完整版本见 [`examples/echo_worker.py`](examples/echo_worker.py)(Worker)和
225
+ [`examples/send_and_verify.py`](examples/send_and_verify.py)(客户端,会一直等到收到回显再退出)——
226
+ `deploy/` 下的 CI 冒烟测试用的就是这一对,见
227
+ [`docs/architecture/production-deployment.md`](docs/architecture/production-deployment.md)。
228
+
224
229
  ---
225
230
 
226
231
  ## 核心概念
@@ -592,11 +597,27 @@ python -m by_framework --worker-class my_agent.MyAgent --worker-id worker-02 &
592
597
  python -m by_framework --worker-class my_agent.MyAgent --worker-id worker-03 &
593
598
  ```
594
599
 
600
+ `&` 适合本地快速验证,但不是真正的进程编排——实际部署请使用
601
+ [`deploy/`](deploy/) 目录下的参考 Dockerfile、Compose 文件和 Kubernetes
602
+ Deployment:
603
+
604
+ ```bash
605
+ # Docker Compose —— N 个受进程守护的副本,各自独立的 worker id、重启策略
606
+ docker compose -f deploy/docker-compose.yml up --build --scale worker=3
607
+
608
+ # Kubernetes —— 同样的思路,写成 Deployment
609
+ kubectl apply -f deploy/kubernetes/worker-deployment.yaml
610
+ ```
611
+
612
+ CLI 现在也支持 `--redis-password`、`--redis-username`、`--redis-mode`、
613
+ `--redis-cluster-nodes`(与上面 Compose/Kubernetes 示例里用的 `REDIS_*`
614
+ 环境变量一一对应)——见 `python -m by_framework --help`。
615
+
595
616
  ### 可靠性
596
617
 
597
618
  - **消息持久化:** 消息存储在 Redis Streams 中,直到显式确认(`XACK`)。未确认的消息在 Worker 重启后重新投递。
598
619
  - **配置持久化:** Agent 配置快照持久化到 Redis,Worker 重启后恢复上次已知配置。
599
- - **优雅退出:** `WorkerRunner` 在退出前排空进行中的任务,确认已完成的工作。
620
+ - **优雅退出:** `WorkerRunner` 在退出前排空进行中的任务,确认已完成的工作。这一逻辑同时挂在 `SIGINT`(Ctrl+C)和 `SIGTERM`——也就是 `docker stop`/Kubernetes Pod 终止实际发送的信号——上,因此在真实容器编排下也能触发,而不仅是交互式终端里的 Ctrl+C。请给 `stop_grace_period`/`terminationGracePeriodSeconds` 留出覆盖最长任务耗时的余量(见 `deploy/` 示例),因为宽限期后的强制 `SIGKILL` 会完全跳过排空过程。
600
621
  - **数据与控制分离:** 数据输出到会话级 Stream,与 Worker 扩缩容解耦。
601
622
 
602
623
  ### 日志
@@ -0,0 +1,61 @@
1
+ # syntax=docker/dockerfile:1
2
+ #
3
+ # Template Dockerfile for a by-framework Worker. This installs the published
4
+ # `by-framework` package from PyPI and expects YOUR worker code (the module
5
+ # containing your GatewayWorker subclass) to sit next to this Dockerfile in
6
+ # the build context - copy this file into your own project and adjust the
7
+ # COPY line and the default --worker-class below.
8
+ #
9
+ # Build: docker build -f deploy/Dockerfile -t my-agent-worker .
10
+ # Run: docker run --rm -e REDIS_HOST=redis my-agent-worker \
11
+ # --worker-class my_agent.MyAgent
12
+
13
+ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
14
+
15
+ ENV PYTHONUNBUFFERED=1 \
16
+ PATH="/opt/venv/bin:${PATH}"
17
+
18
+ WORKDIR /app
19
+
20
+ # Pin this in production (e.g. --build-arg BY_FRAMEWORK_VERSION=0.2.2).
21
+ ARG BY_FRAMEWORK_VERSION=""
22
+ # "pypi" (default - for downstream projects) or "local" (used only by this
23
+ # repo's own .github/workflows/deploy-smoke-test.yml, to validate this
24
+ # Dockerfile against a PR's code before it's ever released). Leave this
25
+ # alone unless you're working on by-framework-python itself.
26
+ ARG BY_FRAMEWORK_SOURCE="pypi"
27
+
28
+ # Replace this with your own worker package/module.
29
+ COPY . /app/worker
30
+ ENV PYTHONPATH=/app/worker
31
+
32
+ # In "local" mode, /app/worker above IS the by-framework-python checkout, so
33
+ # install it editable from there instead of from PyPI.
34
+ RUN uv venv /opt/venv \
35
+ && if [ "$BY_FRAMEWORK_SOURCE" = "local" ]; then \
36
+ uv pip install --python /opt/venv/bin/python -e /app/worker; \
37
+ else \
38
+ uv pip install --python /opt/venv/bin/python \
39
+ "by-framework${BY_FRAMEWORK_VERSION:+==${BY_FRAMEWORK_VERSION}}"; \
40
+ fi
41
+
42
+ COPY deploy/entrypoint.sh /entrypoint.sh
43
+
44
+ # Opt-in readiness endpoint (see
45
+ # docs/architecture/worker-readiness-endpoint.md) - BYAI_WORKER_HEALTH_PORT
46
+ # is run_worker()'s own env-var fallback for --health-port, so this alone
47
+ # is enough to turn it on; no CMD change needed even if you override
48
+ # --worker-class below.
49
+ ENV BYAI_WORKER_HEALTH_PORT=8080
50
+ EXPOSE 8080
51
+
52
+ # Readiness only - see the hard rule in
53
+ # docs/architecture/worker-readiness-endpoint.md: never turn this into a
54
+ # liveness/restart-on-unhealthy check. urlopen() raises (non-zero exit) on
55
+ # the endpoint's real 503, so this actually fails on "not ready" - unlike
56
+ # a healthcheck that only checks "did the server respond at all".
57
+ HEALTHCHECK --interval=10s --timeout=3s --start-period=10s --retries=3 \
58
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/readyz', timeout=3)"
59
+
60
+ ENTRYPOINT ["/entrypoint.sh"]
61
+ CMD ["--worker-class", "my_agent.MyAgent"]
@@ -0,0 +1,70 @@
1
+ # Illustrates the README's "水平扩展"/"Horizontal Scaling" section as a real
2
+ # orchestration form instead of backgrounded shell processes: N Worker
3
+ # replicas, same agent type, distinct worker ids (see entrypoint.sh),
4
+ # competing for the same Redis control stream via a consumer group.
5
+ #
6
+ # Usage (downstream project, default my_agent.MyAgent + published PyPI package):
7
+ # docker compose -f deploy/docker-compose.yml up --build --scale worker=3
8
+ #
9
+ # Usage (this repo's own CI smoke test - see
10
+ # .github/workflows/deploy-smoke-test.yml - builds from local source and
11
+ # runs examples/echo_worker.py instead):
12
+ # BY_FRAMEWORK_SOURCE=local WORKER_CLASS=examples.echo_worker.EchoWorker \
13
+ # docker compose -f deploy/docker-compose.yml up --build
14
+
15
+ services:
16
+ redis:
17
+ image: redis:7-alpine
18
+ ports:
19
+ - "6379:6379"
20
+ healthcheck:
21
+ test: ["CMD", "redis-cli", "ping"]
22
+ interval: 5s
23
+ timeout: 3s
24
+ retries: 5
25
+
26
+ worker:
27
+ build:
28
+ context: ..
29
+ dockerfile: deploy/Dockerfile
30
+ args:
31
+ BY_FRAMEWORK_SOURCE: ${BY_FRAMEWORK_SOURCE:-pypi}
32
+ depends_on:
33
+ redis:
34
+ condition: service_healthy
35
+ # Mirrors deploy/Dockerfile's HEALTHCHECK - redeclared here (Compose
36
+ # would otherwise just inherit the image's own) so this file is a
37
+ # self-contained example of the readiness endpoint's wiring, and so any
38
+ # future service added here can depend on
39
+ # `worker: condition: service_healthy` without having to go trace
40
+ # through the Dockerfile to confirm one exists. Readiness only - never
41
+ # liveness, see docs/architecture/worker-readiness-endpoint.md.
42
+ #
43
+ # No host port published for 8080/readyz on purpose: this file's
44
+ # documented `--scale worker=N` usage above would collide trying to
45
+ # publish the same fixed host port for every replica. The healthcheck
46
+ # itself needs no host port - Compose evaluates it inside the
47
+ # container's own network. deploy-smoke-test.yml verifies it via
48
+ # `up --wait`.
49
+ healthcheck:
50
+ test:
51
+ [
52
+ "CMD",
53
+ "python",
54
+ "-c",
55
+ "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/readyz', timeout=3)",
56
+ ]
57
+ interval: 10s
58
+ timeout: 3s
59
+ start_period: 10s
60
+ retries: 3
61
+ environment:
62
+ REDIS_HOST: redis
63
+ REDIS_PORT: "6379"
64
+ # REDIS_PASSWORD, REDIS_USERNAME, REDIS_MODE, REDIS_CLUSTER_HOST, etc.
65
+ # all follow RedisConfig.from_env() - see docs/architecture/redis-cluster-mode.md.
66
+ BYAI_WORKER_CONCURRENCY: "50"
67
+ command: ["--worker-class", "${WORKER_CLASS:-my_agent.MyAgent}"]
68
+ # Give WorkerRunner._shutdown() room to drain in-flight tasks before
69
+ # Compose escalates to SIGKILL on `docker compose down`/stop.
70
+ stop_grace_period: 30s
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+ # Uses `exec` so the Python process replaces this shell as PID 1, receiving
3
+ # SIGTERM directly - a shell left as PID 1 does not forward signals to its
4
+ # child by default, which would silently defeat the graceful-shutdown fix in
5
+ # by_framework.worker.app (see docs/architecture/production-deployment.md).
6
+ #
7
+ # `$(hostname)` gives every replica a distinct worker id with no extra
8
+ # wiring: Docker Compose assigns each scaled replica a unique container
9
+ # hostname, and Kubernetes sets a Pod's hostname to its Pod name by default -
10
+ # so the same entrypoint works unchanged under `docker compose up --scale`
11
+ # and a Kubernetes Deployment.
12
+ set -e
13
+ exec python -m by_framework --worker-id "worker-$(hostname)" "$@"
@@ -0,0 +1,62 @@
1
+ # Minimal reference Deployment for a by-framework Worker. Replaces the
2
+ # README's shell-`&` "水平扩展" example with a real, supervised, restart-on-
3
+ # failure orchestration form. Adjust image/replicas/resources for your setup.
4
+ #
5
+ # readinessProbe ONLY below - see docs/architecture/worker-readiness-endpoint.md.
6
+ # Do NOT add a livenessProbe pointed at /readyz (or at anything else,
7
+ # absent a separate deliberate design for one): a Worker's health depends
8
+ # on Redis being reachable, and wiring this to liveness would mean a
9
+ # transient Redis outage kills and restarts every Worker replica
10
+ # simultaneously - a self-inflicted restart storm strictly worse than the
11
+ # outage itself. A failing readinessProbe never kills anything; it only
12
+ # stops this replica from being counted, which is exactly what "not
13
+ # ready" should do.
14
+ apiVersion: apps/v1
15
+ kind: Deployment
16
+ metadata:
17
+ name: my-agent-worker
18
+ spec:
19
+ replicas: 3
20
+ selector:
21
+ matchLabels:
22
+ app: my-agent-worker
23
+ template:
24
+ metadata:
25
+ labels:
26
+ app: my-agent-worker
27
+ spec:
28
+ # WorkerRunner._shutdown() drains in-flight tasks on SIGTERM before
29
+ # exiting; give it real room before Kubernetes escalates to SIGKILL.
30
+ # Must be >= the longest task this Worker is expected to run.
31
+ terminationGracePeriodSeconds: 30
32
+ containers:
33
+ - name: worker
34
+ image: my-agent-worker:latest
35
+ args: ["--worker-class", "my_agent.MyAgent"]
36
+ env:
37
+ - name: REDIS_HOST
38
+ value: redis
39
+ - name: REDIS_PORT
40
+ value: "6379"
41
+ # REDIS_PASSWORD/REDIS_USERNAME: prefer a Secret + secretKeyRef.
42
+ # REDIS_MODE/REDIS_CLUSTER_HOST: see docs/architecture/redis-cluster-mode.md.
43
+ - name: BYAI_WORKER_CONCURRENCY
44
+ value: "50"
45
+ - name: BYAI_WORKER_HEALTH_PORT
46
+ value: "8080"
47
+ ports:
48
+ - name: readiness
49
+ containerPort: 8080
50
+ readinessProbe:
51
+ httpGet:
52
+ path: /readyz
53
+ port: readiness
54
+ periodSeconds: 5
55
+ timeoutSeconds: 3
56
+ failureThreshold: 3
57
+ resources:
58
+ requests:
59
+ cpu: "250m"
60
+ memory: "256Mi"
61
+ limits:
62
+ memory: "512Mi"