by-framework 0.2.2.dev15__tar.gz → 0.2.2.dev16__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.
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/PKG-INFO +1 -1
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/KEY_FILES.md +16 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/worker-readiness-endpoint.md +9 -1
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/pyproject.toml +1 -1
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-langfuse/pyproject.toml +1 -1
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/pyproject.toml +1 -1
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/runner.py +25 -2
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_runner.py +208 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/uv.lock +3 -3
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.codex/hooks.json +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.dockerignore +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/RELEASING.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/workflows/ci.yml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/workflows/deploy-smoke-test.yml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/workflows/publish.yml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/workflows/stale.yml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/workflows/verify.yml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.gitignore +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.pre-commit-config.yaml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/AGENTS.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/CHANGELOG.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/CLAUDE.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/CODE_OF_CONDUCT.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/CONTRIBUTING.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/LICENSE +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/Makefile +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/README_zh.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/SECURITY.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/assets/img/architecture_en.png +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/assets/img/architecture_zh.png +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/autoformat.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/deploy/Dockerfile +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/deploy/docker-compose.yml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/deploy/entrypoint.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/deploy/kubernetes/worker-deployment.yaml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/GUARD_AUTHORING.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/langfuse-tracing-memory.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/production-deployment.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/redis-cluster-mode.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/suspend-resume-liveness.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/by-framework-trace-change-usage.html +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/by-framework-trace-complete-guide.html +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/plans/2026-05-15-worker-task-state-stats.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/plans/2026-06-10-trace-metrics-correlation.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/worker_management.html +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/examples/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/examples/echo_worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/examples/send_and_verify.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/src/by_framework_adk/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/src/by_framework_adk/_utils.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/src/by_framework_adk/adapter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/src/by_framework_adk/worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/tests/test_adapter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/tests/test_worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/01_basic_chat.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/02_tools_and_ask_user.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/03_agent_delegation.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/04_task_group.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/05_real_model_react.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/_infra.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/litellm_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/loop.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/model_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/testing.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/tool_spec.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/src/by_framework_agent/worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/conftest.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/test_agent_as_tool.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/test_ask_user_suspend_resume.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/test_cancel_cleanup.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/test_native_agent_worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/test_task_group_batching.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/test_tool_calling_loop.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/Dockerfile +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/frontend/index.html +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/frontend/package-lock.json +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/frontend/package.json +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/frontend/src/main.jsx +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/frontend/src/styles.css +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/frontend/vite.config.js +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/adapters.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/dashboard.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/static/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/static/app.js +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/static/index.html +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/src/by_framework_dashboard/static/styles.css +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/tests/test_dashboard_server.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-byclaw/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-byclaw/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-byclaw/src/by_framework_history_byclaw/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-byclaw/src/by_framework_history_byclaw/byclaw_history.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-byclaw/tests/test_byclaw_history.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-postgres/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-postgres/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-postgres/src/by_framework_history_postgres/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-postgres/src/by_framework_history_postgres/postgres.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-postgres/tests/test_postgres_history_storage.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/src/by_framework_langgraph/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/src/by_framework_langgraph/_utils.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/src/by_framework_langgraph/adapter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/src/by_framework_langgraph/tools.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/src/by_framework_langgraph/worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/tests/test_adapter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/tests/test_tools.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-langgraph/tests/test_utils.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-langfuse/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/langfuse.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-langfuse/tests/test_langfuse_import.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-phoenix/README.md +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-phoenix/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-phoenix/src/by_framework_trace_phoenix/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-phoenix/src/by_framework_trace_phoenix/phoenix.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-phoenix/tests/test_phoenix_import.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-phoenix/tests/test_phoenix_plugin.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/pyproject.toml +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/src/by_framework_trace_query/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/src/by_framework_trace_query/client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/src/by_framework_trace_query/merger.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/src/by_framework_trace_query/models.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/src/by_framework_trace_query/redis_source.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-trace-query/tests/test_trace_query_sdk.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/pylintrc +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/.map.conf +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/check-doc-discipline.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/check-entry-freshness.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/check-map-territory.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/check-metric-catalog.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/map-stop-hook.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/python_quality.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/test-growth-ladder.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/scripts/verify.sh +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/__main__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/admin/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/admin/cli.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/admin/worker_manager.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/client/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/client/byai_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/client/client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/config.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/constants.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/emitter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/exceptions.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/logger.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/common/redis_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/availability.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/delivery_gate.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/discovery.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/extensions/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/extensions/agent_config.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/extensions/agent_config_audit.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/extensions/plugin.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/extensions/registry.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/extensions/trace_provider.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/action_type.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/agent_state.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/byai_codec.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/byai_command.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/byai_types.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/commands.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/content_codec.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/content_type.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/data_message.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/data_shapes.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/event_type.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/events.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/message.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/message_header.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/responses.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/protocol/results.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/registry.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/agent_config_manager.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/agent_runtime_state.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/file_manager.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/file_paths.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/file_permissions.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/filestore/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/filestore/base.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/filestore/local.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/history/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/history/base.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/history/history_manager.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/history/in_memory.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/runtime/session_manager.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/wait_gate.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/wait_index.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/wait_reply.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/wait_sweeper.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/wakeup_controller.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/core/workspace.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/base.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/common.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/execution.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/http.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/protocol.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/errors/registry.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/metrics/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/metrics/catalog.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/metrics/collector.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/metrics/read_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/metrics/snapshot.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/trace/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/trace/external_trace.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/trace/span_recorder.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/trace/trace_schema.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/trace/trace_writer.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/util/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/util/discovery_http_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/util/generate_message_id.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/util/http_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/_control_handling.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/_execution_tracking.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/_message_processing.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/_resume_metadata.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/app.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/byai_context.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/byai_worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/context.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/health_server.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/heartbeat.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/processor.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/sandbox/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/sandbox/hook_sandbox.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/src/by_framework/worker/worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/admin/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/admin/test_cli.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/client/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/client/test_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/common/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/common/test_config.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/common/test_constants.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/common/test_exceptions.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/common/test_logger.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/common/test_redis_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/conftest.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/protocol/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/protocol/test_byai_codec.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/protocol/test_command_wire.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/protocol/test_protocol.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/protocol/test_results.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/history/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/history/test_history_persistence.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_file_access_context.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_file_manager_default_storage.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_file_paths.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_file_permissions.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_filestore_local_collection.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_filestore_local_mutation.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_filestore_local_read.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/runtime/test_filestore_local_search.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_agent_config_audit.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_availability.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_discovery.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_registry.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_wait_gate.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_wait_index.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_wait_sweeper.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/core/test_worker_manager.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/test_ask_user_flow.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/test_callback_flow.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/test_logger_integration.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/test_nested_chain.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/test_orphan_recovery.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/integration/test_scatter_gather.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/metrics/test_catalog.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/metrics/test_collector.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/metrics/test_metrics.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/metrics/test_read_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/metrics/test_snapshot.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/plugin/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/plugin/test_langfuse_plugin.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/plugin/test_plugin_discovery.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/plugin/test_plugin_improvements.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/plugin/test_plugin_registry.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/plugin/test_plugin_system.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/test_main.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/trace/test_external_trace.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/trace/test_logger_correlation.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/trace/test_otel_exporter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/trace/test_span_recorder.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/trace/test_trace_writer.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/util/test_discovery_http_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/util/test_discovery_http_client_download.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/util/test_discovery_http_client_upload.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/util/test_http_client.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/__init__.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_admin_control_handling.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_app.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_byai_worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_context.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_control_handling.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_emitter.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_fetch_messages.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_gateway_worker.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_health_server.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_heartbeat.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_message_processing.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_processor.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_resume_metadata.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_sandbox.py +0 -0
- {by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/tests/worker/test_workspace.py +0 -0
|
@@ -314,6 +314,22 @@ Entry anatomy:
|
|
|
314
314
|
best-effort — a background component that fails to construct must never
|
|
315
315
|
prevent the worker from consuming — and every one of them must be
|
|
316
316
|
cancelled and awaited in `_shutdown()`, or shutdown hangs on it.
|
|
317
|
+
`_run_once()` acquires a concurrency slot via `_acquire_slot()`, never a
|
|
318
|
+
bare `await self.semaphore.acquire()` — a saturated pool (all
|
|
319
|
+
`max_concurrency` slots held by legitimately long-running tasks) must not
|
|
320
|
+
be indistinguishable from a genuinely stuck consume loop. `_acquire_slot()`
|
|
321
|
+
polls `len(self._running_tasks) >= self.max_concurrency` and calls
|
|
322
|
+
`_mark_consumer_tick()` on every poll while waiting, so `_is_consumer_healthy()`
|
|
323
|
+
(whose own comparison logic is untouched) keeps seeing fresh ticks for as
|
|
324
|
+
long as the loop is merely busy, not stalled. `self._slot_wait_poll_seconds`
|
|
325
|
+
is derived from `_consumer_health_timeout_seconds` (not hardcoded) so the
|
|
326
|
+
two stay proportional under any lease-TTL/stream-block-ms configuration.
|
|
327
|
+
Trade-off this does *not* solve, by design: it cannot distinguish a
|
|
328
|
+
legitimately long task from a deadlocked one that will never return — both
|
|
329
|
+
present as `_running_tasks` stuck at `max_concurrency`; task-level SLA
|
|
330
|
+
enforcement (detecting and cancelling an individual stuck task) is a
|
|
331
|
+
separate concern from consumer-loop liveness and is not implemented here —
|
|
332
|
+
see `CancelTaskCommand` for the existing per-task cancel path.
|
|
317
333
|
|
|
318
334
|
- `src/by_framework/worker/health_server.py` — `WorkerHealthServer`: the
|
|
319
335
|
`/readyz` readiness HTTP endpoint, on its own daemon thread (mirrors
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/worker-readiness-endpoint.md
RENAMED
|
@@ -216,7 +216,15 @@ regardless.
|
|
|
216
216
|
2. `draining` — `SIGTERM`/`SIGINT` received, shutdown in progress
|
|
217
217
|
3. `evicted` — `admin_lifecycle == "evicted"`
|
|
218
218
|
4. `suspended` — `admin_lifecycle == "suspended"`
|
|
219
|
-
5. `consumer_stalled` — consume loop stale past `_consumer_health_timeout_seconds
|
|
219
|
+
5. `consumer_stalled` — consume loop stale past `_consumer_health_timeout_seconds`.
|
|
220
|
+
"Stale" means the loop itself has stopped making progress (crashed task,
|
|
221
|
+
or an unexpected hang outside slot-waiting) — it deliberately excludes a
|
|
222
|
+
consume loop that is merely waiting for every `max_concurrency` slot to
|
|
223
|
+
free up while legitimately long-running tasks are in flight. A saturated-
|
|
224
|
+
but-alive loop keeps refreshing its liveness signal while it waits (see
|
|
225
|
+
`runner.py`'s `_acquire_slot()` in `docs/architecture/KEY_FILES.md`), so
|
|
226
|
+
it never surfaces here; only a loop that has actually stopped responding
|
|
227
|
+
does.
|
|
220
228
|
6. `serving` — none of the above; `ready=true`
|
|
221
229
|
|
|
222
230
|
`ready` is `true` if and only if `reason == "serving"`.
|
|
@@ -83,6 +83,7 @@ class WorkerRunner:
|
|
|
83
83
|
self.worker = worker
|
|
84
84
|
self.group_name = group_name or self._auto_group_name()
|
|
85
85
|
self.consumer_name = worker.worker_id
|
|
86
|
+
self.max_concurrency = max_concurrency
|
|
86
87
|
self.semaphore = asyncio.Semaphore(max_concurrency)
|
|
87
88
|
self.fetch_count = fetch_count
|
|
88
89
|
# OTel for worker.execute is emitted via a live wrapping span (see
|
|
@@ -121,6 +122,14 @@ class WorkerRunner:
|
|
|
121
122
|
float(self.worker.heartbeat_lease_ttl_seconds) * 2.0,
|
|
122
123
|
stream_block_seconds * 3.0,
|
|
123
124
|
)
|
|
125
|
+
# Poll interval used by _acquire_slot() while waiting for a saturated
|
|
126
|
+
# semaphore. Derived from _consumer_health_timeout_seconds (not a
|
|
127
|
+
# hardcoded constant) so it stays well under the health-check
|
|
128
|
+
# deadline under any configuration, with a floor to avoid busy-
|
|
129
|
+
# polling if the timeout is configured very small.
|
|
130
|
+
self._slot_wait_poll_seconds = max(
|
|
131
|
+
self._consumer_health_timeout_seconds / 4.0, 1.0
|
|
132
|
+
)
|
|
124
133
|
# Set as the first step of _shutdown() - see
|
|
125
134
|
# docs/architecture/worker-readiness-endpoint.md Decision 6.
|
|
126
135
|
self._draining: bool = False
|
|
@@ -386,9 +395,23 @@ class WorkerRunner:
|
|
|
386
395
|
finally:
|
|
387
396
|
await self.redis.xack(stream_name, self.group_name, msg_id)
|
|
388
397
|
|
|
398
|
+
async def _acquire_slot(self) -> None:
|
|
399
|
+
"""Wait for a concurrency slot, marking the consumer tick on every
|
|
400
|
+
poll so a saturated-but-alive loop isn't judged stalled.
|
|
401
|
+
|
|
402
|
+
Polling on `len(self._running_tasks)` instead of wrapping
|
|
403
|
+
`semaphore.acquire()` in `asyncio.wait_for()` avoids relying on
|
|
404
|
+
Semaphore cancellation semantics for a lock this runner is the only
|
|
405
|
+
waiter on — see design.md's "why not asyncio.wait_for" section.
|
|
406
|
+
"""
|
|
407
|
+
while len(self._running_tasks) >= self.max_concurrency:
|
|
408
|
+
self._mark_consumer_tick()
|
|
409
|
+
await asyncio.sleep(self._slot_wait_poll_seconds)
|
|
410
|
+
await self.semaphore.acquire()
|
|
411
|
+
|
|
389
412
|
async def _run_once(self) -> bool:
|
|
390
413
|
"""Fetch and start processing messages."""
|
|
391
|
-
await self.
|
|
414
|
+
await self._acquire_slot()
|
|
392
415
|
|
|
393
416
|
try:
|
|
394
417
|
messages = await self.fetch_messages(
|
|
@@ -401,7 +424,7 @@ class WorkerRunner:
|
|
|
401
424
|
|
|
402
425
|
for i, (stream_name, msg_id, data_dict) in enumerate(messages):
|
|
403
426
|
if i > 0:
|
|
404
|
-
await self.
|
|
427
|
+
await self._acquire_slot()
|
|
405
428
|
|
|
406
429
|
task = asyncio.create_task(
|
|
407
430
|
self._process_and_release(stream_name, msg_id, data_dict)
|
|
@@ -193,6 +193,81 @@ class StartupOrderStop(RuntimeError):
|
|
|
193
193
|
"""Sentinel used to stop the infinite runner loop in startup-order tests."""
|
|
194
194
|
|
|
195
195
|
|
|
196
|
+
class _ContinuousMockRedis(MockRedisRunner):
|
|
197
|
+
"""Returns a fresh AskAgentCommand message on every xreadgroup call.
|
|
198
|
+
|
|
199
|
+
Used by the semaphore-saturation tests to simulate a control stream
|
|
200
|
+
that always has more work waiting, so the consume loop is genuinely
|
|
201
|
+
busy (not idle) while a concurrency slot is unavailable.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
def __init__(self, agent_type: str = "dummy_agent"):
|
|
205
|
+
super().__init__(message_to_return=None)
|
|
206
|
+
self.agent_type = agent_type
|
|
207
|
+
self._counter = 0
|
|
208
|
+
|
|
209
|
+
async def xreadgroup(self, groupname, consumername, streams, count=1, block=0):
|
|
210
|
+
self.called_xreadgroup = True
|
|
211
|
+
self._counter += 1
|
|
212
|
+
msg = AskAgentCommand(
|
|
213
|
+
header=MessageHeader(
|
|
214
|
+
message_id=f"msg-{self._counter}",
|
|
215
|
+
session_id="sess-1",
|
|
216
|
+
trace_id="trace-1",
|
|
217
|
+
target_agent_type=self.agent_type,
|
|
218
|
+
),
|
|
219
|
+
content="test",
|
|
220
|
+
)
|
|
221
|
+
return [
|
|
222
|
+
[
|
|
223
|
+
RedisKeys.ctrl_stream(self.agent_type).encode(),
|
|
224
|
+
[
|
|
225
|
+
(
|
|
226
|
+
f"{self._counter}-0".encode(),
|
|
227
|
+
{b"data": json.dumps(msg.to_dict()).encode()},
|
|
228
|
+
)
|
|
229
|
+
],
|
|
230
|
+
]
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class _SlowWorker(DummyWorker):
|
|
235
|
+
"""Every task takes `delay` seconds - stands in for a long-running
|
|
236
|
+
LLM/tool-call agent task that legitimately occupies a concurrency slot."""
|
|
237
|
+
|
|
238
|
+
def __init__(self, delay: float):
|
|
239
|
+
super().__init__()
|
|
240
|
+
self.delay = delay
|
|
241
|
+
self.completed = 0
|
|
242
|
+
|
|
243
|
+
async def _handle_message(self, command, **kwargs):
|
|
244
|
+
await asyncio.sleep(self.delay)
|
|
245
|
+
self.completed += 1
|
|
246
|
+
return AgentTaskResult(status=AgentState.COMPLETED.value)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class _MixedDurationWorker(DummyWorker):
|
|
250
|
+
"""The first message processed takes `long_delay`; every subsequent one
|
|
251
|
+
takes `short_delay` - simulates one slot pinned by a long task while
|
|
252
|
+
the rest of the pool cycles normally."""
|
|
253
|
+
|
|
254
|
+
def __init__(self, long_delay: float, short_delay: float):
|
|
255
|
+
super().__init__()
|
|
256
|
+
self.long_delay = long_delay
|
|
257
|
+
self.short_delay = short_delay
|
|
258
|
+
self.completed = 0
|
|
259
|
+
self._long_dispatched = False
|
|
260
|
+
self._lock = asyncio.Lock()
|
|
261
|
+
|
|
262
|
+
async def _handle_message(self, command, **kwargs):
|
|
263
|
+
async with self._lock:
|
|
264
|
+
is_long = not self._long_dispatched
|
|
265
|
+
self._long_dispatched = True
|
|
266
|
+
await asyncio.sleep(self.long_delay if is_long else self.short_delay)
|
|
267
|
+
self.completed += 1
|
|
268
|
+
return AgentTaskResult(status=AgentState.COMPLETED.value)
|
|
269
|
+
|
|
270
|
+
|
|
196
271
|
class TestWorkerRunner(unittest.IsolatedAsyncioTestCase):
|
|
197
272
|
|
|
198
273
|
async def test_runner_pull_and_dispatch(self):
|
|
@@ -1398,6 +1473,139 @@ class TestWorkerRunner(unittest.IsolatedAsyncioTestCase):
|
|
|
1398
1473
|
with self.assertRaises(asyncio.CancelledError):
|
|
1399
1474
|
await runner._consumer_task
|
|
1400
1475
|
|
|
1476
|
+
async def test_runner_healthy_during_single_slot_saturation_live(self):
|
|
1477
|
+
"""max_concurrency=1: a single task running well past the (shrunk)
|
|
1478
|
+
health timeout, with more messages continuously available, must
|
|
1479
|
+
never flip _is_consumer_healthy() to False - this is the exact
|
|
1480
|
+
scenario from the PRD's Background (real asyncio scheduling, no
|
|
1481
|
+
mocked clock): the consume loop is busy, not stuck."""
|
|
1482
|
+
worker = _SlowWorker(delay=0.3)
|
|
1483
|
+
redis_mock = _ContinuousMockRedis()
|
|
1484
|
+
runner = WorkerRunner(
|
|
1485
|
+
redis_client=redis_mock,
|
|
1486
|
+
worker=worker,
|
|
1487
|
+
group_name="test_group",
|
|
1488
|
+
max_concurrency=1,
|
|
1489
|
+
fetch_count=1,
|
|
1490
|
+
)
|
|
1491
|
+
# Shrink well below the task duration so a stale tick would be
|
|
1492
|
+
# caught, and re-derive the poll interval the same way __init__
|
|
1493
|
+
# does (a smaller floor than production's 1.0s so the test runs
|
|
1494
|
+
# fast, without changing the ratio the design specifies).
|
|
1495
|
+
runner._consumer_health_timeout_seconds = 0.1
|
|
1496
|
+
runner._slot_wait_poll_seconds = max(
|
|
1497
|
+
runner._consumer_health_timeout_seconds / 4.0, 0.02
|
|
1498
|
+
)
|
|
1499
|
+
runner._mark_consumer_tick()
|
|
1500
|
+
runner._consumer_task = asyncio.ensure_future(runner._consume_loop())
|
|
1501
|
+
try:
|
|
1502
|
+
loop = asyncio.get_running_loop()
|
|
1503
|
+
deadline = loop.time() + 1.0
|
|
1504
|
+
saw_unhealthy = False
|
|
1505
|
+
while loop.time() < deadline:
|
|
1506
|
+
if not runner._is_consumer_healthy():
|
|
1507
|
+
saw_unhealthy = True
|
|
1508
|
+
break
|
|
1509
|
+
await asyncio.sleep(0.01)
|
|
1510
|
+
self.assertFalse(
|
|
1511
|
+
saw_unhealthy,
|
|
1512
|
+
"consumer was judged unhealthy while merely saturated, not stuck",
|
|
1513
|
+
)
|
|
1514
|
+
# Sanity: the loop was actually doing work throughout, not
|
|
1515
|
+
# idling because fetch never returned anything.
|
|
1516
|
+
self.assertGreater(worker.completed, 0)
|
|
1517
|
+
finally:
|
|
1518
|
+
runner._consumer_task.cancel()
|
|
1519
|
+
with self.assertRaises(asyncio.CancelledError):
|
|
1520
|
+
await runner._consumer_task
|
|
1521
|
+
await runner.wait_for_tasks()
|
|
1522
|
+
|
|
1523
|
+
async def test_runner_healthy_during_partial_saturation_live(self):
|
|
1524
|
+
"""max_concurrency>1: one slot pinned by a long task while the rest
|
|
1525
|
+
of the pool keeps cycling normally must never flip
|
|
1526
|
+
_is_consumer_healthy() to False."""
|
|
1527
|
+
worker = _MixedDurationWorker(long_delay=0.4, short_delay=0.05)
|
|
1528
|
+
redis_mock = _ContinuousMockRedis()
|
|
1529
|
+
runner = WorkerRunner(
|
|
1530
|
+
redis_client=redis_mock,
|
|
1531
|
+
worker=worker,
|
|
1532
|
+
group_name="test_group",
|
|
1533
|
+
max_concurrency=3,
|
|
1534
|
+
fetch_count=1,
|
|
1535
|
+
)
|
|
1536
|
+
runner._consumer_health_timeout_seconds = 0.1
|
|
1537
|
+
runner._slot_wait_poll_seconds = max(
|
|
1538
|
+
runner._consumer_health_timeout_seconds / 4.0, 0.02
|
|
1539
|
+
)
|
|
1540
|
+
runner._mark_consumer_tick()
|
|
1541
|
+
runner._consumer_task = asyncio.ensure_future(runner._consume_loop())
|
|
1542
|
+
try:
|
|
1543
|
+
loop = asyncio.get_running_loop()
|
|
1544
|
+
deadline = loop.time() + 1.0
|
|
1545
|
+
saw_unhealthy = False
|
|
1546
|
+
while loop.time() < deadline:
|
|
1547
|
+
if not runner._is_consumer_healthy():
|
|
1548
|
+
saw_unhealthy = True
|
|
1549
|
+
break
|
|
1550
|
+
await asyncio.sleep(0.01)
|
|
1551
|
+
self.assertFalse(
|
|
1552
|
+
saw_unhealthy,
|
|
1553
|
+
"consumer was judged unhealthy while one slot was merely "
|
|
1554
|
+
"pinned by a long task, not stuck",
|
|
1555
|
+
)
|
|
1556
|
+
# The short-task slots must have cycled multiple times while
|
|
1557
|
+
# the long task was still occupying its own slot.
|
|
1558
|
+
self.assertGreater(worker.completed, 1)
|
|
1559
|
+
finally:
|
|
1560
|
+
runner._consumer_task.cancel()
|
|
1561
|
+
with self.assertRaises(asyncio.CancelledError):
|
|
1562
|
+
await runner._consumer_task
|
|
1563
|
+
await runner.wait_for_tasks()
|
|
1564
|
+
|
|
1565
|
+
async def test_runner_consumer_stalled_detected_despite_free_slot_live(self):
|
|
1566
|
+
"""Regression guard: a free concurrency slot must not mask a
|
|
1567
|
+
genuinely stuck consume loop. If fetch/dispatch itself stops
|
|
1568
|
+
making progress - not because every slot is occupied -
|
|
1569
|
+
_is_consumer_healthy() must still flip to False. Uses real
|
|
1570
|
+
asyncio scheduling (wall-clock sleep past the shrunk timeout, no
|
|
1571
|
+
mocked clock) so this fix cannot degrade into "saturated (or
|
|
1572
|
+
merely idle) == always healthy"."""
|
|
1573
|
+
worker = DummyWorker()
|
|
1574
|
+
redis_mock = MockRedisRunner(message_to_return=[])
|
|
1575
|
+
runner = WorkerRunner(
|
|
1576
|
+
redis_client=redis_mock,
|
|
1577
|
+
worker=worker,
|
|
1578
|
+
group_name="test_group",
|
|
1579
|
+
max_concurrency=5,
|
|
1580
|
+
)
|
|
1581
|
+
runner._consumer_health_timeout_seconds = 0.2
|
|
1582
|
+
runner._slot_wait_poll_seconds = 0.05
|
|
1583
|
+
runner._mark_consumer_tick()
|
|
1584
|
+
|
|
1585
|
+
hang_forever = asyncio.Event()
|
|
1586
|
+
|
|
1587
|
+
async def _hanging_fetch(*args, **kwargs):
|
|
1588
|
+
await hang_forever.wait()
|
|
1589
|
+
return []
|
|
1590
|
+
|
|
1591
|
+
# Simulate the consume loop getting stuck somewhere other than the
|
|
1592
|
+
# slot wait (e.g. an unexpected hang inside fetch/dispatch) while a
|
|
1593
|
+
# slot is freely available - _acquire_slot()'s polling branch must
|
|
1594
|
+
# never even be entered here (len(_running_tasks) stays 0, well
|
|
1595
|
+
# under max_concurrency), so it cannot be the thing masking this.
|
|
1596
|
+
runner.fetch_messages = _hanging_fetch
|
|
1597
|
+
|
|
1598
|
+
runner._consumer_task = asyncio.ensure_future(runner._consume_loop())
|
|
1599
|
+
try:
|
|
1600
|
+
await asyncio.sleep(runner._consumer_health_timeout_seconds + 0.3)
|
|
1601
|
+
self.assertFalse(runner._is_consumer_healthy())
|
|
1602
|
+
self.assertEqual(len(runner._running_tasks), 0)
|
|
1603
|
+
finally:
|
|
1604
|
+
hang_forever.set()
|
|
1605
|
+
runner._consumer_task.cancel()
|
|
1606
|
+
with self.assertRaises(asyncio.CancelledError):
|
|
1607
|
+
await runner._consumer_task
|
|
1608
|
+
|
|
1401
1609
|
|
|
1402
1610
|
if __name__ == "__main__":
|
|
1403
1611
|
unittest.main()
|
|
@@ -315,7 +315,7 @@ wheels = [
|
|
|
315
315
|
|
|
316
316
|
[[package]]
|
|
317
317
|
name = "by-framework"
|
|
318
|
-
version = "0.2.2.
|
|
318
|
+
version = "0.2.2.dev16"
|
|
319
319
|
source = { editable = "." }
|
|
320
320
|
dependencies = [
|
|
321
321
|
{ name = "dill" },
|
|
@@ -531,7 +531,7 @@ provides-extras = ["dev"]
|
|
|
531
531
|
|
|
532
532
|
[[package]]
|
|
533
533
|
name = "by-framework-langgraph"
|
|
534
|
-
version = "0.0.3.
|
|
534
|
+
version = "0.0.3.dev5"
|
|
535
535
|
source = { editable = "libs/by-framework-langgraph" }
|
|
536
536
|
dependencies = [
|
|
537
537
|
{ name = "by-framework" },
|
|
@@ -577,7 +577,7 @@ provides-extras = ["dev", "langfuse", "phoenix"]
|
|
|
577
577
|
|
|
578
578
|
[[package]]
|
|
579
579
|
name = "by-framework-trace-langfuse"
|
|
580
|
-
version = "0.0.3.
|
|
580
|
+
version = "0.0.3.dev5"
|
|
581
581
|
source = { editable = "libs/by-framework-trace-langfuse" }
|
|
582
582
|
dependencies = [
|
|
583
583
|
{ name = "by-framework" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/ISSUE_TEMPLATE/feature_request.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/.github/workflows/deploy-smoke-test.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/deploy/kubernetes/worker-deployment.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/langfuse-tracing-memory.md
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/production-deployment.md
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/redis-cluster-mode.md
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/architecture/suspend-resume-liveness.md
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/by-framework-trace-change-usage.html
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/docs/by-framework-trace-complete-guide.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/tests/test_adapter.py
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-adk/tests/test_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/README.md
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/examples/_infra.py
RENAMED
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-agent/tests/conftest.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/Dockerfile
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-dashboard/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{by_framework-0.2.2.dev15 → by_framework-0.2.2.dev16}/libs/by-framework-history-byclaw/README.md
RENAMED
|
File without changes
|
|
File without changes
|