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,180 @@
1
+ """Aria Code lifecycle hooks — JSON-configurable, shell-executable.
2
+
3
+ Config file: ~/.arthera/hooks.json
4
+ Project-local override: .aria/hooks.json (takes precedence)
5
+
6
+ Schema
7
+ ------
8
+ {
9
+ "PreToolUse": [{"tool": "run_command", "command": "echo $ARIA_TOOL"}],
10
+ "PostToolUse": [{"command": "notify-send 'done'"}],
11
+ "ResponseDone": [{"command": "afplay /System/Sounds/Glass.aiff"}],
12
+ "SessionStart": [{"command": "echo starting $ARIA_SESSION"}],
13
+ "SessionEnd": [{"command": "echo ended"}]
14
+ }
15
+
16
+ Each hook entry:
17
+ command — shell command to execute (required)
18
+ tool — if set, only fires when tool name matches (PreToolUse / PostToolUse)
19
+ timeout — seconds before the hook is killed (default 10)
20
+ blocking — if true AND exit code != 0, execution is blocked (PreToolUse only)
21
+
22
+ Env vars injected into every hook:
23
+ ARIA_EVENT — hook event name
24
+ ARIA_TOOL — tool name (Pre/PostToolUse only)
25
+ ARIA_TOOL_PARAMS — JSON-encoded params (Pre/PostToolUse only)
26
+ ARIA_RESULT — JSON-encoded result (PostToolUse only)
27
+ ARIA_RESPONSE — first 500 chars of response (ResponseDone)
28
+ ARIA_SESSION — session ID
29
+ """
30
+ from __future__ import annotations
31
+
32
+ import json
33
+ import logging
34
+ import os
35
+ import subprocess
36
+ from pathlib import Path
37
+ from typing import Optional
38
+
39
+ from aria_code.apps.cli.config_paths import resolve_config_dir
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ _CONFIG_DIR = resolve_config_dir()
44
+ _GLOBAL_HOOKS_FILE = _CONFIG_DIR / "hooks.json"
45
+ _LOCAL_HOOKS_FILE = Path.cwd() / ".aria" / "hooks.json"
46
+
47
+ _VALID_EVENTS = frozenset([
48
+ "PreToolUse", "PostToolUse",
49
+ "ResponseDone",
50
+ "SessionStart", "SessionEnd",
51
+ ])
52
+
53
+
54
+ def load_hooks() -> dict:
55
+ """Load and merge global + project-local hooks config."""
56
+ merged: dict[str, list] = {e: [] for e in _VALID_EVENTS}
57
+
58
+ for path in (_GLOBAL_HOOKS_FILE, _LOCAL_HOOKS_FILE):
59
+ if path.exists():
60
+ try:
61
+ data = json.loads(path.read_text(encoding="utf-8"))
62
+ for event, entries in data.items():
63
+ if event in _VALID_EVENTS and isinstance(entries, list):
64
+ merged[event].extend(entries)
65
+ except Exception as exc:
66
+ logger.debug("hooks.json parse error (%s): %s", path, exc)
67
+
68
+ return merged
69
+
70
+
71
+ def fire(
72
+ event: str,
73
+ *,
74
+ tool: Optional[str] = None,
75
+ params: Optional[dict] = None,
76
+ result: Optional[dict] = None,
77
+ response: str = "",
78
+ session_id: str = "",
79
+ hooks: Optional[dict] = None,
80
+ ) -> bool:
81
+ """Fire all matching hooks for an event.
82
+
83
+ Returns False if any *blocking* PreToolUse hook exits non-zero
84
+ (meaning the tool call should be suppressed). Returns True otherwise.
85
+ """
86
+ if hooks is None:
87
+ hooks = load_hooks()
88
+
89
+ entries = hooks.get(event, [])
90
+ if not entries:
91
+ return True
92
+
93
+ base_env = dict(os.environ)
94
+ base_env["ARIA_EVENT"] = event
95
+ base_env["ARIA_SESSION"] = session_id or ""
96
+ if tool:
97
+ base_env["ARIA_TOOL"] = tool
98
+ if params is not None:
99
+ base_env["ARIA_TOOL_PARAMS"] = json.dumps(params, ensure_ascii=False)[:2000]
100
+ if result is not None:
101
+ base_env["ARIA_RESULT"] = json.dumps(result, ensure_ascii=False)[:2000]
102
+ if response:
103
+ base_env["ARIA_RESPONSE"] = response[:500]
104
+
105
+ blocked = False
106
+ for entry in entries:
107
+ if not isinstance(entry, dict):
108
+ continue
109
+ cmd = entry.get("command", "").strip()
110
+ if not cmd:
111
+ continue
112
+
113
+ # Tool filter: skip if hook is scoped to a different tool
114
+ if entry.get("tool") and tool and entry["tool"] != tool:
115
+ continue
116
+
117
+ timeout = int(entry.get("timeout", 10))
118
+ is_blocking = bool(entry.get("blocking", False))
119
+
120
+ try:
121
+ proc = subprocess.run(
122
+ cmd,
123
+ shell=True,
124
+ env=base_env,
125
+ timeout=timeout,
126
+ capture_output=True,
127
+ text=True,
128
+ )
129
+ if is_blocking and proc.returncode != 0 and event == "PreToolUse":
130
+ logger.info(
131
+ "Blocking hook vetoed tool '%s': exit %d — %s",
132
+ tool, proc.returncode, proc.stderr[:120],
133
+ )
134
+ blocked = True
135
+ except subprocess.TimeoutExpired:
136
+ logger.debug("Hook timed out after %ds: %s", timeout, cmd[:60])
137
+ except Exception as exc:
138
+ logger.debug("Hook error: %s", exc)
139
+
140
+ return not blocked
141
+
142
+
143
+ def list_hooks() -> list[dict]:
144
+ """Return a flat list of configured hooks for display."""
145
+ hooks = load_hooks()
146
+ rows = []
147
+ for event, entries in hooks.items():
148
+ for entry in entries:
149
+ if isinstance(entry, dict) and entry.get("command"):
150
+ rows.append({
151
+ "event": event,
152
+ "tool": entry.get("tool", "*"),
153
+ "command": entry["command"][:80],
154
+ "blocking": entry.get("blocking", False),
155
+ "timeout": entry.get("timeout", 10),
156
+ })
157
+ return rows
158
+
159
+
160
+ def hooks_file_path(scope: str = "global") -> Path:
161
+ """Return the hooks.json path for a given scope."""
162
+ if scope == "local":
163
+ return Path.cwd() / ".aria" / "hooks.json"
164
+ return _GLOBAL_HOOKS_FILE
165
+
166
+
167
+ def create_example_hooks(path: Path) -> None:
168
+ """Write an annotated example hooks.json if it doesn't exist."""
169
+ if path.exists():
170
+ return
171
+ path.parent.mkdir(parents=True, exist_ok=True)
172
+ example = {
173
+ "_comment": "Aria Code hooks — https://aria.code/docs/hooks",
174
+ "PreToolUse": [],
175
+ "PostToolUse": [],
176
+ "ResponseDone": [],
177
+ "SessionStart": [],
178
+ "SessionEnd": [],
179
+ }
180
+ path.write_text(json.dumps(example, indent=2, ensure_ascii=False), encoding="utf-8")
@@ -0,0 +1,297 @@
1
+ """i18n.py — System language detection and UI string translations for Aria Code.
2
+
3
+ Priority order for UI language:
4
+ 1. config["ui_lang"] (user explicitly set via /config set ui_lang=zh)
5
+ 2. OS locale at first-run (written into config automatically)
6
+ 3. Fallback: "en"
7
+
8
+ Supported languages: "zh" (Simplified Chinese), "en" (English)
9
+ Future: "ja", "ko" — extend STRINGS dict below.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ from typing import Optional
15
+
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # String catalogue
19
+ # ---------------------------------------------------------------------------
20
+
21
+ STRINGS: dict[str, dict[str, str]] = {
22
+ # Banner labels
23
+ "local_first_agent": {
24
+ "zh": "本地优先智能体",
25
+ "en": "local-first agent",
26
+ },
27
+ "model": {
28
+ "zh": "模型",
29
+ "en": "model",
30
+ },
31
+ "workspace": {
32
+ "zh": "工作区",
33
+ "en": "workspace",
34
+ },
35
+ "mode": {
36
+ "zh": "模式",
37
+ "en": "mode",
38
+ },
39
+ "status": {
40
+ "zh": "状态",
41
+ "en": "status",
42
+ },
43
+ "tools": {
44
+ "zh": "工具",
45
+ "en": "tools",
46
+ },
47
+ "skills": {
48
+ "zh": "技能",
49
+ "en": "skills",
50
+ },
51
+ "quant": {
52
+ "zh": "量化",
53
+ "en": "quant",
54
+ },
55
+ # Status labels
56
+ "sharing_on": {
57
+ "zh": "数据共享",
58
+ "en": "sharing on",
59
+ },
60
+ "local_only": {
61
+ "zh": "纯本地",
62
+ "en": "local-only",
63
+ },
64
+ "local_retention": {
65
+ "zh": "本地留存",
66
+ "en": "local retention",
67
+ },
68
+ "cloud": {
69
+ "zh": "云端",
70
+ "en": "cloud",
71
+ },
72
+ "local": {
73
+ "zh": "本地",
74
+ "en": "local",
75
+ },
76
+ "lite": {
77
+ "zh": "轻量",
78
+ "en": "lite",
79
+ },
80
+ "ollama_online": {
81
+ "zh": "Ollama 在线",
82
+ "en": "Ollama online",
83
+ },
84
+ "ollama_offline": {
85
+ "zh": "Ollama 离线",
86
+ "en": "Ollama offline",
87
+ },
88
+ "cloud_connected": {
89
+ "zh": "云端已连接",
90
+ "en": "cloud ✓",
91
+ },
92
+ "model_singular": {
93
+ "zh": "个模型",
94
+ "en": "model",
95
+ },
96
+ "model_plural": {
97
+ "zh": "个模型",
98
+ "en": "models",
99
+ },
100
+ # Hint line
101
+ "try": {
102
+ "zh": "试试",
103
+ "en": "try",
104
+ },
105
+ # Model picker
106
+ "select_model": {
107
+ "zh": "选择模型",
108
+ "en": "Select Model",
109
+ },
110
+ "installed": {
111
+ "zh": "已安装",
112
+ "en": "installed",
113
+ },
114
+ "not_installed": {
115
+ "zh": "未安装",
116
+ "en": "not installed",
117
+ },
118
+ "cancelled": {
119
+ "zh": "已取消",
120
+ "en": "Cancelled",
121
+ },
122
+ "no_change": {
123
+ "zh": "未更改",
124
+ "en": "No change",
125
+ },
126
+ "community_models": {
127
+ "zh": "社区模型 (Ollama)",
128
+ "en": "Community (Ollama)",
129
+ },
130
+ "ollama_unreachable": {
131
+ "zh": "Ollama 无法连接",
132
+ "en": "Ollama unreachable",
133
+ },
134
+ "switch_model_hint": {
135
+ "zh": "使用 /model <id> 切换模型",
136
+ "en": "Use /model <id> to switch",
137
+ },
138
+ "current": {
139
+ "zh": "当前",
140
+ "en": "current",
141
+ },
142
+ # Permission / mode labels
143
+ "network_on": {
144
+ "zh": "网络开",
145
+ "en": "network on",
146
+ },
147
+ "network_off": {
148
+ "zh": "网络关",
149
+ "en": "network off",
150
+ },
151
+ "privacy": {
152
+ "zh": "隐私",
153
+ "en": "privacy",
154
+ },
155
+ # Setup wizard
156
+ "detecting_lang": {
157
+ "zh": "检测到系统语言:中文",
158
+ "en": "Detected system language: English",
159
+ },
160
+ "first_run_welcome": {
161
+ "zh": "欢迎使用 Aria Code!首次运行,正在自动配置...",
162
+ "en": "Welcome to Aria Code! First run — auto-configuring...",
163
+ },
164
+ "auto_model_selected": {
165
+ "zh": "已自动选择本地模型:",
166
+ "en": "Auto-selected local model: ",
167
+ },
168
+ "no_ollama_models": {
169
+ "zh": "未发现本地模型,使用默认配置",
170
+ "en": "No local models found, using default config",
171
+ },
172
+ # Thinking mode
173
+ "thinking_mode": {
174
+ "zh": "思考模式",
175
+ "en": "Thinking Mode",
176
+ },
177
+ # Misc
178
+ "tip": {
179
+ "zh": "提示",
180
+ "en": "tip",
181
+ },
182
+ "auto_matched": {
183
+ "zh": "自动匹配",
184
+ "en": "auto-matched",
185
+ },
186
+ }
187
+
188
+
189
+ # ---------------------------------------------------------------------------
190
+ # Detection
191
+ # ---------------------------------------------------------------------------
192
+
193
+ def detect_system_lang() -> str:
194
+ """Detect OS language. Returns 'zh' for Chinese systems, 'en' for everything else.
195
+
196
+ Checks (in order): $LANGUAGE, $LANG, $LC_ALL, $LC_MESSAGES, Python locale module.
197
+ Treats zh_CN, zh_TW, zh_HK, zh_SG as 'zh'.
198
+ """
199
+ for var in ("LANGUAGE", "LANG", "LC_ALL", "LC_MESSAGES"):
200
+ raw = os.environ.get(var, "").strip()
201
+ if not raw or raw in ("C", "POSIX", "C.UTF-8"):
202
+ continue
203
+ # LANGUAGE may be colon-separated list: zh_CN:en
204
+ code = raw.split(":")[0].split(".")[0].split("_")[0].lower()
205
+ if code == "zh":
206
+ return "zh"
207
+ if code in ("en", "fr", "de", "es", "pt", "ja", "ko", "ru", "ar"):
208
+ return code if code in ("ja", "ko") else "en"
209
+
210
+ # Fallback: Python locale module (works on macOS/Windows when env vars absent)
211
+ try:
212
+ import locale as _locale
213
+ lang_code, _ = _locale.getdefaultlocale()
214
+ if lang_code:
215
+ prefix = lang_code.split("_")[0].lower()
216
+ if prefix == "zh":
217
+ return "zh"
218
+ if prefix in ("ja", "ko"):
219
+ return prefix
220
+ except Exception:
221
+ pass
222
+
223
+ return "en"
224
+
225
+
226
+ def get_ui_lang(config: Optional[dict] = None) -> str:
227
+ """Return effective UI language.
228
+
229
+ 1. config["ui_lang"] if explicitly set
230
+ 2. detect_system_lang()
231
+ """
232
+ if config:
233
+ saved = config.get("ui_lang", "")
234
+ if saved in STRINGS.get("model", {}): # valid lang code
235
+ return saved
236
+ return detect_system_lang()
237
+
238
+
239
+ def t(key: str, lang: Optional[str] = None, config: Optional[dict] = None) -> str:
240
+ """Translate a UI key to the given language (or auto-detect).
241
+
242
+ Falls back to 'en' if key/lang not found.
243
+ """
244
+ if lang is None:
245
+ lang = get_ui_lang(config)
246
+ entry = STRINGS.get(key, {})
247
+ return entry.get(lang) or entry.get("en") or key
248
+
249
+
250
+ # ---------------------------------------------------------------------------
251
+ # Ollama model helpers. No longer called during config load — see
252
+ # SettingsService.load(), which no longer overrides the configured model.
253
+ # ---------------------------------------------------------------------------
254
+
255
+ _MODEL_PRIORITY = [
256
+ "qwen2.5:7b",
257
+ "qwen2.5-coder:7b",
258
+ "deepseek-r1:7b",
259
+ "qwen2.5:3b",
260
+ "qwen2.5-coder:3b",
261
+ "llama3.2:3b",
262
+ "mistral:7b",
263
+ "qwen2.5-coder:1.5b",
264
+ "qwen2.5:1.5b",
265
+ "llama3.2:1b",
266
+ ]
267
+
268
+
269
+ def installed_ollama_models(ollama_url: str = "http://localhost:11434") -> set[str]:
270
+ """The model names Ollama reports, or an empty set if it cannot be reached."""
271
+ try:
272
+ import urllib.request as _ur
273
+ import json as _json
274
+ with _ur.urlopen(f"{ollama_url}/api/tags", timeout=3) as resp:
275
+ data = _json.loads(resp.read())
276
+ return {m["name"] for m in data.get("models", [])}
277
+ except Exception:
278
+ return set()
279
+
280
+
281
+ def preferred_installed_model(installed: set[str]) -> Optional[str]:
282
+ """The best model from *installed* that this list vouches for, else None.
283
+
284
+ Pure, so it is testable without a running Ollama.
285
+
286
+ Note what this does NOT do: there is no alphabetical last resort. The
287
+ function it replaced (``auto_select_model``) ended with
288
+ ``sorted(installed)[0]``, and it was called during config load to overwrite
289
+ the caller's default model. A machine with one stray 0.5B model got that
290
+ model as its agent. Declining to answer is the correct answer when nothing
291
+ on the curated list is present; ``model_catalog.pick_best_installed_model``
292
+ is the richer version that also consults the capability registry.
293
+ """
294
+ for pref in _MODEL_PRIORITY:
295
+ if pref in installed:
296
+ return pref
297
+ return None
@@ -0,0 +1,136 @@
1
+ """Intent classification helpers extracted from aria_cli.py.
2
+
3
+ All functions are pure — no I/O, no globals, fully unit-testable.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ # ── Keyword lists ─────────────────────────────────────────────────────────────
8
+
9
+ CODING_KEYWORDS = (
10
+ "write", "generate", "create", "script", "code", "plot", "backtest",
11
+ "策略", "代码", "回测", "编写", "生成", "k线", "k-line", "kline",
12
+ "analyze and save", "analysis script", "python", "dashboard",
13
+ "写一个", "生成代码", "写代码", "编写代码",
14
+ )
15
+
16
+ VISUAL_ARTIFACT_KEYWORDS = (
17
+ "图表", "走势图", "k线图", "k线", "k-line", "kline", "candlestick",
18
+ "chart", "plot", "dashboard", "看板", "晨报", "日报", "周报", "月报",
19
+ "report", "热力图", "heatmap",
20
+ )
21
+
22
+ ANALYSIS_KEYWORDS = (
23
+ "analyze", "analysis", "分析", "研究", "评估", "研判",
24
+ "技术面", "基本面", "走势", "趋势", "行情",
25
+ "技术分析", "技术指标", "支撑", "阻力", "支撑位", "阻力位",
26
+ "rsi", "macd", "bollinger", "布林", "均线", "kdj", "kdj指标",
27
+ "stock analysis", "technical analysis", "fundamental",
28
+ "valuation", "estimate", "outlook", "投资建议", "买入", "卖出",
29
+ "看多", "看空", "多头", "空头", "金叉", "死叉",
30
+ )
31
+
32
+ ANALYSIS_NON_STOCK_TOPICS = (
33
+ "房价", "楼市", "房产", "房地产", "租金", "二手房", "新房", "商铺", "折旧",
34
+ "宏观", "宏观经济", "宏观政策", "宏观角度", "经济政策", "货币政策",
35
+ "财政政策", "gdp", "通胀", "通货膨胀", "cpi", "ppi", "利率政策",
36
+ "黄金", "原油", "大宗商品", "汇率", "外汇", "美元指数",
37
+ )
38
+
39
+ GENERAL_KNOWLEDGE_KEYWORDS = (
40
+ "什么是", "what is", "what are", "how does", "explain", "define",
41
+ "解释", "定义", "概念", "原理", "介绍", "步骤", "流程", "怎么",
42
+ "如何理解", "是什么", "为什么", "区别", "difference between",
43
+ "tell me about", "describe", "how to", "注册", "成立", "公司",
44
+ "基本概念", "简介", "举例", "example", "例子",
45
+ "足球", "篮球", "网球", "棒球", "橄榄球", "排球", "乒乓球", "羽毛球",
46
+ "世界杯", "欧冠", "英超", "德甲", "西甲", "意甲", "法甲", "bundesliga",
47
+ "比赛", "赛事", "比分", "进球", "射门", "门将", "球队", "球员", "教练",
48
+ "联赛", "积分榜", "赛程", "晋级", "淘汰赛", "决赛", "半决赛",
49
+ "football", "soccer", "match", "goal", "league", "champion",
50
+ "nba", "nfl", "mlb", "f1", "赛车", "奥运", "olympic",
51
+ )
52
+
53
+ FINANCE_CONCEPT_TERMS = (
54
+ "dcf", "pe", "pb", "ps", "ev", "ebitda", "ebit", "wacc", "capm",
55
+ "beta", "alpha", "sharpe", "sortino", "var", "cvar", "drawdown",
56
+ "black-scholes", "bs模型", "期权", "期货", "衍生品", "套利",
57
+ "量化", "quant", "回测", "factor", "因子", "ic值", "ir值",
58
+ "市盈率", "市净率", "净利润", "营业收入", "自由现金流", "贴现",
59
+ "折现", "估值", "valuation", "ipo", "etf", "reits", "债券",
60
+ "利率", "收益率", "久期", "凸性", "信用利差", "风险溢价",
61
+ "动量", "均值回归", "布林带", "macd", "rsi", "kdj", "技术指标",
62
+ "北向资金", "融资融券", "股指期货", "沪深300", "中证500",
63
+ )
64
+
65
+ SPORTS_KEYWORDS = (
66
+ "足球", "世界杯", "欧冠", "英超", "德甲", "西甲", "意甲", "法甲",
67
+ "篮球", "nba", "网球", "f1", "赛车", "奥运", "olympic",
68
+ "比赛", "赛事", "比分", "进球", "球队", "球员", "联赛",
69
+ "football", "soccer", "world cup", "champions league",
70
+ "match", "score", "league", "premier league", "bundesliga",
71
+ )
72
+
73
+
74
+ # ── Classifier functions ──────────────────────────────────────────────────────
75
+
76
+ def is_coding_request(message: str) -> bool:
77
+ """Return True if message looks like a coding/file-generation task."""
78
+ low = message.lower()
79
+ if any(k in low for k in VISUAL_ARTIFACT_KEYWORDS):
80
+ return True
81
+ if any(k in low for k in CODING_KEYWORDS):
82
+ return True
83
+ if low.startswith("/code") or low.startswith("/gen-"):
84
+ return True
85
+ return False
86
+
87
+
88
+ def is_sports_query(message: str) -> bool:
89
+ """Return True if the message is about sports/football."""
90
+ low = message.lower()
91
+ return any(k in low for k in SPORTS_KEYWORDS)
92
+
93
+
94
+ def is_analysis_request(message: str) -> bool:
95
+ """Return True if message is a stock/crypto technical analysis request (not coding).
96
+
97
+ Excludes real-estate, pure macro, and sports questions: those match keywords
98
+ like '分析'/'走势' but should NOT use the stock technical-analysis template
99
+ (which requires injected market data to be useful).
100
+ """
101
+ if is_coding_request(message):
102
+ return False
103
+ low = message.lower()
104
+ if any(k in low for k in ANALYSIS_NON_STOCK_TOPICS):
105
+ return False
106
+ if is_sports_query(message):
107
+ return False
108
+ return any(k in low for k in ANALYSIS_KEYWORDS)
109
+
110
+
111
+ def is_general_knowledge(message: str) -> bool:
112
+ """Return True for pure knowledge/explanation questions that don't need tools.
113
+
114
+ Finance/quant terms are excluded so they keep the full FINANCE_CHAT_PROMPT
115
+ even when phrased as "X是什么" explanatory questions.
116
+
117
+ Pure macro/conceptual analysis questions are treated as general knowledge:
118
+ routing them to the finance prompt with tools causes the model to fetch live
119
+ prices and output the stock-analysis template instead of thoughtful commentary.
120
+ """
121
+ if is_coding_request(message) or is_analysis_request(message):
122
+ return False
123
+ low = message.lower().strip()
124
+ if any(term in low for term in FINANCE_CONCEPT_TERMS):
125
+ return False
126
+ _macro_conceptual = (
127
+ "宏观", "宏观经济", "宏观政策", "宏观角度", "宏观分析",
128
+ "货币政策", "财政政策", "值得投资吗", "应该投资吗", "是否值得",
129
+ "投资逻辑", "长期展望", "未来前景",
130
+ )
131
+ if (any(k in low for k in _macro_conceptual)
132
+ and not any(c.isdigit() for c in low)):
133
+ return True
134
+ if len(low) < 30 and not any(c.isdigit() for c in low):
135
+ return True
136
+ return any(k in low for k in GENERAL_KNOWLEDGE_KEYWORDS)