aria-code 4.1.7__tar.gz → 4.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (422) hide show
  1. {aria_code-4.1.7 → aria_code-4.2.0}/PKG-INFO +4 -2
  2. {aria_code-4.1.7 → aria_code-4.2.0}/agents/__init__.py +2 -0
  3. {aria_code-4.1.7 → aria_code-4.2.0}/agents/base.py +6 -0
  4. {aria_code-4.1.7 → aria_code-4.2.0}/agents/portfolio_agent.py +43 -13
  5. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/asset_diagnosis.py +6 -4
  6. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/business_match.py +5 -4
  7. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/cashflow_verify.py +6 -5
  8. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/contract_rules.py +5 -4
  9. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/energy_anomaly.py +6 -5
  10. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/exit_settlement.py +6 -5
  11. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/fulfillment_risk.py +8 -7
  12. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/ops_optimize.py +7 -6
  13. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/revenue_share.py +7 -6
  14. aria_code-4.2.0/agents/signal_scheme.py +97 -0
  15. {aria_code-4.1.7 → aria_code-4.2.0}/agents/sports/football_agent.py +33 -5
  16. {aria_code-4.1.7 → aria_code-4.2.0}/agents/team.py +146 -52
  17. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/bootstrap.py +2 -0
  18. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/catalog.py +1 -1
  19. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/diagnostic_ops_cmds.py +51 -10
  20. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market.py +19 -1
  21. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/model_cmds.py +102 -0
  22. aria_code-4.2.0/apps/cli/commands/pdf_export_cmds.py +97 -0
  23. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/portfolio_cmds.py +110 -19
  24. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/report.py +60 -0
  25. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/team.py +70 -2
  26. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/workflow_cmds.py +109 -0
  27. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/intent_router.py +32 -5
  28. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/market_universe.py +79 -1
  29. aria_code-4.2.0/apps/cli/pdf_report.py +977 -0
  30. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/preflight.py +33 -28
  31. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/system_prompts.py +8 -0
  32. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/llm/ollama_stream.py +94 -6
  33. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/runtime_bridge.py +6 -0
  34. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/runtime_consumer.py +61 -6
  35. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/write_tools.py +79 -0
  36. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/utils/market_detect.py +3 -0
  37. {aria_code-4.1.7 → aria_code-4.2.0}/aria_cli.py +508 -178
  38. {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/PKG-INFO +4 -2
  39. {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/SOURCES.txt +27 -0
  40. {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/requires.txt +4 -0
  41. {aria_code-4.1.7 → aria_code-4.2.0}/artifacts.py +66 -0
  42. {aria_code-4.1.7 → aria_code-4.2.0}/file_analysis_tools.py +36 -9
  43. {aria_code-4.1.7 → aria_code-4.2.0}/market_data_client.py +87 -16
  44. {aria_code-4.1.7 → aria_code-4.2.0}/mcp_client.py +20 -0
  45. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/tools.py +2 -0
  46. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/__init__.py +13 -0
  47. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/context.py +100 -13
  48. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/registry.py +24 -2
  49. aria_code-4.2.0/packages/aria_services/research_protocol.py +57 -0
  50. aria_code-4.2.0/packages/aria_services/research_quality.py +186 -0
  51. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/usage.py +7 -2
  52. aria_code-4.2.0/packages/aria_skills/__init__.py +46 -0
  53. aria_code-4.2.0/packages/aria_skills/catalog.py +148 -0
  54. aria_code-4.2.0/packages/aria_skills/loader.py +429 -0
  55. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_skills/registry.py +26 -1
  56. {aria_code-4.1.7 → aria_code-4.2.0}/pyproject.toml +14 -2
  57. {aria_code-4.1.7 → aria_code-4.2.0}/report_generator.py +201 -4
  58. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/__init__.py +40 -0
  59. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/agent_loop.py +69 -6
  60. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/approval.py +6 -0
  61. aria_code-4.2.0/runtime/checkpoints.py +432 -0
  62. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/events.py +13 -2
  63. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/gateway.py +6 -0
  64. aria_code-4.2.0/runtime/run_state.py +127 -0
  65. aria_code-4.2.0/runtime/run_store.py +449 -0
  66. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/subagent.py +176 -5
  67. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/tool_executor.py +35 -7
  68. aria_code-4.2.0/runtime/worktrees.py +215 -0
  69. aria_code-4.2.0/tests/test_agent_team_fallback.py +105 -0
  70. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_analyze_file_tool.py +20 -0
  71. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_aria_cli_core.py +2 -0
  72. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_artifacts_and_reports.py +26 -0
  73. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_app_split.py +71 -2
  74. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_runtime_consumer.py +27 -0
  75. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_context_service.py +41 -4
  76. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_finance_renderers.py +52 -2
  77. aria_code-4.2.0/tests/test_football_agent.py +103 -0
  78. aria_code-4.2.0/tests/test_markdown_pdf.py +60 -0
  79. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_data_client.py +50 -0
  80. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_universe.py +36 -0
  81. aria_code-4.2.0/tests/test_ollama_stream_tools.py +137 -0
  82. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_output_rendering.py +33 -0
  83. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_packages_facade.py +6 -0
  84. aria_code-4.2.0/tests/test_pdf_report.py +270 -0
  85. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_preflight.py +30 -2
  86. aria_code-4.2.0/tests/test_report_generator.py +65 -0
  87. aria_code-4.2.0/tests/test_research_protocol.py +26 -0
  88. aria_code-4.2.0/tests/test_research_quality.py +96 -0
  89. aria_code-4.2.0/tests/test_responsive_rendering.py +90 -0
  90. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_agent_loop.py +129 -1
  91. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_approval.py +31 -0
  92. aria_code-4.2.0/tests/test_runtime_checkpoints.py +175 -0
  93. aria_code-4.2.0/tests/test_runtime_run_store.py +146 -0
  94. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_tool_executor.py +26 -0
  95. aria_code-4.2.0/tests/test_runtime_worktrees.py +151 -0
  96. aria_code-4.2.0/tests/test_skill_agent_binding.py +103 -0
  97. aria_code-4.2.0/tests/test_skill_catalog.py +187 -0
  98. aria_code-4.2.0/tests/test_skill_loader.py +208 -0
  99. aria_code-4.2.0/tests/test_spreadsheet_tools.py +92 -0
  100. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_subagent.py +44 -0
  101. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_console_theme.py +8 -1
  102. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_input_box.py +22 -0
  103. {aria_code-4.1.7 → aria_code-4.2.0}/ui/banner.py +9 -2
  104. {aria_code-4.1.7 → aria_code-4.2.0}/ui/console.py +8 -0
  105. {aria_code-4.1.7 → aria_code-4.2.0}/ui/input_box.py +17 -7
  106. {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/finance.py +148 -21
  107. {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/output.py +78 -0
  108. aria_code-4.2.0/ui/render/responsive.py +75 -0
  109. {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/team.py +10 -2
  110. aria_code-4.1.7/packages/aria_skills/__init__.py +0 -5
  111. aria_code-4.1.7/tests/test_ollama_stream_tools.py +0 -57
  112. {aria_code-4.1.7 → aria_code-4.2.0}/LICENSE +0 -0
  113. {aria_code-4.1.7 → aria_code-4.2.0}/README.md +0 -0
  114. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/__init__.py +0 -0
  115. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/calibration_loop.py +0 -0
  116. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/critic.py +0 -0
  117. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/deepen.py +0 -0
  118. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/models.py +0 -0
  119. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/pipeline.py +0 -0
  120. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/quant_fusion.py +0 -0
  121. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/themes.py +0 -0
  122. {aria_code-4.1.7 → aria_code-4.2.0}/agents/deep/tiers.py +0 -0
  123. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/__init__.py +0 -0
  124. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/catalyst.py +0 -0
  125. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/debate.py +0 -0
  126. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/earnings.py +0 -0
  127. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/fundamental.py +0 -0
  128. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/macro.py +0 -0
  129. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/news.py +0 -0
  130. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/risk.py +0 -0
  131. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/sector.py +0 -0
  132. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/synthesis.py +0 -0
  133. {aria_code-4.1.7 → aria_code-4.2.0}/agents/financial/technical.py +0 -0
  134. {aria_code-4.1.7 → aria_code-4.2.0}/agents/realty/__init__.py +0 -0
  135. {aria_code-4.1.7 → aria_code-4.2.0}/agents/registry.py +0 -0
  136. {aria_code-4.1.7 → aria_code-4.2.0}/agents/sports/__init__.py +0 -0
  137. {aria_code-4.1.7 → aria_code-4.2.0}/aliyun_data_client.py +0 -0
  138. {aria_code-4.1.7 → aria_code-4.2.0}/apps/README.md +0 -0
  139. {aria_code-4.1.7 → aria_code-4.2.0}/apps/__init__.py +0 -0
  140. {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/README.md +0 -0
  141. {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/__init__.py +0 -0
  142. {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/intake.py +0 -0
  143. {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/registry.py +0 -0
  144. {aria_code-4.1.7 → aria_code-4.2.0}/apps/channels/tradingview.py +0 -0
  145. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/README.md +0 -0
  146. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/__init__.py +0 -0
  147. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/codegen_paths.py +0 -0
  148. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/__init__.py +0 -0
  149. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/analysis_cmds.py +0 -0
  150. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/auth_cmds.py +0 -0
  151. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/backtest_cmds.py +0 -0
  152. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/broker_cmds.py +0 -0
  153. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/business_workflow_cmds.py +0 -0
  154. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/data_cmds.py +0 -0
  155. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/diagnostic_cmds.py +0 -0
  156. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/file_cmds.py +0 -0
  157. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/finance_render.py +0 -0
  158. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/fx_commodity_cmds.py +0 -0
  159. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market_cmds.py +0 -0
  160. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market_context.py +0 -0
  161. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/market_render.py +0 -0
  162. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/ops_cmds.py +0 -0
  163. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/scaffold_templates.py +0 -0
  164. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/session_cmds.py +0 -0
  165. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/session_ux_cmds.py +0 -0
  166. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/team_render.py +0 -0
  167. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/ui_cmds.py +0 -0
  168. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/commands/workspace_cmds.py +0 -0
  169. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/config_paths.py +0 -0
  170. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/config_store.py +0 -0
  171. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/deterministic.py +0 -0
  172. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/direct.py +0 -0
  173. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/github_app_auth.py +0 -0
  174. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/__init__.py +0 -0
  175. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/broker_handlers.py +0 -0
  176. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/chart_handlers.py +0 -0
  177. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/market_handlers.py +0 -0
  178. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/realty_handlers.py +0 -0
  179. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/handlers/strategy_advice.py +0 -0
  180. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/hooks.py +0 -0
  181. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/i18n.py +0 -0
  182. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/intent.py +0 -0
  183. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/lifecycle_hooks.py +0 -0
  184. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/main.py +0 -0
  185. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/market_metadata.py +0 -0
  186. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/message_processing.py +0 -0
  187. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/plan_mode.py +0 -0
  188. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/plotly_html.py +0 -0
  189. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prediction_feedback.py +0 -0
  190. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/project_aria.py +0 -0
  191. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompt_assembly.py +0 -0
  192. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/__init__.py +0 -0
  193. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/coding.py +0 -0
  194. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/prompts/ui.py +0 -0
  195. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/__init__.py +0 -0
  196. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/base.py +0 -0
  197. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/chat_routing.py +0 -0
  198. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/llm/__init__.py +0 -0
  199. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/providers/llm/sse_stream.py +0 -0
  200. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/session_export.py +0 -0
  201. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/session_jsonl.py +0 -0
  202. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/session_store.py +0 -0
  203. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/todo_tracker.py +0 -0
  204. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/__init__.py +0 -0
  205. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/context.py +0 -0
  206. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/file_tools.py +0 -0
  207. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/market_tools.py +0 -0
  208. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/notebook_tools.py +0 -0
  209. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tools/system_tools.py +0 -0
  210. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/tradingview_bridge.py +0 -0
  211. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/turn_planning.py +0 -0
  212. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/update_check.py +0 -0
  213. {aria_code-4.1.7 → aria_code-4.2.0}/apps/cli/utils/__init__.py +0 -0
  214. {aria_code-4.1.7 → aria_code-4.2.0}/apps/daemon/README.md +0 -0
  215. {aria_code-4.1.7 → aria_code-4.2.0}/apps/vscode/README.md +0 -0
  216. {aria_code-4.1.7 → aria_code-4.2.0}/apps/vscode/package.json +0 -0
  217. {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/dependency_links.txt +0 -0
  218. {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/entry_points.txt +0 -0
  219. {aria_code-4.1.7 → aria_code-4.2.0}/aria_code.egg-info/top_level.txt +0 -0
  220. {aria_code-4.1.7 → aria_code-4.2.0}/aria_daemon.py +0 -0
  221. {aria_code-4.1.7 → aria_code-4.2.0}/aria_feishu_bot.py +0 -0
  222. {aria_code-4.1.7 → aria_code-4.2.0}/aria_relay_client.py +0 -0
  223. {aria_code-4.1.7 → aria_code-4.2.0}/aria_relay_server.py +0 -0
  224. {aria_code-4.1.7 → aria_code-4.2.0}/aria_telegram_bot.py +0 -0
  225. {aria_code-4.1.7 → aria_code-4.2.0}/ariarc.py +0 -0
  226. {aria_code-4.1.7 → aria_code-4.2.0}/backtest_engine.py +0 -0
  227. {aria_code-4.1.7 → aria_code-4.2.0}/backtest_report.py +0 -0
  228. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/__init__.py +0 -0
  229. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/automation.py +0 -0
  230. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/base.py +0 -0
  231. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/capabilities.py +0 -0
  232. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/__init__.py +0 -0
  233. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/easytrader_broker.py +0 -0
  234. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/futu_broker.py +0 -0
  235. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/longbridge_broker.py +0 -0
  236. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/tiger_broker.py +0 -0
  237. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/cn/xtquant_broker.py +0 -0
  238. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/config.py +0 -0
  239. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/__init__.py +0 -0
  240. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/alpaca_broker.py +0 -0
  241. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/ibkr_broker.py +0 -0
  242. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/intl/webull_broker.py +0 -0
  243. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/paper_broker.py +0 -0
  244. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/planning.py +0 -0
  245. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/registry.py +0 -0
  246. {aria_code-4.1.7 → aria_code-4.2.0}/brokers/trading.py +0 -0
  247. {aria_code-4.1.7 → aria_code-4.2.0}/change_store.py +0 -0
  248. {aria_code-4.1.7 → aria_code-4.2.0}/command_safety.py +0 -0
  249. {aria_code-4.1.7 → aria_code-4.2.0}/computer_use_tools.py +0 -0
  250. {aria_code-4.1.7 → aria_code-4.2.0}/dashboard_generator.py +0 -0
  251. {aria_code-4.1.7 → aria_code-4.2.0}/data_analysis_tools.py +0 -0
  252. {aria_code-4.1.7 → aria_code-4.2.0}/data_cleaner.py +0 -0
  253. {aria_code-4.1.7 → aria_code-4.2.0}/data_service.py +0 -0
  254. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/__init__.py +0 -0
  255. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/base.py +0 -0
  256. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/router.py +0 -0
  257. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/__init__.py +0 -0
  258. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/akshare_source.py +0 -0
  259. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/alpha_vantage_source.py +0 -0
  260. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/edgar_source.py +0 -0
  261. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/finnhub_source.py +0 -0
  262. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/fred_source.py +0 -0
  263. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/tushare_source.py +0 -0
  264. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/web_scraper_source.py +0 -0
  265. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/world_bank_source.py +0 -0
  266. {aria_code-4.1.7 → aria_code-4.2.0}/datasources/sources/yfinance_source.py +0 -0
  267. {aria_code-4.1.7 → aria_code-4.2.0}/demo_player.py +0 -0
  268. {aria_code-4.1.7 → aria_code-4.2.0}/doctor.py +0 -0
  269. {aria_code-4.1.7 → aria_code-4.2.0}/finance_formulas.py +0 -0
  270. {aria_code-4.1.7 → aria_code-4.2.0}/football_data_client.py +0 -0
  271. {aria_code-4.1.7 → aria_code-4.2.0}/intent_classifier.py +0 -0
  272. {aria_code-4.1.7 → aria_code-4.2.0}/licensing.py +0 -0
  273. {aria_code-4.1.7 → aria_code-4.2.0}/local_finance_tools.py +0 -0
  274. {aria_code-4.1.7 → aria_code-4.2.0}/local_llm_provider.py +0 -0
  275. {aria_code-4.1.7 → aria_code-4.2.0}/macro_tools.py +0 -0
  276. {aria_code-4.1.7 → aria_code-4.2.0}/memory_manager.py +0 -0
  277. {aria_code-4.1.7 → aria_code-4.2.0}/model_capability.py +0 -0
  278. {aria_code-4.1.7 → aria_code-4.2.0}/notification_tools.py +0 -0
  279. {aria_code-4.1.7 → aria_code-4.2.0}/packages/__init__.py +0 -0
  280. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_agents/__init__.py +0 -0
  281. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_agents/manifest.py +0 -0
  282. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/__init__.py +0 -0
  283. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/architecture.py +0 -0
  284. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/export.py +0 -0
  285. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_core/manifest.py +0 -0
  286. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/__init__.py +0 -0
  287. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/arthera.py +0 -0
  288. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/doctor.py +0 -0
  289. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_infra/product.py +0 -0
  290. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/__init__.py +0 -0
  291. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/bridge.py +0 -0
  292. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/circuit.py +0 -0
  293. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_mcp/config.py +0 -0
  294. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/__init__.py +0 -0
  295. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/client.py +0 -0
  296. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/providers.py +0 -0
  297. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/streaming.py +0 -0
  298. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_sdk/types.py +0 -0
  299. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/context_checkpoints.py +0 -0
  300. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/data.py +0 -0
  301. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/provider_health.py +0 -0
  302. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/references.py +0 -0
  303. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_services/settings.py +0 -0
  304. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_tools/__init__.py +0 -0
  305. {aria_code-4.1.7 → aria_code-4.2.0}/packages/aria_tools/registry.py +0 -0
  306. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/__init__.py +0 -0
  307. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/__init__.py +0 -0
  308. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/calibrator.py +0 -0
  309. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/dixon_coles.py +0 -0
  310. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/elo.py +0 -0
  311. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/form.py +0 -0
  312. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/h2h.py +0 -0
  313. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/ml_model.py +0 -0
  314. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/predictor.py +0 -0
  315. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/sports/tracker.py +0 -0
  316. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/__init__.py +0 -0
  317. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/gbm_enhanced.py +0 -0
  318. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/ito_calculus.py +0 -0
  319. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/kelly_criterion.py +0 -0
  320. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/monte_carlo_advanced.py +0 -0
  321. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/options_pricing.py +0 -0
  322. {aria_code-4.1.7 → aria_code-4.2.0}/packages/quant_engine/stochastic/stochastic_processes.py +0 -0
  323. {aria_code-4.1.7 → aria_code-4.2.0}/plan_utils.py +0 -0
  324. {aria_code-4.1.7 → aria_code-4.2.0}/plugin_loader.py +0 -0
  325. {aria_code-4.1.7 → aria_code-4.2.0}/portfolio_ledger.py +0 -0
  326. {aria_code-4.1.7 → aria_code-4.2.0}/privacy/__init__.py +0 -0
  327. {aria_code-4.1.7 → aria_code-4.2.0}/privacy/feedback.py +0 -0
  328. {aria_code-4.1.7 → aria_code-4.2.0}/project_tools.py +0 -0
  329. {aria_code-4.1.7 → aria_code-4.2.0}/providers/__init__.py +0 -0
  330. {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/__init__.py +0 -0
  331. {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/anthropic.py +0 -0
  332. {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/base.py +0 -0
  333. {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/ollama.py +0 -0
  334. {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/openai_compat.py +0 -0
  335. {aria_code-4.1.7 → aria_code-4.2.0}/providers/llm/registry.py +0 -0
  336. {aria_code-4.1.7 → aria_code-4.2.0}/realty_data_tools.py +0 -0
  337. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/lsp.py +0 -0
  338. {aria_code-4.1.7 → aria_code-4.2.0}/runtime/tool_policy.py +0 -0
  339. {aria_code-4.1.7 → aria_code-4.2.0}/safety/__init__.py +0 -0
  340. {aria_code-4.1.7 → aria_code-4.2.0}/safety/permissions.py +0 -0
  341. {aria_code-4.1.7 → aria_code-4.2.0}/safety/service.py +0 -0
  342. {aria_code-4.1.7 → aria_code-4.2.0}/setup.cfg +0 -0
  343. {aria_code-4.1.7 → aria_code-4.2.0}/setup_wizard.py +0 -0
  344. {aria_code-4.1.7 → aria_code-4.2.0}/strategy_vault.py +0 -0
  345. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_architecture_report.py +0 -0
  346. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_aria_sdk.py +0 -0
  347. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_backtest_cmds.py +0 -0
  348. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_backtest_engine.py +0 -0
  349. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_backtest_report.py +0 -0
  350. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_broker_automation.py +0 -0
  351. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_broker_planning.py +0 -0
  352. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_broker_safety.py +0 -0
  353. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_business_workflow_cmds.py +0 -0
  354. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_channel_intake.py +0 -0
  355. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_channels.py +0 -0
  356. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_chart_handlers.py +0 -0
  357. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_chat_routing.py +0 -0
  358. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_bootstrap.py +0 -0
  359. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_config_store.py +0 -0
  360. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_cli_lifecycle_hooks.py +0 -0
  361. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_codegen_output.py +0 -0
  362. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_command_safety.py +0 -0
  363. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_completions_builder.py +0 -0
  364. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_config_paths.py +0 -0
  365. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_configured_provider.py +0 -0
  366. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_context_checkpoints.py +0 -0
  367. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_context_references.py +0 -0
  368. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_dashboard_generator.py +0 -0
  369. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_data_service.py +0 -0
  370. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_deep_analysis.py +0 -0
  371. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_doctor.py +0 -0
  372. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_football_prediction_output.py +0 -0
  373. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_image_inputs.py +0 -0
  374. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_intent_router.py +0 -0
  375. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_licensing.py +0 -0
  376. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_lsp.py +0 -0
  377. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_history_tool.py +0 -0
  378. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_market_symbol_extraction.py +0 -0
  379. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_mcp_circuit.py +0 -0
  380. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_mcp_client.py +0 -0
  381. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_model_selection_state.py +0 -0
  382. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_new_modules.py +0 -0
  383. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_pick_best_installed_model.py +0 -0
  384. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_plan_mode.py +0 -0
  385. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_plotly_html_output.py +0 -0
  386. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_portfolio_ledger.py +0 -0
  387. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_privacy_feedback.py +0 -0
  388. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_project_aria.py +0 -0
  389. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_prompt_assembly.py +0 -0
  390. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_provider_integration.py +0 -0
  391. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_provider_registry.py +0 -0
  392. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_bridge.py +0 -0
  393. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_bridge_fallback.py +0 -0
  394. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_runtime_gateway.py +0 -0
  395. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_safety_permissions.py +0 -0
  396. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_safety_service.py +0 -0
  397. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_session_search.py +0 -0
  398. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_settings_service.py +0 -0
  399. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_startup_dashboard.py +0 -0
  400. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_streaming_pipeline.py +0 -0
  401. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_system_prompts.py +0 -0
  402. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_system_tools_output.py +0 -0
  403. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_team_synthesis.py +0 -0
  404. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_tool_policy.py +0 -0
  405. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_trading_service.py +0 -0
  406. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_tradingview_bridge.py +0 -0
  407. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_turn_planning.py +0 -0
  408. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_completer_references.py +0 -0
  409. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_ui_robot_banner.py +0 -0
  410. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_workspace_files.py +0 -0
  411. {aria_code-4.1.7 → aria_code-4.2.0}/tests/test_workspace_verify.py +0 -0
  412. {aria_code-4.1.7 → aria_code-4.2.0}/ui/__init__.py +0 -0
  413. {aria_code-4.1.7 → aria_code-4.2.0}/ui/completer.py +0 -0
  414. {aria_code-4.1.7 → aria_code-4.2.0}/ui/image_render.py +0 -0
  415. {aria_code-4.1.7 → aria_code-4.2.0}/ui/picker.py +0 -0
  416. {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/__init__.py +0 -0
  417. {aria_code-4.1.7 → aria_code-4.2.0}/ui/render/market.py +0 -0
  418. {aria_code-4.1.7 → aria_code-4.2.0}/ui/robot.py +0 -0
  419. {aria_code-4.1.7 → aria_code-4.2.0}/ui/startup_dashboard.py +0 -0
  420. {aria_code-4.1.7 → aria_code-4.2.0}/workspace/__init__.py +0 -0
  421. {aria_code-4.1.7 → aria_code-4.2.0}/workspace/files.py +0 -0
  422. {aria_code-4.1.7 → aria_code-4.2.0}/workspace/verify.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aria-code
3
- Version: 4.1.7
3
+ Version: 4.2.0
4
4
  Summary: AI-powered financial terminal — local LLM + multi-source market data
5
5
  License: BUSL-1.1
6
6
  Project-URL: Homepage, https://github.com/artherahq/aria-code
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Classifier: Topic :: Office/Business :: Financial
20
20
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
- Requires-Python: >=3.10
21
+ Requires-Python: <3.14,>=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: aiohttp>=3.9.0
@@ -37,6 +37,8 @@ Requires-Dist: pandas>=2.2.0
37
37
  Requires-Dist: scipy>=1.13.0
38
38
  Requires-Dist: pandas_ta>=0.4.67b0; python_version >= "3.12"
39
39
  Requires-Dist: yfinance>=0.2.55
40
+ Requires-Dist: pyobjc-framework-WebKit>=10.0; sys_platform == "darwin"
41
+ Requires-Dist: markdown>=3.6
40
42
  Provides-Extra: cn
41
43
  Requires-Dist: akshare>=1.14.68; extra == "cn"
42
44
  Provides-Extra: crypto
@@ -24,9 +24,11 @@ agents/ — Aria Code 可组合多智能体系统
24
24
  from .base import BaseAgent, AgentResult
25
25
  from .registry import AgentRegistry, get_registry
26
26
  from .team import AgentTeam, run_team
27
+ from .signal_scheme import SignalScheme, FINANCIAL_SCHEME, REALTY_SCHEME
27
28
 
28
29
  __all__ = [
29
30
  "BaseAgent", "AgentResult",
30
31
  "AgentRegistry", "get_registry",
31
32
  "AgentTeam", "run_team",
33
+ "SignalScheme", "FINANCIAL_SCHEME", "REALTY_SCHEME",
32
34
  ]
@@ -26,6 +26,9 @@ class AgentResult:
26
26
  key_points: List[str] = field(default_factory=list) # 关键结论(用于 synthesis)
27
27
  data_used: Dict[str, Any] = field(default_factory=dict) # 使用的原始数据
28
28
  error: Optional[str] = None # 失败时的错误信息
29
+ degraded: bool = False # True when a deterministic fallback was used
30
+ provenance: List[str] = field(default_factory=list)
31
+ limitations: List[str] = field(default_factory=list)
29
32
 
30
33
  @property
31
34
  def success(self) -> bool:
@@ -40,6 +43,9 @@ class AgentResult:
40
43
  "signal": self.signal,
41
44
  "key_points": self.key_points,
42
45
  "error": self.error,
46
+ "degraded": self.degraded,
47
+ "provenance": list(self.provenance),
48
+ "limitations": list(self.limitations),
43
49
  }
44
50
 
45
51
 
@@ -47,12 +47,24 @@ class PortfolioAgent(BaseAgent):
47
47
 
48
48
  # ── Multi-symbol interface ────────────────────────────────────────────────
49
49
 
50
- async def run_portfolio(self, symbols: List[str]) -> AgentResult:
51
- """Primary entry point for multi-symbol analysis."""
52
- data = await self.fetch_portfolio_data(symbols)
50
+ async def run_portfolio(
51
+ self, symbols: List[str], weights: Optional[Dict[str, float]] = None
52
+ ) -> AgentResult:
53
+ """Primary entry point for multi-symbol analysis.
54
+
55
+ weights: optional {symbol: dollar_cost_basis} from the user's real
56
+ holdings (portfolio_ledger.PortfolioLedger.get_positions()). Without
57
+ it, every position is silently treated as equal-weight — which used
58
+ to be the ONLY mode this agent supported, so a user who actually
59
+ holds 80% NVDA and 20% everything else got a risk verdict computed
60
+ on a fictional 1/n-weighted portfolio instead of their real exposure.
61
+ """
62
+ data = await self.fetch_portfolio_data(symbols, weights=weights)
53
63
  return await self.analyze_portfolio(symbols, data)
54
64
 
55
- async def fetch_portfolio_data(self, symbols: List[str]) -> Dict[str, Any]:
65
+ async def fetch_portfolio_data(
66
+ self, symbols: List[str], weights: Optional[Dict[str, float]] = None
67
+ ) -> Dict[str, Any]:
56
68
  data: Dict[str, Any] = {"symbols": symbols}
57
69
  if len(symbols) < 2:
58
70
  return data
@@ -97,8 +109,15 @@ class PortfolioAgent(BaseAgent):
97
109
  cov_matrix = returns.cov() * 252
98
110
  valid_syms = list(df.columns)
99
111
  n = len(valid_syms)
100
- weights = np.ones(n) / n
101
- port_vol = float(np.sqrt(weights @ cov_matrix.values @ weights))
112
+ if weights and any(weights.get(s, 0) > 0 for s in valid_syms):
113
+ raw = np.array([max(weights.get(s, 0.0), 0.0) for s in valid_syms])
114
+ w_vec = raw / raw.sum() if raw.sum() > 0 else np.ones(n) / n
115
+ weight_source = "ledger"
116
+ else:
117
+ w_vec = np.ones(n) / n
118
+ weight_source = "equal"
119
+ port_vol = float(np.sqrt(w_vec @ cov_matrix.values @ w_vec))
120
+ position_weights = {s: round(float(w_vec[i]), 4) for i, s in enumerate(valid_syms)}
102
121
 
103
122
  # High correlation pairs (|r| > 0.70)
104
123
  high_corr: List[Dict] = []
@@ -112,8 +131,10 @@ class PortfolioAgent(BaseAgent):
112
131
  "corr": round(c, 3),
113
132
  })
114
133
 
115
- # Diversification ratio: weighted avg individual vol / portfolio vol
116
- avg_vol = float(np.mean([float(ann_vols.get(s, 0)) for s in valid_syms]))
134
+ # Diversification ratio: weighted avg individual vol / portfolio vol.
135
+ # Was np.mean() (unweighted) despite the comment already claiming
136
+ # "weighted" — with real ledger weights now available, actually weight it.
137
+ avg_vol = float(sum(w_vec[i] * float(ann_vols.get(s, 0)) for i, s in enumerate(valid_syms)))
117
138
  div_ratio = round(avg_vol / port_vol, 2) if port_vol > 0 else 1.0
118
139
 
119
140
  # 52-week return per symbol
@@ -140,6 +161,8 @@ class PortfolioAgent(BaseAgent):
140
161
  "best_performer": sorted_ret[0] if sorted_ret else None,
141
162
  "worst_performer": sorted_ret[-1] if sorted_ret else None,
142
163
  "sector_map": sector_map,
164
+ "position_weights": position_weights,
165
+ "weight_source": weight_source,
143
166
  })
144
167
 
145
168
  except ImportError:
@@ -171,9 +194,11 @@ class PortfolioAgent(BaseAgent):
171
194
 
172
195
  valid_syms = data.get("valid_symbols", symbols)
173
196
  port_block = _format_portfolio_stats(data)
197
+ weight_desc = ("your actual position sizes" if data.get("weight_source") == "ledger"
198
+ else "equal weight — no real position sizes available")
174
199
 
175
200
  prompt = (
176
- f"Portfolio: {', '.join(valid_syms)} ({len(valid_syms)} positions, equal weight)\n\n"
201
+ f"Portfolio: {', '.join(valid_syms)} ({len(valid_syms)} positions, weighted by {weight_desc})\n\n"
177
202
  f"{port_block}\n\n"
178
203
  "Analyze this portfolio:\n"
179
204
  "1. Overall risk level (Low / Medium / High)\n"
@@ -217,15 +242,17 @@ def _format_portfolio_stats(d: Dict) -> str:
217
242
  vols = d.get("ann_vols", {})
218
243
  rets = d.get("ann_returns", {})
219
244
  rets_1y = d.get("returns_1y", {})
245
+ pweights = d.get("position_weights", {})
220
246
  if vols:
221
- lines.append("Symbol │ Ann.Vol │ Ann.Ret │ 1Y Return")
222
- lines.append("─" * 42)
247
+ lines.append("Symbol │ Weight │ Ann.Vol │ Ann.Ret │ 1Y Return")
248
+ lines.append("─" * 52)
223
249
  for sym in d.get("valid_symbols", list(vols)):
224
250
  v = vols.get(sym, 0)
225
251
  r = rets.get(sym, 0)
226
252
  y = rets_1y.get(sym, 0)
253
+ w = pweights.get(sym, 0)
227
254
  lines.append(
228
- f"{sym:<6} │ {v*100:>6.1f}% │ {r*100:>6.1f}% │ {y*100:>+7.1f}%"
255
+ f"{sym:<6} │ {w*100:>5.1f}% │ {v*100:>6.1f}% │ {r*100:>6.1f}% │ {y*100:>+7.1f}%"
229
256
  )
230
257
 
231
258
  port_vol = d.get("port_vol_ann", 0)
@@ -288,7 +315,10 @@ def _estimate_confidence(d: Dict) -> float:
288
315
  def _build_key_points(d: Dict, verdict: str) -> List[str]:
289
316
  pts = []
290
317
  n = len(d.get("valid_symbols", []))
291
- pts.append(f"{n} 个标的,等权配置")
318
+ if d.get("weight_source") == "ledger":
319
+ pts.append(f"{n} 个标的,按真实持仓成本加权")
320
+ else:
321
+ pts.append(f"{n} 个标的,等权配置(无真实持仓数据,非实际风险暴露)")
292
322
 
293
323
  port_vol = d.get("port_vol_ann", 0)
294
324
  if port_vol:
@@ -10,7 +10,9 @@ agents/realty/asset_diagnosis.py — 资产诊断 Agent
10
10
 
11
11
  输出:
12
12
  analysis — 详细分析文本
13
- signal — BUY=推荐共创 / HOLD=需观察 / SELL=建议出租或出售
13
+ signal — GOOD=推荐共创 / WATCH=需观察 / CONCERN=建议出租或出售
14
+ (地产健康度尺度,见 agents/signal_scheme.py::REALTY_SCHEME,
15
+ 不是股票 BUY/SELL 那套交易动作词汇)
14
16
  key_points — 3-5 条关键结论
15
17
  """
16
18
  from __future__ import annotations
@@ -101,9 +103,9 @@ def _score_to_signal(asset: Dict, reno: float) -> str:
101
103
  if state != "正常": score -= 2
102
104
  if reno > rent * 24: score -= 1 # 改造成本超过2年租金则不划算
103
105
 
104
- if score >= 4: return "BUY" # 非常适合共创
105
- if score >= 2: return "HOLD" # 需进一步评估
106
- return "SELL" # 建议传统出租或出售
106
+ if score >= 4: return "GOOD" # 非常适合共创
107
+ if score >= 2: return "WATCH" # 需进一步评估
108
+ return "CONCERN" # 建议传统出租或出售
107
109
 
108
110
 
109
111
  def _calc_confidence(asset: Dict) -> float:
@@ -10,7 +10,8 @@ agents/realty/business_match.py — 业态匹配 Agent
10
10
 
11
11
  输出:
12
12
  analysis — 业态匹配建议
13
- signal — BUY=高度匹配 / HOLD=一般匹配 / SELL=低匹配
13
+ signal — GOOD=高度匹配 / WATCH=一般匹配 / CONCERN=低匹配
14
+ (地产健康度尺度,见 signal_scheme.py)
14
15
  key_points — 推荐业态 Top3 + 理由
15
16
  """
16
17
  from __future__ import annotations
@@ -115,9 +116,9 @@ def _match_signal(asset: Dict, market: Dict) -> str:
115
116
  if market_score >= 7: score += 1
116
117
  elif 0 < market_score <= 3: score -= 1
117
118
 
118
- if score >= 4: return "BUY"
119
- if score >= 2: return "HOLD"
120
- return "SELL"
119
+ if score >= 4: return "GOOD"
120
+ if score >= 2: return "WATCH"
121
+ return "CONCERN"
121
122
 
122
123
 
123
124
  def _match_confidence(asset: Dict, market: Dict) -> float:
@@ -14,7 +14,8 @@ agents/realty/cashflow_verify.py — 流水核验 Agent
14
14
 
15
15
  输出:
16
16
  analysis — 核验报告
17
- signal — BUY=流水真实 / HOLD=轻度异常需复核 / SELL=疑似造假/私账
17
+ signal — GOOD=流水真实 / WATCH=轻度异常需复核 / CONCERN=疑似造假/私账
18
+ / SEVERE=多项异常+差距极大(地产健康度尺度,见 signal_scheme.py)
18
19
  key_points — 异常项目清单
19
20
  """
20
21
  from __future__ import annotations
@@ -174,10 +175,10 @@ def _cross_verify(
174
175
  def _verify_signal(check: Dict) -> str:
175
176
  n = check.get("anomaly_count", 0)
176
177
  gap = abs(check.get("gap_pct", 0))
177
- if n == 0 and gap < 15: return "BUY"
178
- if n <= 1 and gap < 30: return "HOLD"
179
- if n <= 2 and gap < 50: return "SELL"
180
- return "STRONG_SELL"
178
+ if n == 0 and gap < 15: return "GOOD"
179
+ if n <= 1 and gap < 30: return "WATCH"
180
+ if n <= 2 and gap < 50: return "CONCERN"
181
+ return "SEVERE"
181
182
 
182
183
 
183
184
  def _verify_confidence(check: Dict) -> float:
@@ -10,7 +10,8 @@ agents/realty/contract_rules.py — 合同规则 Agent
10
10
 
11
11
  输出:
12
12
  analysis — 合同条款草案文本
13
- signal — BUY=条款清晰可执行 / HOLD=需补充条款 / SELL=有重大风险条款
13
+ signal — GOOD=条款清晰可执行 / WATCH=需补充条款 / CONCERN=有重大风险条款
14
+ (地产健康度尺度,见 signal_scheme.py)
14
15
  key_points — 关键条款摘要(保底金额/分润比例/结算周期/违约条款)
15
16
  """
16
17
  from __future__ import annotations
@@ -139,9 +140,9 @@ def _contract_signal(nego: Dict) -> str:
139
140
  if not nego.get("settlement_cycle"): issues += 1
140
141
  if not nego.get("contract_years"): issues += 1
141
142
 
142
- if issues == 0: return "BUY"
143
- if issues <= 2: return "HOLD"
144
- return "SELL"
143
+ if issues == 0: return "GOOD"
144
+ if issues <= 2: return "WATCH"
145
+ return "CONCERN"
145
146
 
146
147
 
147
148
  def _contract_confidence(nego: Dict) -> float:
@@ -13,7 +13,8 @@ agents/realty/energy_anomaly.py — 能耗异常 Agent
13
13
 
14
14
  输出:
15
15
  analysis — 能耗分析报告
16
- signal — BUY=正常 / HOLD=轻度异常 / SELL=严重异常/疑似空置
16
+ signal — GOOD=正常 / WATCH=轻度异常 / CONCERN=中度异常 / SEVERE=严重异常/疑似空置
17
+ (地产健康度尺度,见 signal_scheme.py)
17
18
  key_points — 异常指标清单
18
19
  """
19
20
  from __future__ import annotations
@@ -154,10 +155,10 @@ def _analyze_energy(
154
155
 
155
156
  def _energy_signal(check: Dict) -> str:
156
157
  n = check.get("anomaly_count", 0)
157
- if n == 0: return "BUY"
158
- if n == 1: return "HOLD"
159
- if n == 2: return "SELL"
160
- return "STRONG_SELL"
158
+ if n == 0: return "GOOD"
159
+ if n == 1: return "WATCH"
160
+ if n == 2: return "CONCERN"
161
+ return "SEVERE"
161
162
 
162
163
 
163
164
  def _energy_confidence(check: Dict) -> float:
@@ -11,7 +11,8 @@ agents/realty/exit_settlement.py — 退出清算 Agent
11
11
 
12
12
  输出:
13
13
  analysis — 清算方案草案
14
- signal — BUY=清算顺利无纠纷 / HOLD=有待确认项 / SELL=存在较大争议
14
+ signal — GOOD=清算顺利无纠纷 / WATCH=有待确认项 / CONCERN=存在较大争议
15
+ (地产健康度尺度,见 signal_scheme.py)
15
16
  key_points — 各方清算金额摘要
16
17
  data_used — 包含 settlement_result(结构化清算数据)
17
18
  """
@@ -145,12 +146,12 @@ def _calculate_settlement(
145
146
 
146
147
  def _settlement_signal(s: Dict, reason: str) -> str:
147
148
  if s["net_settlement"] > 0 and not s["is_breach"]:
148
- return "HOLD" # 经营方有欠款但无违约,需催收
149
+ return "WATCH" # 经营方有欠款但无违约,需催收
149
150
  if s["is_breach"] and s["net_settlement"] > 0:
150
- return "SELL" # 违约且有欠款
151
+ return "CONCERN" # 违约且有欠款
151
152
  if s["operator_owes"] == 0 and s["platform_owes"] == 0:
152
- return "BUY" # 干净退出
153
- return "HOLD"
153
+ return "GOOD" # 干净退出
154
+ return "WATCH"
154
155
 
155
156
 
156
157
  def _settlement_confidence(fin: Dict) -> float:
@@ -12,7 +12,8 @@ agents/realty/fulfillment_risk.py — 履约风控 Agent
12
12
 
13
13
  输出:
14
14
  analysis — 风险报告
15
- signal — BUY=低风险 / HOLD=中等风险 / SELL=高风险 / STRONG_SELL=极高风险
15
+ signal — GOOD=低风险 / WATCH=中等风险 / CONCERN=高风险 / SEVERE=极高风险
16
+ (地产健康度尺度,见 signal_scheme.py)
16
17
  key_points — 风险事项清单(按级别)
17
18
  """
18
19
  from __future__ import annotations
@@ -134,7 +135,7 @@ def _assess_risk(
134
135
 
135
136
  # 5. 流水核验异常
136
137
  cf_signal = cf.get("signal", "")
137
- if cf_signal in ("SELL", "STRONG_SELL"):
138
+ if cf_signal in ("CONCERN", "SEVERE"):
138
139
  risk_items.append({"level": "高",
139
140
  "desc": f"流水核验异常({cf.get('anomaly_summary','')}),需稽查"})
140
141
 
@@ -157,12 +158,12 @@ def _assess_risk(
157
158
 
158
159
 
159
160
  def _risk_signal(risk: Dict) -> str:
160
- if risk.get("has_extreme_risk"): return "STRONG_SELL"
161
- if risk.get("has_high_risk"): return "SELL"
161
+ if risk.get("has_extreme_risk"): return "SEVERE"
162
+ if risk.get("has_high_risk"): return "CONCERN"
162
163
  mid_count = sum(1 for r in risk.get("risk_items", []) if r["level"] == "中")
163
- if mid_count >= 2: return "SELL"
164
- if mid_count >= 1: return "HOLD"
165
- return "BUY"
164
+ if mid_count >= 2: return "CONCERN"
165
+ if mid_count >= 1: return "WATCH"
166
+ return "GOOD"
166
167
 
167
168
 
168
169
  def _risk_confidence(risk: Dict, invoices: List) -> float:
@@ -11,7 +11,8 @@ agents/realty/ops_optimize.py — 运营提升 Agent
11
11
 
12
12
  输出:
13
13
  analysis — 运营优化建议
14
- signal — BUY=经营健康/高潜力 / HOLD=有改善空间 / SELL=经营不佳需干预
14
+ signal — GOOD=经营健康/高潜力 / WATCH=有改善空间 / CONCERN=经营不佳 / SEVERE=急需干预
15
+ (地产健康度尺度,见 signal_scheme.py)
15
16
  key_points — Top3 优化建议
16
17
  """
17
18
  from __future__ import annotations
@@ -101,12 +102,12 @@ def _calc_metrics(project: Dict, perf: Dict, marketing: Dict, bench: Dict) -> Di
101
102
  def _ops_signal(metrics: Dict, bench: Dict) -> str:
102
103
  psm = metrics.get("revenue_per_sqm", 0)
103
104
  bench_psm = metrics.get("bench_psm", 300)
104
- if bench_psm <= 0: return "HOLD"
105
+ if bench_psm <= 0: return "WATCH"
105
106
  ratio = psm / bench_psm
106
- if ratio >= 1.2: return "BUY"
107
- if ratio >= 0.8: return "HOLD"
108
- if ratio >= 0.5: return "SELL"
109
- return "STRONG_SELL"
107
+ if ratio >= 1.2: return "GOOD"
108
+ if ratio >= 0.8: return "WATCH"
109
+ if ratio >= 0.5: return "CONCERN"
110
+ return "SEVERE"
110
111
 
111
112
 
112
113
  def _ops_confidence(perf: Dict, marketing: Dict) -> float:
@@ -10,7 +10,8 @@ agents/realty/revenue_share.py — 分账规则 Agent
10
10
 
11
11
  输出:
12
12
  analysis — 分账计算说明文本
13
- signal — BUY=分账正常 / HOLD=有补足情况 / SELL=流水严重不足
13
+ signal — GOOD=分账正常 / WATCH=有补足情况 / CONCERN=流水勉强覆盖 / SEVERE=流水严重不足
14
+ (地产健康度尺度,见 signal_scheme.py)
14
15
  key_points — 各方金额摘要
15
16
  data_used — 包含 split_result(可直接入库)
16
17
  """
@@ -159,12 +160,12 @@ def _split_signal(split: Dict) -> str:
159
160
  guaranteed = split.get("guaranteed", 0)
160
161
  op_net = split.get("operator_net", 0)
161
162
 
162
- if guaranteed <= 0: return "HOLD"
163
+ if guaranteed <= 0: return "WATCH"
163
164
  coverage = net / guaranteed if guaranteed else 0
164
- if coverage >= 2.0 and op_net > 0: return "BUY"
165
- if coverage >= 1.0 and op_net > 0: return "HOLD"
166
- if op_net > 0 and coverage >= 0.5: return "SELL" # 经营方能勉强覆盖
167
- return "STRONG_SELL" # 经营方净收入为负或流水极低
165
+ if coverage >= 2.0 and op_net > 0: return "GOOD"
166
+ if coverage >= 1.0 and op_net > 0: return "WATCH"
167
+ if op_net > 0 and coverage >= 0.5: return "CONCERN" # 经营方能勉强覆盖
168
+ return "SEVERE" # 经营方净收入为负或流水极低
168
169
 
169
170
 
170
171
  def _split_status(split: Dict) -> str:
@@ -0,0 +1,97 @@
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
+ )
@@ -1,7 +1,23 @@
1
1
  """
2
2
  agents/sports/football_agent.py — Football Analysis Agent
3
3
  ===========================================================
4
- LLM-powered football match analysis using Poisson prediction + form data.
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.
5
21
  """
6
22
 
7
23
  from __future__ import annotations
@@ -61,10 +77,19 @@ class FootballAgent:
61
77
  away_team: str,
62
78
  league: str = "pl",
63
79
  with_llm: bool = True,
80
+ neutral_venue: bool = False,
64
81
  ) -> MatchPrediction:
65
- from football_data_client import predict_match, get_team_stats
66
-
67
- raw = predict_match(home_team, away_team, league)
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
+ )
68
93
  h_stats = get_team_stats(league, home_team)
69
94
  a_stats = get_team_stats(league, away_team)
70
95
 
@@ -73,7 +98,10 @@ class FootballAgent:
73
98
  key_factors.append(f"{home_team} 近5场: {h_stats['form']} (场均进球 {h_stats['avg_gf']})")
74
99
  if a_stats:
75
100
  key_factors.append(f"{away_team} 近5场: {a_stats['form']} (场均进球 {a_stats['avg_gf']})")
76
- key_factors.append(f"主场优势系数: ×1.25 (泊松模型)")
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
+ )
77
105
 
78
106
  analysis = ""
79
107
  if with_llm and self._llm: