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.
Files changed (478) hide show
  1. aria_code/__init__.py +42 -0
  2. aria_code/_version.py +20 -0
  3. aria_code/adk_apps/__init__.py +1 -0
  4. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  5. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  6. aria_code/adk_apps/aria_research/__init__.py +1 -0
  7. aria_code/adk_apps/aria_research/agent.py +31 -0
  8. aria_code/agents/__init__.py +34 -0
  9. aria_code/agents/base.py +318 -0
  10. aria_code/agents/code_review.py +200 -0
  11. aria_code/agents/deep/__init__.py +37 -0
  12. aria_code/agents/deep/calibration_loop.py +144 -0
  13. aria_code/agents/deep/critic.py +125 -0
  14. aria_code/agents/deep/deepen.py +193 -0
  15. aria_code/agents/deep/models.py +149 -0
  16. aria_code/agents/deep/pipeline.py +164 -0
  17. aria_code/agents/deep/quant_fusion.py +192 -0
  18. aria_code/agents/deep/themes.py +95 -0
  19. aria_code/agents/deep/tiers.py +106 -0
  20. aria_code/agents/engineering/__init__.py +14 -0
  21. aria_code/agents/engineering/coder.py +222 -0
  22. aria_code/agents/engineering/tester.py +145 -0
  23. aria_code/agents/financial/__init__.py +21 -0
  24. aria_code/agents/financial/cashflow_burn.py +119 -0
  25. aria_code/agents/financial/catalyst.py +279 -0
  26. aria_code/agents/financial/corporate_finance.py +175 -0
  27. aria_code/agents/financial/debate.py +224 -0
  28. aria_code/agents/financial/earnings.py +303 -0
  29. aria_code/agents/financial/fundamental.py +191 -0
  30. aria_code/agents/financial/macro.py +99 -0
  31. aria_code/agents/financial/news.py +207 -0
  32. aria_code/agents/financial/risk.py +165 -0
  33. aria_code/agents/financial/sector.py +279 -0
  34. aria_code/agents/financial/strategist.py +121 -0
  35. aria_code/agents/financial/stripe_revenue.py +127 -0
  36. aria_code/agents/financial/synthesis.py +274 -0
  37. aria_code/agents/financial/technical.py +258 -0
  38. aria_code/agents/orchestrator.py +44 -0
  39. aria_code/agents/portfolio_agent.py +363 -0
  40. aria_code/agents/realty/__init__.py +62 -0
  41. aria_code/agents/realty/asset_diagnosis.py +152 -0
  42. aria_code/agents/realty/business_match.py +166 -0
  43. aria_code/agents/realty/cashflow_verify.py +209 -0
  44. aria_code/agents/realty/contract_rules.py +210 -0
  45. aria_code/agents/realty/energy_anomaly.py +189 -0
  46. aria_code/agents/realty/exit_settlement.py +208 -0
  47. aria_code/agents/realty/fulfillment_risk.py +206 -0
  48. aria_code/agents/realty/ops_optimize.py +160 -0
  49. aria_code/agents/realty/revenue_share.py +215 -0
  50. aria_code/agents/registry.py +158 -0
  51. aria_code/agents/signal_scheme.py +111 -0
  52. aria_code/agents/sports/__init__.py +0 -0
  53. aria_code/agents/sports/football_agent.py +197 -0
  54. aria_code/agents/supervisor.py +113 -0
  55. aria_code/agents/team.py +492 -0
  56. aria_code/agents/warehouse/__init__.py +25 -0
  57. aria_code/agents/warehouse/contracts.py +26 -0
  58. aria_code/agents/warehouse/dashboard.py +155 -0
  59. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  60. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  61. aria_code/agents/warehouse/inventory_health.py +24 -0
  62. aria_code/agents/warehouse/local_run.py +71 -0
  63. aria_code/agents/warehouse/local_snapshot.py +132 -0
  64. aria_code/agents/warehouse/logistics_cost.py +84 -0
  65. aria_code/agents/warehouse/logistics_sync.py +21 -0
  66. aria_code/agents/warehouse/workflow.py +31 -0
  67. aria_code/aliyun_data_client.py +4 -0
  68. aria_code/apps/README.md +12 -0
  69. aria_code/apps/__init__.py +2 -0
  70. aria_code/apps/channels/README.md +15 -0
  71. aria_code/apps/channels/__init__.py +17 -0
  72. aria_code/apps/channels/intake.py +92 -0
  73. aria_code/apps/channels/registry.py +95 -0
  74. aria_code/apps/channels/tradingview.py +94 -0
  75. aria_code/apps/cli/README.md +13 -0
  76. aria_code/apps/cli/__init__.py +2 -0
  77. aria_code/apps/cli/_optional.py +120 -0
  78. aria_code/apps/cli/bootstrap.py +145 -0
  79. aria_code/apps/cli/broker_render.py +206 -0
  80. aria_code/apps/cli/codegen_paths.py +29 -0
  81. aria_code/apps/cli/commands/__init__.py +16 -0
  82. aria_code/apps/cli/commands/_business_render.py +78 -0
  83. aria_code/apps/cli/commands/_ui.py +71 -0
  84. aria_code/apps/cli/commands/analysis_cmds.py +369 -0
  85. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  86. aria_code/apps/cli/commands/auth_cmds.py +239 -0
  87. aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
  88. aria_code/apps/cli/commands/broker_cmds.py +1234 -0
  89. aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
  90. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  91. aria_code/apps/cli/commands/catalog.py +87 -0
  92. aria_code/apps/cli/commands/core_cmds.py +2520 -0
  93. aria_code/apps/cli/commands/data_cmds.py +457 -0
  94. aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
  95. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  96. aria_code/apps/cli/commands/file_cmds.py +312 -0
  97. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  98. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  99. aria_code/apps/cli/commands/market.py +434 -0
  100. aria_code/apps/cli/commands/market_cmds.py +1381 -0
  101. aria_code/apps/cli/commands/market_context.py +425 -0
  102. aria_code/apps/cli/commands/market_render.py +7 -0
  103. aria_code/apps/cli/commands/model_cmds.py +2153 -0
  104. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  105. aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
  106. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  107. aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
  108. aria_code/apps/cli/commands/report.py +437 -0
  109. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  110. aria_code/apps/cli/commands/session_cmds.py +236 -0
  111. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  112. aria_code/apps/cli/commands/team.py +669 -0
  113. aria_code/apps/cli/commands/team_render.py +8 -0
  114. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  115. aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
  116. aria_code/apps/cli/commands/workflow_cmds.py +480 -0
  117. aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
  118. aria_code/apps/cli/config_paths.py +73 -0
  119. aria_code/apps/cli/config_store.py +78 -0
  120. aria_code/apps/cli/constants.py +88 -0
  121. aria_code/apps/cli/context.py +34 -0
  122. aria_code/apps/cli/deterministic.py +191 -0
  123. aria_code/apps/cli/direct.py +48 -0
  124. aria_code/apps/cli/finance_service_catalog.py +111 -0
  125. aria_code/apps/cli/football_reports.py +231 -0
  126. aria_code/apps/cli/github_app_auth.py +135 -0
  127. aria_code/apps/cli/google_login.py +196 -0
  128. aria_code/apps/cli/handlers/__init__.py +11 -0
  129. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  130. aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
  131. aria_code/apps/cli/handlers/market_handlers.py +2513 -0
  132. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  133. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  134. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  135. aria_code/apps/cli/helpers.py +302 -0
  136. aria_code/apps/cli/hooks.py +180 -0
  137. aria_code/apps/cli/i18n.py +297 -0
  138. aria_code/apps/cli/intent.py +136 -0
  139. aria_code/apps/cli/intent_router.py +276 -0
  140. aria_code/apps/cli/intent_signals.py +344 -0
  141. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  142. aria_code/apps/cli/local_tool_schemas.py +536 -0
  143. aria_code/apps/cli/main.py +29 -0
  144. aria_code/apps/cli/market_metadata.py +135 -0
  145. aria_code/apps/cli/market_universe.py +487 -0
  146. aria_code/apps/cli/message_processing.py +310 -0
  147. aria_code/apps/cli/model_catalog.py +620 -0
  148. aria_code/apps/cli/pdf_report.py +977 -0
  149. aria_code/apps/cli/plan_mode.py +139 -0
  150. aria_code/apps/cli/plotly_html.py +15 -0
  151. aria_code/apps/cli/prediction_feedback.py +202 -0
  152. aria_code/apps/cli/preflight.py +502 -0
  153. aria_code/apps/cli/project_aria.py +60 -0
  154. aria_code/apps/cli/prompt_assembly.py +59 -0
  155. aria_code/apps/cli/prompts/__init__.py +0 -0
  156. aria_code/apps/cli/prompts/coding.py +53 -0
  157. aria_code/apps/cli/prompts/select.py +142 -0
  158. aria_code/apps/cli/prompts/system_prompts.py +552 -0
  159. aria_code/apps/cli/prompts/ui.py +436 -0
  160. aria_code/apps/cli/provider_endpoints.py +237 -0
  161. aria_code/apps/cli/provider_keys.py +73 -0
  162. aria_code/apps/cli/providers/__init__.py +1 -0
  163. aria_code/apps/cli/providers/base.py +521 -0
  164. aria_code/apps/cli/providers/chat_routing.py +128 -0
  165. aria_code/apps/cli/providers/collaboration.py +98 -0
  166. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  167. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  168. aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
  169. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  170. aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
  171. aria_code/apps/cli/providers/runtime_bridge.py +353 -0
  172. aria_code/apps/cli/providers/vertexai_stream.py +316 -0
  173. aria_code/apps/cli/runtime_consumer.py +657 -0
  174. aria_code/apps/cli/sandbox.py +32 -0
  175. aria_code/apps/cli/session_export.py +120 -0
  176. aria_code/apps/cli/session_jsonl.py +208 -0
  177. aria_code/apps/cli/session_store.py +112 -0
  178. aria_code/apps/cli/skills_catalog.py +273 -0
  179. aria_code/apps/cli/todo_tracker.py +190 -0
  180. aria_code/apps/cli/tool_executor.py +823 -0
  181. aria_code/apps/cli/tool_registry.py +34 -0
  182. aria_code/apps/cli/tool_scope.py +106 -0
  183. aria_code/apps/cli/tools/__init__.py +40 -0
  184. aria_code/apps/cli/tools/context.py +46 -0
  185. aria_code/apps/cli/tools/file_tools.py +180 -0
  186. aria_code/apps/cli/tools/market_tools.py +620 -0
  187. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  188. aria_code/apps/cli/tools/system_tools.py +726 -0
  189. aria_code/apps/cli/tools/write_tools.py +845 -0
  190. aria_code/apps/cli/tradingview_bridge.py +529 -0
  191. aria_code/apps/cli/turn_planning.py +137 -0
  192. aria_code/apps/cli/update_check.py +153 -0
  193. aria_code/apps/cli/utils/__init__.py +0 -0
  194. aria_code/apps/cli/utils/market_detect.py +1597 -0
  195. aria_code/apps/daemon/README.md +14 -0
  196. aria_code/apps/vscode/README.md +115 -0
  197. aria_code/apps/vscode/package.json +70 -0
  198. aria_code/aria_cli.py +6743 -0
  199. aria_code/aria_daemon.py +1398 -0
  200. aria_code/aria_feishu_bot.py +1423 -0
  201. aria_code/aria_mcp_server.py +7 -0
  202. aria_code/aria_relay_client.py +4 -0
  203. aria_code/aria_relay_server.py +490 -0
  204. aria_code/aria_telegram_bot.py +202 -0
  205. aria_code/ariarc.py +385 -0
  206. aria_code/artifacts.py +581 -0
  207. aria_code/backtest_engine.py +4 -0
  208. aria_code/backtest_report.py +4 -0
  209. aria_code/brokers/__init__.py +78 -0
  210. aria_code/brokers/automation.py +193 -0
  211. aria_code/brokers/base.py +231 -0
  212. aria_code/brokers/capabilities.py +264 -0
  213. aria_code/brokers/cn/__init__.py +10 -0
  214. aria_code/brokers/cn/easytrader_broker.py +193 -0
  215. aria_code/brokers/cn/futu_broker.py +194 -0
  216. aria_code/brokers/cn/longbridge_broker.py +190 -0
  217. aria_code/brokers/cn/tiger_broker.py +196 -0
  218. aria_code/brokers/cn/xtquant_broker.py +225 -0
  219. aria_code/brokers/config.py +414 -0
  220. aria_code/brokers/intl/__init__.py +5 -0
  221. aria_code/brokers/intl/alpaca_broker.py +183 -0
  222. aria_code/brokers/intl/ibkr_broker.py +215 -0
  223. aria_code/brokers/intl/trading212_broker.py +183 -0
  224. aria_code/brokers/intl/webull_broker.py +156 -0
  225. aria_code/brokers/paper_broker.py +266 -0
  226. aria_code/brokers/planning.py +296 -0
  227. aria_code/brokers/registry.py +213 -0
  228. aria_code/brokers/trading.py +267 -0
  229. aria_code/canva_client.py +4 -0
  230. aria_code/change_store.py +127 -0
  231. aria_code/clients/__init__.py +0 -0
  232. aria_code/clients/aliyun_data_client.py +660 -0
  233. aria_code/clients/aria_relay_client.py +182 -0
  234. aria_code/clients/canva_client.py +284 -0
  235. aria_code/clients/figma_client.py +100 -0
  236. aria_code/clients/football_data_client.py +1671 -0
  237. aria_code/clients/kling_video_client.py +182 -0
  238. aria_code/clients/market_data_client.py +1976 -0
  239. aria_code/clients/openai_image_client.py +242 -0
  240. aria_code/clients/runway_video_client.py +157 -0
  241. aria_code/clients/warehouse_erp_client.py +105 -0
  242. aria_code/cloud_memory.py +181 -0
  243. aria_code/command_safety.py +19 -0
  244. aria_code/computer_use_tools.py +4 -0
  245. aria_code/dashboard_generator.py +579 -0
  246. aria_code/data_analysis_tools.py +4 -0
  247. aria_code/data_cleaner.py +483 -0
  248. aria_code/data_service.py +513 -0
  249. aria_code/datasources/__init__.py +23 -0
  250. aria_code/datasources/base.py +166 -0
  251. aria_code/datasources/router.py +253 -0
  252. aria_code/datasources/sources/__init__.py +15 -0
  253. aria_code/datasources/sources/akshare_source.py +269 -0
  254. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  255. aria_code/datasources/sources/edgar_source.py +219 -0
  256. aria_code/datasources/sources/finnhub_source.py +198 -0
  257. aria_code/datasources/sources/fred_source.py +223 -0
  258. aria_code/datasources/sources/tushare_source.py +143 -0
  259. aria_code/datasources/sources/web_scraper_source.py +278 -0
  260. aria_code/datasources/sources/world_bank_source.py +206 -0
  261. aria_code/datasources/sources/yfinance_source.py +152 -0
  262. aria_code/demo_player.py +207 -0
  263. aria_code/doctor.py +813 -0
  264. aria_code/domain/__init__.py +0 -0
  265. aria_code/domain/backtest_engine.py +354 -0
  266. aria_code/domain/backtest_report.py +472 -0
  267. aria_code/domain/finance_formulas.py +389 -0
  268. aria_code/domain/portfolio_ledger.py +307 -0
  269. aria_code/domain/strategy_vault.py +421 -0
  270. aria_code/evals/__init__.py +37 -0
  271. aria_code/evals/harness.py +598 -0
  272. aria_code/evals/runner.py +238 -0
  273. aria_code/external_agent_runner.py +115 -0
  274. aria_code/figma_client.py +4 -0
  275. aria_code/file_analysis_tools.py +4 -0
  276. aria_code/finance_formulas.py +4 -0
  277. aria_code/football_data_client.py +4 -0
  278. aria_code/image_gen_tools.py +4 -0
  279. aria_code/intent_classifier.py +386 -0
  280. aria_code/kling_video_client.py +4 -0
  281. aria_code/licensing.py +151 -0
  282. aria_code/local_finance_tools.py +4 -0
  283. aria_code/local_image_provider.py +4 -0
  284. aria_code/local_llm_provider.py +4 -0
  285. aria_code/macro_tools.py +4 -0
  286. aria_code/markdown_pdf.py +289 -0
  287. aria_code/market_data_client.py +4 -0
  288. aria_code/mcp_client.py +639 -0
  289. aria_code/memory_manager.py +246 -0
  290. aria_code/model_capability.py +486 -0
  291. aria_code/notification_tools.py +4 -0
  292. aria_code/openai_image_client.py +4 -0
  293. aria_code/packages/__init__.py +23 -0
  294. aria_code/packages/adk_bridge/__init__.py +11 -0
  295. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  296. aria_code/packages/adk_bridge/market_tools.py +125 -0
  297. aria_code/packages/aria_agents/__init__.py +5 -0
  298. aria_code/packages/aria_agents/manifest.py +78 -0
  299. aria_code/packages/aria_core/__init__.py +34 -0
  300. aria_code/packages/aria_core/architecture.py +269 -0
  301. aria_code/packages/aria_core/export.py +147 -0
  302. aria_code/packages/aria_core/manifest.py +65 -0
  303. aria_code/packages/aria_core/paths.py +57 -0
  304. aria_code/packages/aria_core/secure_file.py +68 -0
  305. aria_code/packages/aria_infra/__init__.py +15 -0
  306. aria_code/packages/aria_infra/arthera.py +52 -0
  307. aria_code/packages/aria_infra/doctor.py +246 -0
  308. aria_code/packages/aria_infra/product.py +40 -0
  309. aria_code/packages/aria_mcp/__init__.py +25 -0
  310. aria_code/packages/aria_mcp/bridge.py +201 -0
  311. aria_code/packages/aria_mcp/circuit.py +82 -0
  312. aria_code/packages/aria_mcp/config.py +111 -0
  313. aria_code/packages/aria_mcp/installer.py +95 -0
  314. aria_code/packages/aria_mcp/server.py +1550 -0
  315. aria_code/packages/aria_mcp/tools.py +81 -0
  316. aria_code/packages/aria_sdk/__init__.py +19 -0
  317. aria_code/packages/aria_sdk/client.py +396 -0
  318. aria_code/packages/aria_sdk/providers.py +70 -0
  319. aria_code/packages/aria_sdk/streaming.py +79 -0
  320. aria_code/packages/aria_sdk/types.py +86 -0
  321. aria_code/packages/aria_services/__init__.py +92 -0
  322. aria_code/packages/aria_services/cache.py +60 -0
  323. aria_code/packages/aria_services/context.py +356 -0
  324. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  325. aria_code/packages/aria_services/data.py +11 -0
  326. aria_code/packages/aria_services/provider_health.py +268 -0
  327. aria_code/packages/aria_services/references.py +247 -0
  328. aria_code/packages/aria_services/registry.py +249 -0
  329. aria_code/packages/aria_services/research_protocol.py +57 -0
  330. aria_code/packages/aria_services/research_quality.py +186 -0
  331. aria_code/packages/aria_services/settings.py +157 -0
  332. aria_code/packages/aria_services/usage.py +151 -0
  333. aria_code/packages/aria_skills/__init__.py +46 -0
  334. aria_code/packages/aria_skills/catalog.py +149 -0
  335. aria_code/packages/aria_skills/loader.py +455 -0
  336. aria_code/packages/aria_skills/registry.py +84 -0
  337. aria_code/packages/aria_tools/__init__.py +5 -0
  338. aria_code/packages/aria_tools/financial/__init__.py +8 -0
  339. aria_code/packages/aria_tools/financial/_paths.py +130 -0
  340. aria_code/packages/aria_tools/financial/compliance.py +31 -0
  341. aria_code/packages/aria_tools/financial/factors.py +33 -0
  342. aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
  343. aria_code/packages/aria_tools/financial/strategy.py +31 -0
  344. aria_code/packages/aria_tools/registry.py +128 -0
  345. aria_code/packages/quant_engine/__init__.py +34 -0
  346. aria_code/packages/quant_engine/_namespace.py +62 -0
  347. aria_code/packages/quant_engine/backtest/__init__.py +14 -0
  348. aria_code/packages/quant_engine/backtest/core.py +53 -0
  349. aria_code/packages/quant_engine/backtest/engine.py +96 -0
  350. aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
  351. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  352. aria_code/packages/quant_engine/sports/__init__.py +80 -0
  353. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  354. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  355. aria_code/packages/quant_engine/sports/elo.py +300 -0
  356. aria_code/packages/quant_engine/sports/form.py +188 -0
  357. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  358. aria_code/packages/quant_engine/sports/ml_model.py +377 -0
  359. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  360. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  361. aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
  362. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  363. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  364. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  365. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  366. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  367. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  368. aria_code/packs/__init__.py +85 -0
  369. aria_code/packs/base.py +168 -0
  370. aria_code/packs/finance/__init__.py +250 -0
  371. aria_code/packs/logistics/__init__.py +169 -0
  372. aria_code/packs/payments/__init__.py +139 -0
  373. aria_code/packs/realty/__init__.py +190 -0
  374. aria_code/packs/registry.py +202 -0
  375. aria_code/packs/rules.py +90 -0
  376. aria_code/plan_utils.py +194 -0
  377. aria_code/plugin_loader.py +328 -0
  378. aria_code/portfolio_ledger.py +4 -0
  379. aria_code/preview_server.py +449 -0
  380. aria_code/privacy/__init__.py +5 -0
  381. aria_code/privacy/feedback.py +123 -0
  382. aria_code/project_review.py +278 -0
  383. aria_code/project_review_api.py +235 -0
  384. aria_code/project_review_server.py +18 -0
  385. aria_code/project_tools.py +4 -0
  386. aria_code/providers/__init__.py +30 -0
  387. aria_code/providers/llm/__init__.py +19 -0
  388. aria_code/providers/llm/anthropic.py +184 -0
  389. aria_code/providers/llm/autoconfig.py +213 -0
  390. aria_code/providers/llm/base.py +139 -0
  391. aria_code/providers/llm/custom.py +158 -0
  392. aria_code/providers/llm/ollama.py +129 -0
  393. aria_code/providers/llm/openai_compat.py +313 -0
  394. aria_code/providers/llm/registry.py +444 -0
  395. aria_code/providers/local_image_provider.py +202 -0
  396. aria_code/providers/local_llm_provider.py +589 -0
  397. aria_code/realty_data_tools.py +4 -0
  398. aria_code/report_exporters.py +150 -0
  399. aria_code/report_generator.py +1764 -0
  400. aria_code/runtime/__init__.py +169 -0
  401. aria_code/runtime/acceptance.py +481 -0
  402. aria_code/runtime/agent_loop.py +1520 -0
  403. aria_code/runtime/approval.py +57 -0
  404. aria_code/runtime/budget.py +232 -0
  405. aria_code/runtime/checkpoints.py +432 -0
  406. aria_code/runtime/crash_report.py +174 -0
  407. aria_code/runtime/events.py +113 -0
  408. aria_code/runtime/gateway.py +150 -0
  409. aria_code/runtime/lsp.py +484 -0
  410. aria_code/runtime/orchestrator.py +55 -0
  411. aria_code/runtime/repo_map.py +700 -0
  412. aria_code/runtime/run_state.py +127 -0
  413. aria_code/runtime/run_store.py +450 -0
  414. aria_code/runtime/self_healing.py +422 -0
  415. aria_code/runtime/subagent.py +547 -0
  416. aria_code/runtime/task_ledger.py +86 -0
  417. aria_code/runtime/task_orchestrator.py +90 -0
  418. aria_code/runtime/tool_executor.py +217 -0
  419. aria_code/runtime/tool_policy.py +107 -0
  420. aria_code/runtime/worktrees.py +215 -0
  421. aria_code/runway_video_client.py +4 -0
  422. aria_code/safety/__init__.py +23 -0
  423. aria_code/safety/permissions.py +306 -0
  424. aria_code/safety/service.py +102 -0
  425. aria_code/setup_wizard.py +673 -0
  426. aria_code/spreadsheet_tools.py +4 -0
  427. aria_code/strategy_vault.py +4 -0
  428. aria_code/tools/__init__.py +0 -0
  429. aria_code/tools/artifact_tools.py +252 -0
  430. aria_code/tools/broker_tools.py +92 -0
  431. aria_code/tools/build_quant_engine.py +97 -0
  432. aria_code/tools/code_audit_tools.py +192 -0
  433. aria_code/tools/computer_use_tools.py +504 -0
  434. aria_code/tools/data_analysis_tools.py +809 -0
  435. aria_code/tools/enterprise_finance_tools.py +156 -0
  436. aria_code/tools/extended_tools.py +240 -0
  437. aria_code/tools/file_analysis_tools.py +885 -0
  438. aria_code/tools/image_gen_tools.py +114 -0
  439. aria_code/tools/local_finance_tools.py +3417 -0
  440. aria_code/tools/logistics_tools.py +135 -0
  441. aria_code/tools/macro_tools.py +369 -0
  442. aria_code/tools/notification_tools.py +249 -0
  443. aria_code/tools/project_tools.py +525 -0
  444. aria_code/tools/realty_data_tools.py +659 -0
  445. aria_code/tools/spreadsheet_tools.py +388 -0
  446. aria_code/tools/stripe_tools.py +115 -0
  447. aria_code/ui/__init__.py +105 -0
  448. aria_code/ui/banner.py +508 -0
  449. aria_code/ui/completer.py +501 -0
  450. aria_code/ui/console.py +281 -0
  451. aria_code/ui/image_render.py +243 -0
  452. aria_code/ui/input_box.py +488 -0
  453. aria_code/ui/picker.py +201 -0
  454. aria_code/ui/render/__init__.py +11 -0
  455. aria_code/ui/render/finance.py +1705 -0
  456. aria_code/ui/render/market.py +225 -0
  457. aria_code/ui/render/output.py +775 -0
  458. aria_code/ui/render/responsive.py +75 -0
  459. aria_code/ui/render/team.py +354 -0
  460. aria_code/ui/robot.py +235 -0
  461. aria_code/ui/startup_dashboard.py +109 -0
  462. aria_code/utils/vscode_uri.py +37 -0
  463. aria_code/video_analysis.py +147 -0
  464. aria_code/video_editor.py +271 -0
  465. aria_code/workspace/__init__.py +6 -0
  466. aria_code/workspace/files.py +193 -0
  467. aria_code/workspace/verify.py +113 -0
  468. aria_code/workspace_changes.py +199 -0
  469. aria_code/workspace_context.py +233 -0
  470. aria_code/workspace_service.py +196 -0
  471. aria_code/workspace_tools.py +150 -0
  472. aria_code-0.52.0.dist-info/METADATA +237 -0
  473. aria_code-0.52.0.dist-info/RECORD +478 -0
  474. aria_code-0.52.0.dist-info/WHEEL +5 -0
  475. aria_code-0.52.0.dist-info/entry_points.txt +3 -0
  476. aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
  477. aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
  478. aria_code-0.52.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,276 @@
1
+ """Canonical lightweight intent routing for CLI services.
2
+
3
+ This module keeps routing side-effect free. It does not call tools, install
4
+ packages, or fetch data; it only classifies a user message into stable service
5
+ intents that other layers can reuse.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from typing import Iterable
12
+
13
+
14
+ def _contains_any(text: str, keywords: Iterable[str]) -> bool:
15
+ return any(keyword in text for keyword in keywords)
16
+
17
+
18
+ def _first_token(text: str) -> str:
19
+ stripped = text.strip()
20
+ if not stripped:
21
+ return ""
22
+ return stripped.split(maxsplit=1)[0].lower()
23
+
24
+
25
+ def _add_unique(items: list[str], name: str) -> None:
26
+ if name not in items:
27
+ items.append(name)
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class IntentRoute:
32
+ message: str
33
+ primary: str
34
+ intents: tuple[str, ...]
35
+ services: tuple[str, ...]
36
+ explicit_code: bool = False
37
+ visual_artifact: bool = False
38
+ market_related: bool = False
39
+
40
+ @property
41
+ def wants_market_prefetch(self) -> bool:
42
+ return self.market_related and not self.visual_artifact and self.primary != "general"
43
+
44
+ @property
45
+ def allows_code_autorun(self) -> bool:
46
+ return self.primary in {"code", "strategy", "backtest"} and self.explicit_code
47
+
48
+
49
+ COMMAND_INTENTS = {
50
+ "/chart": "chart",
51
+ "/dashboard": "dashboard",
52
+ "/report": "report",
53
+ "/team": "market_research",
54
+ "/analyze": "market_analysis",
55
+ "/ta": "market_analysis",
56
+ "/quote": "market_snapshot",
57
+ "/backtest": "backtest",
58
+ "/auto-strategy": "strategy",
59
+ "/strategy": "strategy",
60
+ "/ui": "ui_artifact",
61
+ "/vision": "vision",
62
+ "/upload-image": "vision",
63
+ "/screenshot": "screenshot",
64
+ "/browser": "browser",
65
+ "/file": "file_analysis",
66
+ "/github": "github",
67
+ "/mcp": "mcp",
68
+ "/cloud": "cloud",
69
+ }
70
+
71
+
72
+ def detect_intents(message: str) -> tuple[str, ...]:
73
+ low = message.lower().strip()
74
+ cmd = _first_token(low)
75
+ intents: list[str] = []
76
+
77
+ mapped = COMMAND_INTENTS.get(cmd)
78
+ if mapped:
79
+ _add_unique(intents, mapped)
80
+ # Arguments to /file are usually filenames. Words such as “报告” or
81
+ # “分析” inside those paths describe the document, not a second market
82
+ # command, and must not pull in report/chart dependencies.
83
+ if cmd == "/file":
84
+ return tuple(intents)
85
+
86
+ if _contains_any(low, ("k线图", "k线", "k-line", "kline", "candlestick", "走势图", "图表", "chart", "plot")):
87
+ _add_unique(intents, "chart")
88
+ if _contains_any(low, ("看板", "晨报", "日报", "dashboard", "market board", "持仓看板")):
89
+ _add_unique(intents, "dashboard")
90
+ if _contains_any(low, ("研究报告", "财报", "报告", "report", "研报")):
91
+ _add_unique(intents, "report")
92
+ if _contains_any(low, ("回测", "backtest", "收益曲线", "最大回撤")):
93
+ _add_unique(intents, "backtest")
94
+ if _contains_any(low, ("策略代码", "写策略", "量化策略", "交易策略", "strategy code", "trading bot")):
95
+ _add_unique(intents, "strategy")
96
+ if _contains_any(low, ("技术分析", "技术指标", "rsi", "macd", "均线", "支撑", "阻力")):
97
+ _add_unique(intents, "market_analysis")
98
+ if _contains_any(low, ("股票", "行情", "持仓", "portfolio", "quote", "market data")):
99
+ _add_unique(intents, "market_snapshot")
100
+ if _contains_any(low, ("图片", "图像", "截图", "上传图片", "分析图片", "识别图片", "image", "screenshot")):
101
+ _add_unique(intents, "vision")
102
+ if _contains_any(low, ("浏览器", "网页截图", "打开网页", "browser", "playwright")):
103
+ _add_unique(intents, "browser")
104
+ if _contains_any(low, ("pdf", "docx", "word", "excel", "xlsx", "csv", "文件分析", "上传文件")):
105
+ _add_unique(intents, "file_analysis")
106
+ if _contains_any(low, ("github", "pull request", "pr ", "issue", "ci")):
107
+ _add_unique(intents, "github")
108
+ if _contains_any(low, ("mcp", "server", "tools", "skills")):
109
+ _add_unique(intents, "mcp")
110
+ if _contains_any(low, ("ollama", "本地模型", "local model")):
111
+ _add_unique(intents, "local_model")
112
+ if _contains_any(low, ("阿里云", "aliyun", "cloud service", "云端服务")):
113
+ _add_unique(intents, "cloud")
114
+ if _contains_any(low, ("搜索", "联网", "上网查", "web search", "google", "查一下", "搜一下", "最新消息")):
115
+ _add_unique(intents, "web_search")
116
+ if _contains_any(low, ("加密货币", "比特币", "以太坊", "bitcoin", "btc", "eth", "crypto", "币安", "binance", "okx", "资金费率", "funding rate")):
117
+ _add_unique(intents, "crypto")
118
+ if _contains_any(low, ("外汇", "汇率", "美元兑", "欧元兑", "eur/", "usd/", "jpy", "forex", "fx ")):
119
+ _add_unique(intents, "forex")
120
+ if _contains_any(low, ("期货", "商品", "黄金", "白银", "原油", "铜价", "天然气", "commodity", "futures")):
121
+ _add_unique(intents, "commodity")
122
+ if _contains_any(low, ("a股", "沪深", "上证", "深证", "创业板", "科创板")):
123
+ _add_unique(intents, "ashare")
124
+ if _contains_any(low, ("港股", "恒生", "h股", ".hk")):
125
+ _add_unique(intents, "hk_market")
126
+ if _contains_any(low, ("美股", "纳斯达克", "纽交所", "标普500", "道琼斯", "us stock")):
127
+ _add_unique(intents, "us_market")
128
+ if _contains_any(low, ("足球", "球赛", "比分预测", "世界杯", "欧洲杯", "英超", "西甲", "football", "soccer", "world cup", "premier league")):
129
+ _add_unique(intents, "sports")
130
+
131
+ if "file_analysis" in intents and "report" in intents and cmd != "/report":
132
+ intents = [intent for intent in intents if intent != "report"]
133
+
134
+ return tuple(intents)
135
+
136
+
137
+ def _service_names(intents: tuple[str, ...]) -> tuple[str, ...]:
138
+ services: list[str] = []
139
+
140
+ def service(name: str) -> None:
141
+ _add_unique(services, name)
142
+
143
+ if any(i in intents for i in ("market_snapshot", "market_analysis", "chart", "dashboard", "report", "backtest", "strategy", "market_research", "ashare", "hk_market", "us_market", "forex", "commodity")):
144
+ service("market_data")
145
+ if "chart" in intents:
146
+ service("chart_renderer")
147
+ if "dashboard" in intents:
148
+ service("dashboard_generator")
149
+ if "report" in intents:
150
+ service("report_generator")
151
+ if "backtest" in intents or "strategy" in intents:
152
+ service("backtest_engine")
153
+ if "vision" in intents:
154
+ service("vision_input")
155
+ if "screenshot" in intents:
156
+ service("screenshot")
157
+ if "browser" in intents:
158
+ service("browser")
159
+ if "file_analysis" in intents:
160
+ service("file_parser")
161
+ if "github" in intents:
162
+ service("github_cli")
163
+ if "mcp" in intents:
164
+ service("mcp")
165
+ if "local_model" in intents:
166
+ service("local_llm")
167
+ if "cloud" in intents:
168
+ service("cloud_runtime")
169
+ if "web_search" in intents:
170
+ service("web_search")
171
+ if "crypto" in intents:
172
+ service("crypto_data")
173
+ if "forex" in intents:
174
+ service("forex_data")
175
+ if "commodity" in intents:
176
+ service("commodity_data")
177
+ if "ashare" in intents:
178
+ service("ashare_data")
179
+ if "hk_market" in intents:
180
+ service("hk_market_data")
181
+ if "us_market" in intents:
182
+ service("us_market_data")
183
+ if "sports" in intents:
184
+ service("sports_data")
185
+ return tuple(services)
186
+
187
+
188
+ def build_intent_route(message: str) -> IntentRoute:
189
+ low = message.lower().strip()
190
+ intents = detect_intents(message)
191
+ conceptual_market_question = (
192
+ any(topic in low for topic in ("新闻面", "技术面", "基本面"))
193
+ and any(marker in low for marker in (
194
+ "有用吗", "是否有用", "区别", "关系", "怎么结合", "如何结合",
195
+ "你觉得", "为什么",
196
+ ))
197
+ and not any(marker in low for marker in (
198
+ "最新", "今天", "当前", "实时", "查一下", "搜一下", "搜索",
199
+ "/news", "/quote", "/analyze",
200
+ ))
201
+ )
202
+ explicit_code = _contains_any(low, (
203
+ "代码", "脚本", "python", "程序", "实现", "开发", "修改文件",
204
+ "写代码", "编写代码", "策略代码", "保存为.py", ".py",
205
+ "script", "code", "program", "implement", "edit file", "write file",
206
+ ))
207
+ try:
208
+ try:
209
+ from aria_code.intent_classifier import (
210
+ INTENT_ANALYSIS,
211
+ INTENT_CODING,
212
+ INTENT_FINANCE,
213
+ INTENT_GENERAL,
214
+ INTENT_REALTIME,
215
+ classify_intent_sync,
216
+ is_visual_market_artifact_request,
217
+ )
218
+ except ImportError:
219
+ from intent_classifier import ( # type: ignore[no-redef]
220
+ INTENT_ANALYSIS,
221
+ INTENT_CODING,
222
+ INTENT_FINANCE,
223
+ INTENT_GENERAL,
224
+ INTENT_REALTIME,
225
+ classify_intent_sync,
226
+ is_visual_market_artifact_request,
227
+ )
228
+ classifier_intent = classify_intent_sync(message)
229
+ visual_artifact = bool(is_visual_market_artifact_request(message))
230
+ except Exception:
231
+ INTENT_ANALYSIS = "analysis"
232
+ INTENT_CODING = "coding"
233
+ INTENT_FINANCE = "finance"
234
+ INTENT_GENERAL = "general"
235
+ INTENT_REALTIME = "realtime"
236
+ classifier_intent = INTENT_FINANCE
237
+ visual_artifact = any(i in intents for i in ("chart", "dashboard", "report", "ui_artifact"))
238
+
239
+ if conceptual_market_question:
240
+ # Methodology/capability questions need an explanation, not live market
241
+ # calls. Treating the word "新闻面" as a news lookup caused the whole
242
+ # sentence to be forwarded to search providers as the query.
243
+ primary = "general"
244
+ elif intents:
245
+ primary = intents[0]
246
+ elif classifier_intent == INTENT_REALTIME:
247
+ primary = "market_snapshot"
248
+ elif classifier_intent == INTENT_ANALYSIS:
249
+ primary = "market_analysis"
250
+ elif classifier_intent == INTENT_CODING:
251
+ primary = "code"
252
+ elif classifier_intent == INTENT_GENERAL:
253
+ primary = "general"
254
+ elif classifier_intent == INTENT_FINANCE:
255
+ primary = "finance"
256
+ else:
257
+ primary = "finance"
258
+
259
+ market_related = not conceptual_market_question and (
260
+ any(i in intents for i in (
261
+ "market_snapshot", "market_analysis", "chart", "dashboard", "report",
262
+ "backtest", "strategy", "market_research", "ashare", "hk_market",
263
+ "us_market", "crypto", "forex", "commodity",
264
+ ))
265
+ or classifier_intent in {INTENT_ANALYSIS, INTENT_REALTIME, INTENT_FINANCE}
266
+ )
267
+
268
+ return IntentRoute(
269
+ message=message,
270
+ primary=primary,
271
+ intents=intents,
272
+ services=_service_names(intents),
273
+ explicit_code=explicit_code,
274
+ visual_artifact=visual_artifact,
275
+ market_related=market_related,
276
+ )
@@ -0,0 +1,344 @@
1
+ """Signal extraction and intent precedence for message classification.
2
+
3
+ Replaces a keyword-ordering scheme that had accumulated six layers of
4
+ counter-patches (labelled "Bug ①"–"Bug ⑥" in intent_classifier.py) with no
5
+ regression tests behind any of them. That design failed in four recurring
6
+ ways, all of which this module addresses directly:
7
+
8
+ - **Substring collisions.** The coding keyword "repo" matched inside
9
+ "report_2024.docx", so asking about a document was classified as a code
10
+ task. ASCII terms are now matched on word boundaries.
11
+ - **Spacing variants.** The artifact keyword "k线" missed "K 线图", so a
12
+ chart request fell through to general. CJK terms are now matched against
13
+ a whitespace-stripped form of the message.
14
+ - **Rules cancelling each other.** A question word suppressed the coding
15
+ rule, so "这段代码为什么报错" — a debugging request — became a general
16
+ question. Signals are now extracted independently and combined by one
17
+ explicit precedence table, rather than by the order of early returns.
18
+ - **Generic words as intent.** Bare "分析"/"研究"/"评估" are ordinary
19
+ Chinese and were treated as market-analysis intent, held back only by an
20
+ entity allowlist. A market intent now *requires* a concrete entity.
21
+
22
+ The precedence table is the whole decision: read it top to bottom to know how
23
+ any message is classified.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import re
29
+ from dataclasses import dataclass
30
+
31
+ INTENT_CODING = "coding"
32
+ INTENT_ANALYSIS = "analysis"
33
+ INTENT_REALTIME = "realtime"
34
+ INTENT_GENERAL = "general"
35
+ INTENT_FINANCE = "finance"
36
+
37
+ _CJK = r"一-鿿"
38
+ _ASCII_TERM_RE = re.compile(r"^[a-z0-9][a-z0-9 .+#/_-]*$")
39
+
40
+
41
+ def _normalize(text: str) -> tuple[str, str]:
42
+ """Return (spaced, compact) lowercase forms of *text*.
43
+
44
+ ``spaced`` collapses whitespace runs and is used for boundary-anchored
45
+ ASCII matching. ``compact`` removes whitespace entirely and is used for
46
+ CJK terms, so "K 线图" and "K线图" are the same message.
47
+ """
48
+ low = (text or "").strip().lower()
49
+ spaced = re.sub(r"\s+", " ", low)
50
+ compact = re.sub(r"\s+", "", low)
51
+ return spaced, compact
52
+
53
+
54
+ def _matches(term: str, spaced: str, compact: str) -> bool:
55
+ """True if *term* occurs in the message under the right matching rule."""
56
+ term = term.strip().lower()
57
+ if not term:
58
+ return False
59
+ if _ASCII_TERM_RE.match(term):
60
+ # Word boundaries stop "repo" from matching inside "report".
61
+ return re.search(rf"(?<![a-z0-9]){re.escape(term)}(?![a-z0-9])", spaced) is not None
62
+ return re.sub(r"\s+", "", term) in compact
63
+
64
+
65
+ def _any(terms, spaced: str, compact: str) -> bool:
66
+ return any(_matches(t, spaced, compact) for t in terms)
67
+
68
+
69
+ # ── Term inventories ────────────────────────────────────────────────────────
70
+ # Each list answers one question. Terms live in exactly one list, so a change
71
+ # has one obvious place to go.
72
+
73
+ _CODE_TERMS = (
74
+ # Actions on code
75
+ "写代码", "编写代码", "重构", "调试", "报错", "修复", "改一下", "改成",
76
+ "实现", "开发", "部署", "上线", "打包", "编译", "跑一下", "运行一下",
77
+ "单元测试", "集成测试", "代码审查", "代码审核", "审核代码", "审查代码",
78
+ "refactor", "debug", "implement", "deploy", "compile", "lint",
79
+ "unit test", "integration test", "code review", "stack trace", "traceback",
80
+ "bug", "fix", "patch", "commit", "merge", "rebase", "pull request",
81
+ # Code nouns
82
+ "代码", "脚本", "函数", "方法", "类", "模块", "接口", "仓库", "代码库",
83
+ "前端", "后端", "数据库", "编译器", "依赖", "报错信息", "异常",
84
+ "script", "function", "module", "repo", "repository", "codebase",
85
+ "frontend", "backend", "database", "api", "sdk", "cli",
86
+ "python", "typescript", "javascript", "rust", "golang", "java",
87
+ "react", "vue", "next.js", "nextjs", "svelte", "swiftui", "flutter",
88
+ "fastapi", "django", "flask", "express", "pytest", "docker", "kubernetes",
89
+ # Build requests. "写一个 AAPL 动量策略" is a request to produce code, even
90
+ # though the subject is a ticker — without these it fell through to the
91
+ # market branches and was answered as prose.
92
+ "写一个", "写个", "做一个", "搭一个", "建一个", "编写", "创建", "生成",
93
+ "策略", "交易策略", "量化策略", "回测", "选股",
94
+ "write a", "create a", "build a", "generate", "backtest", "strategy",
95
+ # How people actually report a defect. The list above named tools and
96
+ # actions ("重构", "pytest", "traceback") but not the plain sentence a
97
+ # person writes when something is broken, so "这个项目的测试挂了,找出原因
98
+ # 并修好" classified as GENERAL — and the general prompt does not tell the
99
+ # model to act, so a 7B model with every tool available simply asked for
100
+ # more details and changed nothing. An eval suite run caught this at 0/5.
101
+ #
102
+ # The bias here is deliberate: an unsure classification should fail toward
103
+ # capability. Sending "测试一下这个想法" down the coding path costs a longer
104
+ # system prompt; sending "测试挂了,修好" to general costs the entire task,
105
+ # silently.
106
+ "测试挂", "测试失败", "测试不过", "测试没过", "跑不通", "跑不过",
107
+ "修好", "修一下", "修掉", "改好", "没通过", "挂了",
108
+ "断言", "崩溃", "空指针", "越界", "校验", "入参", "边界条件", "打日志",
109
+ "failing test", "test fails", "tests fail", "test failure", "broken",
110
+ "crash", "assertion", "exception", "stacktrace", "regression",
111
+ "edge case", "off-by-one", "validation", "refactoring",
112
+ )
113
+
114
+ # Words that name a project/product artefact rather than code. When these
115
+ # appear without a code term, the task is documentation or product work.
116
+ _PRODUCT_TERMS = (
117
+ "产品", "需求", "文档", "架构设计", "商业模式", "市场定位", "用户体验",
118
+ "运营", "品牌", "文案", "白皮书", "商业计划",
119
+ )
120
+
121
+ _ARTIFACT_TERMS = (
122
+ "图表", "走势图", "k线图", "k线", "k-line", "kline", "candlestick",
123
+ "蜡烛图", "热力图", "heatmap", "chart", "plot", "dashboard",
124
+ "看板", "晨报", "日报", "周报", "月报", "报表",
125
+ )
126
+
127
+ _MARKET_CONTEXT_TERMS = (
128
+ "股票", "股价", "行情", "市场", "美股", "港股", "a股", "指数", "大盘",
129
+ "持仓", "portfolio", "回测", "财报", "earnings", "基金", "etf",
130
+ "资产", "组合", "市值", "backtest", "market data", "stock",
131
+ )
132
+
133
+ _REALTIME_TERMS = (
134
+ "今天", "今日", "现在", "当前", "此刻", "最新", "最近", "实时",
135
+ "多少钱", "多少点", "是多少", "什么价", "现价", "报价", "涨跌", "涨幅",
136
+ "新闻", "消息", "快讯", "今天的", "盘中",
137
+ "today", "now", "current", "latest", "price", "quote", "news",
138
+ "market cap", "how much",
139
+ )
140
+
141
+ _ANALYSIS_TERMS = (
142
+ "分析", "研究", "评估", "研判", "看法", "怎么样", "如何",
143
+ "技术面", "基本面", "走势", "趋势", "估值",
144
+ "analysis", "analyze", "outlook", "valuation", "technical analysis",
145
+ "fundamental",
146
+ )
147
+
148
+ _CONCEPTUAL_TERMS = (
149
+ "什么是", "什么叫", "是什么", "为什么", "怎么理解", "如何理解",
150
+ "解释", "定义", "概念", "原理", "介绍一下", "区别", "举例",
151
+ "what is", "what are", "how does", "explain", "define",
152
+ "difference between", "tell me about",
153
+ )
154
+
155
+ _MACRO_TERMS = (
156
+ "宏观", "宏观经济", "宏观政策", "宏观角度", "货币政策", "财政政策",
157
+ "gdp", "通胀", "通货膨胀", "cpi", "ppi", "利率", "加息", "降息",
158
+ "美联储", "央行", "收益率曲线", "国债", "产业政策", "行业监管",
159
+ )
160
+
161
+ _REALTY_TERMS = (
162
+ "房价", "楼市", "房产", "房地产", "租金", "二手房", "商铺", "户型",
163
+ )
164
+
165
+ _RECOMMENDATION_TERMS = (
166
+ "应该买", "应该卖", "该不该", "要不要", "值不值", "是否值得", "值得投资",
167
+ "建议买", "建议卖", "能买吗", "可以买吗",
168
+ )
169
+
170
+ _FINANCE_CONCEPT_TERMS = (
171
+ "dcf", "wacc", "capm", "sharpe", "sortino", "ebitda", "beta", "alpha",
172
+ "var", "cvar", "drawdown", "black-scholes", "期权", "期货", "衍生品",
173
+ "套利", "量化", "quant", "因子", "夏普比率", "最大回撤",
174
+ "市盈率", "市净率", "估值模型", "pe", "pb", "roe", "roa",
175
+ )
176
+
177
+ _METRIC_TERMS = (
178
+ "pe", "pb", "ps", "市盈率", "市净率", "市销率", "eps", "净利润",
179
+ "营收", "市值", "股息", "分红", "毛利率", "roe", "roa",
180
+ )
181
+
182
+ _FILE_EXT_RE = re.compile(
183
+ r"[^\s]+\.(?:docx?|pdf|xlsx?|pptx?|txt|csv|json|ya?ml|md|log|ipynb)\b"
184
+ )
185
+ _CODE_EXT_RE = re.compile(r"[^\s]+\.(?:py|js|ts|tsx|jsx|go|rs|java|rb|c|cpp|h|sh)\b")
186
+
187
+ # Concrete, named financial entities. A market intent requires one of these
188
+ # (or a resolvable ticker) — generic category words like "美股" deliberately do
189
+ # not qualify, because they appear throughout macro discussion.
190
+ _ENTITY_TERMS = (
191
+ "苹果", "谷歌", "英伟达", "微软", "特斯拉", "亚马逊", "腾讯", "阿里",
192
+ "百度", "比亚迪", "茅台", "招商银行", "中国平安", "华为", "小米",
193
+ "美团", "京东", "字节", "宁德时代", "中芯国际",
194
+ "apple", "google", "nvidia", "microsoft", "tesla", "amazon", "meta",
195
+ "netflix", "palantir", "snowflake", "mongodb",
196
+ "比特币", "以太坊", "bitcoin", "ethereum",
197
+ "纳斯达克", "标普500", "道琼斯", "沪深300", "中证500", "恒生指数",
198
+ )
199
+
200
+ _TICKER_RE = re.compile(r"(?<![A-Za-z0-9])[A-Z]{2,5}(?![A-Za-z0-9])")
201
+ _A_SHARE_RE = re.compile(r"(?<!\d)(?:60|68|00|30)\d{4}(?!\d)")
202
+
203
+
204
+ @dataclass(frozen=True)
205
+ class IntentSignals:
206
+ """Independent observations about a message, with no precedence applied."""
207
+
208
+ entity: bool
209
+ ticker: bool
210
+ market_context: bool
211
+ code: bool
212
+ product: bool
213
+ file_ref: bool
214
+ code_file_ref: bool
215
+ artifact: bool
216
+ realtime: bool
217
+ analysis: bool
218
+ conceptual: bool
219
+ macro: bool
220
+ realty: bool
221
+ recommendation: bool
222
+ finance_concept: bool
223
+ metric: bool
224
+
225
+ @property
226
+ def any_entity(self) -> bool:
227
+ return self.entity or self.ticker
228
+
229
+
230
+ def extract_signals(message: str) -> IntentSignals:
231
+ """Observe *message* without deciding anything about it."""
232
+ spaced, compact = _normalize(message)
233
+ raw = message or ""
234
+ return IntentSignals(
235
+ entity=_any(_ENTITY_TERMS, spaced, compact),
236
+ ticker=bool(_TICKER_RE.search(raw) or _A_SHARE_RE.search(raw)),
237
+ market_context=_any(_MARKET_CONTEXT_TERMS, spaced, compact),
238
+ code=_any(_CODE_TERMS, spaced, compact),
239
+ product=_any(_PRODUCT_TERMS, spaced, compact),
240
+ file_ref=bool(_FILE_EXT_RE.search(raw)),
241
+ code_file_ref=bool(_CODE_EXT_RE.search(raw)),
242
+ artifact=_any(_ARTIFACT_TERMS, spaced, compact),
243
+ realtime=_any(_REALTIME_TERMS, spaced, compact),
244
+ analysis=_any(_ANALYSIS_TERMS, spaced, compact),
245
+ conceptual=_any(_CONCEPTUAL_TERMS, spaced, compact),
246
+ macro=_any(_MACRO_TERMS, spaced, compact),
247
+ realty=_any(_REALTY_TERMS, spaced, compact),
248
+ recommendation=_any(_RECOMMENDATION_TERMS, spaced, compact),
249
+ finance_concept=_any(_FINANCE_CONCEPT_TERMS, spaced, compact),
250
+ metric=_any(_METRIC_TERMS, spaced, compact),
251
+ )
252
+
253
+
254
+ def is_visual_artifact_request(message: str) -> bool:
255
+ """True for chart/dashboard/report requests that should be built, not looked up."""
256
+ spaced, _ = _normalize(message)
257
+ if spaced.startswith(("/chart", "/dashboard", "/report")):
258
+ return True
259
+ signals = extract_signals(message)
260
+ if not signals.artifact:
261
+ return False
262
+ return signals.market_context or signals.any_entity or signals.finance_concept
263
+
264
+
265
+ def classify(message: str) -> str:
266
+ """Classify *message* into one INTENT_* label.
267
+
268
+ The precedence below is the entire decision. Each rule states why it
269
+ outranks the ones after it.
270
+ """
271
+ if not (message or "").strip():
272
+ return INTENT_GENERAL
273
+
274
+ s = extract_signals(message)
275
+
276
+ # 1. A chart/dashboard/report over market data is something to *build*.
277
+ # It needs the code path, not a quote lookup.
278
+ if is_visual_artifact_request(message):
279
+ return INTENT_CODING
280
+
281
+ # 2. A source file named outright is a code task regardless of phrasing.
282
+ if s.code_file_ref:
283
+ return INTENT_CODING
284
+
285
+ # 3. A document named outright is a reading task, not a market query —
286
+ # even though "report_2024.docx" contains market-ish letters.
287
+ if s.file_ref:
288
+ return INTENT_CODING if s.code else INTENT_GENERAL
289
+
290
+ # 4. Code signals win over question phrasing. "这段代码为什么报错" is a
291
+ # debugging request; the old order let "为什么" demote it to general.
292
+ if s.code:
293
+ return INTENT_CODING
294
+
295
+ # 5. Real estate never routes to the stock templates, which expect market
296
+ # data that does not exist for a housing question.
297
+ if s.realty:
298
+ return INTENT_GENERAL
299
+
300
+ # 6. Macro topics are discussion unless a specific company is named.
301
+ if s.macro and not s.any_entity:
302
+ return INTENT_GENERAL
303
+
304
+ # 7. "What is X" wants an explanation, not a lookup — but only when it is
305
+ # not asking about a specific company's live numbers.
306
+ if s.conceptual and not (s.any_entity and (s.realtime or s.metric)):
307
+ return INTENT_GENERAL
308
+
309
+ # 8. "Should I buy X" is advice, not a chart.
310
+ if s.recommendation:
311
+ return INTENT_FINANCE if (s.any_entity or s.market_context) else INTENT_GENERAL
312
+
313
+ # 9. Live data wins over analysis: "分析苹果今天的市场" needs a fetch, or
314
+ # the model answers a price question from memory.
315
+ if s.realtime and (s.any_entity or s.market_context or s.metric):
316
+ return INTENT_REALTIME
317
+
318
+ # 10. Market analysis requires a concrete entity. Bare "分析"/"研究" is
319
+ # ordinary Chinese and must not reach the stock-analysis template.
320
+ if s.analysis and s.any_entity:
321
+ return INTENT_ANALYSIS
322
+
323
+ # 11. Finance vocabulary without an entity is finance chat.
324
+ if s.finance_concept or (s.market_context and s.analysis):
325
+ return INTENT_FINANCE
326
+
327
+ # 12. A bare live-data question with no market subject ("最近有什么新闻").
328
+ if s.realtime:
329
+ return INTENT_REALTIME
330
+
331
+ return INTENT_GENERAL
332
+
333
+
334
+ __all__ = [
335
+ "INTENT_ANALYSIS",
336
+ "INTENT_CODING",
337
+ "INTENT_FINANCE",
338
+ "INTENT_GENERAL",
339
+ "INTENT_REALTIME",
340
+ "IntentSignals",
341
+ "classify",
342
+ "extract_signals",
343
+ "is_visual_artifact_request",
344
+ ]
@@ -0,0 +1,48 @@
1
+ """Simple lifecycle shell hooks for the CLI adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import Mapping
9
+
10
+
11
+ def run_event_hook(
12
+ event: str,
13
+ *,
14
+ config_dir: Path,
15
+ cwd: Path | None = None,
16
+ env_extra: Mapping[str, str] | None = None,
17
+ timeout: int = 10,
18
+ ) -> None:
19
+ """Run executable hook scripts for a lifecycle event.
20
+
21
+ Script locations are intentionally simple for compatibility:
22
+ `<config_dir>/hooks/<event>.sh` and `<cwd>/.aria/hooks/<event>.sh`.
23
+ Hook failures are non-fatal.
24
+ """
25
+ root = cwd or Path.cwd()
26
+ dirs = [
27
+ config_dir / "hooks",
28
+ root / ".aria" / "hooks",
29
+ ]
30
+ env = dict(os.environ)
31
+ env["ARIA_EVENT"] = event
32
+ if env_extra:
33
+ env.update({str(k): str(v) for k, v in env_extra.items()})
34
+ for hook_dir in dirs:
35
+ script = hook_dir / f"{event}.sh"
36
+ if not script.exists() or script.stat().st_size <= 0:
37
+ continue
38
+ try:
39
+ subprocess.run(
40
+ [str(script)],
41
+ env=env,
42
+ timeout=timeout,
43
+ capture_output=True,
44
+ text=True,
45
+ check=False,
46
+ )
47
+ except Exception:
48
+ continue