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,481 @@
1
+ """Durable, conflict-aware file checkpoints for agent write operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import os
8
+ import sqlite3
9
+ import stat
10
+ import time
11
+ import uuid
12
+ from dataclasses import dataclass, field, replace
13
+ from pathlib import Path
14
+ from typing import Any, Callable, Dict, Iterable, Optional
15
+
16
+ from .run_store import RunStore
17
+
18
+
19
+ def _sha256(content: str) -> str:
20
+ return hashlib.sha256(content.encode("utf-8", errors="replace")).hexdigest()
21
+
22
+
23
+ def _json_dumps(value: Any) -> str:
24
+ return json.dumps(value, ensure_ascii=False, default=str, separators=(",", ":"))
25
+
26
+
27
+ def _json_loads(value: str | None) -> Dict[str, Any]:
28
+ if not value:
29
+ return {}
30
+ try:
31
+ loaded = json.loads(value)
32
+ return loaded if isinstance(loaded, dict) else {"value": loaded}
33
+ except (TypeError, json.JSONDecodeError):
34
+ return {}
35
+
36
+
37
+ @dataclass(frozen=True)
38
+ class CheckpointFile:
39
+ checkpoint_id: str
40
+ path: str
41
+ existed_before: bool
42
+ before_content: str
43
+ after_content: str
44
+ before_hash: str
45
+ after_hash: str
46
+ before_mode: Optional[int]
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class CheckpointRecord:
51
+ checkpoint_id: str
52
+ sequence: int
53
+ run_id: Optional[str]
54
+ session_id: str
55
+ source: str
56
+ label: str
57
+ status: str
58
+ created_at: float
59
+ restored_at: Optional[float]
60
+ metadata: Dict[str, Any] = field(default_factory=dict)
61
+ files: tuple[CheckpointFile, ...] = ()
62
+
63
+
64
+ @dataclass(frozen=True)
65
+ class RestoreResult:
66
+ checkpoint_ids: tuple[str, ...]
67
+ run_id: Optional[str]
68
+ restored_paths: tuple[str, ...]
69
+
70
+
71
+ class CheckpointNotFoundError(KeyError):
72
+ """Raised when a checkpoint or checkpoint group cannot be found."""
73
+
74
+
75
+ class CheckpointConflictError(RuntimeError):
76
+ """Raised when a file changed after the checkpoint was recorded."""
77
+
78
+
79
+ class CheckpointStore:
80
+ """Store file pre-images and restore them only when hashes still match."""
81
+
82
+ def __init__(self, database_path: Path | str | None = None) -> None:
83
+ self.run_store = RunStore(database_path)
84
+ self.database_path = self.run_store.database_path
85
+ self._initialize()
86
+
87
+ def _connect(self) -> sqlite3.Connection:
88
+ connection = sqlite3.connect(str(self.database_path), timeout=10.0)
89
+ connection.row_factory = sqlite3.Row
90
+ connection.execute("PRAGMA foreign_keys = ON")
91
+ connection.execute("PRAGMA busy_timeout = 10000")
92
+ return connection
93
+
94
+ def _initialize(self) -> None:
95
+ with self._connect() as connection:
96
+ connection.executescript(
97
+ """
98
+ CREATE TABLE IF NOT EXISTS checkpoints (
99
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
100
+ checkpoint_id TEXT NOT NULL UNIQUE,
101
+ run_id TEXT,
102
+ session_id TEXT NOT NULL DEFAULT '',
103
+ source TEXT NOT NULL,
104
+ label TEXT NOT NULL DEFAULT '',
105
+ status TEXT NOT NULL DEFAULT 'active',
106
+ created_at REAL NOT NULL,
107
+ restored_at REAL,
108
+ metadata_json TEXT NOT NULL DEFAULT '{}',
109
+ FOREIGN KEY(run_id) REFERENCES runs(run_id)
110
+ );
111
+
112
+ CREATE TABLE IF NOT EXISTS checkpoint_files (
113
+ checkpoint_id TEXT NOT NULL,
114
+ path TEXT NOT NULL,
115
+ existed_before INTEGER NOT NULL,
116
+ before_content TEXT NOT NULL,
117
+ after_content TEXT NOT NULL,
118
+ before_hash TEXT NOT NULL,
119
+ after_hash TEXT NOT NULL,
120
+ before_mode INTEGER,
121
+ PRIMARY KEY(checkpoint_id, path),
122
+ FOREIGN KEY(checkpoint_id)
123
+ REFERENCES checkpoints(checkpoint_id) ON DELETE CASCADE
124
+ );
125
+
126
+ CREATE INDEX IF NOT EXISTS idx_checkpoints_run_sequence
127
+ ON checkpoints(run_id, sequence DESC);
128
+ CREATE INDEX IF NOT EXISTS idx_checkpoints_session_sequence
129
+ ON checkpoints(session_id, sequence DESC);
130
+ CREATE INDEX IF NOT EXISTS idx_checkpoints_status_sequence
131
+ ON checkpoints(status, sequence DESC);
132
+ """
133
+ )
134
+
135
+ @staticmethod
136
+ def _row_to_file(row: sqlite3.Row) -> CheckpointFile:
137
+ return CheckpointFile(
138
+ checkpoint_id=row["checkpoint_id"],
139
+ path=row["path"],
140
+ existed_before=bool(row["existed_before"]),
141
+ before_content=row["before_content"],
142
+ after_content=row["after_content"],
143
+ before_hash=row["before_hash"],
144
+ after_hash=row["after_hash"],
145
+ before_mode=int(row["before_mode"]) if row["before_mode"] is not None else None,
146
+ )
147
+
148
+ def _row_to_checkpoint(
149
+ self,
150
+ connection: sqlite3.Connection,
151
+ row: sqlite3.Row,
152
+ ) -> CheckpointRecord:
153
+ file_rows = connection.execute(
154
+ "SELECT * FROM checkpoint_files WHERE checkpoint_id = ? ORDER BY path",
155
+ (row["checkpoint_id"],),
156
+ ).fetchall()
157
+ return CheckpointRecord(
158
+ checkpoint_id=row["checkpoint_id"],
159
+ sequence=int(row["sequence"]),
160
+ run_id=row["run_id"],
161
+ session_id=row["session_id"],
162
+ source=row["source"],
163
+ label=row["label"],
164
+ status=row["status"],
165
+ created_at=float(row["created_at"]),
166
+ restored_at=float(row["restored_at"]) if row["restored_at"] is not None else None,
167
+ metadata=_json_loads(row["metadata_json"]),
168
+ files=tuple(self._row_to_file(file_row) for file_row in file_rows),
169
+ )
170
+
171
+ def record_change(
172
+ self,
173
+ *,
174
+ path: Path | str,
175
+ before_content: str,
176
+ after_content: str,
177
+ existed_before: bool,
178
+ source: str,
179
+ run_id: str | None = None,
180
+ session_id: str = "",
181
+ before_mode: int | None = None,
182
+ label: str = "",
183
+ metadata: Dict[str, Any] | None = None,
184
+ ) -> CheckpointRecord:
185
+ target = Path(path).expanduser().resolve()
186
+ if not target.is_file():
187
+ raise CheckpointConflictError(f"Written file is missing: {target}")
188
+ current = target.read_text(encoding="utf-8", errors="replace")
189
+ after_hash = _sha256(after_content)
190
+ if _sha256(current) != after_hash:
191
+ raise CheckpointConflictError(
192
+ f"File changed before checkpoint could be recorded: {target}"
193
+ )
194
+ if run_id and self.run_store.get_run(run_id) is None:
195
+ raise CheckpointNotFoundError(f"Unknown run id: {run_id}")
196
+
197
+ checkpoint_id = uuid.uuid4().hex[:16]
198
+ created_at = time.time()
199
+ mode = before_mode
200
+ if existed_before and mode is None:
201
+ mode = stat.S_IMODE(target.stat().st_mode)
202
+ with self._connect() as connection:
203
+ connection.execute("BEGIN IMMEDIATE")
204
+ connection.execute(
205
+ """INSERT INTO checkpoints
206
+ (checkpoint_id, run_id, session_id, source, label, status,
207
+ created_at, restored_at, metadata_json)
208
+ VALUES (?, ?, ?, ?, ?, 'active', ?, NULL, ?)""",
209
+ (
210
+ checkpoint_id,
211
+ run_id,
212
+ session_id,
213
+ source,
214
+ label,
215
+ created_at,
216
+ _json_dumps(metadata or {}),
217
+ ),
218
+ )
219
+ connection.execute(
220
+ """INSERT INTO checkpoint_files
221
+ (checkpoint_id, path, existed_before, before_content,
222
+ after_content, before_hash, after_hash, before_mode)
223
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
224
+ (
225
+ checkpoint_id,
226
+ str(target),
227
+ int(existed_before),
228
+ before_content,
229
+ after_content,
230
+ _sha256(before_content),
231
+ after_hash,
232
+ mode,
233
+ ),
234
+ )
235
+ row = connection.execute(
236
+ "SELECT * FROM checkpoints WHERE checkpoint_id = ?",
237
+ (checkpoint_id,),
238
+ ).fetchone()
239
+
240
+ if run_id:
241
+ self.run_store.append_event(run_id, "checkpoint_created", {
242
+ "checkpoint_id": checkpoint_id,
243
+ "path": str(target),
244
+ "source": source,
245
+ })
246
+ assert row is not None
247
+ with self._connect() as connection:
248
+ return self._row_to_checkpoint(connection, row)
249
+
250
+ def get(self, checkpoint_id: str) -> Optional[CheckpointRecord]:
251
+ key = (checkpoint_id or "").strip()
252
+ with self._connect() as connection:
253
+ row = connection.execute(
254
+ "SELECT * FROM checkpoints WHERE checkpoint_id = ?",
255
+ (key,),
256
+ ).fetchone()
257
+ if row is None and key:
258
+ rows = connection.execute(
259
+ "SELECT * FROM checkpoints WHERE checkpoint_id LIKE ? ORDER BY sequence DESC LIMIT 2",
260
+ (f"{key}%",),
261
+ ).fetchall()
262
+ row = rows[0] if len(rows) == 1 else None
263
+ return self._row_to_checkpoint(connection, row) if row is not None else None
264
+
265
+ def list(
266
+ self,
267
+ *,
268
+ run_id: str | None = None,
269
+ session_id: str | None = None,
270
+ status: str | None = "active",
271
+ limit: int = 50,
272
+ ) -> list[CheckpointRecord]:
273
+ clauses = []
274
+ values: list[Any] = []
275
+ if run_id:
276
+ clauses.append("run_id = ?")
277
+ values.append(run_id)
278
+ if session_id:
279
+ clauses.append("session_id = ?")
280
+ values.append(session_id)
281
+ if status:
282
+ clauses.append("status = ?")
283
+ values.append(status)
284
+ where = f" WHERE {' AND '.join(clauses)}" if clauses else ""
285
+ values.append(max(1, int(limit)))
286
+ with self._connect() as connection:
287
+ rows = connection.execute(
288
+ f"SELECT * FROM checkpoints{where} ORDER BY sequence DESC LIMIT ?",
289
+ values,
290
+ ).fetchall()
291
+ return [self._row_to_checkpoint(connection, row) for row in rows]
292
+
293
+ def latest_run_id(self, *, session_id: str | None = None) -> Optional[str]:
294
+ clauses = ["status = 'active'", "run_id IS NOT NULL"]
295
+ values: list[Any] = []
296
+ if session_id:
297
+ clauses.append("session_id = ?")
298
+ values.append(session_id)
299
+ with self._connect() as connection:
300
+ row = connection.execute(
301
+ f"SELECT run_id FROM checkpoints WHERE {' AND '.join(clauses)} "
302
+ "ORDER BY sequence DESC LIMIT 1",
303
+ values,
304
+ ).fetchone()
305
+ return row["run_id"] if row is not None else None
306
+
307
+ @staticmethod
308
+ def _snapshot(path: Path) -> tuple[bool, str, Optional[int]]:
309
+ if not path.exists():
310
+ return False, "", None
311
+ if not path.is_file():
312
+ raise CheckpointConflictError(f"Checkpoint path is not a file: {path}")
313
+ return (
314
+ True,
315
+ path.read_text(encoding="utf-8", errors="replace"),
316
+ stat.S_IMODE(path.stat().st_mode),
317
+ )
318
+
319
+ @staticmethod
320
+ def _write_atomic(path: Path, content: str, mode: int | None) -> None:
321
+ path.parent.mkdir(parents=True, exist_ok=True)
322
+ temporary = path.with_name(f".{path.name}.aria-rewind-{uuid.uuid4().hex[:8]}")
323
+ try:
324
+ temporary.write_text(content, encoding="utf-8")
325
+ if mode is not None:
326
+ temporary.chmod(mode)
327
+ os.replace(temporary, path)
328
+ finally:
329
+ if temporary.exists():
330
+ temporary.unlink()
331
+
332
+ def _restore(self, checkpoints: Iterable[CheckpointRecord]) -> RestoreResult:
333
+ records = list(checkpoints)
334
+ if not records:
335
+ raise CheckpointNotFoundError("No active checkpoints to restore")
336
+ files = [file for record in records for file in record.files]
337
+ if not files:
338
+ raise CheckpointNotFoundError("Checkpoint contains no files")
339
+
340
+ simulated: Dict[str, tuple[bool, str]] = {}
341
+ backups: Dict[str, tuple[bool, str, Optional[int]]] = {}
342
+ for file in files:
343
+ path = Path(file.path)
344
+ if file.path not in simulated:
345
+ exists, content, mode = self._snapshot(path)
346
+ backups[file.path] = (exists, content, mode)
347
+ simulated[file.path] = (exists, _sha256(content))
348
+ exists, current_hash = simulated[file.path]
349
+ if not exists or current_hash != file.after_hash:
350
+ raise CheckpointConflictError(
351
+ f"Refusing to overwrite a file changed after the checkpoint: {path}"
352
+ )
353
+ simulated[file.path] = (file.existed_before, file.before_hash)
354
+
355
+ restored_paths: list[str] = []
356
+ try:
357
+ for file in files:
358
+ path = Path(file.path)
359
+ exists, current, _ = self._snapshot(path)
360
+ if not exists or _sha256(current) != file.after_hash:
361
+ raise CheckpointConflictError(
362
+ f"File changed while rewind was running: {path}"
363
+ )
364
+ if file.existed_before:
365
+ self._write_atomic(path, file.before_content, file.before_mode)
366
+ else:
367
+ path.unlink()
368
+ if file.path not in restored_paths:
369
+ restored_paths.append(file.path)
370
+ except Exception:
371
+ for path_text, (existed, content, mode) in backups.items():
372
+ path = Path(path_text)
373
+ if existed:
374
+ self._write_atomic(path, content, mode)
375
+ elif path.exists() and path.is_file():
376
+ path.unlink()
377
+ raise
378
+
379
+ restored_at = time.time()
380
+ checkpoint_ids = tuple(record.checkpoint_id for record in records)
381
+ with self._connect() as connection:
382
+ connection.execute("BEGIN IMMEDIATE")
383
+ connection.executemany(
384
+ "UPDATE checkpoints SET status = 'restored', restored_at = ? WHERE checkpoint_id = ?",
385
+ [(restored_at, checkpoint_id) for checkpoint_id in checkpoint_ids],
386
+ )
387
+
388
+ run_id = records[0].run_id if all(
389
+ record.run_id == records[0].run_id for record in records
390
+ ) else None
391
+ if run_id:
392
+ self.run_store.append_event(run_id, "checkpoint_restored", {
393
+ "checkpoint_ids": list(checkpoint_ids),
394
+ "paths": restored_paths,
395
+ })
396
+ return RestoreResult(checkpoint_ids, run_id, tuple(restored_paths))
397
+
398
+ def max_sequence(self) -> int:
399
+ """The newest checkpoint's sequence; a later rewind undoes everything after it."""
400
+ with self._connect() as connection:
401
+ row = connection.execute("SELECT MAX(sequence) AS top FROM checkpoints").fetchone()
402
+ return int(row["top"] or 0)
403
+
404
+ def since(self, sequence: int, *, session_id: str | None = None) -> list[CheckpointRecord]:
405
+ """Active checkpoints recorded after ``sequence``, newest first."""
406
+ clauses = ["status = 'active'", "sequence > ?"]
407
+ values: list[Any] = [int(sequence)]
408
+ if session_id:
409
+ clauses.append("session_id = ?")
410
+ values.append(session_id)
411
+ with self._connect() as connection:
412
+ rows = connection.execute(
413
+ f"SELECT * FROM checkpoints WHERE {' AND '.join(clauses)} ORDER BY sequence DESC",
414
+ values,
415
+ ).fetchall()
416
+ return [self._row_to_checkpoint(connection, row) for row in rows]
417
+
418
+ def restore_since(
419
+ self,
420
+ sequence: int,
421
+ *,
422
+ session_id: str | None = None,
423
+ skip: Callable[[str], bool] = lambda _path: False,
424
+ ) -> RestoreResult:
425
+ """Undo every change recorded after ``sequence``, newest first, all or nothing.
426
+
427
+ ``skip`` drops files that no longer have a place to be restored to —
428
+ an edit inside a task worktree that has since been removed, whose
429
+ effect on the user's files has its own checkpoint. Nothing to undo is
430
+ not an error: a point with no file changes after it rewinds to itself.
431
+ """
432
+ records = self.since(sequence, session_id=session_id)
433
+ filtered = [replace(record, files=tuple(f for f in record.files if not skip(f.path)))
434
+ for record in records]
435
+ if any(record.files for record in filtered):
436
+ return self._restore(filtered)
437
+ if records:
438
+ restored_at = time.time()
439
+ with self._connect() as connection:
440
+ connection.execute("BEGIN IMMEDIATE")
441
+ connection.executemany(
442
+ "UPDATE checkpoints SET status = 'restored', restored_at = ? WHERE checkpoint_id = ?",
443
+ [(restored_at, record.checkpoint_id) for record in records],
444
+ )
445
+ return RestoreResult(tuple(record.checkpoint_id for record in records), None, ())
446
+
447
+ def restore_checkpoint(self, checkpoint_id: str) -> RestoreResult:
448
+ record = self.get(checkpoint_id)
449
+ if record is None or record.status != "active":
450
+ raise CheckpointNotFoundError(checkpoint_id)
451
+ return self._restore([record])
452
+
453
+ def restore_run(self, run_id: str) -> RestoreResult:
454
+ records = self.list(run_id=run_id, status="active", limit=10_000)
455
+ if not records:
456
+ raise CheckpointNotFoundError(run_id)
457
+ return self._restore(records)
458
+
459
+ def restore_latest_run(self, *, session_id: str | None = None) -> RestoreResult:
460
+ run_id = self.latest_run_id(session_id=session_id)
461
+ if not run_id:
462
+ raise CheckpointNotFoundError("No active run checkpoint found")
463
+ return self.restore_run(run_id)
464
+
465
+ def restore_latest(self, *, session_id: str | None = None) -> RestoreResult:
466
+ clauses = ["status = 'active'"]
467
+ values: list[Any] = []
468
+ if session_id:
469
+ clauses.append("session_id = ?")
470
+ values.append(session_id)
471
+ with self._connect() as connection:
472
+ row = connection.execute(
473
+ f"SELECT checkpoint_id, run_id FROM checkpoints "
474
+ f"WHERE {' AND '.join(clauses)} ORDER BY sequence DESC LIMIT 1",
475
+ values,
476
+ ).fetchone()
477
+ if row is None:
478
+ raise CheckpointNotFoundError("No active checkpoint found")
479
+ if row["run_id"]:
480
+ return self.restore_run(row["run_id"])
481
+ return self.restore_checkpoint(row["checkpoint_id"])
@@ -0,0 +1,65 @@
1
+ """Ask another model — Claude, ChatGPT, Gemini — and bring its answer back.
2
+
3
+ Aria's own model does the work; another provider's model is useful when you want
4
+ a second opinion on a design, an unfamiliar API, or a bug the first model keeps
5
+ circling. `/consult claude <question>` sends the question (and whatever `@file`
6
+ references you put in it) to that model and files the answer in the conversation,
7
+ so the next thing you tell Aria can build on it.
8
+
9
+ Nothing goes out unless you type the command: the other model sees only the
10
+ question, never the conversation, the project or the tools.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Mapping, Optional, Tuple
16
+
17
+ CONSULT_SYSTEM = (
18
+ "You are being consulted by an AI coding assistant on behalf of a developer. "
19
+ "Answer the question directly and concisely, and say what you are unsure of. "
20
+ "You cannot see the project or the conversation; use only what is in the question."
21
+ )
22
+
23
+ #: Short names that mean a model. Only what is certain is built in; add the rest with
24
+ #: `/config set consult_aliases=...` or just type the full `provider/model`.
25
+ DEFAULT_ALIASES = {"claude": "anthropic/claude-sonnet-5-5"}
26
+
27
+
28
+ def resolve_model(name: str, config: Optional[Mapping] = None) -> Optional[str]:
29
+ """`claude` or `provider/model` as a provider-qualified id, or None when it is neither."""
30
+ from aria_code.apps.cli.providers.chat_routing import model_provider
31
+
32
+ aliases = dict(DEFAULT_ALIASES)
33
+ custom = (config or {}).get("consult_aliases")
34
+ if isinstance(custom, Mapping):
35
+ aliases.update({str(k).lower(): str(v) for k, v in custom.items()})
36
+ model = aliases.get(name.strip().lower(), name.strip())
37
+ return model if model_provider(model) else None
38
+
39
+
40
+ def split_request(args: str) -> Tuple[str, str]:
41
+ """`claude why does this race?` -> ("claude", "why does this race?")."""
42
+ parts = args.strip().split(maxsplit=1)
43
+ return (parts[0], parts[1].strip()) if len(parts) == 2 else ((parts[0], "") if parts else ("", ""))
44
+
45
+
46
+ def note_for_conversation(model: str, question: str, answer: str) -> str:
47
+ """How the answer is filed in the conversation, so Aria's model can use it."""
48
+ return f"[second opinion from {model}]\nQuestion: {question}\n\nAnswer:\n{answer}"
49
+
50
+
51
+ async def ask(model: str, question: str, config: Mapping, *, ollama_url: str = "http://localhost:11434") -> str:
52
+ """The other model's answer to `question`; raises on a failed call."""
53
+ from aria_code.apps.cli.providers.runtime_bridge import make_provider_fn
54
+
55
+ call = make_provider_fn(
56
+ model=model, config=dict(config), api_url=None, ollama_url=ollama_url,
57
+ tool_schemas=[], system_override=CONSULT_SYSTEM,
58
+ )
59
+ result = await call(question, [])
60
+ if not result.get("success", True):
61
+ raise RuntimeError(result.get("error") or "the model did not answer")
62
+ answer = str(result.get("response") or "").strip()
63
+ if not answer:
64
+ raise RuntimeError("the model returned an empty answer")
65
+ return answer