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,656 @@
1
+ """Persistent terminal application service. The host owns the TTY.
2
+
3
+ Bidirectional UTF-8 JSONL, protocol 1: submit/cancel a turn, answer a menu or
4
+ input request, resume a session, and shut down. Inference, commands, task
5
+ isolation, risk assessment, tool approvals and persistence stay in the existing
6
+ ArtheraTerminal. Only its presentation/input adapters are replaced here.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import asyncio
12
+ import builtins
13
+ import getpass
14
+ import io
15
+ import json
16
+ import os
17
+ import queue
18
+ import re
19
+ import sys
20
+ import threading
21
+ import uuid
22
+ from pathlib import Path
23
+
24
+ MAX_MESSAGE = 1_048_576
25
+ MAX_INPUT = 65_536
26
+ PROTOCOL = 1
27
+
28
+
29
+ def session_id(value: str) -> str:
30
+ if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_-]{0,127}", value):
31
+ raise ValueError("Invalid session ID")
32
+ return value
33
+
34
+
35
+ class Output(io.TextIOBase):
36
+ """Capture legacy command/Rich output; never write it on the protocol pipe."""
37
+ def __init__(self, server):
38
+ self.server = server
39
+
40
+ def write(self, text):
41
+ if text:
42
+ # Bound an individual event even when a legacy command prints a file.
43
+ for offset in range(0, len(text), 16_384):
44
+ self.server.emit("output.delta", text=text[offset:offset + 16_384])
45
+ return len(text)
46
+
47
+ def flush(self):
48
+ pass
49
+
50
+ def isatty(self):
51
+ return False
52
+
53
+
54
+ class Server:
55
+ def __init__(self, incoming, outgoing, options):
56
+ self.incoming, self.outgoing, self.options = incoming, outgoing, options
57
+ self.lock = threading.Lock()
58
+ self.requests = queue.Queue(maxsize=32)
59
+ self.dialog_lock = threading.Lock()
60
+ self.dialog = None
61
+ self.turn_id = None
62
+ self.task = None
63
+ self.loop = None
64
+ self.stopping = threading.Event()
65
+ self.terminal = None
66
+ self.cli = None
67
+ self.background = []
68
+ self.tool_lock = threading.Lock()
69
+ self.active_tools = 0
70
+ self.cancel_requested = False
71
+
72
+ def emit(self, kind, **fields):
73
+ record = {"type": kind, "protocol": PROTOCOL, "turn_id": self.turn_id, **fields}
74
+ encoded = json.dumps(record, ensure_ascii=False, default=str) + "\n"
75
+ if len(encoded.encode("utf-8")) > MAX_MESSAGE:
76
+ raise ValueError("Application event exceeds 1 MiB")
77
+ with self.lock:
78
+ self.outgoing.write(encoded)
79
+ self.outgoing.flush()
80
+
81
+ def ask(self, kind, **fields):
82
+ ident = uuid.uuid4().hex
83
+ replies = queue.Queue(maxsize=1)
84
+ with self.dialog_lock:
85
+ self.dialog = (ident, replies)
86
+ self.emit(kind, request_id=ident, **fields)
87
+ try:
88
+ value = replies.get()
89
+ if value is None:
90
+ raise KeyboardInterrupt
91
+ return value
92
+ finally:
93
+ with self.dialog_lock:
94
+ self.dialog = None
95
+ self.emit("dialog.closed", request_id=ident)
96
+
97
+ def input(self, prompt="", *, secret=False):
98
+ value = self.ask("input.requested", prompt=str(prompt), secret=secret)
99
+ text = value.get("text")
100
+ if not isinstance(text, str) or len(text.encode("utf-8")) > MAX_INPUT:
101
+ raise ValueError("Invalid input response")
102
+ return text
103
+
104
+ def select(self, options, selected=0, title="", **kwargs):
105
+ # The existing approval function supplies its actual options. Returning
106
+ # an index to it preserves deny lists, L4 ask-every-time, hooks, symbol
107
+ # previews and the exact scope of session grants.
108
+ choices = [[str(label), str(help_text)] for label, help_text in options]
109
+ extra = {}
110
+ picker = bool(kwargs.get("picker"))
111
+ if picker:
112
+ # A long list to search (models): the frontend draws a picker, not an approval.
113
+ extra["picker"] = True
114
+ groups = kwargs.get("groups")
115
+ if isinstance(groups, list) and len(groups) == len(choices):
116
+ extra["groups"] = [str(group) for group in groups]
117
+ if not picker and getattr(self, "approval_risk", None):
118
+ extra["risk"] = self.approval_risk
119
+ answer = self.ask("approval.requested", title=str(title or "Approval / selection"),
120
+ choices=choices, selected=selected,
121
+ shortcuts=kwargs.get("shortcuts", {}),
122
+ context="" if picker else getattr(self, "approval_context", ""),
123
+ **extra)
124
+ chosen = answer.get("choice", -1)
125
+ if type(chosen) is not int or not -1 <= chosen < len(choices):
126
+ raise ValueError("Invalid menu response")
127
+ return chosen
128
+
129
+ def abort(self):
130
+ with self.dialog_lock:
131
+ if self.dialog:
132
+ try:
133
+ self.dialog[1].put_nowait(None)
134
+ except queue.Full:
135
+ pass
136
+ if self.loop:
137
+ def cancel():
138
+ if self.terminal and self.terminal.cancel_event:
139
+ self.terminal.cancel_event.set()
140
+ if self.task and not self.task.done() and not self.cancel_requested:
141
+ self.cancel_requested = True
142
+ self.task.cancel()
143
+ self.loop.call_soon_threadsafe(cancel)
144
+
145
+ def read_requests(self):
146
+ try:
147
+ while not self.stopping.is_set():
148
+ raw = self.incoming.readline(MAX_MESSAGE + 1)
149
+ if not raw:
150
+ break
151
+ if len(raw) > MAX_MESSAGE or not raw.endswith(b"\n"):
152
+ self.emit("protocol.error", error="Request must be a JSONL line of at most 1 MiB")
153
+ break
154
+ try:
155
+ value = json.loads(raw.decode("utf-8"))
156
+ if not isinstance(value, dict) or type(value.get("protocol")) is not int or value["protocol"] != PROTOCOL:
157
+ raise ValueError("Unsupported application protocol")
158
+ kind = value.get("type")
159
+ if kind == "dialog.respond":
160
+ with self.dialog_lock:
161
+ if not self.dialog or value.get("request_id") != self.dialog[0] or value.get("turn_id") != self.turn_id:
162
+ raise ValueError("Stale or unknown dialog")
163
+ self.dialog[1].put_nowait(value)
164
+ continue
165
+ if kind == "turn.cancel":
166
+ if value.get("turn_id") != self.turn_id or not self.turn_id:
167
+ raise ValueError("Stale or unknown turn")
168
+ self.abort()
169
+ continue
170
+ if kind == "shutdown":
171
+ break
172
+ if kind == "completion.request":
173
+ # Answered here, not queued behind a running turn: it is
174
+ # a lookup, and the list it feeds should not wait.
175
+ self.complete_reference(value)
176
+ continue
177
+ self.requests.put_nowait(value)
178
+ except (ValueError, UnicodeError, queue.Full) as error:
179
+ self.emit("protocol.error", error=str(error))
180
+ finally:
181
+ self.stopping.set()
182
+ self.abort()
183
+ # Wake the dispatcher even if the queue is full.
184
+ try:
185
+ self.requests.put_nowait({"type": "shutdown"})
186
+ except queue.Full:
187
+ pass
188
+
189
+ def initialize(self):
190
+ # Resolve the selected package, not a legacy top-level installation.
191
+ from aria_code import aria_cli as cli
192
+ from rich.console import Console
193
+ from aria_code.apps.cli.runtime_consumer import TerminalRuntimeEventConsumer
194
+ from aria_code.apps.cli.exec_events import ExecEvents
195
+
196
+ self.cli = cli
197
+ output = Output(self)
198
+ # Console captures markup/tables without ANSI. Command modules get the
199
+ # same console through AriaContext. Model-visible reasoning is never
200
+ # sent as answer/output events by this consumer.
201
+ sys.stdout = output
202
+ sys.stderr = output
203
+ cli.console = Console(file=output, force_terminal=False, color_system=None, width=100)
204
+ cli.HAS_RICH = True
205
+ builtins.input = self.input
206
+ getpass.getpass = lambda prompt="Password: ", stream=None: self.input(prompt, secret=True)
207
+ cli.console.input = lambda prompt="", **kw: self.input(prompt, secret=bool(kw.get("password")))
208
+ cli._arrow_select = self.select
209
+ cli._render_answer_block = lambda text, *a, **kw: self.emit("answer.replace", text=str(text))
210
+ server = self
211
+
212
+ class Events(ExecEvents):
213
+ def __init__(self):
214
+ self.streaming = True
215
+ def emit(self, kind, **fields):
216
+ server.emit(kind, **fields)
217
+
218
+ events = Events()
219
+
220
+ class Consumer(TerminalRuntimeEventConsumer):
221
+ def __init__(self, **kwargs):
222
+ kwargs.update(has_rich=False, action_view=None, print_tool_call=None,
223
+ print_tool_done=None, on_response_start=None,
224
+ set_robot_state=None)
225
+ super().__init__(**kwargs)
226
+ def on_token(self, token):
227
+ self.first_token_received = True
228
+ self.streamed_any = True
229
+ self.token_count += 1
230
+ self.response_text += token
231
+ events.text_delta(token)
232
+ def on_thinking(self, content):
233
+ # No hidden reasoning in the protocol/transcript.
234
+ self.thinking_tokens += 1
235
+ self.set_phase(cli.TurnPhase.THINKING)
236
+ def on_tool_call(self, tool, params):
237
+ events.tool_started(tool, params)
238
+ def on_tool_result(self, tool, result):
239
+ events.tool_completed(tool, result)
240
+ def on_status(self, state, message):
241
+ events.status(state, message)
242
+ def stop_live(self, discard=False):
243
+ self.stop_spinner()
244
+
245
+ cli.TerminalRuntimeEventConsumer = Consumer
246
+ approval_base = cli.TerminalApprovalEventConsumer
247
+ class Approvals(approval_base):
248
+ async def approve(self, tool_name, tool_params, **kwargs):
249
+ from aria_code.apps.cli.exec_events import _param_view
250
+ params = _param_view(tool_params)
251
+ zh = str(server.terminal.config.get("ui_lang", "en")).startswith("zh")
252
+ context = [("工具" if zh else "Tool") + ": " + tool_name]
253
+ for key, en, cn in (("path", "File", "文件"), ("command", "Command", "命令"), ("directory", "Directory", "目录")):
254
+ if isinstance(params.get(key), str):
255
+ context.append((cn if zh else en) + ": " + params[key])
256
+ server.approval_context = "\n".join(context)
257
+ server.approval_risk = server.assess_for_approval(tool_name, tool_params)
258
+ try:
259
+ return await super().approve(tool_name, tool_params, **kwargs)
260
+ finally:
261
+ server.approval_context = ""
262
+ server.approval_risk = None
263
+ cli.TerminalApprovalEventConsumer = Approvals
264
+ config = cli.load_config()
265
+ config["_session_workspace_root"] = str(Path.cwd().resolve())
266
+ config["_session_write_roots"] = [str(Path(p).expanduser().resolve()) for p in self.options.add_dir]
267
+ config["_session_read_roots"] = [str(Path(p).expanduser().resolve()) for p in self.options.read_dir]
268
+ if self.options.resume_last and not self.options.resume:
269
+ self.options.resume = config.get("last_session_id")
270
+ if not self.options.resume:
271
+ raise ValueError("No last session to resume")
272
+ resumed = self.load_session(self.options.resume) if self.options.resume else None
273
+ config["last_session_id"] = self.options.resume or uuid.uuid4().hex[:8]
274
+ if self.options.model:
275
+ model = self.options.model
276
+ if "/" in model and not model.startswith("http"):
277
+ from aria_code.apps.cli.providers.chat_routing import normalize_provider_name, KNOWN_MODEL_PROVIDERS
278
+ provider, model = model.split("/", 1)
279
+ provider = normalize_provider_name(provider)
280
+ if provider in KNOWN_MODEL_PROVIDERS:
281
+ config["backend_chat"] = False
282
+ config.update(model=model, local_provider=provider,
283
+ local_mode=provider in {"ollama", "lmstudio", "vllm", "llamacpp", "jan", "custom"})
284
+ else:
285
+ key = cli.resolve_model_key(model)
286
+ config.update(model=cli.MODELS[key]["id"] if key in cli.MODELS else model, local_provider="ollama")
287
+ if self.options.url:
288
+ config["api_url"] = self.options.url
289
+ if self.options.thinking:
290
+ config["thinking_mode"] = "thinking"
291
+ if self.options.local:
292
+ config["local_mode"] = True
293
+ cli._auto_approve_session = self.options.dangerously_skip_permissions
294
+ cli._session_always_allow.update(t.strip() for t in self.options.allow_tools.split(",") if t.strip())
295
+ self.terminal = self.make_terminal(config)
296
+ if resumed:
297
+ self.terminal.conversation = resumed["messages"]
298
+ self.persist()
299
+ self.remember_session()
300
+ self.snapshot("session.ready")
301
+
302
+ def make_terminal(self, config):
303
+ terminal = self.cli.ArtheraTerminal(config)
304
+ # The host draws its own turn footer. Keep this presentation flag out
305
+ # of saved user settings and retain normal Python CLI behaviour.
306
+ terminal._native_frontend = True
307
+ # Commands that need a choice (/model) draw it in the host's own menu.
308
+ # This process's stdin is a pipe, so the TTY arrow picker can never run.
309
+ terminal._native_select = self.select
310
+ execute = terminal.tool_executor.execute_local
311
+ def tracked(*args, **kwargs):
312
+ with self.tool_lock:
313
+ self.active_tools += 1
314
+ try:
315
+ return execute(*args, **kwargs)
316
+ finally:
317
+ with self.tool_lock:
318
+ self.active_tools -= 1
319
+ terminal.tool_executor.execute_local = tracked
320
+ return terminal
321
+
322
+ def load_session(self, ident):
323
+ # Validate before the constructor creates a JSONL log for this ID.
324
+ ident = session_id(ident)
325
+ data = self.cli.SessionManager(self.cli.SESSIONS_DIR).load_session(ident)
326
+ if not data:
327
+ from aria_code.apps.cli.session_jsonl import JsonlSessionStore
328
+ data = JsonlSessionStore().load_session(ident)
329
+ if not data:
330
+ raise ValueError("Session not found")
331
+ messages = data.get("messages")
332
+ if not isinstance(messages, list) or any(not isinstance(m, dict) for m in messages):
333
+ raise ValueError("Invalid session messages")
334
+ return data
335
+
336
+ def end_hooks(self):
337
+ if self.cli._HAS_JSON_HOOKS:
338
+ try:
339
+ self.cli._fire_json_hook("SessionEnd", session_id=self.terminal.session_id,
340
+ hooks=self.cli._JSON_HOOKS)
341
+ except Exception:
342
+ pass
343
+ self.cli._run_event_hook("session_end", {"ARIA_SESSION": self.terminal.session_id})
344
+
345
+ def switch_session(self, ident=None):
346
+ data = self.load_session(ident) if ident is not None else None
347
+ self.persist()
348
+ self.end_hooks()
349
+ config = dict(self.terminal.config, last_session_id=ident or uuid.uuid4().hex[:8])
350
+ registry = self.terminal._mcp_registry
351
+ self.cli._session_always_allow.clear()
352
+ self.cli._session_command_prefixes.clear()
353
+ self.cli._auto_approve_session = self.options.dangerously_skip_permissions
354
+ self.cli._session_always_allow.update(t.strip() for t in self.options.allow_tools.split(",") if t.strip())
355
+ # A fresh terminal also resets plans, images, loaded-project context,
356
+ # telemetry, tool trace and pending artifacts. MCP connections survive.
357
+ self.terminal = self.make_terminal(config)
358
+ self.terminal._mcp_registry = registry
359
+ if data:
360
+ self.terminal.conversation = data["messages"]
361
+ self.persist()
362
+ self.remember_session()
363
+ self.snapshot("session.ready")
364
+
365
+ def remember_session(self):
366
+ # Save only the pointer in the user configuration, not transient
367
+ # project roots or launch-only model/permission overrides.
368
+ config = self.cli.load_config()
369
+ config["last_session_id"] = self.terminal.session_id
370
+ self.cli.save_config(config)
371
+
372
+ def complete_reference(self, value):
373
+ """Answer a completion request with candidates for the `@file` being typed."""
374
+ text = value.get("text")
375
+ if not isinstance(text, str) or len(text.encode("utf-8")) > MAX_INPUT:
376
+ raise ValueError("Completion text must be at most 65536 UTF-8 bytes")
377
+ from aria_code.apps.cli.file_references import reference_candidates
378
+
379
+ try:
380
+ candidates = reference_candidates(text, Path.cwd())
381
+ except Exception:
382
+ candidates = []
383
+ self.emit("completion.result", session_id=value.get("session_id", ""), text=text, candidates=candidates)
384
+
385
+ def assess_for_approval(self, tool_name, params):
386
+ """What the action reaches, for the approval card: level, files, hosts, why.
387
+
388
+ The same assessment the terminal's text card is built from, sent as data
389
+ so the frontend can draw it. None when it cannot be assessed; the dialog
390
+ then shows only the tool and its target.
391
+ """
392
+ try:
393
+ from aria_code.safety.risk import assess_tool
394
+ from aria_code.ui.render.output import _file_impact
395
+
396
+ assessment = assess_tool(tool_name, dict(params or {}), root=os.getcwd())
397
+ card = assessment.as_dict()
398
+ card["impact"] = _file_impact(assessment)
399
+ for key in ("hosts", "files", "systems", "reasons"):
400
+ card[key] = [str(x)[:200] for x in card.get(key, [])[:8]]
401
+ return card
402
+ except Exception:
403
+ return None
404
+
405
+ def commands_info(self):
406
+ """Every slash command with what it does, in the order the list shows them.
407
+
408
+ The frontend's list opens on a bare `/`, so what comes first matters: the
409
+ core commands and the entry points, then the rest alphabetically, the same
410
+ order the terminal completer has always used. Descriptions are localised.
411
+ """
412
+ from aria_code.apps.cli.commands.catalog import CORE_SLASH_COMMANDS, ENTRY_SLASH_COMMANDS, describe
413
+
414
+ t = self.terminal
415
+ registry = t.commands.commands
416
+ lang = t.config.get("ui_lang", "en")
417
+ first = [n for n in (*CORE_SLASH_COMMANDS, *ENTRY_SLASH_COMMANDS) if n in registry]
418
+ rest = [n for n in sorted(registry) if n not in set(first)]
419
+ info = []
420
+ for name in first + rest:
421
+ try:
422
+ detail = describe(name, registry[name][1], lang)
423
+ except Exception:
424
+ detail = ""
425
+ info.append({"name": name, "description": str(detail or "")[:160]})
426
+ return info
427
+
428
+ def snapshot(self, kind):
429
+ from aria_code.apps.cli.native_branding import robot_rows
430
+ from aria_code.ui import robot
431
+ t = self.terminal
432
+ rows = robot_rows(hidden=self.options.no_banner or self.options.banner == "off")
433
+ # Older Rust frontends still consume the spans. New frontends draw the
434
+ # named design themselves, sharing the same mascot as the Go runtime.
435
+ # An empty drawing must continue to mean that the banner is disabled.
436
+ # A display snapshot is bounded independently of the model's context.
437
+ messages = [{"role": m.get("role", ""), "content": str(m.get("content", ""))[:4096]}
438
+ for m in t.conversation[-40:]]
439
+ self.emit(kind, session_id=t.session_id, messages=messages,
440
+ version=self.cli.__version__,
441
+ robot=rows, robot_design="cream-block-v2" if rows else "",
442
+ model=t.config.get("model", ""), provider=t.config.get("local_provider", ""),
443
+ workspace=str(Path.cwd()), commands=sorted(t.commands.commands),
444
+ commands_info=self.commands_info(), reference_completion=True,
445
+ permission=t.config.get("permission_mode", "workspace-write"),
446
+ network=bool(t.config.get("network_enabled", True)),
447
+ ui_lang=t.config.get("ui_lang", "en"),
448
+ ui_theme=robot._theme_cache or robot._resolve_theme(),
449
+ home_workspace=Path.cwd().resolve() == Path.home().resolve())
450
+
451
+ def persist(self):
452
+ t = self.terminal
453
+ if t.config.get("auto_save_sessions", True):
454
+ t.session_mgr.save_session(t.session_id, t.conversation)
455
+
456
+ async def turn(self, value):
457
+ t = self.terminal
458
+ t._last_turn_envelope = None
459
+ t._last_response = ""
460
+ # Set by the turn when it has already told the user, in their own
461
+ # language, what went wrong; cleared here so one turn's answer is
462
+ # never taken for the next one's.
463
+ t._error_presented = False
464
+ t.cancel_event = asyncio.Event()
465
+ self.emit("turn.started", prompt=value["text"])
466
+ outcome, error = "completed", ""
467
+ try:
468
+ prompt = value["text"]
469
+ if t.commands.is_command(prompt.strip()):
470
+ await t.commands.execute(prompt.strip())
471
+ elif prompt.startswith("!"):
472
+ # User-initiated shell commands still go through the executor's
473
+ # workspace/command policy, rather than bypassing it with shell=True.
474
+ from aria_code.runtime.approval import ApprovalDecision
475
+ result = await asyncio.to_thread(t.tool_executor.execute_local, "run_command",
476
+ {"command": prompt[1:].strip()},
477
+ approval=ApprovalDecision.allow(policy=t.config.get("command_policy", "safe"), user_approved=True))
478
+ self.emit("output.delta", text=json.dumps(result, ensure_ascii=False, default=str))
479
+ t.conversation.append({"role": "user", "content": f"[shell {prompt}]\n{result}"})
480
+ else:
481
+ await t.send_message(prompt, route_text=True)
482
+ envelope = t._last_turn_envelope
483
+ if envelope:
484
+ outcome = "cancelled" if envelope.cancelled else str(envelope.status)
485
+ error = str(envelope.error or "")
486
+ if t._last_response:
487
+ self.emit("answer.replace", text=t._last_response)
488
+ except (asyncio.CancelledError, KeyboardInterrupt):
489
+ outcome = "cancelled"
490
+ except (Exception, SystemExit) as exc:
491
+ outcome, error = "failed", str(exc)
492
+ finally:
493
+ # Cancelling an asyncio Future cannot stop an executor thread.
494
+ # Never accept a next turn while a tool from this one is still
495
+ # running. The native host kills the worker/process group if this
496
+ # boundary cannot settle within its cancellation grace period.
497
+ while True:
498
+ with self.tool_lock:
499
+ busy = self.active_tools
500
+ if not busy:
501
+ break
502
+ await asyncio.sleep(0.01)
503
+ t._streaming = False
504
+ t.cancel_event = None
505
+ try:
506
+ self.persist()
507
+ except Exception as exc:
508
+ outcome, error = "failed", f"Session save failed: {exc}"
509
+ # `error` stays the raw text for scripts and exec mode. `presented`
510
+ # tells a human-facing front end it has already been shown, so it
511
+ # does not print the same failure again under an error heading.
512
+ self.emit("turn.completed", status=outcome, error=error,
513
+ presented=bool(error and getattr(t, "_error_presented", False)),
514
+ session_id=t.session_id)
515
+ self.turn_id = None
516
+ self.snapshot("session.state")
517
+
518
+ async def update_notice(self):
519
+ # Only metadata, after session.ready. Respect the same preference as
520
+ # the old UI; never install software or wait on the check at startup.
521
+ if (os.environ.get("ARIA_OFFLINE", "").lower() in {"1", "true", "yes", "on"}
522
+ or not self.terminal.config.get("check_for_update_on_startup", True)):
523
+ return
524
+ try:
525
+ from aria_code.apps.cli.update_check import start_update_check, get_update_notice
526
+ from rich.text import Text
527
+ start_update_check(self.cli.__version__, lang=self.terminal.config.get("ui_lang", "en"))
528
+ for _ in range(100):
529
+ notice = get_update_notice(wait_ms=0)
530
+ if notice:
531
+ self.emit("update.available", turn_id=None, text=Text.from_markup(notice).plain)
532
+ await self.install_update_quietly()
533
+ return
534
+ await asyncio.sleep(0.1)
535
+ except Exception:
536
+ pass # A metadata failure must not interrupt the user's task.
537
+
538
+ async def install_update_quietly(self):
539
+ """Managed macOS/Linux installs update in the background.
540
+
541
+ Windows presents its PowerShell installer command in the update notice
542
+ instead: replacing the running executable is blocked by Windows file
543
+ locks, so installing there must happen after the user closes Aria.
544
+ """
545
+ if sys.platform == "win32":
546
+ return
547
+ from aria_code.apps.cli import auto_update, updater
548
+ from aria_code.apps.cli.update_check import _install_channel, _newer
549
+
550
+ loop = asyncio.get_running_loop()
551
+ installed = await loop.run_in_executor(
552
+ None,
553
+ lambda: auto_update.install_if_newer(
554
+ self.cli.__version__, _install_channel(), self.terminal.config,
555
+ check=lambda channel: updater.check_update(channel, prefer_native=True),
556
+ install=updater.install_native,
557
+ newer=_newer, app_root=updater._app_root(),
558
+ ),
559
+ )
560
+ if installed:
561
+ zh = self.terminal.config.get("ui_lang", "en") == "zh"
562
+ text = (f"已更新到 {installed} · 重启 Aria 后生效" if zh
563
+ else f"Updated to {installed} · restart Aria to use it")
564
+ self.emit("update.available", turn_id=None, text=text)
565
+
566
+ async def serve(self):
567
+ self.loop = asyncio.get_running_loop()
568
+ threading.Thread(target=self.read_requests, daemon=True).start()
569
+ self.initialize()
570
+ self.background.append(asyncio.create_task(self.update_notice()))
571
+ # Start configured MCP connections without delaying the first frame.
572
+ # Keep the same registration path used by the Python REPL.
573
+ if self.cli._HAS_MCP:
574
+ async def mcp():
575
+ try:
576
+ from aria_code.mcp_client import MCPToolRegistry
577
+ registry = MCPToolRegistry()
578
+ self.terminal._mcp_registry = registry
579
+ results = await registry.start_all()
580
+ if results:
581
+ registry.register_into(self.cli.LOCAL_TOOLS, self.cli.LOCAL_TOOL_SCHEMAS)
582
+ self.cli._mcp_registry = registry
583
+ except Exception:
584
+ pass
585
+ self.background.append(asyncio.create_task(mcp()))
586
+ while not self.stopping.is_set():
587
+ value = await asyncio.to_thread(self.requests.get)
588
+ kind = value.get("type")
589
+ if kind == "shutdown":
590
+ break
591
+ try:
592
+ if self.task and not self.task.done():
593
+ raise ValueError("A turn is already running")
594
+ if kind == "turn.submit":
595
+ text = value.get("text")
596
+ ident = value.get("turn_id")
597
+ if not isinstance(text, str) or not text.strip() or len(text.encode("utf-8")) > MAX_INPUT:
598
+ raise ValueError("Turn text must be 1..65536 UTF-8 bytes")
599
+ if not isinstance(ident, str) or not re.fullmatch(r"[A-Za-z0-9_-]{1,128}", ident):
600
+ raise ValueError("Invalid turn ID")
601
+ self.turn_id = ident
602
+ self.cancel_requested = False
603
+ self.task = asyncio.create_task(self.turn(value))
604
+ elif kind == "session.resume":
605
+ self.switch_session(value.get("session_id", ""))
606
+ elif kind == "session.new":
607
+ self.switch_session()
608
+ else:
609
+ raise ValueError("Unknown application request")
610
+ except (ValueError, OSError, TypeError) as exc:
611
+ self.emit("protocol.error", error=str(exc))
612
+ self.abort()
613
+ if self.task:
614
+ try:
615
+ await self.task
616
+ except (asyncio.CancelledError, KeyboardInterrupt):
617
+ pass
618
+ self.persist()
619
+ for task in self.background:
620
+ task.cancel()
621
+ if self.terminal._mcp_registry:
622
+ await self.terminal._mcp_registry.stop_all()
623
+ from aria_code.runtime.processes import stop_all
624
+ await asyncio.to_thread(stop_all)
625
+ self.end_hooks()
626
+ self.emit("session.closed")
627
+
628
+
629
+ def main():
630
+ parser = argparse.ArgumentParser(description=__doc__)
631
+ parser.add_argument("--model")
632
+ parser.add_argument("--url")
633
+ parser.add_argument("--resume")
634
+ parser.add_argument("--resume-last", action="store_true")
635
+ parser.add_argument("--no-banner", action="store_true")
636
+ parser.add_argument("--banner", choices=["full", "compact", "off"])
637
+ parser.add_argument("--thinking", action="store_true")
638
+ parser.add_argument("--local", action="store_true")
639
+ parser.add_argument("--add-dir", action="append", default=[])
640
+ parser.add_argument("--read-dir", action="append", default=[])
641
+ parser.add_argument("--allow-tools", default="")
642
+ parser.add_argument("--dangerously-skip-permissions", action="store_true")
643
+ options = parser.parse_args()
644
+ incoming, outgoing = sys.stdin.buffer, sys.stdout
645
+ server = Server(incoming, outgoing, options)
646
+ try:
647
+ asyncio.run(server.serve())
648
+ except (BrokenPipeError, KeyboardInterrupt):
649
+ return
650
+ except Exception as exc:
651
+ server.emit("session.failed", error=str(exc))
652
+ raise SystemExit(1) from exc
653
+
654
+
655
+ if __name__ == "__main__":
656
+ main()