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,213 @@
1
+ """
2
+ brokers/registry.py — 券商注册表 & 连接管理器
3
+ ================================================
4
+ 统一管理所有已连接的券商实例。
5
+ 支持多账户并发持有(如同时连接 IBKR + 富途)。
6
+
7
+ 用法::
8
+
9
+ from brokers.registry import BrokerRegistry
10
+
11
+ reg = BrokerRegistry()
12
+ broker = reg.connect("xt_main") # 从 brokers.json 读取并连接
13
+ acct = broker.account_info()
14
+ pos = broker.positions()
15
+
16
+ # 切换默认账户
17
+ reg.set_active("ibkr_us")
18
+ broker = reg.active()
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ from typing import Any, Dict, List, Optional, Type
25
+
26
+ from .base import BrokerBase
27
+ from .config import (
28
+ get_broker_config, get_default_broker_config,
29
+ list_broker_configs, set_default_broker,
30
+ )
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+ # ── 适配器注册表 ───────────────────────────────────────────────────────────────
35
+
36
+ _BROKER_CLASSES: Dict[str, Type[BrokerBase]] = {}
37
+
38
+
39
+ def _register_all() -> None:
40
+ """延迟注册所有内置适配器(避免 import 循环)。"""
41
+ # No `global` needed: _BROKER_CLASSES is only read and mutated in place.
42
+ if _BROKER_CLASSES:
43
+ return
44
+ _map: Dict[str, tuple] = {
45
+ "paper": ("brokers.paper_broker", "PaperBroker"),
46
+ "xtquant": ("brokers.cn.xtquant_broker", "XTQuantBroker"),
47
+ "easytrader": ("brokers.cn.easytrader_broker", "EasyTraderBroker"),
48
+ "futu": ("brokers.cn.futu_broker", "FutuBroker"),
49
+ "tiger": ("brokers.cn.tiger_broker", "TigerBroker"),
50
+ "longbridge": ("brokers.cn.longbridge_broker", "LongbridgeBroker"),
51
+ "ibkr": ("brokers.intl.ibkr_broker", "IBKRBroker"),
52
+ "alpaca": ("brokers.intl.alpaca_broker", "AlpacaBroker"),
53
+ "webull": ("brokers.intl.webull_broker", "WebullBroker"),
54
+ "trading212": ("brokers.intl.trading212_broker", "Trading212Broker"),
55
+ }
56
+ for btype, (module_path, class_name) in _map.items():
57
+ try:
58
+ import importlib
59
+ mod = importlib.import_module(module_path)
60
+ _BROKER_CLASSES[btype] = getattr(mod, class_name)
61
+ except Exception as e:
62
+ logger.debug("Broker class load failed for %s: %s", btype, e)
63
+
64
+
65
+ def get_broker_class(broker_type: str) -> Optional[Type[BrokerBase]]:
66
+ _register_all()
67
+ return _BROKER_CLASSES.get(broker_type)
68
+
69
+
70
+ # ── 连接管理器 ────────────────────────────────────────────────────────────────
71
+
72
+ class BrokerRegistry:
73
+ """全局券商连接池,单例使用。"""
74
+
75
+ def __init__(self):
76
+ self._instances: Dict[str, BrokerBase] = {} # broker_id → instance
77
+ self._active_id: Optional[str] = None
78
+
79
+ # ── 连接 ──────────────────────────────────────────────────────────────────
80
+
81
+ def connect(self, broker_id: str) -> BrokerBase:
82
+ """连接指定 id 的券商(如已连接则直接返回)。"""
83
+ if broker_id in self._instances and self._instances[broker_id].is_connected:
84
+ return self._instances[broker_id]
85
+
86
+ cfg = get_broker_config(broker_id)
87
+ if not cfg:
88
+ raise ValueError(f"未找到券商配置: {broker_id!r} (请在 ~/.arthera/brokers.json 添加)")
89
+
90
+ broker_type = cfg.get("type", "")
91
+ cls = get_broker_class(broker_type)
92
+ if not cls:
93
+ raise ValueError(
94
+ f"不支持的券商类型: {broker_type!r}\n"
95
+ f"支持的类型: {', '.join(_BROKER_CLASSES)}"
96
+ )
97
+
98
+ instance = cls(broker_id=broker_id, config=cfg)
99
+ instance.connect()
100
+ self._instances[broker_id] = instance
101
+
102
+ if self._active_id is None:
103
+ self._active_id = broker_id
104
+
105
+ logger.info("✓ 已连接券商: %s (%s)", instance.label, broker_type)
106
+ return instance
107
+
108
+ def connect_default(self) -> Optional[BrokerBase]:
109
+ """连接 brokers.json 中标记为 default 的券商。"""
110
+ cfg = get_default_broker_config()
111
+ if not cfg:
112
+ return None
113
+ return self.connect(cfg["id"])
114
+
115
+ def connect_all(self) -> List[BrokerBase]:
116
+ """尝试连接所有已配置的券商,跳过连接失败的。"""
117
+ connected = []
118
+ for cfg in list_broker_configs():
119
+ try:
120
+ b = self.connect(cfg["id"])
121
+ connected.append(b)
122
+ except Exception as e:
123
+ logger.warning("连接券商 %s 失败: %s", cfg.get("id"), e)
124
+ return connected
125
+
126
+ # ── 查询 ──────────────────────────────────────────────────────────────────
127
+
128
+ def active(self) -> Optional[BrokerBase]:
129
+ """返回当前活跃的券商实例。"""
130
+ if not self._active_id:
131
+ return None
132
+ return self._instances.get(self._active_id)
133
+
134
+ def get(self, broker_id: str) -> Optional[BrokerBase]:
135
+ """按 id 获取已连接的实例。"""
136
+ return self._instances.get(broker_id)
137
+
138
+ def ensure(self, broker_id: str) -> BrokerBase:
139
+ """返回可用实例,链路掉线则透明重连。长驻调用方应优先用此方法而非 get()/connect()。"""
140
+ inst = self._instances.get(broker_id)
141
+ if inst is not None:
142
+ try:
143
+ if inst.ensure_connected():
144
+ return inst
145
+ except Exception:
146
+ pass
147
+ # 实例级重连失败 → 丢弃后整体重建
148
+ self._instances.pop(broker_id, None)
149
+ return self.connect(broker_id)
150
+
151
+ def health(self) -> List[Dict[str, Any]]:
152
+ """连接健康快照(供 /broker 状态展示)。"""
153
+ out: List[Dict[str, Any]] = []
154
+ for bid, inst in self._instances.items():
155
+ try:
156
+ healthy = bool(inst.is_connected and inst.ping())
157
+ except Exception:
158
+ healthy = False
159
+ out.append({
160
+ "broker_id": bid,
161
+ "label": getattr(inst, "label", bid),
162
+ "type": getattr(inst, "broker_type", ""),
163
+ "connected": bool(inst.is_connected),
164
+ "healthy": healthy,
165
+ "active": bid == self._active_id,
166
+ })
167
+ return out
168
+
169
+ def list_connected(self) -> List[BrokerBase]:
170
+ """返回所有已连接的券商。"""
171
+ return [b for b in self._instances.values() if b.is_connected]
172
+
173
+ def set_active(self, broker_id: str) -> bool:
174
+ """设置当前活跃账户。"""
175
+ if broker_id not in self._instances:
176
+ return False
177
+ self._active_id = broker_id
178
+ set_default_broker(broker_id)
179
+ return True
180
+
181
+ # ── 断开 ──────────────────────────────────────────────────────────────────
182
+
183
+ def disconnect(self, broker_id: str) -> None:
184
+ b = self._instances.pop(broker_id, None)
185
+ if b:
186
+ b.disconnect()
187
+ if self._active_id == broker_id:
188
+ remaining = list(self._instances)
189
+ self._active_id = remaining[0] if remaining else None
190
+
191
+ def disconnect_all(self) -> None:
192
+ for b in list(self._instances.values()):
193
+ try:
194
+ b.disconnect()
195
+ except Exception:
196
+ pass
197
+ self._instances.clear()
198
+ self._active_id = None
199
+
200
+ def __repr__(self) -> str:
201
+ ids = list(self._instances)
202
+ return f"<BrokerRegistry active={self._active_id!r} connected={ids}>"
203
+
204
+
205
+ # 全局单例(在 aria_cli.py 中 import 后使用)
206
+ _global_registry: Optional[BrokerRegistry] = None
207
+
208
+
209
+ def get_registry() -> BrokerRegistry:
210
+ global _global_registry
211
+ if _global_registry is None:
212
+ _global_registry = BrokerRegistry()
213
+ return _global_registry
@@ -0,0 +1,267 @@
1
+ """Trading service layer for paper/live execution.
2
+
3
+ All order execution flows through a preview id. Live trading is denied unless
4
+ the broker config explicitly enables ``allow_live_trade``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ import time
12
+ import uuid
13
+ from dataclasses import dataclass, field
14
+ from pathlib import Path
15
+ from typing import Any, Dict, Optional
16
+
17
+ from .config import BROKERS_CONFIG_PATH
18
+ from .planning import RiskRuleSet, StrategyIntent, plan_order, snapshot_from_broker
19
+
20
+
21
+ TRADE_PREVIEWS_PATH = BROKERS_CONFIG_PATH.parent / "trade_previews.json"
22
+ TRADE_AUDIT_PATH = BROKERS_CONFIG_PATH.parent / "trade_audit.jsonl"
23
+
24
+ _DRY_RUN_VALUES = {"1", "true", "yes", "on"}
25
+
26
+
27
+ def global_dry_run() -> bool:
28
+ """Global trading kill-switch.
29
+
30
+ When ``ARIA_DRY_RUN`` is truthy, ALL brokers are forced read-only regardless
31
+ of their per-broker config — order previews are never executable. A single
32
+ operational switch for demos, testing, or a risk-off freeze:
33
+ export ARIA_DRY_RUN=1
34
+ """
35
+ return str(os.getenv("ARIA_DRY_RUN", "")).strip().lower() in _DRY_RUN_VALUES
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class TradingPolicy:
40
+ mode: str = "read_only" # read_only | paper | live
41
+ allow_live_trade: bool = False
42
+ require_confirm: bool = True
43
+ max_single_position_weight: float = 0.20
44
+ min_cash_reserve_weight: float = 0.02
45
+ max_order_value_weight: float = 0.10
46
+ allow_short: bool = False
47
+ allow_fractional: bool = False
48
+
49
+ def rules(self) -> RiskRuleSet:
50
+ return RiskRuleSet(
51
+ max_single_position_weight=self.max_single_position_weight,
52
+ min_cash_reserve_weight=self.min_cash_reserve_weight,
53
+ max_order_value_weight=self.max_order_value_weight,
54
+ allow_short=self.allow_short,
55
+ allow_fractional=self.allow_fractional,
56
+ )
57
+
58
+
59
+ @dataclass(frozen=True)
60
+ class OrderIntent:
61
+ symbol: str
62
+ side: str
63
+ quantity: Optional[float] = None
64
+ order_type: str = "limit"
65
+ price: Optional[float] = None
66
+ source: str = "manual"
67
+ target_weight: Optional[float] = None
68
+ user_message: str = ""
69
+ metadata: Dict[str, Any] = field(default_factory=dict)
70
+
71
+
72
+ def resolve_trading_mode(config: Dict[str, Any], broker_type: str = "") -> str:
73
+ if global_dry_run():
74
+ return "read_only"
75
+ explicit = str(config.get("mode", "") or "").lower()
76
+ if explicit in {"read_only", "paper", "live"}:
77
+ return explicit
78
+ if broker_type == "paper" or config.get("paper") is True:
79
+ return "paper"
80
+ return "read_only"
81
+
82
+
83
+ def policy_from_config(config: Dict[str, Any], broker_type: str = "") -> TradingPolicy:
84
+ mode = resolve_trading_mode(config, broker_type=broker_type)
85
+ return TradingPolicy(
86
+ mode=mode,
87
+ allow_live_trade=bool(config.get("allow_live_trade", False)),
88
+ require_confirm=bool(config.get("require_confirm", True)),
89
+ max_single_position_weight=float(config.get("max_single_position_weight", 0.20) or 0.20),
90
+ min_cash_reserve_weight=float(config.get("min_cash_reserve_weight", 0.02) or 0.02),
91
+ max_order_value_weight=float(config.get("max_order_value_weight", 0.10) or 0.10),
92
+ allow_short=bool(config.get("allow_short", False)),
93
+ allow_fractional=bool(config.get("allow_fractional", False)),
94
+ )
95
+
96
+
97
+ def _load_previews() -> Dict[str, Any]:
98
+ if not TRADE_PREVIEWS_PATH.exists():
99
+ return {"previews": {}}
100
+ try:
101
+ data = json.loads(TRADE_PREVIEWS_PATH.read_text(encoding="utf-8"))
102
+ if isinstance(data, dict):
103
+ data.setdefault("previews", {})
104
+ return data
105
+ except Exception:
106
+ pass
107
+ return {"previews": {}}
108
+
109
+
110
+ def _save_previews(data: Dict[str, Any]) -> None:
111
+ TRADE_PREVIEWS_PATH.parent.mkdir(parents=True, exist_ok=True)
112
+ TRADE_PREVIEWS_PATH.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
113
+
114
+
115
+ def _audit(event: Dict[str, Any]) -> None:
116
+ TRADE_AUDIT_PATH.parent.mkdir(parents=True, exist_ok=True)
117
+ row = {"ts": int(time.time()), **event}
118
+ with TRADE_AUDIT_PATH.open("a", encoding="utf-8") as handle:
119
+ handle.write(json.dumps(row, ensure_ascii=False) + "\n")
120
+
121
+
122
+ def _execution_blockers(policy: TradingPolicy, plan: Dict[str, Any]) -> list[str]:
123
+ blockers: list[str] = []
124
+ if global_dry_run():
125
+ blockers.append("全局 dry-run 模式已启用 (ARIA_DRY_RUN),所有下单被冻结")
126
+ risk = plan.get("risk") or {}
127
+ blockers.extend(str(item) for item in risk.get("violations") or [])
128
+ if plan.get("action") in {"buy", "sell", "rebalance"} and not plan.get("estimated_order"):
129
+ blockers.append("订单计划没有可执行订单,通常是缺少价格、数量或持仓")
130
+ if policy.mode == "read_only":
131
+ blockers.append("账户处于 read_only 模式,不能执行订单")
132
+ if policy.mode == "live" and not policy.allow_live_trade:
133
+ blockers.append("实盘账户未设置 allow_live_trade=true")
134
+ return blockers
135
+
136
+
137
+ def build_order_preview(broker: Any, intent: OrderIntent) -> Dict[str, Any]:
138
+ policy = policy_from_config(getattr(broker, "config", {}) or {}, getattr(broker, "broker_type", ""))
139
+ snapshot = snapshot_from_broker(broker)
140
+ strategy_intent = StrategyIntent(
141
+ symbol=intent.symbol,
142
+ action=intent.side,
143
+ target_weight=intent.target_weight,
144
+ reason=intent.user_message,
145
+ source=intent.source,
146
+ metadata=dict(intent.metadata),
147
+ )
148
+ planned = plan_order(
149
+ snapshot,
150
+ strategy_intent,
151
+ price=float(intent.price) if intent.price is not None else None,
152
+ quantity=float(intent.quantity) if intent.quantity is not None else None,
153
+ order_type=intent.order_type,
154
+ rules=policy.rules(),
155
+ )
156
+ plan_dict = planned.to_dict()
157
+ preview_id = "tp_" + uuid.uuid4().hex[:12]
158
+ blockers = _execution_blockers(policy, plan_dict)
159
+ preview = {
160
+ "preview_id": preview_id,
161
+ "created_at": int(time.time()),
162
+ "status": "pending",
163
+ "broker_id": getattr(broker, "broker_id", ""),
164
+ "broker_label": getattr(broker, "label", ""),
165
+ "broker_type": getattr(broker, "broker_type", ""),
166
+ "mode": policy.mode,
167
+ "allow_live_trade": policy.allow_live_trade,
168
+ "require_confirm": policy.require_confirm,
169
+ "intent": {
170
+ "symbol": intent.symbol.upper(),
171
+ "side": intent.side.lower(),
172
+ "quantity": float(intent.quantity) if intent.quantity is not None else None,
173
+ "order_type": intent.order_type.lower(),
174
+ "price": intent.price,
175
+ "source": intent.source,
176
+ },
177
+ "order_plan": plan_dict,
178
+ "execution_blockers": blockers,
179
+ "can_execute": not blockers,
180
+ "audit_path": str(TRADE_AUDIT_PATH),
181
+ }
182
+ store = _load_previews()
183
+ store.setdefault("previews", {})[preview_id] = preview
184
+ _save_previews(store)
185
+ _audit({"event": "trade_preview", "preview": preview})
186
+ return preview
187
+
188
+
189
+ def load_order_preview(preview_id: str) -> Dict[str, Any] | None:
190
+ return (_load_previews().get("previews") or {}).get(preview_id)
191
+
192
+
193
+ def list_order_previews(limit: int = 10) -> list[Dict[str, Any]]:
194
+ rows = list((_load_previews().get("previews") or {}).values())
195
+ rows.sort(key=lambda row: int(row.get("created_at", 0)), reverse=True)
196
+ return rows[: max(0, int(limit or 10))]
197
+
198
+
199
+ def mark_preview_status(preview_id: str, status: str, extra: Optional[Dict[str, Any]] = None) -> None:
200
+ store = _load_previews()
201
+ preview = (store.get("previews") or {}).get(preview_id)
202
+ if not preview:
203
+ return
204
+ preview["status"] = status
205
+ preview["updated_at"] = int(time.time())
206
+ if extra:
207
+ preview.update(extra)
208
+ _save_previews(store)
209
+
210
+
211
+ def execute_order_preview(
212
+ broker: Any,
213
+ preview_id: str,
214
+ *,
215
+ confirmed: bool = False,
216
+ source: str = "terminal",
217
+ ) -> Dict[str, Any]:
218
+ """`source` is audit-trail metadata only, never a trust signal — it does
219
+ not change what this function will or won't execute. It exists so the
220
+ audit log can distinguish a human typing /trade confirm at the terminal
221
+ keyboard ("terminal", the default) from the separate, explicitly-gated
222
+ chat-confirm MCP path ("chat_mcp") — see packages/aria_mcp/server.py's
223
+ _call_broker_confirm_order for that gate."""
224
+ preview = load_order_preview(preview_id)
225
+ if not preview:
226
+ return {"success": False, "error": f"preview not found: {preview_id}"}
227
+ if not confirmed:
228
+ return {"success": False, "confirmation_required": True, "preview": preview}
229
+ if preview.get("broker_id") != getattr(broker, "broker_id", ""):
230
+ return {"success": False, "error": "preview broker does not match active broker", "preview": preview}
231
+
232
+ policy = policy_from_config(getattr(broker, "config", {}) or {}, getattr(broker, "broker_type", ""))
233
+ blockers = _execution_blockers(policy, preview.get("order_plan") or {})
234
+ if blockers:
235
+ mark_preview_status(preview_id, "rejected", {"execution_blockers": blockers})
236
+ _audit({"event": "trade_rejected", "preview_id": preview_id, "blockers": blockers})
237
+ return {"success": False, "risk_rejected": True, "execution_blockers": blockers, "preview": preview}
238
+
239
+ intent = preview.get("intent") or {}
240
+ planned_order = ((preview.get("order_plan") or {}).get("estimated_order") or {})
241
+ if not planned_order:
242
+ return {"success": False, "error": "preview has no executable order", "preview": preview}
243
+ result = broker.place_order(
244
+ symbol=str(planned_order.get("symbol") or intent.get("symbol", "")),
245
+ side=str(planned_order.get("side") or intent.get("side", "")),
246
+ quantity=float(planned_order.get("quantity", intent.get("quantity", 0.0)) or 0.0),
247
+ order_type=str(planned_order.get("order_type") or intent.get("order_type", "limit")),
248
+ price=float(planned_order.get("price", intent.get("price", 0.0)) or 0.0),
249
+ )
250
+ payload = {
251
+ "success": bool(getattr(result, "success", False)),
252
+ "order_id": getattr(result, "order_id", ""),
253
+ "message": getattr(result, "message", ""),
254
+ "broker": getattr(broker, "label", ""),
255
+ "broker_id": getattr(broker, "broker_id", ""),
256
+ "mode": policy.mode,
257
+ "preview_id": preview_id,
258
+ "symbol": str(planned_order.get("symbol") or intent.get("symbol", "")),
259
+ "side": str(planned_order.get("side") or intent.get("side", "")),
260
+ "qty": float(planned_order.get("quantity", intent.get("quantity", 0.0)) or 0.0),
261
+ "order_plan": preview.get("order_plan"),
262
+ }
263
+ mark_preview_status(preview_id, "executed" if payload["success"] else "failed", {
264
+ "result": payload,
265
+ })
266
+ _audit({"event": "trade_execute", "preview_id": preview_id, "result": payload, "source": source})
267
+ return payload
@@ -0,0 +1,4 @@
1
+ """Compatibility import for :mod:`clients.canva_client`."""
2
+ from importlib import import_module as _import_module
3
+ import sys as _sys
4
+ _sys.modules[__name__] = _import_module("clients.canva_client")
@@ -0,0 +1,127 @@
1
+ """Staged file-change store for Aria Code.
2
+
3
+ The CLI still supports direct writes for existing workflows, but every write can
4
+ now be represented as a hash-checked change first. This gives us Codex/Claude
5
+ Code style review/apply/reject primitives without coupling the logic to the REPL.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import difflib
11
+ import hashlib
12
+ import os
13
+ import pathlib
14
+ import time
15
+ import uuid
16
+ from dataclasses import asdict, dataclass
17
+ from typing import Dict, List, Optional
18
+
19
+
20
+ class ChangeConflictError(RuntimeError):
21
+ """Raised when the file changed after a staged change was created."""
22
+
23
+
24
+ def sha256_text(text: str) -> str:
25
+ return hashlib.sha256(text.encode("utf-8", errors="replace")).hexdigest()
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class StagedChange:
30
+ change_id: str
31
+ path: str
32
+ before_content: str
33
+ after_content: str
34
+ before_hash: str
35
+ after_hash: str
36
+ diff: str
37
+ created_at: float
38
+ source: str = "aria-code"
39
+ applied: bool = False
40
+ rejected: bool = False
41
+
42
+ def to_dict(self) -> dict:
43
+ return asdict(self)
44
+
45
+
46
+ class ChangeStore:
47
+ """In-memory staged change store with conflict-aware apply."""
48
+
49
+ def __init__(self) -> None:
50
+ self._changes: Dict[str, StagedChange] = {}
51
+
52
+ def stage(self, path: str | pathlib.Path, after_content: str, source: str = "aria-code") -> StagedChange:
53
+ target = pathlib.Path(path).expanduser().resolve()
54
+ before = target.read_text(encoding="utf-8", errors="replace") if target.is_file() else ""
55
+ rel = str(target)
56
+ diff = "".join(difflib.unified_diff(
57
+ before.splitlines(keepends=True),
58
+ after_content.splitlines(keepends=True),
59
+ fromfile=f"a/{rel}",
60
+ tofile=f"b/{rel}",
61
+ ))
62
+ change = StagedChange(
63
+ change_id=uuid.uuid4().hex[:12],
64
+ path=rel,
65
+ before_content=before,
66
+ after_content=after_content,
67
+ before_hash=sha256_text(before),
68
+ after_hash=sha256_text(after_content),
69
+ diff=diff,
70
+ created_at=time.time(),
71
+ source=source,
72
+ )
73
+ self._changes[change.change_id] = change
74
+ return change
75
+
76
+ def list(self, include_closed: bool = False) -> List[StagedChange]:
77
+ changes = list(self._changes.values())
78
+ if not include_closed:
79
+ changes = [c for c in changes if not c.applied and not c.rejected]
80
+ return sorted(changes, key=lambda c: c.created_at)
81
+
82
+ def get(self, change_id: str) -> Optional[StagedChange]:
83
+ return self._changes.get(change_id)
84
+
85
+ def apply(self, change_id: str) -> StagedChange:
86
+ change = self._require_open(change_id)
87
+ target = pathlib.Path(change.path)
88
+ current = target.read_text(encoding="utf-8", errors="replace") if target.is_file() else ""
89
+ if sha256_text(current) != change.before_hash:
90
+ raise ChangeConflictError(f"File changed since staging: {change.path}")
91
+ target.parent.mkdir(parents=True, exist_ok=True)
92
+ tmp = target.with_name(f".{target.name}.aria-tmp-{uuid.uuid4().hex[:8]}")
93
+ tmp.write_text(change.after_content, encoding="utf-8")
94
+ os.replace(tmp, target)
95
+ applied = StagedChange(**{**change.to_dict(), "applied": True})
96
+ self._changes[change.change_id] = applied
97
+ return applied
98
+
99
+ def reject(self, change_id: str) -> StagedChange:
100
+ change = self._require_open(change_id)
101
+ rejected = StagedChange(**{**change.to_dict(), "rejected": True})
102
+ self._changes[change.change_id] = rejected
103
+ return rejected
104
+
105
+ def clear_closed(self) -> int:
106
+ closed = [cid for cid, c in self._changes.items() if c.applied or c.rejected]
107
+ for cid in closed:
108
+ del self._changes[cid]
109
+ return len(closed)
110
+
111
+ def _require_open(self, change_id: str) -> StagedChange:
112
+ key = (change_id or "").strip()
113
+ change = self._changes.get(key)
114
+ if change is None:
115
+ matches = [c for cid, c in self._changes.items() if cid.startswith(key)]
116
+ if len(matches) == 1:
117
+ change = matches[0]
118
+ if change is None:
119
+ raise KeyError(f"Unknown change id: {change_id}")
120
+ if change.applied:
121
+ raise ValueError(f"Change already applied: {change.change_id}")
122
+ if change.rejected:
123
+ raise ValueError(f"Change already rejected: {change.change_id}")
124
+ return change
125
+
126
+
127
+ GLOBAL_CHANGE_STORE = ChangeStore()
File without changes