aria-code 0.52.0__py3-none-any.whl
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.
- aria_code/__init__.py +42 -0
- aria_code/_version.py +20 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +34 -0
- aria_code/agents/base.py +318 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +303 -0
- aria_code/agents/financial/fundamental.py +191 -0
- aria_code/agents/financial/macro.py +99 -0
- aria_code/agents/financial/news.py +207 -0
- aria_code/agents/financial/risk.py +165 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +258 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +363 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +158 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +492 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +15 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +95 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/bootstrap.py +145 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +16 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +369 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +239 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
- aria_code/apps/cli/commands/broker_cmds.py +1234 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +87 -0
- aria_code/apps/cli/commands/core_cmds.py +2520 -0
- aria_code/apps/cli/commands/data_cmds.py +457 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +434 -0
- aria_code/apps/cli/commands/market_cmds.py +1381 -0
- aria_code/apps/cli/commands/market_context.py +425 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2153 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
- aria_code/apps/cli/commands/report.py +437 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +669 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
- aria_code/apps/cli/commands/workflow_cmds.py +480 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +78 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/deterministic.py +191 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +196 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
- aria_code/apps/cli/handlers/market_handlers.py +2513 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/helpers.py +302 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +297 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +276 -0
- aria_code/apps/cli/intent_signals.py +344 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +536 -0
- aria_code/apps/cli/main.py +29 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/model_catalog.py +620 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +59 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +53 -0
- aria_code/apps/cli/prompts/select.py +142 -0
- aria_code/apps/cli/prompts/system_prompts.py +552 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +521 -0
- aria_code/apps/cli/providers/chat_routing.py +128 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
- aria_code/apps/cli/providers/runtime_bridge.py +353 -0
- aria_code/apps/cli/providers/vertexai_stream.py +316 -0
- aria_code/apps/cli/runtime_consumer.py +657 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_store.py +112 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +823 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +106 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +180 -0
- aria_code/apps/cli/tools/market_tools.py +620 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +726 -0
- aria_code/apps/cli/tools/write_tools.py +845 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +153 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1597 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +6743 -0
- aria_code/aria_daemon.py +1398 -0
- aria_code/aria_feishu_bot.py +1423 -0
- aria_code/aria_mcp_server.py +7 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_relay_server.py +490 -0
- aria_code/aria_telegram_bot.py +202 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +182 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1976 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +181 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/demo_player.py +207 -0
- aria_code/doctor.py +813 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/backtest_engine.py +354 -0
- aria_code/domain/backtest_report.py +472 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/harness.py +598 -0
- aria_code/evals/runner.py +238 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +386 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +639 -0
- aria_code/memory_manager.py +246 -0
- aria_code/model_capability.py +486 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +23 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +52 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +201 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +111 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1550 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +396 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +79 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +268 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +57 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +157 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +8 -0
- aria_code/packages/aria_tools/financial/_paths.py +130 -0
- aria_code/packages/aria_tools/financial/compliance.py +31 -0
- aria_code/packages/aria_tools/financial/factors.py +33 -0
- aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
- aria_code/packages/aria_tools/financial/strategy.py +31 -0
- aria_code/packages/aria_tools/registry.py +128 -0
- aria_code/packages/quant_engine/__init__.py +34 -0
- aria_code/packages/quant_engine/_namespace.py +62 -0
- aria_code/packages/quant_engine/backtest/__init__.py +14 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +96 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +80 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/ml_model.py +377 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/logistics/__init__.py +169 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +129 -0
- aria_code/providers/llm/openai_compat.py +313 -0
- aria_code/providers/llm/registry.py +444 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +589 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/runtime/__init__.py +169 -0
- aria_code/runtime/acceptance.py +481 -0
- aria_code/runtime/agent_loop.py +1520 -0
- aria_code/runtime/approval.py +57 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +432 -0
- aria_code/runtime/crash_report.py +174 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +150 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/repo_map.py +700 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +450 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/subagent.py +547 -0
- aria_code/runtime/task_ledger.py +86 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/tool_executor.py +217 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +23 -0
- aria_code/safety/permissions.py +306 -0
- aria_code/safety/service.py +102 -0
- aria_code/setup_wizard.py +673 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +504 -0
- aria_code/tools/data_analysis_tools.py +809 -0
- aria_code/tools/enterprise_finance_tools.py +156 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +885 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3417 -0
- aria_code/tools/logistics_tools.py +135 -0
- aria_code/tools/macro_tools.py +369 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +659 -0
- aria_code/tools/spreadsheet_tools.py +388 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +508 -0
- aria_code/ui/completer.py +501 -0
- aria_code/ui/console.py +281 -0
- aria_code/ui/image_render.py +243 -0
- aria_code/ui/input_box.py +488 -0
- aria_code/ui/picker.py +201 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/finance.py +1705 -0
- aria_code/ui/render/market.py +225 -0
- aria_code/ui/render/output.py +775 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +354 -0
- aria_code/ui/robot.py +235 -0
- aria_code/ui/startup_dashboard.py +109 -0
- aria_code/utils/vscode_uri.py +37 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +271 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +193 -0
- aria_code/workspace/verify.py +113 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_context.py +233 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.52.0.dist-info/METADATA +237 -0
- aria_code-0.52.0.dist-info/RECORD +478 -0
- aria_code-0.52.0.dist-info/WHEEL +5 -0
- aria_code-0.52.0.dist-info/entry_points.txt +3 -0
- aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.52.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/registry.py — Agent 注册与自动发现
|
|
3
|
+
==========================================
|
|
4
|
+
1. 内置 agent 预注册(technical / fundamental / macro / risk)
|
|
5
|
+
2. 扫描 ./aria_agents/ → 自动注册用户自定义 agent
|
|
6
|
+
3. 提供 get() / list() / register() 接口
|
|
7
|
+
|
|
8
|
+
自定义 Agent 放置规则:
|
|
9
|
+
项目根/aria_agents/my_agent.py
|
|
10
|
+
类需继承 BaseAgent,且声明 name 属性
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import importlib.util
|
|
16
|
+
import inspect
|
|
17
|
+
import logging
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Dict, List, Optional, Type
|
|
21
|
+
|
|
22
|
+
from .base import BaseAgent
|
|
23
|
+
from .financial.technical import TechnicalAgent
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
# ── 内置 agent 预注册 ─────────────────────────────────────────────────────────
|
|
28
|
+
_BUILTIN: Dict[str, Type[BaseAgent]] = {
|
|
29
|
+
"technical": TechnicalAgent,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# 尝试加载其他内置 agent(文件存在则注册)
|
|
33
|
+
def _try_import_builtin(module_path: str, name: str) -> None:
|
|
34
|
+
try:
|
|
35
|
+
parts = module_path.split(".")
|
|
36
|
+
mod = importlib.import_module(module_path)
|
|
37
|
+
for _, cls in inspect.getmembers(mod, inspect.isclass):
|
|
38
|
+
if issubclass(cls, BaseAgent) and cls is not BaseAgent:
|
|
39
|
+
_BUILTIN[cls.name] = cls
|
|
40
|
+
except ImportError:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_try_import_builtin("aria_code.agents.financial.macro", "macro")
|
|
45
|
+
_try_import_builtin("aria_code.agents.financial.fundamental", "fundamental")
|
|
46
|
+
_try_import_builtin("aria_code.agents.financial.risk", "risk")
|
|
47
|
+
_try_import_builtin("aria_code.agents.financial.synthesis", "synthesis")
|
|
48
|
+
_try_import_builtin("aria_code.agents.financial.news", "news")
|
|
49
|
+
_try_import_builtin("aria_code.agents.financial.catalyst", "catalyst")
|
|
50
|
+
_try_import_builtin("aria_code.agents.financial.debate", "debate")
|
|
51
|
+
_try_import_builtin("aria_code.agents.financial.earnings", "earnings")
|
|
52
|
+
_try_import_builtin("aria_code.agents.financial.sector", "sector")
|
|
53
|
+
_try_import_builtin("aria_code.agents.financial.strategist", "strategist")
|
|
54
|
+
_try_import_builtin("aria_code.agents.engineering.coder", "coder")
|
|
55
|
+
_try_import_builtin("aria_code.agents.engineering.tester", "tester")
|
|
56
|
+
_try_import_builtin("aria_code.agents.financial.corporate_finance", "corporate_finance")
|
|
57
|
+
_try_import_builtin("aria_code.agents.financial.cashflow_burn", "cashflow_burn")
|
|
58
|
+
_try_import_builtin("aria_code.agents.financial.stripe_revenue", "stripe_revenue")
|
|
59
|
+
_try_import_builtin("aria_code.agents.portfolio_agent", "portfolio")
|
|
60
|
+
_try_import_builtin("aria_code.agents.supervisor", "supervisor")
|
|
61
|
+
|
|
62
|
+
# ── 经营权共创平台 Agent 包 ────────────────────────────────────────────────────
|
|
63
|
+
_try_import_builtin("aria_code.agents.realty.asset_diagnosis", "asset_diagnosis")
|
|
64
|
+
_try_import_builtin("aria_code.agents.realty.business_match", "business_match")
|
|
65
|
+
_try_import_builtin("aria_code.agents.realty.contract_rules", "contract_rules")
|
|
66
|
+
_try_import_builtin("aria_code.agents.realty.revenue_share", "revenue_share")
|
|
67
|
+
_try_import_builtin("aria_code.agents.realty.cashflow_verify", "cashflow_verify")
|
|
68
|
+
_try_import_builtin("aria_code.agents.realty.energy_anomaly", "energy_anomaly")
|
|
69
|
+
_try_import_builtin("aria_code.agents.realty.fulfillment_risk", "fulfillment_risk")
|
|
70
|
+
_try_import_builtin("aria_code.agents.realty.ops_optimize", "ops_optimize")
|
|
71
|
+
_try_import_builtin("aria_code.agents.realty.exit_settlement", "exit_settlement")
|
|
72
|
+
|
|
73
|
+
# ── 海外仓与物流供应链 Agent 包 ──────────────────────────────────────────────────
|
|
74
|
+
_try_import_builtin("aria_code.agents.warehouse.logistics_sync", "warehouse_logistics_sync")
|
|
75
|
+
_try_import_builtin("aria_code.agents.warehouse.inbound_exceptions", "warehouse_inbound_exceptions")
|
|
76
|
+
_try_import_builtin("aria_code.agents.warehouse.inventory_health", "warehouse_inventory_health")
|
|
77
|
+
_try_import_builtin("aria_code.agents.warehouse.logistics_cost", "warehouse_logistics_cost")
|
|
78
|
+
_try_import_builtin("aria_code.agents.warehouse.fulfillment_leadtime", "warehouse_fulfillment_leadtime")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class AgentRegistry:
|
|
82
|
+
"""
|
|
83
|
+
Agent 注册中心(单例)。
|
|
84
|
+
|
|
85
|
+
用法:
|
|
86
|
+
registry = get_registry()
|
|
87
|
+
registry.register(MyAgent)
|
|
88
|
+
agent_cls = registry.get("my_agent")
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self):
|
|
92
|
+
self._agents: Dict[str, Type[BaseAgent]] = dict(_BUILTIN)
|
|
93
|
+
self._scanned = False
|
|
94
|
+
|
|
95
|
+
def register(self, cls: Type[BaseAgent]) -> None:
|
|
96
|
+
"""手动注册一个 Agent 类"""
|
|
97
|
+
if not (isinstance(cls, type) and issubclass(cls, BaseAgent)):
|
|
98
|
+
raise TypeError(f"{cls} 不是 BaseAgent 子类")
|
|
99
|
+
self._agents[cls.name] = cls
|
|
100
|
+
logger.info(f"✓ 注册 Agent: {cls.name}")
|
|
101
|
+
|
|
102
|
+
def get(self, name: str) -> Optional[Type[BaseAgent]]:
|
|
103
|
+
"""按名称获取 Agent 类"""
|
|
104
|
+
self._ensure_scanned()
|
|
105
|
+
return self._agents.get(name.lower())
|
|
106
|
+
|
|
107
|
+
def list(self) -> List[Dict]:
|
|
108
|
+
"""列出所有已注册 Agent"""
|
|
109
|
+
self._ensure_scanned()
|
|
110
|
+
return [
|
|
111
|
+
{"name": name, "description": cls.description, "builtin": name in _BUILTIN}
|
|
112
|
+
for name, cls in self._agents.items()
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
def _ensure_scanned(self) -> None:
|
|
116
|
+
if not self._scanned:
|
|
117
|
+
self._scan_project()
|
|
118
|
+
self._scanned = True
|
|
119
|
+
|
|
120
|
+
def _scan_project(self) -> None:
|
|
121
|
+
"""扫描当前工作目录及父级的 aria_agents/ 目录"""
|
|
122
|
+
search_paths = [Path.cwd(), Path.cwd().parent]
|
|
123
|
+
for base in search_paths:
|
|
124
|
+
agents_dir = base / "aria_agents"
|
|
125
|
+
if not agents_dir.is_dir():
|
|
126
|
+
continue
|
|
127
|
+
for py_file in sorted(agents_dir.glob("*.py")):
|
|
128
|
+
if py_file.name.startswith("_"):
|
|
129
|
+
continue
|
|
130
|
+
self._load_file(py_file)
|
|
131
|
+
break # 找到第一个 aria_agents/ 即停止向上搜索
|
|
132
|
+
|
|
133
|
+
def _load_file(self, path: Path) -> None:
|
|
134
|
+
"""加载一个 .py 文件,自动注册其中的 BaseAgent 子类"""
|
|
135
|
+
try:
|
|
136
|
+
spec = importlib.util.spec_from_file_location(path.stem, path)
|
|
137
|
+
module = importlib.util.module_from_spec(spec)
|
|
138
|
+
spec.loader.exec_module(module)
|
|
139
|
+
for _, cls in inspect.getmembers(module, inspect.isclass):
|
|
140
|
+
if (cls.__module__ == module.__name__
|
|
141
|
+
and issubclass(cls, BaseAgent)
|
|
142
|
+
and cls is not BaseAgent
|
|
143
|
+
and hasattr(cls, "name")
|
|
144
|
+
and cls.name != "base"):
|
|
145
|
+
self._agents[cls.name] = cls
|
|
146
|
+
logger.info(f"✓ 自动发现 Agent: {cls.name} ({path.name})")
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logger.warning(f"加载 agent 文件 {path} 失败: {e}")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# ── 单例 ──────────────────────────────────────────────────────────────────────
|
|
152
|
+
_registry: Optional[AgentRegistry] = None
|
|
153
|
+
|
|
154
|
+
def get_registry() -> AgentRegistry:
|
|
155
|
+
global _registry
|
|
156
|
+
if _registry is None:
|
|
157
|
+
_registry = AgentRegistry()
|
|
158
|
+
return _registry
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/signal_scheme.py — 领域可插拔的信号词汇表
|
|
3
|
+
====================================================
|
|
4
|
+
team.py 里的表决(_vote_signal)、辩论触发(_needs_debate)原本硬编码了金融的
|
|
5
|
+
BUY/HOLD/SELL/STRONG_BUY/STRONG_SELL 五级词汇。realty 的 9 个 agent 长期以来
|
|
6
|
+
借用同一套词汇表达完全不同的含义(BUY=推荐共创、流水真实、条款清晰、低风险……
|
|
7
|
+
每个文件的 BUY 意思都不一样,只在各自 docstring 里注明),靠 aria_cli.py 里
|
|
8
|
+
一张 _SIGNAL_LABELS 翻译表在展示层补救。这意味着一旦有人把多个 realty agent
|
|
9
|
+
接进 AgentTeam 做 vote/debate(cashflow_verify 的 SELL=疑似造假 和
|
|
10
|
+
ops_optimize 的 SELL=经营不佳需干预 完全不是同一个维度),_vote_signal 会把
|
|
11
|
+
它们当同一根多空轴数值平均,产出一个语义上没有意义的"共识"。
|
|
12
|
+
|
|
13
|
+
SignalScheme 把这套词汇表和打分/辩论触发规则抽成领域可配置的对象,
|
|
14
|
+
AgentTeam 默认用 FINANCIAL_SCHEME(对现有金融调用方零行为变化),
|
|
15
|
+
其他领域注册自己的词汇表即可复用同一套并行/表决/辩论/synthesis 编排逻辑,
|
|
16
|
+
而不必借用金融的 BUY/SELL 语义或答案词不达意。
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import Dict, List, Tuple
|
|
23
|
+
|
|
24
|
+
from .base import AgentResult
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class SignalScheme:
|
|
29
|
+
"""一套领域信号词汇表:多空打分 + 辩论触发条件。
|
|
30
|
+
|
|
31
|
+
upper_thresholds / lower_thresholds 特意分成两条腿而不是一条单向扫描的
|
|
32
|
+
区间列表——原始金融判定逻辑本身就是两段非对称的边界(上方 >= 含右端点,
|
|
33
|
+
下方 <= 含左端点,中间落空隙才算 neutral_default),一条单向 >= 扫描的
|
|
34
|
+
区间列表没法同时正确表达"上方含端点"和"下方也含端点"这两种边界方向,
|
|
35
|
+
会把 avg_score=0 这种中性分数错误地吃进最负的那个区间(已在 fuzz 测试里
|
|
36
|
+
实测过这个 bug:单向列表版本对 avg_score=0 的输入返回了 STRONG_SELL)。
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
name: str
|
|
40
|
+
# 信号 → 打分(用于表决时按置信度加权平均);分数越高越"正面"。
|
|
41
|
+
scores: Dict[str, int]
|
|
42
|
+
# 从高到低排列;第一个满足 avg_score >= threshold 的胜出。
|
|
43
|
+
upper_thresholds: List[Tuple[float, str]]
|
|
44
|
+
# 按"最极端优先"排列(比如先检查 <=-1.5 再检查 <=-0.5);
|
|
45
|
+
# 第一个满足 avg_score <= threshold 的胜出。
|
|
46
|
+
lower_thresholds: List[Tuple[float, str]]
|
|
47
|
+
# 触发 debate 的两组信号(出现其一 + 另一组其一即触发,比如金融的"多"与"空")
|
|
48
|
+
positive_signals: frozenset
|
|
49
|
+
negative_signals: frozenset
|
|
50
|
+
neutral_default: str = "HOLD"
|
|
51
|
+
|
|
52
|
+
def vote(self, results: List[AgentResult]) -> Tuple[str, float]:
|
|
53
|
+
valid = [r for r in results if r.success and r.signal in self.scores]
|
|
54
|
+
if not valid:
|
|
55
|
+
return self.neutral_default, 0.0
|
|
56
|
+
avg_score = sum(self.scores[r.signal] * r.confidence for r in valid) / len(valid)
|
|
57
|
+
avg_conf = sum(r.confidence for r in valid) / len(valid)
|
|
58
|
+
for threshold, label in self.upper_thresholds:
|
|
59
|
+
if avg_score >= threshold:
|
|
60
|
+
return label, avg_conf
|
|
61
|
+
for threshold, label in self.lower_thresholds:
|
|
62
|
+
if avg_score <= threshold:
|
|
63
|
+
return label, avg_conf
|
|
64
|
+
return self.neutral_default, avg_conf
|
|
65
|
+
|
|
66
|
+
def needs_debate(self, results: List[AgentResult]) -> bool:
|
|
67
|
+
signals = [r.signal for r in results if r.success and r.signal]
|
|
68
|
+
has_positive = any(s in self.positive_signals for s in signals)
|
|
69
|
+
has_negative = any(s in self.negative_signals for s in signals)
|
|
70
|
+
return has_positive and has_negative
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ── 金融:既有行为,原样保留(upper/lower 拆分精确复刻原 if/elif 分支)────────
|
|
74
|
+
FINANCIAL_SCHEME = SignalScheme(
|
|
75
|
+
name="financial",
|
|
76
|
+
scores={"STRONG_BUY": 2, "BUY": 1, "HOLD": 0, "SELL": -1, "STRONG_SELL": -2},
|
|
77
|
+
upper_thresholds=[(1.5, "STRONG_BUY"), (0.5, "BUY")],
|
|
78
|
+
lower_thresholds=[(-1.5, "STRONG_SELL"), (-0.5, "SELL")],
|
|
79
|
+
positive_signals=frozenset({"BUY", "STRONG_BUY"}),
|
|
80
|
+
negative_signals=frozenset({"SELL", "STRONG_SELL"}),
|
|
81
|
+
neutral_default="HOLD",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# ── 地产资管:健康度评估,不是交易动作 ──────────────────────────────────────
|
|
85
|
+
# GOOD/WATCH/CONCERN/SEVERE —— 这条轴描述"这个维度是否健康",不是"要不要买"。
|
|
86
|
+
# 9 个 realty agent 各自评估不同维度(流水真实性、合同风险、能耗异常、履约风险
|
|
87
|
+
# 等),但共享同一个"健康 → 需关注 → 有问题 → 严重"的四级尺度,用领域自己的
|
|
88
|
+
# 词汇表述比借用股票的 BUY/SELL 更准确,也让 vote/debate 的语义站得住脚。
|
|
89
|
+
REALTY_SCHEME = SignalScheme(
|
|
90
|
+
name="realty",
|
|
91
|
+
scores={"GOOD": 2, "WATCH": 0, "CONCERN": -1, "SEVERE": -2},
|
|
92
|
+
upper_thresholds=[(1.0, "GOOD")],
|
|
93
|
+
lower_thresholds=[(-1.5, "SEVERE"), (-0.5, "CONCERN")],
|
|
94
|
+
positive_signals=frozenset({"GOOD"}),
|
|
95
|
+
negative_signals=frozenset({"CONCERN", "SEVERE"}),
|
|
96
|
+
neutral_default="WATCH",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# ── 仓储 ERP:同样是运营健康度,不是交易动作 ────────────────────────────────
|
|
100
|
+
# Warehouse agents assess carrier synchronisation, inbound exceptions and stock
|
|
101
|
+
# health. Keeping a named scheme prevents callers from accidentally applying
|
|
102
|
+
# the financial BUY/HOLD/SELL vote to these operational signals.
|
|
103
|
+
WAREHOUSE_SCHEME = SignalScheme(
|
|
104
|
+
name="warehouse",
|
|
105
|
+
scores={"GOOD": 2, "WATCH": 0, "CONCERN": -1, "SEVERE": -2},
|
|
106
|
+
upper_thresholds=[(1.0, "GOOD")],
|
|
107
|
+
lower_thresholds=[(-1.5, "SEVERE"), (-0.5, "CONCERN")],
|
|
108
|
+
positive_signals=frozenset({"GOOD"}),
|
|
109
|
+
negative_signals=frozenset({"CONCERN", "SEVERE"}),
|
|
110
|
+
neutral_default="WATCH",
|
|
111
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/sports/football_agent.py — Football Analysis Agent
|
|
3
|
+
===========================================================
|
|
4
|
+
LLM-powered football match analysis using Elo + Dixon-Coles prediction + form data.
|
|
5
|
+
|
|
6
|
+
Prediction comes from packages.quant_engine.sports.predictor (Elo ratings,
|
|
7
|
+
Dixon-Coles with negative-binomial tail for lopsided matches, dynamic
|
|
8
|
+
Elo/DC mixing weights, recency-form and head-to-head adjustments, and
|
|
9
|
+
self-calibration), not football_data_client.predict_match — that function
|
|
10
|
+
is a much simpler independent-Poisson model over a static, hand-maintained
|
|
11
|
+
attack/defense lookup table with a flat home-advantage constant, no
|
|
12
|
+
Dixon-Coles low-score correlation correction, and no Elo. Verified the two
|
|
13
|
+
disagree by double digits on some matchups (13.1pp on a real fixture) rather
|
|
14
|
+
than assuming the richer model is worth switching to on faith.
|
|
15
|
+
|
|
16
|
+
football_data_client itself is left untouched — aria_feishu_bot.py calls
|
|
17
|
+
predict_match directly and has its own tested formatting/localization
|
|
18
|
+
pinned to that function's exact output, which is out of scope here. Only
|
|
19
|
+
get_team_stats() (recent-form text, not part of either prediction model)
|
|
20
|
+
is still sourced from football_data_client.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
from dataclasses import dataclass, field
|
|
27
|
+
from typing import Any, Dict, List, Optional
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class MatchPrediction:
|
|
34
|
+
home_team: str
|
|
35
|
+
away_team: str
|
|
36
|
+
league: str
|
|
37
|
+
home_win: float
|
|
38
|
+
draw: float
|
|
39
|
+
away_win: float
|
|
40
|
+
btts: float
|
|
41
|
+
lambda_home: float
|
|
42
|
+
lambda_away: float
|
|
43
|
+
most_likely: str
|
|
44
|
+
top_scores: List[Dict]
|
|
45
|
+
implied_odds: Dict[str, float]
|
|
46
|
+
analysis: str = ""
|
|
47
|
+
key_factors: List[str] = field(default_factory=list)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def verdict(self) -> str:
|
|
51
|
+
probs = {"home": self.home_win, "draw": self.draw, "away": self.away_win}
|
|
52
|
+
winner = max(probs, key=probs.get)
|
|
53
|
+
dominant = probs[winner] > 0.50
|
|
54
|
+
if winner == "home":
|
|
55
|
+
return f"主队{'强势' if dominant else '略有'}优势 ({self.home_win:.0%})"
|
|
56
|
+
elif winner == "away":
|
|
57
|
+
return f"客队{'强势' if dominant else '略有'}优势 ({self.away_win:.0%})"
|
|
58
|
+
else:
|
|
59
|
+
return f"势均力敌,平局概率较高 ({self.draw:.0%})"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class FootballAgent:
|
|
63
|
+
"""
|
|
64
|
+
Football analysis combining Poisson prediction + LLM interpretation.
|
|
65
|
+
Can run standalone (no LLM) or enhanced with LLM narrative.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
name = "football"
|
|
69
|
+
description = "足球赛事分析与预测 — 泊松模型 + 近期战绩 + xG数据"
|
|
70
|
+
|
|
71
|
+
def __init__(self, llm_call=None):
|
|
72
|
+
self._llm = llm_call # Optional: async fn(prompt) -> str
|
|
73
|
+
|
|
74
|
+
async def predict(
|
|
75
|
+
self,
|
|
76
|
+
home_team: str,
|
|
77
|
+
away_team: str,
|
|
78
|
+
league: str = "pl",
|
|
79
|
+
with_llm: bool = True,
|
|
80
|
+
neutral_venue: bool = False,
|
|
81
|
+
) -> MatchPrediction:
|
|
82
|
+
from football_data_client import get_team_stats
|
|
83
|
+
from packages.quant_engine.sports.predictor import quick_predict
|
|
84
|
+
|
|
85
|
+
# neutral_venue defaults False: club leagues (pl/bl1/sa/pd/fl1, the
|
|
86
|
+
# default `league="pl"`) really do have a home team playing at home.
|
|
87
|
+
# Pass True for a genuinely neutral-site fixture (e.g. a World Cup
|
|
88
|
+
# group match at a third country's stadium).
|
|
89
|
+
raw = quick_predict(home_team, away_team, league, neutral_venue=neutral_venue)
|
|
90
|
+
raw["most_likely_score"] = (
|
|
91
|
+
raw["top_scorelines"][0]["score"] if raw.get("top_scorelines") else "0-0"
|
|
92
|
+
)
|
|
93
|
+
h_stats = get_team_stats(league, home_team)
|
|
94
|
+
a_stats = get_team_stats(league, away_team)
|
|
95
|
+
|
|
96
|
+
key_factors = []
|
|
97
|
+
if h_stats:
|
|
98
|
+
key_factors.append(f"{home_team} 近5场: {h_stats['form']} (场均进球 {h_stats['avg_gf']})")
|
|
99
|
+
if a_stats:
|
|
100
|
+
key_factors.append(f"{away_team} 近5场: {a_stats['form']} (场均进球 {a_stats['avg_gf']})")
|
|
101
|
+
key_factors.append(
|
|
102
|
+
f"模型: {raw['model']} Elo差: {raw['elo_diff']:+.0f}"
|
|
103
|
+
f" (DC权重{raw['w_dc']:.0%}/Elo权重{raw['w_elo']:.0%})"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
analysis = ""
|
|
107
|
+
if with_llm and self._llm:
|
|
108
|
+
prompt = _build_analysis_prompt(raw, h_stats, a_stats)
|
|
109
|
+
try:
|
|
110
|
+
analysis = await self._llm(prompt)
|
|
111
|
+
except Exception as exc:
|
|
112
|
+
logger.warning("LLM analysis failed: %s", exc)
|
|
113
|
+
analysis = _fallback_analysis(raw)
|
|
114
|
+
else:
|
|
115
|
+
analysis = _fallback_analysis(raw)
|
|
116
|
+
|
|
117
|
+
return MatchPrediction(
|
|
118
|
+
home_team=home_team,
|
|
119
|
+
away_team=away_team,
|
|
120
|
+
league=league,
|
|
121
|
+
home_win=raw["home_win"],
|
|
122
|
+
draw=raw["draw"],
|
|
123
|
+
away_win=raw["away_win"],
|
|
124
|
+
btts=raw["btts"],
|
|
125
|
+
lambda_home=raw["lambda_home"],
|
|
126
|
+
lambda_away=raw["lambda_away"],
|
|
127
|
+
most_likely=raw["most_likely_score"],
|
|
128
|
+
top_scores=raw["top_scorelines"],
|
|
129
|
+
implied_odds=raw["implied_odds"],
|
|
130
|
+
analysis=analysis,
|
|
131
|
+
key_factors=key_factors,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _fallback_analysis(raw: Dict) -> str:
|
|
136
|
+
hw, d, aw = raw["home_win"], raw["draw"], raw["away_win"]
|
|
137
|
+
lh, la = raw["lambda_home"], raw["lambda_away"]
|
|
138
|
+
ht, at = raw["home_team"], raw["away_team"]
|
|
139
|
+
|
|
140
|
+
lines = []
|
|
141
|
+
if hw > aw + 0.15:
|
|
142
|
+
lines.append(f"泊松模型显示 **{ht}** 主场优势明显(胜率 {hw:.0%})")
|
|
143
|
+
elif aw > hw + 0.15:
|
|
144
|
+
lines.append(f"泊松模型显示 **{at}** 客场表现更强(胜率 {aw:.0%})")
|
|
145
|
+
else:
|
|
146
|
+
lines.append(f"双方实力相当,平局可能性较大({d:.0%})")
|
|
147
|
+
|
|
148
|
+
lines.append(f"预期进球:{ht} {lh:.1f} / {at} {la:.1f}")
|
|
149
|
+
top = raw["top_scorelines"][:3]
|
|
150
|
+
score_str = " | ".join(f"{s['score']}({s['prob']}%)" for s in top)
|
|
151
|
+
lines.append(f"高概率比分:{score_str}")
|
|
152
|
+
btts = raw["btts"]
|
|
153
|
+
lines.append(f"双方均进球概率:{btts:.0%}")
|
|
154
|
+
|
|
155
|
+
return "\n".join(lines)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _build_analysis_prompt(raw: Dict, h_stats: Optional[Dict], a_stats: Optional[Dict]) -> str:
|
|
159
|
+
top_scores = "、".join(
|
|
160
|
+
f"{s['score']}({s['prob']}%)"
|
|
161
|
+
for s in raw.get("top_scorelines", [])[:5]
|
|
162
|
+
)
|
|
163
|
+
return f"""你是一位专业足球分析师。根据以下泊松预测模型数据,用中文分析这场比赛:
|
|
164
|
+
|
|
165
|
+
【比赛】{raw['home_team']} vs {raw['away_team']}
|
|
166
|
+
|
|
167
|
+
【预测概率】
|
|
168
|
+
主队胜: {raw['home_win']:.1%} 平局: {raw['draw']:.1%} 客队胜: {raw['away_win']:.1%}
|
|
169
|
+
预期进球: 主队 {raw['lambda_home']:.2f} / 客队 {raw['lambda_away']:.2f}
|
|
170
|
+
最可能比分: {raw['most_likely_score']}
|
|
171
|
+
候选比分(按模型概率降序): {top_scores}
|
|
172
|
+
双方均进球: {raw['btts']:.1%}
|
|
173
|
+
|
|
174
|
+
【近期战绩】
|
|
175
|
+
{_format_stats(raw['home_team'], h_stats)}
|
|
176
|
+
{_format_stats(raw['away_team'], a_stats)}
|
|
177
|
+
|
|
178
|
+
请提供:
|
|
179
|
+
1. 比赛走势分析(3-4句)
|
|
180
|
+
2. 关键影响因素(2-3条)
|
|
181
|
+
3. 预测建议(1句话结论)
|
|
182
|
+
|
|
183
|
+
规则:
|
|
184
|
+
- 必须按“候选比分”概率顺序讨论比分,不要把低概率比分排到第一。
|
|
185
|
+
- 不要编造射正率、历史交锋、最近5场客场等输入数据之外的具体数字。
|
|
186
|
+
- 如果给出多个准确比分,直接引用候选比分及概率。
|
|
187
|
+
|
|
188
|
+
简洁专业,不超过200字。"""
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _format_stats(team: str, stats: Optional[Dict]) -> str:
|
|
192
|
+
if not stats:
|
|
193
|
+
return f"{team}: 数据不足"
|
|
194
|
+
return (
|
|
195
|
+
f"{team}: 近{stats['last_n']}场 {stats['w']}胜{stats['d']}平{stats['l']}负, "
|
|
196
|
+
f"进{stats['gf']}球失{stats['ga']}球, 近5场战绩: {stats['form']}"
|
|
197
|
+
)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/supervisor.py — 动态规划与路由 Agent
|
|
3
|
+
===========================================
|
|
4
|
+
负责根据用户意图和资产类型,动态挑选最合适的 Sub-agents 执行分析。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Dict
|
|
10
|
+
|
|
11
|
+
from .base import BaseAgent, AgentResult
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
class SupervisorAgent(BaseAgent):
|
|
16
|
+
name: str = "supervisor"
|
|
17
|
+
description: str = "动态规划与路由 Agent,决定应唤醒哪些子 Agent"
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def _fallback_selection(available: list[str]) -> list[str]:
|
|
21
|
+
"""Choose a deterministic, registry-safe fallback team.
|
|
22
|
+
|
|
23
|
+
The Supervisor is optional infrastructure: losing its LLM response must
|
|
24
|
+
never cause ``AgentTeam`` to receive names that are absent from the
|
|
25
|
+
registry. Prefer the familiar financial specialists, then fill from
|
|
26
|
+
any remaining available read-only agents.
|
|
27
|
+
"""
|
|
28
|
+
preferred = ["macro", "fundamental", "technical", "risk"]
|
|
29
|
+
chosen = [name for name in preferred if name in available]
|
|
30
|
+
for name in available:
|
|
31
|
+
if name not in chosen:
|
|
32
|
+
chosen.append(name)
|
|
33
|
+
if len(chosen) == 5:
|
|
34
|
+
break
|
|
35
|
+
return chosen[:5]
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def _normalize_selection(cls, selected: Any, available: list[str]) -> list[str]:
|
|
39
|
+
"""Validate model output and complete it with safe deterministic choices."""
|
|
40
|
+
if not isinstance(selected, list):
|
|
41
|
+
selected = []
|
|
42
|
+
|
|
43
|
+
allowed = set(available)
|
|
44
|
+
normalized: list[str] = []
|
|
45
|
+
for value in selected:
|
|
46
|
+
name = str(value or "").strip().lower()
|
|
47
|
+
if name in allowed and name not in normalized:
|
|
48
|
+
normalized.append(name)
|
|
49
|
+
if len(normalized) == 5:
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
# The prompt asks for 2–5 agents. On a partial installation, use all
|
|
53
|
+
# available specialists rather than inventing an unavailable name.
|
|
54
|
+
minimum = min(2, len(available))
|
|
55
|
+
if len(normalized) < minimum:
|
|
56
|
+
for name in cls._fallback_selection(available):
|
|
57
|
+
if name not in normalized:
|
|
58
|
+
normalized.append(name)
|
|
59
|
+
if len(normalized) >= minimum:
|
|
60
|
+
break
|
|
61
|
+
|
|
62
|
+
return normalized[:5]
|
|
63
|
+
|
|
64
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
65
|
+
from .registry import get_registry
|
|
66
|
+
registry = get_registry()
|
|
67
|
+
agents_info = [
|
|
68
|
+
info for info in registry.list()
|
|
69
|
+
if info["name"] not in ("supervisor", "synthesis", "debate", "base")
|
|
70
|
+
]
|
|
71
|
+
available = [str(info["name"]).lower() for info in agents_info]
|
|
72
|
+
|
|
73
|
+
system_prompt = (
|
|
74
|
+
"You are the Supervisor Agent of a financial analysis system.\n"
|
|
75
|
+
"Your task is to select the most appropriate specialist agents to analyze the given asset.\n"
|
|
76
|
+
"Available agents:\n"
|
|
77
|
+
)
|
|
78
|
+
for info in agents_info:
|
|
79
|
+
system_prompt += f"- {info['name']}: {info['description']}\n"
|
|
80
|
+
|
|
81
|
+
system_prompt += (
|
|
82
|
+
"\nSelect between 2 to 5 agents that are best suited for this asset.\n"
|
|
83
|
+
"For example, do not select crypto agents for standard stocks, and do not select realty agents for equities.\n"
|
|
84
|
+
"Output a strict JSON object with a single key 'selected_agents' containing a list of strings (the names of the agents to run).\n"
|
|
85
|
+
"Do not include markdown blocks or any other text.\n"
|
|
86
|
+
"Example: {\"selected_agents\": [\"macro\", \"technical\"]}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
user_prompt = f"Analyze asset: {symbol}\n"
|
|
90
|
+
if data and "market_data_block" in data:
|
|
91
|
+
user_prompt += f"Context:\n{data['market_data_block']}\n"
|
|
92
|
+
|
|
93
|
+
response_text = await self._call_llm(system_prompt, user_prompt, max_tokens=200, quote=data.get("quote"))
|
|
94
|
+
|
|
95
|
+
selected: Any = []
|
|
96
|
+
try:
|
|
97
|
+
start = response_text.find('{')
|
|
98
|
+
end = response_text.rfind('}') + 1
|
|
99
|
+
if start != -1 and end != 0:
|
|
100
|
+
parsed = json.loads(response_text[start:end])
|
|
101
|
+
selected = parsed.get("selected_agents", [])
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.warning(f"Supervisor json parse failed: {e}")
|
|
104
|
+
|
|
105
|
+
selected = self._normalize_selection(selected, available)
|
|
106
|
+
|
|
107
|
+
return AgentResult(
|
|
108
|
+
agent=self.name,
|
|
109
|
+
symbol=symbol,
|
|
110
|
+
analysis=json.dumps(selected),
|
|
111
|
+
confidence=1.0,
|
|
112
|
+
signal="HOLD",
|
|
113
|
+
)
|