aria-code 0.167.0__py3-none-win_amd64.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 (601) hide show
  1. aria_bots/__init__.py +7 -0
  2. aria_bots/channels/README.md +97 -0
  3. aria_bots/channels/__init__.py +1 -0
  4. aria_bots/channels/approvals.py +263 -0
  5. aria_bots/channels/conversation.py +280 -0
  6. aria_bots/channels/digest.py +186 -0
  7. aria_bots/channels/registry.py +95 -0
  8. aria_bots/engine.py +144 -0
  9. aria_bots/feishu_bot.py +1385 -0
  10. aria_bots/logistics/__init__.py +1 -0
  11. aria_bots/logistics/carriers.py +253 -0
  12. aria_bots/logistics/freight.py +154 -0
  13. aria_bots/logistics/inventory.py +242 -0
  14. aria_bots/logistics/mcp_server.py +156 -0
  15. aria_bots/logistics/records.py +119 -0
  16. aria_bots/logistics/tenancy.py +152 -0
  17. aria_bots/market.py +91 -0
  18. aria_bots/relay_client.py +326 -0
  19. aria_bots/telegram_bot.py +299 -0
  20. aria_code/__init__.py +111 -0
  21. aria_code/_bin/aria-native.exe +0 -0
  22. aria_code/_bin/aria-runtime.exe +0 -0
  23. aria_code/_version.py +20 -0
  24. aria_code/account_memory.py +296 -0
  25. aria_code/account_session.py +166 -0
  26. aria_code/adk_apps/__init__.py +1 -0
  27. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  28. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  29. aria_code/adk_apps/aria_research/__init__.py +1 -0
  30. aria_code/adk_apps/aria_research/agent.py +31 -0
  31. aria_code/agents/__init__.py +49 -0
  32. aria_code/agents/base.py +329 -0
  33. aria_code/agents/code_review.py +200 -0
  34. aria_code/agents/deep/__init__.py +37 -0
  35. aria_code/agents/deep/calibration_loop.py +144 -0
  36. aria_code/agents/deep/critic.py +125 -0
  37. aria_code/agents/deep/deepen.py +193 -0
  38. aria_code/agents/deep/models.py +149 -0
  39. aria_code/agents/deep/pipeline.py +164 -0
  40. aria_code/agents/deep/quant_fusion.py +192 -0
  41. aria_code/agents/deep/themes.py +95 -0
  42. aria_code/agents/deep/tiers.py +106 -0
  43. aria_code/agents/engineering/__init__.py +14 -0
  44. aria_code/agents/engineering/coder.py +222 -0
  45. aria_code/agents/engineering/tester.py +145 -0
  46. aria_code/agents/financial/__init__.py +21 -0
  47. aria_code/agents/financial/cashflow_burn.py +119 -0
  48. aria_code/agents/financial/catalyst.py +279 -0
  49. aria_code/agents/financial/corporate_finance.py +175 -0
  50. aria_code/agents/financial/debate.py +224 -0
  51. aria_code/agents/financial/earnings.py +315 -0
  52. aria_code/agents/financial/fundamental.py +178 -0
  53. aria_code/agents/financial/macro.py +111 -0
  54. aria_code/agents/financial/news.py +231 -0
  55. aria_code/agents/financial/risk.py +146 -0
  56. aria_code/agents/financial/sector.py +279 -0
  57. aria_code/agents/financial/strategist.py +121 -0
  58. aria_code/agents/financial/stripe_revenue.py +127 -0
  59. aria_code/agents/financial/synthesis.py +274 -0
  60. aria_code/agents/financial/technical.py +277 -0
  61. aria_code/agents/orchestrator.py +44 -0
  62. aria_code/agents/portfolio_agent.py +392 -0
  63. aria_code/agents/realty/__init__.py +62 -0
  64. aria_code/agents/realty/asset_diagnosis.py +152 -0
  65. aria_code/agents/realty/business_match.py +166 -0
  66. aria_code/agents/realty/cashflow_verify.py +209 -0
  67. aria_code/agents/realty/contract_rules.py +210 -0
  68. aria_code/agents/realty/energy_anomaly.py +189 -0
  69. aria_code/agents/realty/exit_settlement.py +208 -0
  70. aria_code/agents/realty/fulfillment_risk.py +206 -0
  71. aria_code/agents/realty/ops_optimize.py +160 -0
  72. aria_code/agents/realty/revenue_share.py +215 -0
  73. aria_code/agents/registry.py +168 -0
  74. aria_code/agents/signal_scheme.py +111 -0
  75. aria_code/agents/sports/__init__.py +0 -0
  76. aria_code/agents/sports/football_agent.py +197 -0
  77. aria_code/agents/supervisor.py +113 -0
  78. aria_code/agents/team.py +500 -0
  79. aria_code/agents/video/__init__.py +16 -0
  80. aria_code/agents/video/director.py +376 -0
  81. aria_code/agents/video/qa_agent.py +143 -0
  82. aria_code/agents/video/script_doctor.py +112 -0
  83. aria_code/agents/warehouse/__init__.py +25 -0
  84. aria_code/agents/warehouse/contracts.py +26 -0
  85. aria_code/agents/warehouse/dashboard.py +155 -0
  86. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  87. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  88. aria_code/agents/warehouse/inventory_health.py +24 -0
  89. aria_code/agents/warehouse/local_run.py +71 -0
  90. aria_code/agents/warehouse/local_snapshot.py +132 -0
  91. aria_code/agents/warehouse/logistics_cost.py +84 -0
  92. aria_code/agents/warehouse/logistics_sync.py +21 -0
  93. aria_code/agents/warehouse/navigation.schema.json +110 -0
  94. aria_code/agents/warehouse/task_agent.py +172 -0
  95. aria_code/agents/warehouse/workflow.py +31 -0
  96. aria_code/aliyun_data_client.py +4 -0
  97. aria_code/apps/README.md +12 -0
  98. aria_code/apps/__init__.py +2 -0
  99. aria_code/apps/channels/README.md +9 -0
  100. aria_code/apps/channels/__init__.py +17 -0
  101. aria_code/apps/channels/approvals.py +11 -0
  102. aria_code/apps/channels/conversation.py +11 -0
  103. aria_code/apps/channels/digest.py +11 -0
  104. aria_code/apps/channels/intake.py +92 -0
  105. aria_code/apps/channels/registry.py +11 -0
  106. aria_code/apps/channels/tradingview.py +94 -0
  107. aria_code/apps/cli/README.md +13 -0
  108. aria_code/apps/cli/__init__.py +2 -0
  109. aria_code/apps/cli/_optional.py +120 -0
  110. aria_code/apps/cli/app_server.py +656 -0
  111. aria_code/apps/cli/auto_update.py +125 -0
  112. aria_code/apps/cli/bootstrap.py +206 -0
  113. aria_code/apps/cli/broker_render.py +206 -0
  114. aria_code/apps/cli/chat_turn.py +1327 -0
  115. aria_code/apps/cli/cloud_models.py +231 -0
  116. aria_code/apps/cli/codegen_paths.py +29 -0
  117. aria_code/apps/cli/commands/__init__.py +34 -0
  118. aria_code/apps/cli/commands/_business_render.py +78 -0
  119. aria_code/apps/cli/commands/_ui.py +71 -0
  120. aria_code/apps/cli/commands/analysis_cmds.py +378 -0
  121. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  122. aria_code/apps/cli/commands/auth_cmds.py +215 -0
  123. aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
  124. aria_code/apps/cli/commands/broker_cmds.py +1236 -0
  125. aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
  126. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  127. aria_code/apps/cli/commands/catalog.py +189 -0
  128. aria_code/apps/cli/commands/core_cmds.py +2748 -0
  129. aria_code/apps/cli/commands/data_cmds.py +521 -0
  130. aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
  131. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  132. aria_code/apps/cli/commands/engineering_cmds.py +399 -0
  133. aria_code/apps/cli/commands/file_cmds.py +312 -0
  134. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  135. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  136. aria_code/apps/cli/commands/market.py +544 -0
  137. aria_code/apps/cli/commands/market_cmds.py +1419 -0
  138. aria_code/apps/cli/commands/market_context.py +432 -0
  139. aria_code/apps/cli/commands/market_render.py +7 -0
  140. aria_code/apps/cli/commands/model_cmds.py +2374 -0
  141. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  142. aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
  143. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  144. aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
  145. aria_code/apps/cli/commands/report.py +476 -0
  146. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  147. aria_code/apps/cli/commands/session_cmds.py +236 -0
  148. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  149. aria_code/apps/cli/commands/team.py +723 -0
  150. aria_code/apps/cli/commands/team_render.py +8 -0
  151. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  152. aria_code/apps/cli/commands/warehouse_cmds.py +297 -0
  153. aria_code/apps/cli/commands/workflow_cmds.py +629 -0
  154. aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
  155. aria_code/apps/cli/config_paths.py +73 -0
  156. aria_code/apps/cli/config_store.py +158 -0
  157. aria_code/apps/cli/constants.py +88 -0
  158. aria_code/apps/cli/context.py +34 -0
  159. aria_code/apps/cli/conversation_policy.py +53 -0
  160. aria_code/apps/cli/deterministic.py +200 -0
  161. aria_code/apps/cli/direct.py +48 -0
  162. aria_code/apps/cli/earnings_view.py +172 -0
  163. aria_code/apps/cli/endpoint_migration.py +64 -0
  164. aria_code/apps/cli/exec_events.py +255 -0
  165. aria_code/apps/cli/file_references.py +155 -0
  166. aria_code/apps/cli/finance_service_catalog.py +111 -0
  167. aria_code/apps/cli/football_reports.py +231 -0
  168. aria_code/apps/cli/github_app_auth.py +135 -0
  169. aria_code/apps/cli/google_login.py +239 -0
  170. aria_code/apps/cli/handlers/__init__.py +11 -0
  171. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  172. aria_code/apps/cli/handlers/chart_handlers.py +1314 -0
  173. aria_code/apps/cli/handlers/market_handlers.py +2570 -0
  174. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  175. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  176. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  177. aria_code/apps/cli/headless.py +352 -0
  178. aria_code/apps/cli/helpers.py +326 -0
  179. aria_code/apps/cli/hooks.py +180 -0
  180. aria_code/apps/cli/i18n.py +310 -0
  181. aria_code/apps/cli/intent.py +136 -0
  182. aria_code/apps/cli/intent_router.py +305 -0
  183. aria_code/apps/cli/intent_shadow.py +72 -0
  184. aria_code/apps/cli/intent_signals.py +347 -0
  185. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  186. aria_code/apps/cli/local_tool_schemas.py +550 -0
  187. aria_code/apps/cli/main.py +39 -0
  188. aria_code/apps/cli/market_hours.py +100 -0
  189. aria_code/apps/cli/market_metadata.py +135 -0
  190. aria_code/apps/cli/market_universe.py +487 -0
  191. aria_code/apps/cli/message_processing.py +310 -0
  192. aria_code/apps/cli/mixin_binding.py +32 -0
  193. aria_code/apps/cli/model_catalog.py +652 -0
  194. aria_code/apps/cli/model_probe.py +169 -0
  195. aria_code/apps/cli/model_retirement.py +65 -0
  196. aria_code/apps/cli/native_branding.py +12 -0
  197. aria_code/apps/cli/native_bridge.py +118 -0
  198. aria_code/apps/cli/native_entry.py +58 -0
  199. aria_code/apps/cli/pdf_report.py +977 -0
  200. aria_code/apps/cli/plan_mode.py +139 -0
  201. aria_code/apps/cli/plotly_html.py +15 -0
  202. aria_code/apps/cli/prediction_feedback.py +202 -0
  203. aria_code/apps/cli/preflight.py +502 -0
  204. aria_code/apps/cli/project_aria.py +60 -0
  205. aria_code/apps/cli/prompt_assembly.py +78 -0
  206. aria_code/apps/cli/prompts/__init__.py +0 -0
  207. aria_code/apps/cli/prompts/coding.py +71 -0
  208. aria_code/apps/cli/prompts/select.py +193 -0
  209. aria_code/apps/cli/prompts/system_prompts.py +562 -0
  210. aria_code/apps/cli/prompts/ui.py +436 -0
  211. aria_code/apps/cli/provider_endpoints.py +237 -0
  212. aria_code/apps/cli/provider_keys.py +73 -0
  213. aria_code/apps/cli/providers/__init__.py +1 -0
  214. aria_code/apps/cli/providers/base.py +775 -0
  215. aria_code/apps/cli/providers/chat_routing.py +139 -0
  216. aria_code/apps/cli/providers/collaboration.py +98 -0
  217. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  218. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  219. aria_code/apps/cli/providers/llm/ollama_stream.py +1574 -0
  220. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  221. aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
  222. aria_code/apps/cli/providers/runtime_bridge.py +586 -0
  223. aria_code/apps/cli/providers/vertexai_stream.py +592 -0
  224. aria_code/apps/cli/release_download.py +159 -0
  225. aria_code/apps/cli/review_runner.py +111 -0
  226. aria_code/apps/cli/runtime_consumer.py +769 -0
  227. aria_code/apps/cli/sandbox.py +32 -0
  228. aria_code/apps/cli/session_export.py +120 -0
  229. aria_code/apps/cli/session_jsonl.py +208 -0
  230. aria_code/apps/cli/session_refresh.py +123 -0
  231. aria_code/apps/cli/session_store.py +125 -0
  232. aria_code/apps/cli/skills_catalog.py +273 -0
  233. aria_code/apps/cli/task_isolation.py +211 -0
  234. aria_code/apps/cli/terminal_chrome.py +412 -0
  235. aria_code/apps/cli/todo_tracker.py +190 -0
  236. aria_code/apps/cli/tool_executor.py +932 -0
  237. aria_code/apps/cli/tool_registry.py +34 -0
  238. aria_code/apps/cli/tool_scope.py +113 -0
  239. aria_code/apps/cli/tools/__init__.py +40 -0
  240. aria_code/apps/cli/tools/context.py +46 -0
  241. aria_code/apps/cli/tools/file_tools.py +181 -0
  242. aria_code/apps/cli/tools/market_tools.py +626 -0
  243. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  244. aria_code/apps/cli/tools/system_tools.py +656 -0
  245. aria_code/apps/cli/tools/write_tools.py +961 -0
  246. aria_code/apps/cli/tradingview_bridge.py +529 -0
  247. aria_code/apps/cli/transactions.py +269 -0
  248. aria_code/apps/cli/turn_planning.py +137 -0
  249. aria_code/apps/cli/update_check.py +257 -0
  250. aria_code/apps/cli/updater.py +373 -0
  251. aria_code/apps/cli/utils/__init__.py +0 -0
  252. aria_code/apps/cli/utils/market_detect.py +1663 -0
  253. aria_code/apps/cli/web_login.py +136 -0
  254. aria_code/apps/cli/workflow_runner.py +127 -0
  255. aria_code/apps/cli/workspace_route.py +121 -0
  256. aria_code/apps/daemon/README.md +14 -0
  257. aria_code/apps/vscode/README.md +115 -0
  258. aria_code/apps/vscode/package.json +70 -0
  259. aria_code/aria_cli.py +5244 -0
  260. aria_code/aria_daemon.py +1372 -0
  261. aria_code/aria_feishu_bot.py +16 -0
  262. aria_code/aria_mcp_server.py +61 -0
  263. aria_code/aria_relay_client.py +4 -0
  264. aria_code/aria_telegram_bot.py +11 -0
  265. aria_code/ariarc.py +385 -0
  266. aria_code/artifacts.py +581 -0
  267. aria_code/backtest_engine.py +4 -0
  268. aria_code/backtest_report.py +4 -0
  269. aria_code/brokers/__init__.py +78 -0
  270. aria_code/brokers/automation.py +193 -0
  271. aria_code/brokers/base.py +231 -0
  272. aria_code/brokers/capabilities.py +264 -0
  273. aria_code/brokers/cn/__init__.py +10 -0
  274. aria_code/brokers/cn/easytrader_broker.py +193 -0
  275. aria_code/brokers/cn/futu_broker.py +194 -0
  276. aria_code/brokers/cn/longbridge_broker.py +190 -0
  277. aria_code/brokers/cn/tiger_broker.py +196 -0
  278. aria_code/brokers/cn/xtquant_broker.py +225 -0
  279. aria_code/brokers/config.py +414 -0
  280. aria_code/brokers/intl/__init__.py +5 -0
  281. aria_code/brokers/intl/alpaca_broker.py +183 -0
  282. aria_code/brokers/intl/ibkr_broker.py +215 -0
  283. aria_code/brokers/intl/trading212_broker.py +183 -0
  284. aria_code/brokers/intl/webull_broker.py +156 -0
  285. aria_code/brokers/paper_broker.py +266 -0
  286. aria_code/brokers/planning.py +296 -0
  287. aria_code/brokers/registry.py +213 -0
  288. aria_code/brokers/trading.py +267 -0
  289. aria_code/canva_client.py +4 -0
  290. aria_code/change_store.py +127 -0
  291. aria_code/clients/__init__.py +0 -0
  292. aria_code/clients/aliyun_data_client.py +660 -0
  293. aria_code/clients/aria_relay_client.py +16 -0
  294. aria_code/clients/canva_client.py +284 -0
  295. aria_code/clients/figma_client.py +100 -0
  296. aria_code/clients/football_data_client.py +1671 -0
  297. aria_code/clients/kling_video_client.py +182 -0
  298. aria_code/clients/market_data_client.py +1985 -0
  299. aria_code/clients/openai_image_client.py +242 -0
  300. aria_code/clients/runway_video_client.py +157 -0
  301. aria_code/clients/warehouse_erp_client.py +105 -0
  302. aria_code/cloud_memory.py +190 -0
  303. aria_code/command_safety.py +19 -0
  304. aria_code/computer_use_server.py +276 -0
  305. aria_code/computer_use_tools.py +4 -0
  306. aria_code/dashboard_generator.py +579 -0
  307. aria_code/data_analysis_tools.py +4 -0
  308. aria_code/data_cleaner.py +483 -0
  309. aria_code/data_service.py +513 -0
  310. aria_code/datasources/__init__.py +23 -0
  311. aria_code/datasources/base.py +166 -0
  312. aria_code/datasources/router.py +253 -0
  313. aria_code/datasources/sec_statements.py +217 -0
  314. aria_code/datasources/sources/__init__.py +15 -0
  315. aria_code/datasources/sources/akshare_source.py +269 -0
  316. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  317. aria_code/datasources/sources/edgar_source.py +219 -0
  318. aria_code/datasources/sources/finnhub_source.py +198 -0
  319. aria_code/datasources/sources/fred_source.py +223 -0
  320. aria_code/datasources/sources/tushare_source.py +143 -0
  321. aria_code/datasources/sources/web_scraper_source.py +278 -0
  322. aria_code/datasources/sources/world_bank_source.py +206 -0
  323. aria_code/datasources/sources/yfinance_source.py +152 -0
  324. aria_code/doctor.py +860 -0
  325. aria_code/domain/__init__.py +0 -0
  326. aria_code/domain/_finance_core/__init__.py +5 -0
  327. aria_code/domain/_finance_core/backtest_engine.py +325 -0
  328. aria_code/domain/_finance_core/performance_stats.py +101 -0
  329. aria_code/domain/backtest_engine.py +75 -0
  330. aria_code/domain/backtest_report.py +488 -0
  331. aria_code/domain/finance_formulas.py +389 -0
  332. aria_code/domain/performance_stats.py +6 -0
  333. aria_code/domain/portfolio_ledger.py +307 -0
  334. aria_code/domain/strategy_vault.py +421 -0
  335. aria_code/evals/__init__.py +37 -0
  336. aria_code/evals/behavior.py +113 -0
  337. aria_code/evals/gap.py +93 -0
  338. aria_code/evals/harness.py +949 -0
  339. aria_code/evals/review_probe.py +132 -0
  340. aria_code/evals/runner.py +425 -0
  341. aria_code/evals/scorecard.py +322 -0
  342. aria_code/evals/summary.py +125 -0
  343. aria_code/external_agent_runner.py +115 -0
  344. aria_code/figma_client.py +4 -0
  345. aria_code/file_analysis_tools.py +4 -0
  346. aria_code/finance_formulas.py +4 -0
  347. aria_code/football_data_client.py +4 -0
  348. aria_code/image_gen_tools.py +4 -0
  349. aria_code/intent_classifier.py +459 -0
  350. aria_code/kling_video_client.py +4 -0
  351. aria_code/licensing.py +151 -0
  352. aria_code/local_finance_tools.py +4 -0
  353. aria_code/local_image_provider.py +4 -0
  354. aria_code/local_llm_provider.py +4 -0
  355. aria_code/macro_tools.py +4 -0
  356. aria_code/markdown_pdf.py +289 -0
  357. aria_code/market_data_client.py +4 -0
  358. aria_code/mcp_client.py +744 -0
  359. aria_code/memory_manager.py +273 -0
  360. aria_code/model_capability.py +512 -0
  361. aria_code/notification_tools.py +4 -0
  362. aria_code/openai_image_client.py +4 -0
  363. aria_code/packages/__init__.py +26 -0
  364. aria_code/packages/adk_bridge/__init__.py +11 -0
  365. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  366. aria_code/packages/adk_bridge/market_tools.py +125 -0
  367. aria_code/packages/aria_agents/__init__.py +5 -0
  368. aria_code/packages/aria_agents/manifest.py +78 -0
  369. aria_code/packages/aria_core/__init__.py +34 -0
  370. aria_code/packages/aria_core/architecture.py +269 -0
  371. aria_code/packages/aria_core/export.py +147 -0
  372. aria_code/packages/aria_core/manifest.py +65 -0
  373. aria_code/packages/aria_core/paths.py +57 -0
  374. aria_code/packages/aria_core/secure_file.py +68 -0
  375. aria_code/packages/aria_infra/__init__.py +15 -0
  376. aria_code/packages/aria_infra/arthera.py +58 -0
  377. aria_code/packages/aria_infra/doctor.py +246 -0
  378. aria_code/packages/aria_infra/product.py +40 -0
  379. aria_code/packages/aria_mcp/__init__.py +25 -0
  380. aria_code/packages/aria_mcp/bridge.py +232 -0
  381. aria_code/packages/aria_mcp/circuit.py +82 -0
  382. aria_code/packages/aria_mcp/config.py +162 -0
  383. aria_code/packages/aria_mcp/installer.py +95 -0
  384. aria_code/packages/aria_mcp/server.py +1705 -0
  385. aria_code/packages/aria_mcp/tools.py +81 -0
  386. aria_code/packages/aria_sdk/__init__.py +19 -0
  387. aria_code/packages/aria_sdk/client.py +393 -0
  388. aria_code/packages/aria_sdk/providers.py +70 -0
  389. aria_code/packages/aria_sdk/streaming.py +75 -0
  390. aria_code/packages/aria_sdk/types.py +86 -0
  391. aria_code/packages/aria_services/__init__.py +92 -0
  392. aria_code/packages/aria_services/cache.py +60 -0
  393. aria_code/packages/aria_services/context.py +356 -0
  394. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  395. aria_code/packages/aria_services/data.py +11 -0
  396. aria_code/packages/aria_services/provider_health.py +304 -0
  397. aria_code/packages/aria_services/references.py +247 -0
  398. aria_code/packages/aria_services/registry.py +249 -0
  399. aria_code/packages/aria_services/research_protocol.py +137 -0
  400. aria_code/packages/aria_services/research_quality.py +186 -0
  401. aria_code/packages/aria_services/settings.py +160 -0
  402. aria_code/packages/aria_services/usage.py +151 -0
  403. aria_code/packages/aria_skills/__init__.py +46 -0
  404. aria_code/packages/aria_skills/catalog.py +149 -0
  405. aria_code/packages/aria_skills/loader.py +455 -0
  406. aria_code/packages/aria_skills/registry.py +84 -0
  407. aria_code/packages/aria_tools/__init__.py +5 -0
  408. aria_code/packages/aria_tools/financial/__init__.py +5 -0
  409. aria_code/packages/aria_tools/financial/_paths.py +92 -0
  410. aria_code/packages/aria_tools/registry.py +129 -0
  411. aria_code/packages/quant_engine/__init__.py +33 -0
  412. aria_code/packages/quant_engine/_namespace.py +24 -0
  413. aria_code/packages/quant_engine/backtest/__init__.py +10 -0
  414. aria_code/packages/quant_engine/backtest/core.py +53 -0
  415. aria_code/packages/quant_engine/backtest/engine.py +102 -0
  416. aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
  417. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  418. aria_code/packages/quant_engine/sports/__init__.py +76 -0
  419. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  420. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  421. aria_code/packages/quant_engine/sports/elo.py +300 -0
  422. aria_code/packages/quant_engine/sports/form.py +188 -0
  423. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  424. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  425. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  426. aria_code/packages/quant_engine/stochastic/__init__.py +31 -0
  427. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  428. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  429. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  430. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  431. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  432. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  433. aria_code/packs/__init__.py +85 -0
  434. aria_code/packs/base.py +168 -0
  435. aria_code/packs/finance/__init__.py +250 -0
  436. aria_code/packs/healthcare/__init__.py +40 -0
  437. aria_code/packs/logistics/__init__.py +171 -0
  438. aria_code/packs/payments/__init__.py +139 -0
  439. aria_code/packs/realty/__init__.py +190 -0
  440. aria_code/packs/registry.py +202 -0
  441. aria_code/packs/rules.py +90 -0
  442. aria_code/plan_utils.py +194 -0
  443. aria_code/plugin_loader.py +328 -0
  444. aria_code/portfolio_ledger.py +4 -0
  445. aria_code/preview_server.py +449 -0
  446. aria_code/privacy/__init__.py +5 -0
  447. aria_code/privacy/feedback.py +123 -0
  448. aria_code/project_review.py +278 -0
  449. aria_code/project_review_api.py +235 -0
  450. aria_code/project_review_server.py +18 -0
  451. aria_code/project_tools.py +4 -0
  452. aria_code/providers/__init__.py +30 -0
  453. aria_code/providers/google_video_provider.py +256 -0
  454. aria_code/providers/llm/__init__.py +19 -0
  455. aria_code/providers/llm/anthropic.py +184 -0
  456. aria_code/providers/llm/arthera_gateway.py +90 -0
  457. aria_code/providers/llm/autoconfig.py +213 -0
  458. aria_code/providers/llm/base.py +139 -0
  459. aria_code/providers/llm/custom.py +158 -0
  460. aria_code/providers/llm/ollama.py +137 -0
  461. aria_code/providers/llm/openai_compat.py +350 -0
  462. aria_code/providers/llm/registry.py +457 -0
  463. aria_code/providers/local_image_provider.py +202 -0
  464. aria_code/providers/local_llm_provider.py +549 -0
  465. aria_code/providers/ollama_models.py +79 -0
  466. aria_code/providers/openai_params.py +32 -0
  467. aria_code/providers/tool_messages.py +100 -0
  468. aria_code/realty_data_tools.py +4 -0
  469. aria_code/report_exporters.py +150 -0
  470. aria_code/report_generator.py +1764 -0
  471. aria_code/review_service.py +497 -0
  472. aria_code/runtime/__init__.py +176 -0
  473. aria_code/runtime/acceptance.py +632 -0
  474. aria_code/runtime/agent_loop.py +1851 -0
  475. aria_code/runtime/agent_profiles.py +75 -0
  476. aria_code/runtime/approval.py +71 -0
  477. aria_code/runtime/baseline.py +219 -0
  478. aria_code/runtime/budget.py +232 -0
  479. aria_code/runtime/checkpoints.py +481 -0
  480. aria_code/runtime/consult.py +65 -0
  481. aria_code/runtime/contract.py +282 -0
  482. aria_code/runtime/delivery.py +432 -0
  483. aria_code/runtime/events.py +113 -0
  484. aria_code/runtime/gateway.py +167 -0
  485. aria_code/runtime/lsp.py +484 -0
  486. aria_code/runtime/native_index.py +153 -0
  487. aria_code/runtime/orchestrator.py +55 -0
  488. aria_code/runtime/processes.py +343 -0
  489. aria_code/runtime/project_graph.py +614 -0
  490. aria_code/runtime/repo_map.py +712 -0
  491. aria_code/runtime/research_bundle.py +105 -0
  492. aria_code/runtime/review.py +269 -0
  493. aria_code/runtime/run_state.py +127 -0
  494. aria_code/runtime/run_store.py +522 -0
  495. aria_code/runtime/scoped_runs.py +113 -0
  496. aria_code/runtime/self_healing.py +422 -0
  497. aria_code/runtime/semantic_diff.py +171 -0
  498. aria_code/runtime/subagent.py +721 -0
  499. aria_code/runtime/symbol_edit.py +117 -0
  500. aria_code/runtime/task_brief.py +46 -0
  501. aria_code/runtime/task_context.py +145 -0
  502. aria_code/runtime/task_ledger.py +108 -0
  503. aria_code/runtime/task_orchestrator.py +90 -0
  504. aria_code/runtime/task_outcome.py +33 -0
  505. aria_code/runtime/task_verification.py +266 -0
  506. aria_code/runtime/task_worktree.py +448 -0
  507. aria_code/runtime/tool_executor.py +329 -0
  508. aria_code/runtime/tool_policy.py +107 -0
  509. aria_code/runtime/transactions.py +216 -0
  510. aria_code/runtime/windows_job.py +115 -0
  511. aria_code/runtime/workflows.py +222 -0
  512. aria_code/runtime/worktrees.py +215 -0
  513. aria_code/runway_video_client.py +4 -0
  514. aria_code/safety/__init__.py +27 -0
  515. aria_code/safety/client_isolation.py +178 -0
  516. aria_code/safety/permissions.py +339 -0
  517. aria_code/safety/risk.py +699 -0
  518. aria_code/safety/sandbox.py +148 -0
  519. aria_code/safety/service.py +102 -0
  520. aria_code/service_endpoints.py +14 -0
  521. aria_code/setup_wizard.py +684 -0
  522. aria_code/spreadsheet_tools.py +4 -0
  523. aria_code/strategy_vault.py +4 -0
  524. aria_code/tools/__init__.py +0 -0
  525. aria_code/tools/artifact_tools.py +252 -0
  526. aria_code/tools/broker_tools.py +92 -0
  527. aria_code/tools/build_quant_engine.py +97 -0
  528. aria_code/tools/code_audit_tools.py +192 -0
  529. aria_code/tools/computer_use_tools.py +509 -0
  530. aria_code/tools/data_analysis_tools.py +831 -0
  531. aria_code/tools/enterprise_finance_tools.py +202 -0
  532. aria_code/tools/extended_tools.py +240 -0
  533. aria_code/tools/file_analysis_tools.py +880 -0
  534. aria_code/tools/image_gen_tools.py +114 -0
  535. aria_code/tools/local_finance_tools.py +3488 -0
  536. aria_code/tools/logistics_carriers.py +11 -0
  537. aria_code/tools/logistics_inventory.py +11 -0
  538. aria_code/tools/logistics_io.py +11 -0
  539. aria_code/tools/logistics_tenancy.py +11 -0
  540. aria_code/tools/logistics_tools.py +11 -0
  541. aria_code/tools/macro_tools.py +412 -0
  542. aria_code/tools/notification_tools.py +249 -0
  543. aria_code/tools/project_tools.py +525 -0
  544. aria_code/tools/realty_data_tools.py +662 -0
  545. aria_code/tools/spreadsheet_tools.py +399 -0
  546. aria_code/tools/stripe_tools.py +115 -0
  547. aria_code/tools/video_tools.py +500 -0
  548. aria_code/training/__init__.py +1 -0
  549. aria_code/training/compare.py +117 -0
  550. aria_code/training/prelude_commands.py +111 -0
  551. aria_code/training/prelude_eval.py +390 -0
  552. aria_code/training/prelude_real.py +183 -0
  553. aria_code/training/prelude_train.py +248 -0
  554. aria_code/training/sft_dataset.py +230 -0
  555. aria_code/training/trajectory_dataset.py +263 -0
  556. aria_code/ui/__init__.py +105 -0
  557. aria_code/ui/banner.py +404 -0
  558. aria_code/ui/completer.py +571 -0
  559. aria_code/ui/console.py +285 -0
  560. aria_code/ui/input_box.py +505 -0
  561. aria_code/ui/mentions.py +206 -0
  562. aria_code/ui/picker.py +248 -0
  563. aria_code/ui/render/__init__.py +11 -0
  564. aria_code/ui/render/actions.py +297 -0
  565. aria_code/ui/render/finance.py +1732 -0
  566. aria_code/ui/render/market.py +253 -0
  567. aria_code/ui/render/output.py +954 -0
  568. aria_code/ui/render/responsive.py +75 -0
  569. aria_code/ui/render/team.py +367 -0
  570. aria_code/ui/robot.py +239 -0
  571. aria_code/ui/startup_dashboard.py +110 -0
  572. aria_code/video_analysis.py +147 -0
  573. aria_code/video_editor.py +518 -0
  574. aria_code/video_workflow/__init__.py +8 -0
  575. aria_code/video_workflow/__main__.py +61 -0
  576. aria_code/video_workflow/engines/__init__.py +18 -0
  577. aria_code/video_workflow/engines/base.py +69 -0
  578. aria_code/video_workflow/engines/custom_model.py +204 -0
  579. aria_code/video_workflow/engines/google_veo.py +94 -0
  580. aria_code/video_workflow/engines/local_engine.py +71 -0
  581. aria_code/video_workflow/engines/registry.py +98 -0
  582. aria_code/video_workflow/google_models.py +278 -0
  583. aria_code/video_workflow/music/__init__.py +5 -0
  584. aria_code/video_workflow/music/foley_service.py +132 -0
  585. aria_code/video_workflow/music/service.py +212 -0
  586. aria_code/video_workflow/pipeline.py +620 -0
  587. aria_code/video_workflow/plan.py +202 -0
  588. aria_code/video_workflow/session.py +297 -0
  589. aria_code/workspace/__init__.py +6 -0
  590. aria_code/workspace/files.py +219 -0
  591. aria_code/workspace/verify.py +167 -0
  592. aria_code/workspace_changes.py +199 -0
  593. aria_code/workspace_service.py +196 -0
  594. aria_code/workspace_tools.py +150 -0
  595. aria_code-0.167.0.dist-info/METADATA +330 -0
  596. aria_code-0.167.0.dist-info/RECORD +601 -0
  597. aria_code-0.167.0.dist-info/WHEEL +5 -0
  598. aria_code-0.167.0.dist-info/entry_points.txt +5 -0
  599. aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
  600. aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
  601. aria_code-0.167.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,626 @@
1
+ """Market data and broker tools extracted from aria_cli.py.
2
+
3
+ Lazy-imports ``market_data_client`` and ``brokers`` so the module loads
4
+ even when those optional packages are absent. The import guards mirror
5
+ aria_cli.py lines 134-189 so the same failure modes apply.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ import os
12
+ import sys
13
+ from datetime import datetime, timezone
14
+ from pathlib import Path
15
+
16
+ _ROOT = Path(__file__).parent.parent.parent.parent # aria-code/
17
+ if str(_ROOT) not in sys.path:
18
+ sys.path.insert(0, str(_ROOT))
19
+
20
+ from aria_code.apps.cli.market_metadata import enrich_market_quote
21
+ from aria_code.packages.aria_core.paths import aria_home
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ def _quote_time_metadata(quote: dict) -> dict[str, str]:
27
+ """Return provenance without calling an undated quote 'latest'."""
28
+ retrieved_at = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
29
+ for key in ("as_of", "timestamp", "quote_time", "last_trade_time", "date"):
30
+ value = quote.get(key)
31
+ if value not in (None, ""):
32
+ return {"as_of": str(value), "retrieved_at": retrieved_at,
33
+ "time_quality": "provider_timestamp"}
34
+ return {"retrieved_at": retrieved_at, "time_quality": "retrieval_time_only"}
35
+
36
+ # ── Optional: market data client ────────────────────────────────────────────
37
+ # Loading this client imports pandas, NumPy, and requests. The coding REPL does
38
+ # not need any of them until a market tool is actually invoked.
39
+ from importlib.util import find_spec
40
+
41
+ _HAS_MDC = find_spec("market_data_client") is not None
42
+
43
+
44
+ def _get_mdc():
45
+ if not _HAS_MDC:
46
+ return None
47
+ from market_data_client import get_mdc
48
+ return get_mdc()
49
+
50
+ # ── Unified data service (MDC primary + DataRouter fallback) ──────────────────
51
+ # DataService bridges MarketDataClient with the configured DataRouter, which
52
+ # honours ~/.aria/datasources.yaml (tushare / akshare / finnhub / fred / …).
53
+ # Lazily constructed so importing this module stays cheap.
54
+ _DATA_SERVICE = None
55
+
56
+
57
+ def _get_data_service():
58
+ global _DATA_SERVICE
59
+ if _DATA_SERVICE is None:
60
+ from data_service import DataService
61
+ _DATA_SERVICE = DataService()
62
+ return _DATA_SERVICE
63
+
64
+ # ── Optional: broker integration ────────────────────────────────────────────
65
+ try:
66
+ from brokers import ( # noqa: E402
67
+ get_registry as _get_broker_registry,
68
+ list_broker_configs as _list_broker_configs,
69
+ BROKERS_CONFIG_PATH as _BROKERS_CONFIG_PATH,
70
+ )
71
+ _HAS_BROKERS = True
72
+ except ImportError:
73
+ _HAS_BROKERS = False
74
+ def _get_broker_registry(): return None # type: ignore[return-value]
75
+ def _list_broker_configs(): return []
76
+ _BROKERS_CONFIG_PATH = None
77
+
78
+
79
+ def _get_finnhub_key() -> str:
80
+ """Read Finnhub API key from env or ~/.arthera/providers.json."""
81
+ val = os.getenv("FINNHUB_API_KEY", "")
82
+ if val:
83
+ return val
84
+ providers_file = aria_home() / "providers.json"
85
+ try:
86
+ if providers_file.exists():
87
+ raw = json.loads(providers_file.read_text(encoding="utf-8"))
88
+ for section in ("llm", "data"):
89
+ entry = raw.get(section, {}).get("finnhub", {})
90
+ if entry.get("api_key"):
91
+ return entry["api_key"]
92
+ except Exception:
93
+ pass
94
+ return ""
95
+
96
+
97
+ def _extract_symbol(params: dict) -> str:
98
+ """Robustly extract and clean a stock/crypto symbol from tool params."""
99
+ if not isinstance(params, dict):
100
+ return ""
101
+ val = params.get("symbol") or params.get("symbols") or params.get("ticker") or params.get("code") or params.get("stock")
102
+ if isinstance(val, (list, tuple)):
103
+ val = val[0] if val else ""
104
+ elif isinstance(val, dict):
105
+ val = val.get("symbol") or val.get("ticker") or val.get("code") or ""
106
+ s = str(val or "").strip()
107
+ if (s.startswith("[") and s.endswith("]")) or (s.startswith("(") and s.endswith(")")):
108
+ s = s[1:-1].strip()
109
+ return s.strip("'\"` ").upper()
110
+
111
+
112
+ def tool_get_market_data(params: dict) -> dict:
113
+ """Fetch real-time quote + technical indicators for any stock/ETF/crypto.
114
+
115
+ Supports A-shares (6-digit code), HK (.HK), US tickers, crypto.
116
+ Primary source: MarketDataClient. Fallback: Finnhub (US/global only).
117
+ """
118
+ symbol = _extract_symbol(params)
119
+ if not symbol:
120
+ return {"success": False, "error": "symbol is required"}
121
+ symbol_base = symbol.rsplit(".", 1)[0] if symbol.endswith((".SZ", ".SS", ".SH")) else symbol
122
+ is_ashare_symbol = (
123
+ symbol_base.isdigit() and len(symbol_base) == 6
124
+ ) or (
125
+ symbol_base.startswith(("SH", "SZ"))
126
+ and symbol_base[2:].isdigit()
127
+ and len(symbol_base[2:]) == 6
128
+ )
129
+
130
+ # ── 1. Quote ─────────────────────────────────────────────────────────────
131
+ quote: dict = {"success": False, "error": "market data client unavailable"}
132
+ if _HAS_MDC and _get_mdc is not None:
133
+ import time as _t
134
+ mdc = _get_mdc()
135
+ for _att in range(3):
136
+ try:
137
+ quote = mdc.quote(symbol)
138
+ if quote.get("success"):
139
+ break
140
+ _e = str(quote.get("error", "")).lower()
141
+ if ("rate" in _e or "429" in _e) and _att < 2:
142
+ _t.sleep(2 ** _att)
143
+ continue
144
+ break
145
+ except Exception as exc:
146
+ _es = str(exc).lower()
147
+ if ("rate" in _es or "429" in _es) and _att < 2:
148
+ _t.sleep(2 ** _att)
149
+ continue
150
+ _raw = str(exc)
151
+ if "Connection aborted" in _raw or "RemoteDisconnected" in _raw:
152
+ quote = {"success": False, "error": "网络连接中断,请稍后重试"}
153
+ elif "Connection refused" in _raw:
154
+ quote = {"success": False, "error": "连接被拒绝,数据服务暂时不可用"}
155
+ elif "timeout" in _raw.lower():
156
+ quote = {"success": False, "error": "连接超时,请稍后重试"}
157
+ else:
158
+ quote = {"success": False, "error": _raw}
159
+ break
160
+
161
+ # Finnhub fallback for US/global symbols
162
+ if not quote.get("success"):
163
+ _fh_key = _get_finnhub_key()
164
+ if _fh_key:
165
+ try:
166
+ import requests as _rq
167
+ _r = _rq.get(
168
+ f"https://finnhub.io/api/v1/quote?symbol={symbol}&token={_fh_key}",
169
+ timeout=6,
170
+ )
171
+ if _r.status_code == 200:
172
+ _fh = _r.json()
173
+ if _fh.get("c"):
174
+ quote = {
175
+ "success": True, "symbol": symbol,
176
+ "price": round(_fh["c"], 4),
177
+ "change_pct": round(float(_fh.get("dp") or 0), 4),
178
+ "high": round(_fh.get("h", 0), 4),
179
+ "low": round(_fh.get("l", 0), 4),
180
+ "currency": "USD", "provider": "finnhub",
181
+ }
182
+ except Exception:
183
+ pass
184
+
185
+ # Unified DataService fallback — reaches the user's configured DataRouter
186
+ # sources (tushare / akshare / finnhub / alpha_vantage / …) when both the
187
+ # native MDC chain and Finnhub failed. Additive: only runs on failure.
188
+ if not quote.get("success"):
189
+ try:
190
+ _res = _get_data_service().quote(symbol)
191
+ if _res.success and _res.data:
192
+ quote = dict(_res.data)
193
+ quote.setdefault("success", True)
194
+ except Exception:
195
+ pass
196
+
197
+ if not quote.get("success"):
198
+ return {
199
+ "success": False,
200
+ "symbol": symbol,
201
+ "market": "CN" if is_ashare_symbol else "GLOBAL",
202
+ "provider_chain": quote.get("provider_chain") or (
203
+ ["eastmoney", "akshare", "yfinance"] if is_ashare_symbol
204
+ else ["yfinance", "finnhub"]
205
+ ),
206
+ "error": quote.get("error") or "行情数据源暂时不可用,请稍后重试。",
207
+ }
208
+
209
+ quote = enrich_market_quote(symbol, quote)
210
+ result = {
211
+ "success": True,
212
+ "symbol": symbol,
213
+ "name": quote.get("name") or symbol,
214
+ "price": quote.get("price"),
215
+ "change_pct": quote.get("change_pct"),
216
+ "high": quote.get("high"),
217
+ "low": quote.get("low"),
218
+ "volume": quote.get("volume"),
219
+ "market_cap": quote.get("market_cap"),
220
+ "currency": quote.get("currency") or "USD",
221
+ "provider": quote.get("provider") or "market_data_client",
222
+ "provider_chain": quote.get("provider_chain") or [
223
+ quote.get("provider") or "market_data_client"
224
+ ],
225
+ }
226
+ result.update(_quote_time_metadata(quote))
227
+
228
+ # ── 2. Technical indicators ───────────────────────────────────────────────
229
+ ti: dict = {}
230
+ if _HAS_MDC and _get_mdc is not None:
231
+ try:
232
+ ti = mdc.technical_indicators(symbol, days=120) or {} # type: ignore[name-defined]
233
+ except Exception:
234
+ ti = {}
235
+
236
+ if (not ti.get("success") or ti.get("rsi") is None) and not is_ashare_symbol:
237
+ import yfinance as _yf
238
+ import numpy as _np
239
+ from datetime import date as _date, timedelta as _td
240
+ _yf_sym = symbol
241
+ if symbol.isdigit() and len(symbol) == 6:
242
+ _yf_sym = symbol + (".SS" if symbol.startswith("6") else ".SZ")
243
+
244
+ def _compute_ta(df) -> dict:
245
+ _c = df["Close"] if "Close" in df.columns else df.iloc[:, 0]
246
+ _v = df["Volume"] if "Volume" in df.columns else None
247
+ _d = _c.diff()
248
+ _g = _d.clip(lower=0).rolling(14).mean()
249
+ _l = (-_d.clip(upper=0)).rolling(14).mean()
250
+ _rsi_val = float((100 - 100 / (1 + _g / _l.replace(0, _np.nan))).iloc[-1])
251
+ _ema12 = _c.ewm(span=12).mean()
252
+ _ema26 = _c.ewm(span=26).mean()
253
+ _macd = _ema12 - _ema26
254
+ _mhist = float((_macd - _macd.ewm(span=9).mean()).iloc[-1])
255
+ _ma20 = _c.rolling(20).mean()
256
+ _std20 = _c.rolling(20).std()
257
+ _ma60 = _c.rolling(60).mean() if len(_c) >= 60 else _ma20
258
+ r = {
259
+ "success": True,
260
+ "rsi": round(_rsi_val, 2) if not _np.isnan(_rsi_val) else None,
261
+ "macd_hist": round(_mhist, 4),
262
+ "ma20": round(float(_ma20.iloc[-1]), 2),
263
+ "ma60": round(float(_ma60.iloc[-1]), 2),
264
+ "bb_upper": round(float((_ma20 + 2 * _std20).iloc[-1]), 2),
265
+ "bb_lower": round(float((_ma20 - 2 * _std20).iloc[-1]), 2),
266
+ }
267
+ if _v is not None and result.get("volume") is None:
268
+ _rv = _v.iloc[-1]
269
+ if not _np.isnan(_rv):
270
+ result["volume"] = int(_rv)
271
+ return r
272
+
273
+ _df_ta = None
274
+ try:
275
+ _df_ta = _yf.Ticker(_yf_sym).history(period="6mo", auto_adjust=True)
276
+ if _df_ta.empty:
277
+ _df_ta = None
278
+ except Exception:
279
+ _df_ta = None
280
+
281
+ if _df_ta is None or len(_df_ta) < 20:
282
+ try:
283
+ _start = (_date.today() - _td(days=185)).isoformat()
284
+ _df_ta = _yf.download(
285
+ _yf_sym, start=_start, auto_adjust=True, progress=False, timeout=15
286
+ )
287
+ if hasattr(_df_ta.columns, "levels") and len(_df_ta.columns.levels) > 1:
288
+ _df_ta.columns = _df_ta.columns.droplevel(1)
289
+ if _df_ta.empty:
290
+ _df_ta = None
291
+ except Exception:
292
+ _df_ta = None
293
+
294
+ if _df_ta is not None and len(_df_ta) >= 20:
295
+ try:
296
+ ti = _compute_ta(_df_ta)
297
+ except Exception:
298
+ pass
299
+
300
+ if ti.get("success"):
301
+ for _k in ("rsi", "macd_hist", "ma20", "ma60", "bb_upper", "bb_lower"):
302
+ if ti.get(_k) is not None:
303
+ result[_k] = ti[_k]
304
+
305
+ return result
306
+
307
+
308
+ def tool_get_market_history(params: dict) -> dict:
309
+ """Fetch OHLC price history for any stock/ETF/index/crypto.
310
+
311
+ Returns a *compact* summary (period stats + the most recent candles), NOT
312
+ the full series, so the model can reason about trends without flooding the
313
+ context window. Routes through the unified DataService: MarketDataClient
314
+ first (Tushare for A-shares when configured, then Eastmoney/Sina/AKShare,
315
+ yfinance for HK/US/global), then the configured DataRouter as fallback.
316
+
317
+ Use this instead of writing ad-hoc akshare/tushare scripts: it handles
318
+ symbol normalisation, source fallback, and is environment-independent.
319
+ """
320
+ symbol = _extract_symbol(params)
321
+ if not symbol:
322
+ return {"success": False, "error": "symbol is required"}
323
+ try:
324
+ days = int(params.get("days", 120) or 120)
325
+ except (TypeError, ValueError):
326
+ days = 120
327
+ days = max(5, min(days, 1000))
328
+ interval = str(params.get("interval", "1d") or "1d").lower()
329
+
330
+ # Prefer the unified DataService (MDC + DataRouter fallback, honours the
331
+ # user's datasources.yaml). Fall back to MDC directly if it can't load.
332
+ hist = None
333
+ chain = None
334
+ err = None
335
+ try:
336
+ res = _get_data_service().history(symbol, days=days, interval=interval)
337
+ chain = res.provider_chain
338
+ if res.errors:
339
+ err = res.errors[0]
340
+ if (res.data or {}).get("data"):
341
+ hist = res.data
342
+ except Exception as exc:
343
+ err = str(exc)
344
+ if _HAS_MDC and _get_mdc is not None:
345
+ try:
346
+ _h = _get_mdc().history(symbol, days=days, interval=interval)
347
+ if _h.get("data"):
348
+ hist = _h
349
+ chain = _h.get("provider_chain")
350
+ else:
351
+ err = _h.get("error") or err
352
+ except Exception as exc2:
353
+ err = str(exc2)
354
+
355
+ if not hist or not hist.get("data"):
356
+ return {
357
+ "success": False,
358
+ "symbol": symbol,
359
+ "provider_chain": chain or ["eastmoney", "sina", "akshare", "yfinance"],
360
+ "error": err or "历史行情数据源暂时不可用,请稍后重试。",
361
+ }
362
+
363
+ rows = hist["data"] # ascending by date: [{date,open,high,low,close,volume},...]
364
+ closes = [r["close"] for r in rows if r.get("close")]
365
+ if not closes:
366
+ return {"success": False, "symbol": symbol, "error": "history contained no usable closes"}
367
+
368
+ def _ma(n: int):
369
+ return round(sum(closes[-n:]) / n, 4) if len(closes) >= n else None
370
+
371
+ start_close = closes[0]
372
+ end_close = closes[-1]
373
+ period_high = max(r["high"] for r in rows if r.get("high"))
374
+ period_low = min(r["low"] for r in rows if r.get("low"))
375
+ vols = [r["volume"] for r in rows if r.get("volume")]
376
+
377
+ # Only the most recent candles travel back to the model — the rest is
378
+ # summarised. Keeps the payload small regardless of `days`.
379
+ recent_n = min(30, len(rows))
380
+ return {
381
+ "success": True,
382
+ "symbol": hist.get("symbol") or symbol,
383
+ "name": hist.get("name") or symbol,
384
+ "provider": hist.get("provider"),
385
+ "interval": interval,
386
+ "total_points": len(rows),
387
+ "summary": {
388
+ "start_date": rows[0].get("date"),
389
+ "end_date": rows[-1].get("date"),
390
+ "start_close": round(start_close, 4),
391
+ "end_close": round(end_close, 4),
392
+ "change_pct": round((end_close - start_close) / start_close * 100, 2) if start_close else None,
393
+ "period_high": round(period_high, 4),
394
+ "period_low": round(period_low, 4),
395
+ "avg_volume": int(sum(vols) / len(vols)) if vols else None,
396
+ "ma5": _ma(5),
397
+ "ma20": _ma(20),
398
+ "ma60": _ma(60),
399
+ },
400
+ "recent_candles": rows[-recent_n:],
401
+ }
402
+
403
+
404
+ def tool_broker_query(params: dict) -> dict:
405
+ """Query a connected broker account (read-only): balance, positions, orders."""
406
+ if not _HAS_BROKERS:
407
+ return {"success": False, "error": "brokers 模块未加载,请确认 brokers/ 目录存在"}
408
+
409
+ query = str(params.get("query", "positions")).lower()
410
+ bid = params.get("broker_id", "")
411
+
412
+ try:
413
+ reg = _get_broker_registry()
414
+ if bid:
415
+ broker = reg.get(bid)
416
+ if not broker:
417
+ broker = reg.connect(bid)
418
+ else:
419
+ broker = reg.active()
420
+ if not broker:
421
+ broker = reg.connect_default()
422
+ if not broker:
423
+ cfgs = _list_broker_configs()
424
+ if not cfgs:
425
+ return {
426
+ "success": False,
427
+ "error": (
428
+ "尚未配置任何券商。\n"
429
+ f"请编辑 {_BROKERS_CONFIG_PATH} 或使用 /broker add <type> 命令。"
430
+ ),
431
+ }
432
+ return {
433
+ "success": False,
434
+ "error": "没有已连接的券商。请先运行 /broker connect <id>。",
435
+ }
436
+
437
+ if "account" in query or "balance" in query or "资金" in query or "余额" in query:
438
+ acct = broker.account_info()
439
+ return {
440
+ "success": True, "query": "account",
441
+ "broker": broker.label, "broker_type": broker.broker_type,
442
+ "account_id": acct.masked_account, "currency": acct.currency,
443
+ "total_assets": acct.total_assets, "cash": acct.cash,
444
+ "market_value": acct.market_value, "frozen": acct.frozen,
445
+ "pnl_today": acct.pnl_today, "pnl_total": acct.pnl_total,
446
+ }
447
+
448
+ if "position" in query or "持仓" in query or "portfolio" in query:
449
+ positions = broker.positions()
450
+ return {
451
+ "success": True, "query": "positions",
452
+ "broker": broker.label, "count": len(positions),
453
+ "positions": [
454
+ {
455
+ "symbol": p.symbol, "name": p.name,
456
+ "quantity": p.quantity, "available": p.available_qty,
457
+ "cost": p.cost_price, "price": p.current_price,
458
+ "market_value": p.market_value,
459
+ "pnl": p.pnl, "pnl_pct": round(p.pnl_pct, 2),
460
+ "currency": p.currency,
461
+ }
462
+ for p in positions
463
+ ],
464
+ }
465
+
466
+ if "order" in query or "订单" in query or "委托" in query:
467
+ status = params.get("status", "all")
468
+ orders = broker.orders(status=status, limit=int(params.get("limit", 20)))
469
+ return {
470
+ "success": True, "query": "orders",
471
+ "broker": broker.label, "status_filter": status,
472
+ "count": len(orders),
473
+ "orders": [
474
+ {
475
+ "order_id": o.order_id, "symbol": o.symbol, "name": o.name,
476
+ "side": o.side, "type": o.order_type,
477
+ "quantity": o.quantity, "filled": o.filled_qty,
478
+ "price": o.price, "avg_price": o.avg_price,
479
+ "status": o.status, "time": o.created_at,
480
+ "currency": o.currency,
481
+ }
482
+ for o in orders
483
+ ],
484
+ }
485
+
486
+ # Default: positions
487
+ positions = broker.positions()
488
+ return {
489
+ "success": True, "query": "positions",
490
+ "broker": broker.label, "count": len(positions),
491
+ "positions": [
492
+ {
493
+ "symbol": p.symbol, "name": p.name,
494
+ "quantity": p.quantity, "market_value": p.market_value,
495
+ "pnl": p.pnl, "pnl_pct": round(p.pnl_pct, 2),
496
+ }
497
+ for p in positions
498
+ ],
499
+ }
500
+
501
+ except Exception as e:
502
+ return {"success": False, "error": str(e)}
503
+
504
+
505
+ def tool_broker_order(params: dict) -> dict:
506
+ """Propose or execute a previewed order through the trading service layer."""
507
+ if not _HAS_BROKERS:
508
+ return {"success": False, "error": "brokers 模块未加载"}
509
+
510
+ symbol = str(params.get("symbol", "")).strip().upper()
511
+ side = str(params.get("side", "")).lower()
512
+ qty = params.get("quantity") or params.get("qty")
513
+ price = params.get("price")
514
+ order_type = str(params.get("order_type", "limit")).lower()
515
+ confirmed = bool(params.get("confirmed", False))
516
+ preview_id = str(params.get("preview_id", "") or params.get("order_preview_id", "")).strip()
517
+ target_weight = params.get("target_weight")
518
+
519
+ try:
520
+ reg = _get_broker_registry()
521
+ broker = reg.active()
522
+ if not broker:
523
+ broker = reg.connect_default()
524
+ except Exception as _e:
525
+ logger.debug("broker lookup failed: %s", _e)
526
+ broker = None
527
+
528
+ if not broker:
529
+ return {"success": False, "error": "无已连接账户,请先 /broker connect"}
530
+
531
+ if confirmed:
532
+ if not preview_id:
533
+ return {
534
+ "success": False,
535
+ "confirmation_required": True,
536
+ "error": "confirmed=true 需要 preview_id;请先生成订单预览。",
537
+ }
538
+ try:
539
+ from brokers import execute_order_preview
540
+ return execute_order_preview(broker, preview_id, confirmed=True)
541
+ except Exception as e:
542
+ return {"success": False, "error": str(e)}
543
+
544
+ if not symbol:
545
+ return {"success": False, "error": "symbol 是必填项"}
546
+ if side not in ("buy", "sell"):
547
+ return {"success": False, "error": "side 必须是 'buy' 或 'sell'"}
548
+ if not qty:
549
+ return {"success": False, "error": "quantity 是必填项"}
550
+ try:
551
+ qty = float(qty)
552
+ if qty <= 0:
553
+ raise ValueError
554
+ except (ValueError, TypeError):
555
+ return {"success": False, "error": "quantity 必须是正数"}
556
+
557
+ try:
558
+ from brokers import OrderIntent, build_order_preview
559
+ preview = build_order_preview(
560
+ broker,
561
+ OrderIntent(
562
+ symbol=symbol,
563
+ side=side,
564
+ quantity=qty,
565
+ price=float(price) if price is not None else None,
566
+ order_type=order_type,
567
+ target_weight=float(target_weight) if target_weight is not None else None,
568
+ source=str(params.get("source", "order_preview") or "order_preview"),
569
+ user_message=str(params.get("user_message", "") or ""),
570
+ metadata={"tool": "broker_order"},
571
+ ),
572
+ )
573
+ except Exception as e:
574
+ return {"success": False, "error": str(e)}
575
+
576
+ plan_data = preview.get("order_plan")
577
+ plan_message = ""
578
+ risk = (plan_data or {}).get("risk", {})
579
+ if risk.get("violations"):
580
+ plan_message = "\n".join(f" - {v}" for v in risk.get("violations", []))
581
+ elif risk.get("warnings"):
582
+ plan_message = "\n".join(f" - {w}" for w in risk.get("warnings", []))
583
+ blockers = preview.get("execution_blockers") or []
584
+ if blockers:
585
+ plan_message = "\n".join(f" - {v}" for v in blockers)
586
+
587
+ if plan_data and plan_data.get("risk", {}).get("violations"):
588
+ return {
589
+ "success": False, "risk_rejected": True,
590
+ "order_plan": plan_data,
591
+ "preview_id": preview.get("preview_id"),
592
+ "trade_preview": preview,
593
+ "message": "订单计划未通过风控:\n" + plan_message,
594
+ }
595
+
596
+ _price_str = f"{float(price):.2f}" if price is not None else "市价"
597
+ _side_cn = "买入" if side == "buy" else "卖出"
598
+ _risk_note = ""
599
+ if plan_data:
600
+ if risk.get("warnings"):
601
+ _risk_note = "\n\n风控提示:\n" + plan_message
602
+ elif blockers:
603
+ _risk_note = "\n\n执行限制:\n" + plan_message
604
+ return {
605
+ "success": False,
606
+ "confirmation_required": True,
607
+ "preview_id": preview.get("preview_id"),
608
+ "trade_preview": preview,
609
+ "order_plan": plan_data,
610
+ "order_preview": {
611
+ "preview_id": preview.get("preview_id"),
612
+ "mode": preview.get("mode"),
613
+ "broker": preview.get("broker_label"),
614
+ "symbol": symbol, "side": side, "side_cn": _side_cn,
615
+ "qty": qty, "price": price, "price_display": _price_str,
616
+ "order_type": order_type,
617
+ "can_execute": preview.get("can_execute"),
618
+ },
619
+ "message": (
620
+ f"⚠️ 请确认以下订单预览 `{preview.get('preview_id')}`:\n"
621
+ f" 模式: {preview.get('mode')} 券商: {preview.get('broker_label')}\n"
622
+ f" {_side_cn} **{symbol}** 数量: {qty:,.4g} 价格: {_price_str}\n\n"
623
+ "确认时必须携带 preview_id;其他任何回复取消。"
624
+ f"{_risk_note}"
625
+ ),
626
+ }