by-framework 0.2.1__tar.gz → 0.2.2.dev1__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.1 → by_framework-0.2.2.dev1}/.github/workflows/publish.yml +27 -7
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.gitignore +5 -0
- by_framework-0.2.1/README.md → by_framework-0.2.2.dev1/PKG-INFO +52 -1
- by_framework-0.2.1/PKG-INFO → by_framework-0.2.2.dev1/README.md +28 -21
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/README_zh.md +24 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/pyproject.toml +1 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-byclaw/pyproject.toml +1 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-byclaw/src/by_framework_history_byclaw/byclaw_history.py +27 -10
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-byclaw/tests/test_byclaw_history.py +20 -4
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-postgres/pyproject.toml +1 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/pyproject.toml +1 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/src/by_framework_langgraph/_utils.py +0 -11
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/src/by_framework_langgraph/adapter.py +33 -6
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/tests/test_adapter.py +44 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-langfuse/pyproject.toml +1 -1
- by_framework-0.2.2.dev1/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/__init__.py +17 -0
- by_framework-0.2.2.dev1/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/langfuse.py +699 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-phoenix/pyproject.toml +1 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-phoenix/src/by_framework_trace_phoenix/phoenix.py +31 -3
- by_framework-0.2.2.dev1/libs/by-framework-trace-phoenix/tests/test_phoenix_plugin.py +159 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/pyproject.toml +6 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/__init__.py +2 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/client/__init__.py +2 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/client/client.py +410 -5
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/constants.py +30 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/logger.py +71 -10
- by_framework-0.2.2.dev1/src/by_framework/observability/__init__.py +62 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/dashboard.py +1145 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/external_trace.py +148 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/frontend/index.html +12 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/frontend/package-lock.json +1696 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/frontend/package.json +18 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/frontend/src/main.jsx +1351 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/frontend/src/styles.css +1214 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/frontend/vite.config.js +18 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/metrics.py +195 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/snapshot.py +2294 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/span_recorder.py +840 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/static/app.js +115 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/static/index.html +13 -0
- by_framework-0.2.2.dev1/src/by_framework/observability/static/styles.css +1 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/util/discovery_http_client.py +34 -9
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/util/http_client.py +27 -6
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/_control_handling.py +30 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/context.py +347 -10
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/runner.py +238 -10
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/worker.py +23 -6
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/client/test_client.py +389 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/common/test_logger.py +13 -13
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/integration/test_logger_integration.py +28 -5
- by_framework-0.2.2.dev1/tests/observability/test_dashboard_server.py +436 -0
- by_framework-0.2.2.dev1/tests/observability/test_external_trace.py +134 -0
- by_framework-0.2.2.dev1/tests/observability/test_logger_correlation.py +122 -0
- by_framework-0.2.2.dev1/tests/observability/test_metrics.py +84 -0
- by_framework-0.2.2.dev1/tests/observability/test_otel_exporter.py +252 -0
- by_framework-0.2.2.dev1/tests/observability/test_snapshot.py +839 -0
- by_framework-0.2.2.dev1/tests/observability/test_span_recorder.py +219 -0
- by_framework-0.2.2.dev1/tests/plugin/test_langfuse_plugin.py +606 -0
- by_framework-0.2.2.dev1/tests/util/test_discovery_http_client_upload.py +181 -0
- by_framework-0.2.2.dev1/tests/util/test_http_client.py +172 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_context.py +243 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_gateway_worker.py +46 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_runner.py +151 -1
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/uv.lock +26 -17
- by_framework-0.2.1/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/__init__.py +0 -5
- by_framework-0.2.1/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/langfuse.py +0 -406
- by_framework-0.2.1/src/by_framework/core/__init__.py +0 -95
- by_framework-0.2.1/src/by_framework/core/availability.py +0 -495
- by_framework-0.2.1/src/by_framework/core/delivery_gate.py +0 -60
- by_framework-0.2.1/src/by_framework/core/discovery.py +0 -359
- by_framework-0.2.1/src/by_framework/core/extensions/__init__.py +0 -35
- by_framework-0.2.1/src/by_framework/core/extensions/agent_config.py +0 -64
- by_framework-0.2.1/src/by_framework/core/extensions/plugin.py +0 -282
- by_framework-0.2.1/src/by_framework/core/extensions/registry.py +0 -653
- by_framework-0.2.1/src/by_framework/core/extensions/trace_provider.py +0 -20
- by_framework-0.2.1/src/by_framework/core/protocol/__init__.py +0 -133
- by_framework-0.2.1/src/by_framework/core/protocol/action_type.py +0 -33
- by_framework-0.2.1/src/by_framework/core/protocol/agent_state.py +0 -78
- by_framework-0.2.1/src/by_framework/core/protocol/byai_codec.py +0 -101
- by_framework-0.2.1/src/by_framework/core/protocol/byai_command.py +0 -53
- by_framework-0.2.1/src/by_framework/core/protocol/byai_types.py +0 -7
- by_framework-0.2.1/src/by_framework/core/protocol/commands.py +0 -285
- by_framework-0.2.1/src/by_framework/core/protocol/content_codec.py +0 -17
- by_framework-0.2.1/src/by_framework/core/protocol/content_type.py +0 -38
- by_framework-0.2.1/src/by_framework/core/protocol/data_message.py +0 -45
- by_framework-0.2.1/src/by_framework/core/protocol/data_shapes.py +0 -83
- by_framework-0.2.1/src/by_framework/core/protocol/event_type.py +0 -34
- by_framework-0.2.1/src/by_framework/core/protocol/events.py +0 -69
- by_framework-0.2.1/src/by_framework/core/protocol/message.py +0 -99
- by_framework-0.2.1/src/by_framework/core/protocol/message_header.py +0 -68
- by_framework-0.2.1/src/by_framework/core/protocol/responses.py +0 -94
- by_framework-0.2.1/src/by_framework/core/protocol/results.py +0 -149
- by_framework-0.2.1/src/by_framework/core/registry.py +0 -1025
- by_framework-0.2.1/src/by_framework/core/runtime/__init__.py +0 -29
- by_framework-0.2.1/src/by_framework/core/runtime/agent_config_manager.py +0 -283
- by_framework-0.2.1/src/by_framework/core/runtime/agent_runtime_state.py +0 -75
- by_framework-0.2.1/src/by_framework/core/runtime/file_manager.py +0 -437
- by_framework-0.2.1/src/by_framework/core/runtime/file_paths.py +0 -76
- by_framework-0.2.1/src/by_framework/core/runtime/file_permissions.py +0 -71
- by_framework-0.2.1/src/by_framework/core/runtime/filestore/__init__.py +0 -15
- by_framework-0.2.1/src/by_framework/core/runtime/filestore/base.py +0 -140
- by_framework-0.2.1/src/by_framework/core/runtime/filestore/local.py +0 -321
- by_framework-0.2.1/src/by_framework/core/runtime/history/__init__.py +0 -10
- by_framework-0.2.1/src/by_framework/core/runtime/history/base.py +0 -57
- by_framework-0.2.1/src/by_framework/core/runtime/history/history_manager.py +0 -55
- by_framework-0.2.1/src/by_framework/core/runtime/history/in_memory.py +0 -58
- by_framework-0.2.1/src/by_framework/core/runtime/session_manager.py +0 -118
- by_framework-0.2.1/src/by_framework/core/wakeup_controller.py +0 -151
- by_framework-0.2.1/src/by_framework/core/workspace.py +0 -126
- by_framework-0.2.1/tests/core/protocol/test_byai_codec.py +0 -105
- by_framework-0.2.1/tests/core/protocol/test_command_wire.py +0 -21
- by_framework-0.2.1/tests/core/protocol/test_protocol.py +0 -246
- by_framework-0.2.1/tests/core/protocol/test_results.py +0 -68
- by_framework-0.2.1/tests/core/runtime/history/test_history_persistence.py +0 -181
- by_framework-0.2.1/tests/core/runtime/test_file_access_context.py +0 -48
- by_framework-0.2.1/tests/core/runtime/test_file_manager_default_storage.py +0 -222
- by_framework-0.2.1/tests/core/runtime/test_file_paths.py +0 -28
- by_framework-0.2.1/tests/core/runtime/test_file_permissions.py +0 -85
- by_framework-0.2.1/tests/core/runtime/test_filestore_local_collection.py +0 -41
- by_framework-0.2.1/tests/core/runtime/test_filestore_local_mutation.py +0 -32
- by_framework-0.2.1/tests/core/runtime/test_filestore_local_read.py +0 -50
- by_framework-0.2.1/tests/core/runtime/test_filestore_local_search.py +0 -61
- by_framework-0.2.1/tests/core/test_availability.py +0 -606
- by_framework-0.2.1/tests/core/test_discovery.py +0 -204
- by_framework-0.2.1/tests/core/test_registry.py +0 -933
- by_framework-0.2.1/tests/integration/__init__.py +0 -0
- by_framework-0.2.1/tests/plugin/__init__.py +0 -0
- by_framework-0.2.1/tests/plugin/test_langfuse_plugin.py +0 -258
- by_framework-0.2.1/tests/util/test_http_client.py +0 -41
- by_framework-0.2.1/tests/worker/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.github/RELEASING.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.github/workflows/ci.yml +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.github/workflows/stale.yml +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/.pre-commit-config.yaml +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/AGENTS.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/CHANGELOG.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/CLAUDE.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/CODE_OF_CONDUCT.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/CONTRIBUTING.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/LICENSE +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/Makefile +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/SECURITY.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/assets/img/architecture_en.png +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/assets/img/architecture_zh.png +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/autoformat.sh +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/docs/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/docs/plans/2026-05-15-worker-task-state-stats.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/src/by_framework_adk/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/src/by_framework_adk/_utils.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/src/by_framework_adk/adapter.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/src/by_framework_adk/worker.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-adk/tests/test_worker.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-byclaw/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-byclaw/src/by_framework_history_byclaw/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-postgres/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-postgres/src/by_framework_history_postgres/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-postgres/src/by_framework_history_postgres/postgres.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-history-postgres/tests/test_postgres_history_storage.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/src/by_framework_langgraph/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/src/by_framework_langgraph/tools.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/src/by_framework_langgraph/worker.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/tests/test_tools.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/tests/test_utils.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-langfuse/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-langfuse/tests/test_langfuse_import.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-phoenix/README.md +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-phoenix/src/by_framework_trace_phoenix/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-trace-phoenix/tests/test_phoenix_import.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/pylintrc +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/scripts/python_quality.sh +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/__main__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/client/byai_client.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/config.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/emitter.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/exceptions.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/common/redis_client.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/base.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/common.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/execution.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/http.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/protocol.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/errors/registry.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/util/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/util/generate_message_id.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/_execution_tracking.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/_message_processing.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/app.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/byai_context.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/byai_worker.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/heartbeat.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/processor.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/sandbox/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/src/by_framework/worker/sandbox/hook_sandbox.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/client/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/common/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/common/test_config.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/common/test_exceptions.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/common/test_redis_client.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/conftest.py +0 -0
- {by_framework-0.2.1/tests/core → by_framework-0.2.2.dev1/tests/integration}/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/integration/test_ask_user_flow.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/integration/test_callback_flow.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/integration/test_scatter_gather.py +0 -0
- {by_framework-0.2.1/tests/core/protocol → by_framework-0.2.2.dev1/tests/plugin}/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/plugin/test_plugin_discovery.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/plugin/test_plugin_improvements.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/plugin/test_plugin_registry.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/plugin/test_plugin_system.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/util/test_discovery_http_client.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/util/test_discovery_http_client_download.py +0 -0
- {by_framework-0.2.1/tests/core/runtime/history → by_framework-0.2.2.dev1/tests/worker}/__init__.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_app.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_byai_worker.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_control_handling.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_emitter.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_heartbeat.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_message_processing.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_processor.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_sandbox.py +0 -0
- {by_framework-0.2.1 → by_framework-0.2.2.dev1}/tests/worker/test_workspace.py +0 -0
|
@@ -63,7 +63,7 @@ jobs:
|
|
|
63
63
|
echo "package_name=by-framework-adk" >> "$GITHUB_OUTPUT"
|
|
64
64
|
echo "package_dir=libs/by-framework-adk" >> "$GITHUB_OUTPUT"
|
|
65
65
|
echo "version=${REF_NAME#by-framework-adk-v}" >> "$GITHUB_OUTPUT"
|
|
66
|
-
;;
|
|
66
|
+
;;
|
|
67
67
|
*)
|
|
68
68
|
echo "Unsupported tag: $REF_NAME" >&2
|
|
69
69
|
exit 1
|
|
@@ -152,6 +152,10 @@ jobs:
|
|
|
152
152
|
ref: ${{ github.ref }}
|
|
153
153
|
fetch-depth: 0
|
|
154
154
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
155
|
+
- uses: actions/setup-python@v5
|
|
156
|
+
with:
|
|
157
|
+
python-version: "3.12"
|
|
158
|
+
- uses: astral-sh/setup-uv@v5
|
|
155
159
|
|
|
156
160
|
- name: Create release branch
|
|
157
161
|
env:
|
|
@@ -169,20 +173,36 @@ jobs:
|
|
|
169
173
|
PACKAGE_DIR: ${{ needs.resolve-package.outputs.package_dir }}
|
|
170
174
|
VERSION: ${{ needs.resolve-package.outputs.version }}
|
|
171
175
|
run: |
|
|
172
|
-
# Calculate next
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
# Calculate next version using Python to support pre-releases (e.g., 0.2.3b0 -> 0.2.3b1, 0.2.3 -> 0.2.4.dev0)
|
|
177
|
+
NEXT_VERSION=$(python -c 'if True:
|
|
178
|
+
import re, sys
|
|
179
|
+
version = sys.argv[1]
|
|
180
|
+
match = re.search(r"(a|b|rc|dev)(\d+)$", version)
|
|
181
|
+
if match:
|
|
182
|
+
prefix = version[:match.start()]
|
|
183
|
+
suffix_type = match.group(1)
|
|
184
|
+
suffix_num = int(match.group(2))
|
|
185
|
+
print(f"{prefix}{suffix_type}{suffix_num + 1}")
|
|
186
|
+
else:
|
|
187
|
+
parts = version.split(".")
|
|
188
|
+
try:
|
|
189
|
+
parts[-1] = str(int(parts[-1]) + 1)
|
|
190
|
+
print(".".join(parts) + ".dev0")
|
|
191
|
+
except ValueError:
|
|
192
|
+
print(version + ".dev0")
|
|
193
|
+
' "$VERSION")
|
|
177
194
|
|
|
178
195
|
PYPROJECT="${PACKAGE_DIR}/pyproject.toml"
|
|
179
196
|
sed -i "s/version = \"${VERSION}\"/version = \"${NEXT_VERSION}\"/" "$PYPROJECT"
|
|
180
197
|
|
|
198
|
+
# Regenerate uv.lock to align with the new version bump in workspace
|
|
199
|
+
uv lock
|
|
200
|
+
|
|
181
201
|
BUMP_BRANCH="bump/${PACKAGE_NAME}/v${NEXT_VERSION}"
|
|
182
202
|
git checkout -b "$BUMP_BRANCH"
|
|
183
203
|
git config user.name "github-actions[bot]"
|
|
184
204
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
185
|
-
git add "$PYPROJECT"
|
|
205
|
+
git add "$PYPROJECT" uv.lock
|
|
186
206
|
git commit -m "chore: bump ${PACKAGE_NAME} version to ${NEXT_VERSION}"
|
|
187
207
|
git push origin "$BUMP_BRANCH"
|
|
188
208
|
|
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: by-framework
|
|
3
|
+
Version: 0.2.2.dev1
|
|
4
|
+
Summary: 分布式 Agent 调度框架
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: dill>=0.4.1
|
|
8
|
+
Requires-Dist: httpx>=0.28.1
|
|
9
|
+
Requires-Dist: redis>=7.0.0
|
|
10
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: isort>=5.13.0; extra == 'dev'
|
|
13
|
+
Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
|
|
14
|
+
Requires-Dist: pyink>=24.0.0; extra == 'dev'
|
|
15
|
+
Requires-Dist: pylint>=3.0.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: ruff>=0.3.0; extra == 'dev'
|
|
19
|
+
Provides-Extra: observability
|
|
20
|
+
Requires-Dist: opentelemetry-api>=1.25.0; extra == 'observability'
|
|
21
|
+
Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'observability'
|
|
22
|
+
Requires-Dist: prometheus-client>=0.20.0; extra == 'observability'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
1
25
|
# by-framework
|
|
2
26
|
|
|
3
27
|
<div align="center">
|
|
@@ -608,11 +632,38 @@ import logging
|
|
|
608
632
|
setup_logging(level=logging.INFO, use_json=True) # JSON for log aggregation
|
|
609
633
|
```
|
|
610
634
|
|
|
635
|
+
### Observability Dashboard
|
|
636
|
+
|
|
637
|
+
Serve the built-in dashboard to inspect worker health, agent health, execution
|
|
638
|
+
state counts, recent executions, Redis stream queue depth, consumer-group
|
|
639
|
+
pending/lag, failure details, routing decisions, derived alerts, and segmented
|
|
640
|
+
queue/run/end-to-end task latency:
|
|
641
|
+
|
|
642
|
+
```bash
|
|
643
|
+
uv run python -m by_framework.observability.dashboard --host 127.0.0.1 --port 8765
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Open `http://127.0.0.1:8765/`. For a local UI preview without Redis, open
|
|
647
|
+
`http://127.0.0.1:8765/?demo=1`. Prometheus-style metrics are available at
|
|
648
|
+
`http://127.0.0.1:8765/metrics`, and the dashboard keeps short in-memory trend
|
|
649
|
+
history at `http://127.0.0.1:8765/api/history`. The UI uses split polling
|
|
650
|
+
endpoints (`/api/workers`, `/api/executions`, `/api/queues`, `/api/history`)
|
|
651
|
+
instead of polling the full `/api/snapshot` endpoint on every refresh. Runtime
|
|
652
|
+
self-check data is exposed at `/api/health`, shown in the toolbar, and exported
|
|
653
|
+
through `/metrics`.
|
|
654
|
+
Alert thresholds can be tuned with `--queue-backlog-threshold`,
|
|
655
|
+
`--delivery-pending-threshold`, `--consumer-pending-threshold`, and
|
|
656
|
+
`--failed-execution-threshold`.
|
|
657
|
+
|
|
658
|
+
The dashboard frontend is built with React/Vite under
|
|
659
|
+
`src/by_framework/observability/frontend`; its production build is packaged in
|
|
660
|
+
`src/by_framework/observability/static`.
|
|
661
|
+
|
|
611
662
|
---
|
|
612
663
|
|
|
613
664
|
## Roadmap
|
|
614
665
|
|
|
615
|
-
- [
|
|
666
|
+
- [x] Observability dashboard for Worker health and task streams
|
|
616
667
|
- [ ] WASM-based sandbox for stronger execution isolation
|
|
617
668
|
- [ ] Enhanced LangGraph multi-agent orchestration adapter
|
|
618
669
|
|
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: by-framework
|
|
3
|
-
Version: 0.2.1
|
|
4
|
-
Summary: 分布式 Agent 调度框架
|
|
5
|
-
License-File: LICENSE
|
|
6
|
-
Requires-Python: >=3.12
|
|
7
|
-
Requires-Dist: dill>=0.4.1
|
|
8
|
-
Requires-Dist: httpx>=0.28.1
|
|
9
|
-
Requires-Dist: redis>=7.0.0
|
|
10
|
-
Requires-Dist: typing-extensions>=4.0.0
|
|
11
|
-
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: isort>=5.13.0; extra == 'dev'
|
|
13
|
-
Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
|
|
14
|
-
Requires-Dist: pyink>=24.0.0; extra == 'dev'
|
|
15
|
-
Requires-Dist: pylint>=3.0.0; extra == 'dev'
|
|
16
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
17
|
-
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
18
|
-
Requires-Dist: ruff>=0.3.0; extra == 'dev'
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
|
|
21
1
|
# by-framework
|
|
22
2
|
|
|
23
3
|
<div align="center">
|
|
@@ -628,11 +608,38 @@ import logging
|
|
|
628
608
|
setup_logging(level=logging.INFO, use_json=True) # JSON for log aggregation
|
|
629
609
|
```
|
|
630
610
|
|
|
611
|
+
### Observability Dashboard
|
|
612
|
+
|
|
613
|
+
Serve the built-in dashboard to inspect worker health, agent health, execution
|
|
614
|
+
state counts, recent executions, Redis stream queue depth, consumer-group
|
|
615
|
+
pending/lag, failure details, routing decisions, derived alerts, and segmented
|
|
616
|
+
queue/run/end-to-end task latency:
|
|
617
|
+
|
|
618
|
+
```bash
|
|
619
|
+
uv run python -m by_framework.observability.dashboard --host 127.0.0.1 --port 8765
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
Open `http://127.0.0.1:8765/`. For a local UI preview without Redis, open
|
|
623
|
+
`http://127.0.0.1:8765/?demo=1`. Prometheus-style metrics are available at
|
|
624
|
+
`http://127.0.0.1:8765/metrics`, and the dashboard keeps short in-memory trend
|
|
625
|
+
history at `http://127.0.0.1:8765/api/history`. The UI uses split polling
|
|
626
|
+
endpoints (`/api/workers`, `/api/executions`, `/api/queues`, `/api/history`)
|
|
627
|
+
instead of polling the full `/api/snapshot` endpoint on every refresh. Runtime
|
|
628
|
+
self-check data is exposed at `/api/health`, shown in the toolbar, and exported
|
|
629
|
+
through `/metrics`.
|
|
630
|
+
Alert thresholds can be tuned with `--queue-backlog-threshold`,
|
|
631
|
+
`--delivery-pending-threshold`, `--consumer-pending-threshold`, and
|
|
632
|
+
`--failed-execution-threshold`.
|
|
633
|
+
|
|
634
|
+
The dashboard frontend is built with React/Vite under
|
|
635
|
+
`src/by_framework/observability/frontend`; its production build is packaged in
|
|
636
|
+
`src/by_framework/observability/static`.
|
|
637
|
+
|
|
631
638
|
---
|
|
632
639
|
|
|
633
640
|
## Roadmap
|
|
634
641
|
|
|
635
|
-
- [
|
|
642
|
+
- [x] Observability dashboard for Worker health and task streams
|
|
636
643
|
- [ ] WASM-based sandbox for stronger execution isolation
|
|
637
644
|
- [ ] Enhanced LangGraph multi-agent orchestration adapter
|
|
638
645
|
|
|
@@ -608,11 +608,34 @@ import logging
|
|
|
608
608
|
setup_logging(level=logging.INFO, use_json=True) # JSON 格式便于日志聚合
|
|
609
609
|
```
|
|
610
610
|
|
|
611
|
+
### 可观测仪表盘
|
|
612
|
+
|
|
613
|
+
启动内置仪表盘,用于查看 Worker 健康、Agent 健康、执行状态计数、最近执行、Redis Stream 队列深度、consumer group pending/lag、失败详情、路由决策、派生告警,以及排队/执行/端到端分段延迟:
|
|
614
|
+
|
|
615
|
+
```bash
|
|
616
|
+
uv run python -m by_framework.observability.dashboard --host 127.0.0.1 --port 8765
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
打开 `http://127.0.0.1:8765/`。如果本地没有 Redis,可打开
|
|
620
|
+
`http://127.0.0.1:8765/?demo=1` 预览 UI。Prometheus 风格指标位于
|
|
621
|
+
`http://127.0.0.1:8765/metrics`,仪表盘也会在
|
|
622
|
+
`http://127.0.0.1:8765/api/history` 保留短期内存趋势历史。UI 使用拆分后的
|
|
623
|
+
轮询接口(`/api/workers`、`/api/executions`、`/api/queues`、`/api/history`),
|
|
624
|
+
不会每次刷新都请求完整的 `/api/snapshot`。运行时自检数据位于
|
|
625
|
+
`/api/health`,会显示在工具栏中,也会通过 `/metrics` 导出。
|
|
626
|
+
告警阈值可通过 `--queue-backlog-threshold`、
|
|
627
|
+
`--delivery-pending-threshold`、`--consumer-pending-threshold` 和
|
|
628
|
+
`--failed-execution-threshold` 调整。
|
|
629
|
+
|
|
630
|
+
仪表盘前端使用 React/Vite 构建,源码位于
|
|
631
|
+
`src/by_framework/observability/frontend`,生产构建产物打包在
|
|
632
|
+
`src/by_framework/observability/static`。
|
|
633
|
+
|
|
611
634
|
---
|
|
612
635
|
|
|
613
636
|
## 路线图
|
|
614
637
|
|
|
615
|
-
- [
|
|
638
|
+
- [x] Worker 健康与任务流的可观测仪表盘
|
|
616
639
|
- [ ] 基于 WASM 的沙箱,实现更强隔离
|
|
617
640
|
- [ ] 增强的 LangGraph 多 Agent 编排适配器
|
|
618
641
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# pylint: disable=C0114,C0301,R0914,W0718
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import json
|
|
4
5
|
import os
|
|
5
6
|
from typing import Any, Dict, List, Optional
|
|
6
7
|
|
|
@@ -152,16 +153,32 @@ class ByClawHistoryBackend(BaseHistoryBackend):
|
|
|
152
153
|
else item.get("role", "unknown")
|
|
153
154
|
)
|
|
154
155
|
# 兼容多种字段名:messageContent 是 ByClaw 风格,content 是标准风格
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
raw_content = item.get("messageContent") or item.get("content") or ""
|
|
157
|
+
related_resources = item.get("relatedResources")
|
|
158
|
+
files = []
|
|
159
|
+
if related_resources:
|
|
160
|
+
try:
|
|
161
|
+
res_dict = json.loads(related_resources)
|
|
162
|
+
files = res_dict.get("files") or []
|
|
163
|
+
except Exception:
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
if role and (raw_content or files):
|
|
167
|
+
content_list = []
|
|
168
|
+
if raw_content:
|
|
169
|
+
content_list.append({"type": "text", "text": raw_content})
|
|
170
|
+
|
|
171
|
+
if files:
|
|
172
|
+
for f in files:
|
|
173
|
+
content_list.append({"type": "file", "file": f})
|
|
174
|
+
|
|
175
|
+
message = {
|
|
176
|
+
"role": role,
|
|
177
|
+
"content": content_list,
|
|
178
|
+
"metadata": item.get("metadata", {}),
|
|
179
|
+
}
|
|
180
|
+
transformed.append(message)
|
|
181
|
+
|
|
165
182
|
return transformed
|
|
166
183
|
|
|
167
184
|
async def save_message(
|
|
@@ -57,8 +57,16 @@ async def test_byclaw_history_backend_formats_messages(monkeypatch) -> None:
|
|
|
57
57
|
history = await backend.get_history("sess-1", limit=2)
|
|
58
58
|
|
|
59
59
|
assert history == [
|
|
60
|
-
{
|
|
61
|
-
|
|
60
|
+
{
|
|
61
|
+
"role": "user",
|
|
62
|
+
"content": [{"type": "text", "text": "hello"}],
|
|
63
|
+
"metadata": {"n": 1},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"role": "assistant",
|
|
67
|
+
"content": [{"type": "text", "text": "world"}],
|
|
68
|
+
"metadata": {"n": 2},
|
|
69
|
+
},
|
|
62
70
|
]
|
|
63
71
|
|
|
64
72
|
|
|
@@ -101,8 +109,16 @@ async def test_byclaw_history_backend_with_discovery() -> None:
|
|
|
101
109
|
|
|
102
110
|
# Verify transformed results
|
|
103
111
|
assert history == [
|
|
104
|
-
{
|
|
105
|
-
|
|
112
|
+
{
|
|
113
|
+
"role": "user",
|
|
114
|
+
"content": [{"type": "text", "text": "hello from discovery"}],
|
|
115
|
+
"metadata": {},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"role": "assistant",
|
|
119
|
+
"content": [{"type": "text", "text": "response from discovery"}],
|
|
120
|
+
"metadata": {},
|
|
121
|
+
},
|
|
106
122
|
]
|
|
107
123
|
|
|
108
124
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import hashlib
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
8
7
|
from by_framework.core.protocol.commands import ResumeCommand
|
|
@@ -52,13 +51,3 @@ def extract_resume_data(command: ResumeCommand) -> str:
|
|
|
52
51
|
return extract_content_text(command.content)
|
|
53
52
|
|
|
54
53
|
return ""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def str_to_uint128(s: str) -> int:
|
|
58
|
-
"""Convert a string to a 128-bit integer (for OTEL TraceId)."""
|
|
59
|
-
return int(hashlib.md5(s.encode()).hexdigest(), 16)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def str_to_uint64(s: str) -> int:
|
|
63
|
-
"""Convert a string to a 64-bit integer (for OTEL SpanId)."""
|
|
64
|
-
return int(hashlib.md5(s.encode()).hexdigest()[:16], 16)
|
|
@@ -16,15 +16,11 @@ from by_framework.common.logger import logger
|
|
|
16
16
|
from by_framework.core.protocol.agent_state import AgentState
|
|
17
17
|
from by_framework.core.protocol.commands import ResumeCommand
|
|
18
18
|
from by_framework.core.protocol.events import StreamChunkEvent
|
|
19
|
+
from by_framework.observability.span_recorder import (str_to_uint64, str_to_uint128)
|
|
19
20
|
from langchain_core.messages import HumanMessage
|
|
20
21
|
from langgraph.types import Command
|
|
21
22
|
|
|
22
|
-
from ._utils import
|
|
23
|
-
extract_content_text,
|
|
24
|
-
extract_resume_data,
|
|
25
|
-
str_to_uint64,
|
|
26
|
-
str_to_uint128,
|
|
27
|
-
)
|
|
23
|
+
from ._utils import extract_content_text, extract_resume_data
|
|
28
24
|
|
|
29
25
|
if TYPE_CHECKING:
|
|
30
26
|
from by_framework.core.protocol.commands import GatewayCommand
|
|
@@ -383,6 +379,26 @@ class LangGraphAdapter:
|
|
|
383
379
|
@contextmanager
|
|
384
380
|
def _langfuse_callback_manager(self, callbacks: list[Any]) -> Iterator[None]:
|
|
385
381
|
"""Prepare Langfuse callback and observation for LangChain."""
|
|
382
|
+
# Prefer AgentContext's callback factory so trace and parent ids align.
|
|
383
|
+
# Filter out auto-generated MagicMock attributes when tests use a mock
|
|
384
|
+
# context — real callback objects always come from a non-test module.
|
|
385
|
+
langfuse_callback_value = getattr(self._context, "langfuse_callback", None)
|
|
386
|
+
is_real_callback = langfuse_callback_value is not None and type(
|
|
387
|
+
langfuse_callback_value
|
|
388
|
+
).__module__ not in ("unittest.mock",)
|
|
389
|
+
|
|
390
|
+
if is_real_callback:
|
|
391
|
+
handler = (
|
|
392
|
+
langfuse_callback_value()
|
|
393
|
+
if callable(langfuse_callback_value)
|
|
394
|
+
else langfuse_callback_value
|
|
395
|
+
)
|
|
396
|
+
if handler is not None:
|
|
397
|
+
callbacks.append(handler)
|
|
398
|
+
yield
|
|
399
|
+
return
|
|
400
|
+
|
|
401
|
+
# Fallback to local import if context method is missing
|
|
386
402
|
# pylint: disable=import-outside-toplevel
|
|
387
403
|
try:
|
|
388
404
|
langfuse_config = import_module(
|
|
@@ -414,6 +430,17 @@ class LangGraphAdapter:
|
|
|
414
430
|
},
|
|
415
431
|
metadata=self._default_metadata(),
|
|
416
432
|
):
|
|
433
|
+
# Prevent the generated OTel span from being promoted to a trace root.
|
|
434
|
+
# The native LangfusePlugin sets the same attribute on its own path
|
|
435
|
+
# (via _SdkLangfuseTracer); this covers the LangGraph fallback path.
|
|
436
|
+
try:
|
|
437
|
+
from opentelemetry import trace
|
|
438
|
+
|
|
439
|
+
current_span = trace.get_current_span()
|
|
440
|
+
if current_span and hasattr(current_span, "set_attribute"):
|
|
441
|
+
current_span.set_attribute("langfuse.internal.as_root", False)
|
|
442
|
+
except Exception: # pylint: disable=broad-exception-caught
|
|
443
|
+
pass
|
|
417
444
|
yield
|
|
418
445
|
|
|
419
446
|
@staticmethod
|
{by_framework-0.2.1 → by_framework-0.2.2.dev1}/libs/by-framework-langgraph/tests/test_adapter.py
RENAMED
|
@@ -259,6 +259,50 @@ class TestAdapterRun:
|
|
|
259
259
|
}
|
|
260
260
|
assert observation_calls[0]["name"] == "planner:langgraph"
|
|
261
261
|
|
|
262
|
+
@pytest.mark.asyncio
|
|
263
|
+
async def test_uses_context_langfuse_callback_property(self):
|
|
264
|
+
"""Verify AgentContext.langfuse_callback property value is used directly as a handler."""
|
|
265
|
+
handler = object()
|
|
266
|
+
|
|
267
|
+
# pylint: disable=too-few-public-methods,missing-class-docstring,missing-function-docstring
|
|
268
|
+
class ContextWithCallbackProperty:
|
|
269
|
+
session_id = "test-session"
|
|
270
|
+
trace_id = "trace-ctx"
|
|
271
|
+
message_id = "msg-ctx"
|
|
272
|
+
parent_message_id = ""
|
|
273
|
+
current_agent_id = "planner"
|
|
274
|
+
current_command = SimpleNamespace(
|
|
275
|
+
header=MessageHeader(
|
|
276
|
+
message_id="msg-ctx",
|
|
277
|
+
session_id="test-session",
|
|
278
|
+
trace_id="trace-ctx",
|
|
279
|
+
target_agent_type="planner",
|
|
280
|
+
)
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
def __init__(self):
|
|
284
|
+
self.emit_chunk = AsyncMock()
|
|
285
|
+
|
|
286
|
+
@property
|
|
287
|
+
def langfuse_callback(self):
|
|
288
|
+
return handler
|
|
289
|
+
|
|
290
|
+
ctx = ContextWithCallbackProperty()
|
|
291
|
+
graph = MagicMock()
|
|
292
|
+
graph.ainvoke = AsyncMock(
|
|
293
|
+
return_value={"messages": [MagicMock(content="hello")]}
|
|
294
|
+
)
|
|
295
|
+
snapshot = MagicMock()
|
|
296
|
+
snapshot.next = ()
|
|
297
|
+
graph.get_state.return_value = snapshot
|
|
298
|
+
|
|
299
|
+
adapter = LangGraphAdapter(graph, ctx, stream=False)
|
|
300
|
+
result = await adapter.run(AskAgentCommand(header=_make_header(), content="hi"))
|
|
301
|
+
|
|
302
|
+
assert result == "hello"
|
|
303
|
+
_, kwargs = graph.ainvoke.call_args
|
|
304
|
+
assert kwargs["config"]["callbacks"] == [handler]
|
|
305
|
+
|
|
262
306
|
@pytest.mark.asyncio
|
|
263
307
|
async def test_skips_langfuse_tracing_silently_when_not_configured(
|
|
264
308
|
self, monkeypatch, caplog
|
by_framework-0.2.2.dev1/libs/by-framework-trace-langfuse/src/by_framework_trace_langfuse/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Langfuse trace provider package for by-framework."""
|
|
2
|
+
|
|
3
|
+
from .langfuse import (
|
|
4
|
+
LANGFUSE_PARENT_OBSERVATION_METADATA_KEY,
|
|
5
|
+
LangfuseConfig,
|
|
6
|
+
LangfusePlugin,
|
|
7
|
+
LangfuseTraceProviderFactory,
|
|
8
|
+
start_client_dispatch_observation,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"LANGFUSE_PARENT_OBSERVATION_METADATA_KEY",
|
|
13
|
+
"LangfuseConfig",
|
|
14
|
+
"LangfusePlugin",
|
|
15
|
+
"LangfuseTraceProviderFactory",
|
|
16
|
+
"start_client_dispatch_observation",
|
|
17
|
+
]
|