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,269 @@
1
+ """The REPL's transaction points: take one before each turn, rewind to any.
2
+
3
+ ``runtime/transactions.py`` stores points; this reads and writes the state a
4
+ point covers, which lives in the terminal and in CLI module globals:
5
+
6
+ * the conversation — ``terminal.conversation``;
7
+ * approvals — ``_auto_approve_session``, ``_session_always_allow`` and
8
+ ``_session_command_prefixes`` in the module the terminal was built in
9
+ (aria_cli rebinds the approval functions onto its own globals, so that copy
10
+ is the one in force, not tool_executor's);
11
+ * the task list — ``aria_code.apps.cli.todo_tracker``, the copy the
12
+ ``update_todos`` tool writes;
13
+ * background tasks — ``runtime.subagent``, the copy the CLI registers;
14
+ * the task worktree — ``apps.cli.task_isolation``.
15
+
16
+ Files are undone first: a conflict there stops the rewind before anything
17
+ else has changed.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import logging
23
+ import sys
24
+ import time
25
+ from dataclasses import dataclass, field
26
+ from pathlib import Path
27
+ from typing import Any, Optional
28
+
29
+ from aria_code.runtime.transactions import (
30
+ TransactionPoint,
31
+ TransactionStore,
32
+ default_transaction_store,
33
+ new_point,
34
+ )
35
+
36
+ logger = logging.getLogger(__name__)
37
+
38
+ _STORE: list[Optional[TransactionStore]] = [None]
39
+
40
+
41
+ def store() -> TransactionStore:
42
+ if _STORE[0] is None:
43
+ _STORE[0] = default_transaction_store()
44
+ return _STORE[0]
45
+
46
+
47
+ def reset_for_tests(replacement: Any = None) -> None:
48
+ _STORE[0] = replacement
49
+
50
+
51
+ def _namespace(terminal: Any) -> dict:
52
+ return vars(sys.modules[type(terminal).__module__])
53
+
54
+
55
+ def _todos():
56
+ from aria_code.apps.cli import todo_tracker
57
+ return todo_tracker
58
+
59
+
60
+ def _checkpoints():
61
+ # The aria_code.* copy, as the write tools record with: a conflict raised
62
+ # from it is the class callers catch.
63
+ from aria_code.runtime.checkpoints import CheckpointStore
64
+ return CheckpointStore()
65
+
66
+
67
+ def _approvals(namespace: dict) -> dict:
68
+ return {
69
+ "allow_all": bool(namespace.get("_auto_approve_session", False)),
70
+ "tools": sorted(namespace.get("_session_always_allow") or ()),
71
+ "prefixes": sorted(list(prefix) for prefix in namespace.get("_session_command_prefixes") or ()),
72
+ }
73
+
74
+
75
+ def _open_task(terminal: Any) -> Optional[dict]:
76
+ try:
77
+ from apps.cli import task_isolation
78
+
79
+ tasks = task_isolation.manager()
80
+ task = tasks.active(task_isolation._workspace(terminal.config))
81
+ if task is None:
82
+ return None
83
+ return {"task_id": task.task_id, "repository": task.repository, "path": task.path,
84
+ "patch": tasks.patch(task)}
85
+ except Exception as exc:
86
+ logger.debug("task state not captured: %s", exc)
87
+ return None
88
+
89
+
90
+ def capture(terminal: Any, prompt: str) -> Optional[TransactionPoint]:
91
+ """Record the state before the turn ``prompt`` starts. Never raises."""
92
+ try:
93
+ session_id = str(getattr(terminal, "session_id", "") or "default")
94
+ turn = sum(1 for message in terminal.conversation if message.get("role") == "user") + 1
95
+ point = new_point(
96
+ session_id=session_id, turn=turn, prompt=prompt,
97
+ messages=list(terminal.conversation),
98
+ todos=list(_todos().get_active_todos()),
99
+ approvals=_approvals(_namespace(terminal)),
100
+ checkpoint_sequence=_checkpoints().max_sequence(),
101
+ verdict=str(getattr(terminal, "_code_verdict", "") or ""),
102
+ task=_open_task(terminal),
103
+ )
104
+ return store().record(point)
105
+ except Exception as exc:
106
+ logger.debug("transaction point not recorded: %s", exc)
107
+ return None
108
+
109
+
110
+ @dataclass
111
+ class RewindOutcome:
112
+ point: TransactionPoint
113
+ restored_paths: tuple = ()
114
+ messages_removed: int = 0
115
+ approvals_revoked: list = field(default_factory=list)
116
+ tasks_cancelled: list = field(default_factory=list)
117
+ task_note: str = ""
118
+
119
+ def lines(self) -> list[str]:
120
+ count = len(self.restored_paths)
121
+ out = [f"Rewound to before turn {self.point.turn}: “{self.point.prompt}”"]
122
+ out.append(f" files {count} restored" if count else " files no changes to undo")
123
+ out.append(f" conversation {self.messages_removed} message{'s' if self.messages_removed != 1 else ''} removed")
124
+ if self.approvals_revoked:
125
+ out.append(f" approvals revoked {', '.join(self.approvals_revoked)}")
126
+ if self.tasks_cancelled:
127
+ out.append(f" background cancelled {', '.join(self.tasks_cancelled)}")
128
+ if self.task_note:
129
+ out.append(f" task {self.task_note}")
130
+ if self.point.verdict:
131
+ out.append(f" checks {self.point.verdict} at this point")
132
+ if self.point.truncated:
133
+ out.append(" note the oldest messages were too large to keep and are not restored")
134
+ return out
135
+
136
+
137
+ def _worktree_skip(terminal: Any):
138
+ """Files in task worktrees are restored as a whole, not file by file.
139
+
140
+ A worktree still open is reset to the point's patch (which also undoes
141
+ what shell commands changed, which no file checkpoint records); one that
142
+ is gone has nowhere to be restored to and is reopened from the patch.
143
+ The user's own files still go back by checkpoint.
144
+ """
145
+ try:
146
+ from apps.cli import task_isolation
147
+ root = task_isolation.manager().root.resolve()
148
+ except Exception:
149
+ return lambda _path: False
150
+
151
+ def skip(path: str) -> bool:
152
+ try:
153
+ Path(path).resolve().relative_to(root)
154
+ return True
155
+ except (ValueError, OSError):
156
+ return False
157
+
158
+ return skip
159
+
160
+
161
+ def _settle_open_task(terminal: Any, point: TransactionPoint) -> str:
162
+ """The task open now, put back to what it was at ``point``."""
163
+ try:
164
+ from apps.cli import task_isolation
165
+
166
+ tasks = task_isolation.manager()
167
+ current = tasks.active(task_isolation._workspace(terminal.config))
168
+ except Exception as exc:
169
+ logger.debug("task state not restored: %s", exc)
170
+ return ""
171
+ if current is None:
172
+ return ""
173
+ saved = point.task or {}
174
+ if saved.get("path") == current.path:
175
+ tasks.reset_to_patch(current, str(saved.get("patch") or ""))
176
+ return "worktree reset to this point" if str(saved.get("patch") or "").strip() else ""
177
+ if current.created_at > point.created_at:
178
+ tasks.discard(current)
179
+ return f"discarded {current.task_id}, started after this point"
180
+ return ""
181
+
182
+
183
+ def _restore_task(terminal: Any, point: TransactionPoint) -> str:
184
+ saved = point.task
185
+ if not saved or not str(saved.get("patch") or "").strip():
186
+ return ""
187
+ if Path(saved["path"]).is_dir():
188
+ return "" # still open: its files were restored with the rest
189
+ from apps.cli import task_isolation
190
+
191
+ tasks = task_isolation.manager()
192
+ try:
193
+ task = tasks.ensure(task_isolation._workspace(terminal.config))
194
+ if task is None:
195
+ raise RuntimeError("not a git repository")
196
+ tasks.restore_patch(task, saved["patch"])
197
+ return f"reopened as {task.task_id} with its unapplied changes"
198
+ except Exception as exc:
199
+ keep = Path(tasks.root) / f"rewound-{saved['task_id']}.patch"
200
+ keep.parent.mkdir(parents=True, exist_ok=True)
201
+ keep.write_text(saved["patch"], encoding="utf-8")
202
+ return f"could not be reopened ({exc}); its changes are saved in {keep}"
203
+
204
+
205
+ def _cancel_later_tasks(terminal: Any, point: TransactionPoint) -> list[str]:
206
+ try:
207
+ from runtime.subagent import _TASKS, tool_task_cancel
208
+ except Exception:
209
+ return []
210
+ session_id = str(getattr(terminal, "session_id", "") or "")
211
+ cancelled = []
212
+ for task in list(_TASKS.values()):
213
+ if task.created_at <= point.created_at or task.status not in ("pending", "running"):
214
+ continue
215
+ if task.session_id and session_id and task.session_id != session_id:
216
+ continue
217
+ if tool_task_cancel({"task_id": task.task_id}).get("success"):
218
+ cancelled.append(task.task_id)
219
+ return cancelled
220
+
221
+
222
+ def rewind(terminal: Any, point: TransactionPoint) -> RewindOutcome:
223
+ """Put the session back to ``point``. Raises if files cannot be restored."""
224
+ session_id = str(getattr(terminal, "session_id", "") or "default")
225
+ files = _checkpoints().restore_since(point.checkpoint_sequence, session_id=session_id,
226
+ skip=_worktree_skip(terminal))
227
+ outcome = RewindOutcome(point=point, restored_paths=files.restored_paths)
228
+ notes = [_settle_open_task(terminal, point), _restore_task(terminal, point)]
229
+ outcome.task_note = "; ".join(note for note in notes if note)
230
+
231
+ outcome.messages_removed = max(0, len(terminal.conversation) - len(point.messages))
232
+ terminal.conversation[:] = list(point.messages)
233
+
234
+ todos = _todos()
235
+ todos._ACTIVE_TODOS[:] = list(point.todos)
236
+
237
+ namespace = _namespace(terminal)
238
+ before = _approvals(namespace)
239
+ saved = point.approvals or {}
240
+ namespace["_auto_approve_session"] = bool(saved.get("allow_all", False))
241
+ for key, values in (("_session_always_allow", saved.get("tools") or ()),
242
+ ("_session_command_prefixes", [tuple(p) for p in saved.get("prefixes") or ()])):
243
+ current = namespace.get(key)
244
+ if isinstance(current, set):
245
+ current.clear()
246
+ current.update(values)
247
+ revoked = [tool for tool in before["tools"] if tool not in (saved.get("tools") or ())]
248
+ revoked += [" ".join(prefix) for prefix in before["prefixes"] if prefix not in (saved.get("prefixes") or [])]
249
+ if before["allow_all"] and not saved.get("allow_all"):
250
+ revoked.insert(0, "allow-all")
251
+ outcome.approvals_revoked = revoked
252
+
253
+ outcome.tasks_cancelled = _cancel_later_tasks(terminal, point)
254
+ terminal._code_verdict = point.verdict
255
+ store().drop_from(point)
256
+ return outcome
257
+
258
+
259
+ def describe(points: list[TransactionPoint], *, now: Optional[float] = None) -> list[str]:
260
+ """``/rewind turns``: newest first, numbered as ``/rewind turn N`` takes them."""
261
+ now = now or time.time()
262
+ marks = {"passed": "✓", "failed": "✗", "preexisting": "≈", "unverified": "·", "": " "}
263
+ lines = []
264
+ for index, point in enumerate(points, 1):
265
+ age = now - point.created_at
266
+ when = f"{int(age)}s" if age < 60 else f"{int(age // 60)}m" if age < 3600 else f"{age / 3600:.1f}h"
267
+ lines.append(f" {index:>2} {point.point_id[:8]} {marks.get(point.verdict, ' ')} "
268
+ f"{when:>5} ago before turn {point.turn}: {point.prompt[:60]}")
269
+ return lines
@@ -0,0 +1,137 @@
1
+ """Per-turn planning DECISIONS for send_message (pure, testable).
2
+
3
+ Extracted from ``aria_cli.send_message`` — the first slice of the file's
4
+ 1300+ line stateful method to be pulled out. This module holds only the
5
+ *decision* logic (round budget, whether to trigger AI decomposition), which
6
+ depends solely on the user's message text and has no I/O, no ``self`` state,
7
+ and no side effects. It is safe to unit-test in isolation and safe to extract
8
+ without any behavior change, unlike the surrounding streaming/tool-loop code.
9
+
10
+ Mirrors send_message's inline logic exactly:
11
+ • task complexity → message > 120 chars, or contains a multi-step keyword
12
+ • round budget → complex tasks get a larger soft/hard round budget
13
+ • decomposition → long (>150 char), complex, non-slash-command messages
14
+ trigger an upfront AI decomposition pass
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ TASK_COMPLEXITY_LENGTH_THRESHOLD = 120
20
+
21
+ TASK_COMPLEXITY_KEYWORDS = (
22
+ "然后", "接着", "最后", "步骤", "并且", "同时",
23
+ "and then", "step", "finally", "after that", "next",
24
+ "完整", "全面", "详细", "系统", "comprehensive", "complete",
25
+ )
26
+
27
+ DECOMP_THRESHOLD = 150 # chars
28
+
29
+ SOFT_ROUND_BUDGET_SIMPLE = 16
30
+ SOFT_ROUND_BUDGET_COMPLEX = 30
31
+ HARD_ROUND_EXTENSION_SIMPLE = 10
32
+ HARD_ROUND_EXTENSION_COMPLEX = 20
33
+
34
+
35
+ def is_complex_task(message: str) -> bool:
36
+ """A message is 'complex' if it's long or names a multi-step structure."""
37
+ return (
38
+ len(message) > TASK_COMPLEXITY_LENGTH_THRESHOLD
39
+ or any(kw in message for kw in TASK_COMPLEXITY_KEYWORDS)
40
+ )
41
+
42
+
43
+ def round_budget_for(is_complex: bool) -> tuple[int, int]:
44
+ """-> (max_rounds, hard_max_rounds). Complex tasks get a larger budget
45
+ on both the soft limit (where we start checking for real progress) and
46
+ the hard extension (how far a still-progressing task can run past it)."""
47
+ max_rounds = SOFT_ROUND_BUDGET_COMPLEX if is_complex else SOFT_ROUND_BUDGET_SIMPLE
48
+ hard_max_rounds = max_rounds + (
49
+ HARD_ROUND_EXTENSION_COMPLEX if is_complex else HARD_ROUND_EXTENSION_SIMPLE
50
+ )
51
+ return max_rounds, hard_max_rounds
52
+
53
+
54
+ def should_decompose(message: str, is_complex: bool) -> bool:
55
+ """Trigger an upfront AI decomposition pass for long, complex, non-slash
56
+ messages. Slash commands (``/...``) and bang commands (``!...``) are never
57
+ decomposed — they're already a single deterministic action."""
58
+ return (
59
+ len(message) > DECOMP_THRESHOLD
60
+ and is_complex
61
+ and not any(message.startswith(p) for p in ("/", "!"))
62
+ )
63
+
64
+
65
+ # ── post-turn context pressure ───────────────────────────────────────────────
66
+ # send_message had three separate places that decide whether history is too hot
67
+ # to carry into the next turn, and they disagreed. The usage-driven one (real
68
+ # provider prompt_tokens) and the pre-turn one both honour auto_compact_context
69
+ # and auto_compact_threshold; the post-turn char-estimate one honoured neither
70
+ # and hardcoded 90% compact / 70% warn. So `/config set
71
+ # auto_compact_context=false` did not turn auto-compaction off — /status said
72
+ # "auto compact off" while the third path still compacted — and a threshold of
73
+ # 0.95 was capped at the hidden 0.90.
74
+ #
75
+ # Warning is deliberately NOT gated on the toggle. Turning auto-compaction off
76
+ # means "do not rewrite my history", not "stop telling me how full it is" —
77
+ # and it is precisely the user who disabled compaction who needs to be told to
78
+ # run /compact.
79
+
80
+ CONTEXT_WARN_FRACTION = 0.70
81
+ CHARS_PER_TOKEN_ESTIMATE = 3
82
+ DEFAULT_COMPACT_THRESHOLD = 0.78
83
+ MIN_COMPACT_THRESHOLD = 0.50
84
+ MAX_COMPACT_THRESHOLD = 0.95
85
+
86
+
87
+ def estimate_context_tokens(conversation: list) -> int:
88
+ """Rough token count for a conversation, by characters."""
89
+ return sum(
90
+ len(m.get("content", "") or "") for m in (conversation or [])
91
+ ) // CHARS_PER_TOKEN_ESTIMATE
92
+
93
+
94
+ def clamp_compact_threshold(value) -> float:
95
+ """Config threshold as a fraction, clamped to the range /config accepts."""
96
+ try:
97
+ threshold = float(value)
98
+ except (TypeError, ValueError):
99
+ return DEFAULT_COMPACT_THRESHOLD
100
+ return max(MIN_COMPACT_THRESHOLD, min(MAX_COMPACT_THRESHOLD, threshold))
101
+
102
+
103
+ def post_turn_context_decision(
104
+ used_tokens: int,
105
+ max_tokens: int,
106
+ *,
107
+ auto_compact_enabled: bool = True,
108
+ threshold=DEFAULT_COMPACT_THRESHOLD,
109
+ already_compacted: bool = False,
110
+ ) -> dict:
111
+ """-> {"fill_pct", "should_compact", "should_warn"}.
112
+
113
+ ``already_compacted`` is the usage-driven path having fired this turn; it
114
+ suppresses both outcomes so one turn never compacts twice or warns about a
115
+ figure it just fixed.
116
+ """
117
+ if max_tokens <= 0:
118
+ return {"fill_pct": 0, "should_compact": False, "should_warn": False}
119
+
120
+ fill_pct = min(100, int(used_tokens / max_tokens * 100))
121
+ limit_pct = clamp_compact_threshold(threshold) * 100
122
+
123
+ should_compact = (
124
+ bool(auto_compact_enabled)
125
+ and not already_compacted
126
+ and fill_pct >= limit_pct
127
+ )
128
+ should_warn = (
129
+ not should_compact
130
+ and not already_compacted
131
+ and fill_pct >= CONTEXT_WARN_FRACTION * 100
132
+ )
133
+ return {
134
+ "fill_pct": fill_pct,
135
+ "should_compact": should_compact,
136
+ "should_warn": should_warn,
137
+ }
@@ -0,0 +1,257 @@
1
+ """Background version checker for the active Aria Code install channel.
2
+
3
+ Checks GitHub releases or scoped npm once per 24 hours in a daemon thread so
4
+ startup is never blocked. The result is cached in the Aria home directory and read
5
+ at banner render time.
6
+
7
+ Public API
8
+ ----------
9
+ start_update_check(current_version: str) -> None
10
+ Call once, early in startup. Spawns daemon thread; returns immediately.
11
+
12
+ get_update_notice() -> str | None
13
+ Call at banner render time. Returns a Rich-markup string if a newer
14
+ version is available, otherwise None. Thread-safe — safe to call
15
+ before the background thread finishes (returns cached result then).
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ import os
21
+ import subprocess
22
+ import sys
23
+ import threading
24
+ import time
25
+ from pathlib import Path
26
+ from typing import Optional
27
+ from aria_code.packages.aria_core.paths import aria_home
28
+
29
+ _RELEASE_URL = "https://api.github.com/repos/artheras/aria-code/releases/latest"
30
+ _NPM_URL = "https://registry.npmjs.org/@artheras%2Faria-code/latest"
31
+ _CACHE_FILE = aria_home() / "update_check.json"
32
+ _CACHE_TTL_S = 86_400 # 24 hours
33
+ _FETCH_TIMEOUT = 4 # seconds — fail cleanly on slow networks
34
+
35
+ # These are the project's historical PyPI releases (June–August 2026),
36
+ # published before the current 0.x line. Do not treat arbitrary future 4.x
37
+ # versions as legacy, or recommend these old artifacts to a current install.
38
+ _LEGACY_VERSIONS = frozenset({
39
+ (4, 1, 3), (4, 1, 4), (4, 1, 7), (4, 2, 0),
40
+ (4, 3, 0), (4, 4, 0), (4, 4, 1), (4, 4, 2),
41
+ })
42
+
43
+ _notice: Optional[str] = None
44
+ _lock = threading.Lock()
45
+
46
+
47
+ # ── Version comparison ────────────────────────────────────────────────────────
48
+
49
+ def _parse(v: str) -> tuple[int, int, int] | None:
50
+ """Accept only stable project release tags, never another package's version."""
51
+ import re
52
+ match = re.fullmatch(r"v?(\d+)\.(\d+)\.(\d+)", v.strip())
53
+ return tuple(map(int, match.groups())) if match else None
54
+
55
+
56
+ def _newer(latest: str, current: str) -> bool:
57
+ parsed_latest, parsed_current = _parse(latest), _parse(current)
58
+ if parsed_latest is None or parsed_current is None:
59
+ return False
60
+ if parsed_current in _LEGACY_VERSIONS and parsed_latest[0] == 0:
61
+ return True
62
+ if parsed_latest in _LEGACY_VERSIONS and parsed_current[0] == 0:
63
+ return False
64
+ return parsed_latest > parsed_current
65
+
66
+
67
+ # ── Cache helpers ─────────────────────────────────────────────────────────────
68
+
69
+ def _read_cache() -> dict:
70
+ try:
71
+ return json.loads(_CACHE_FILE.read_text())
72
+ except Exception:
73
+ return {}
74
+
75
+
76
+ def _write_cache(data: dict) -> None:
77
+ try:
78
+ _CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
79
+ _CACHE_FILE.write_text(json.dumps(data))
80
+ except Exception:
81
+ pass
82
+
83
+
84
+ # ── Notice builder ────────────────────────────────────────────────────────────
85
+
86
+ def _install_channel() -> str:
87
+ """Infer which update channel owns the running executable."""
88
+ override = os.environ.get("ARIA_CODE_INSTALL_CHANNEL", "").lower()
89
+ if override in ("npm", "native", "pip", "source"):
90
+ return override
91
+ executable = str(getattr(sys, "executable", "") or "").lower()
92
+ if "node_modules" in executable and "aria" in executable:
93
+ return "npm"
94
+ if getattr(sys, "frozen", False):
95
+ return "native"
96
+ root = Path(__file__).resolve().parents[4]
97
+ if (root / ".git").exists() and (root / "pyproject.toml").exists():
98
+ return "source"
99
+ return "pip"
100
+
101
+
102
+ def _update_command(channel: str, latest: str = "") -> str:
103
+ if channel == "npm":
104
+ return "npm install -g @artheras/aria-code@latest"
105
+ if channel == "source":
106
+ return "git pull && python3 -m pip install -e ."
107
+ if channel == "pip":
108
+ # Pinned: PyPI still lists an older 4.x numbering, so an unpinned
109
+ # --upgrade "updates" 0.73.0 to 4.4.2, which is older code.
110
+ return f'python3 -m pip install --upgrade "aria-code=={latest}"' if latest else \
111
+ 'python3 -m pip install --upgrade "aria-code<4"'
112
+ if sys.platform == "win32":
113
+ return "irm https://raw.githubusercontent.com/artheras/aria-code/main/scripts/install.ps1 | iex"
114
+ return "curl -fsSL https://raw.githubusercontent.com/artheras/aria-code/main/scripts/install.sh | sh"
115
+
116
+
117
+ def _build_notice(latest: str, current: str, lang: str, channel: str = "native") -> str:
118
+ latest = latest.removeprefix("v")
119
+ current = current.removeprefix("v")
120
+ cmd = _update_command(channel, latest) if channel == "source" or (channel == "native" and sys.platform == "win32") else "aria update"
121
+ if lang == "zh":
122
+ return (
123
+ f"[yellow]⬆ 新版本可用[/yellow] "
124
+ f"[dim]v{current}[/dim] [dim]→[/dim] [bold]v{latest}[/bold]"
125
+ f" [dim]{cmd}[/dim]"
126
+ )
127
+ return (
128
+ f"[yellow]⬆ Update available[/yellow] "
129
+ f"[dim]v{current}[/dim] [dim]→[/dim] [bold]v{latest}[/bold]"
130
+ f" [dim]{cmd}[/dim]"
131
+ )
132
+
133
+
134
+ # ── Background worker ─────────────────────────────────────────────────────────
135
+
136
+ def _worker(current: str, lang: str, channel: str = "native") -> None:
137
+ global _notice
138
+ # GitHub releases are the version of record for every channel but npm.
139
+ # PyPI's own "latest" is not: it still points at the old 4.x line.
140
+ source_url, version_field = (_NPM_URL, "version") if channel == "npm" else (_RELEASE_URL, "tag_name")
141
+
142
+ # 1. Serve from cache if still fresh
143
+ cache = _read_cache()
144
+ now = time.time()
145
+ if cache.get("source") == source_url and cache.get("checked_at", 0) + _CACHE_TTL_S > now:
146
+ latest = cache.get("latest", "")
147
+ if latest and _newer(latest, current):
148
+ with _lock:
149
+ _notice = _build_notice(latest, current, lang, channel)
150
+ return
151
+
152
+ # 2. Fetch metadata for this installation channel, never a similarly named package.
153
+ latest = _native_latest(current, channel)
154
+ if latest is None:
155
+ try:
156
+ import urllib.request
157
+ req = urllib.request.Request(
158
+ source_url,
159
+ headers={"Accept": "application/json", "User-Agent": "aria-code-update-check"},
160
+ )
161
+ with urllib.request.urlopen(req, timeout=_FETCH_TIMEOUT) as resp:
162
+ data = json.loads(resp.read())
163
+ latest = data[version_field]
164
+ except Exception:
165
+ return # background checks never interrupt the user's work
166
+
167
+ # 3. Persist to cache
168
+ if _parse(latest) is None:
169
+ return
170
+ _write_cache({"source": source_url, "checked_at": now, "latest": latest})
171
+
172
+ # 4. Set notice
173
+ if _newer(latest, current):
174
+ with _lock:
175
+ _notice = _build_notice(latest, current, lang, channel)
176
+
177
+
178
+ def _native_latest(current: str, channel: str) -> str | None:
179
+ """Ask the bundled Rust updater to validate/cache release metadata.
180
+
181
+ Return None when the helper is unavailable or incompatible so older
182
+ packages and Windows keep their established Python check path.
183
+ """
184
+ payload = _native_check(current, channel)
185
+ latest = payload.get("latest") if payload else None
186
+ return latest.removeprefix("v") if isinstance(latest, str) and _parse(latest) else None
187
+
188
+
189
+ def _native_check(current: str, channel: str, *, refresh: bool = False) -> dict | None:
190
+ """Return checked metadata from the bundled Rust updater, if available."""
191
+ try:
192
+ # Lazy import avoids a module cycle: updater imports this module's
193
+ # release constants and version helpers.
194
+ from aria_code.apps.cli.updater import _native_update_helper
195
+
196
+ helper = _native_update_helper()
197
+ if helper is None:
198
+ return None
199
+ command = [str(helper), "update", "check", "--current", current, "--channel", channel]
200
+ if refresh:
201
+ command.append("--refresh")
202
+ result = subprocess.run(
203
+ command,
204
+ capture_output=True,
205
+ text=True,
206
+ timeout=_FETCH_TIMEOUT + 2,
207
+ check=False,
208
+ )
209
+ if result.returncode != 0:
210
+ return None
211
+ payload = json.loads(result.stdout)
212
+ return payload if isinstance(payload, dict) else None
213
+ except Exception:
214
+ return None
215
+
216
+
217
+ # ── Public API ────────────────────────────────────────────────────────────────
218
+
219
+ def start_update_check(current_version: str, lang: str = "en", enabled: bool = True) -> None:
220
+ """Start background version check. Call once, early in startup."""
221
+ global _notice
222
+ with _lock:
223
+ _notice = None
224
+ if not enabled:
225
+ return
226
+ channel = _install_channel()
227
+ source = _NPM_URL if channel == "npm" else _RELEASE_URL
228
+ cache = _read_cache()
229
+ if cache.get("source") == source and _newer(cache.get("latest", ""), current_version):
230
+ with _lock:
231
+ _notice = _build_notice(cache["latest"], current_version, lang, channel)
232
+ t = threading.Thread(
233
+ target=_worker,
234
+ args=(current_version, lang, channel),
235
+ daemon=True,
236
+ name="aria-update-check",
237
+ )
238
+ t.start()
239
+
240
+
241
+ def get_update_notice(wait_ms: int = 0) -> Optional[str]:
242
+ """Return Rich-markup update notice, or None if up to date / not yet known.
243
+
244
+ Read the cached notice immediately. An explicit wait is supported for
245
+ callers outside startup, but startup never waits for a network request.
246
+ """
247
+ deadline = time.monotonic() + wait_ms / 1000
248
+ while time.monotonic() < deadline:
249
+ with _lock:
250
+ if _notice is not None:
251
+ return _notice
252
+ alive = any(t.name == "aria-update-check" for t in threading.enumerate())
253
+ if not alive:
254
+ break
255
+ time.sleep(0.05)
256
+ with _lock:
257
+ return _notice