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,632 @@
1
+ """The acceptance gate — making "done" a claim that was executed.
2
+
3
+ Why this exists
4
+ ---------------
5
+ Aria could already *suggest* verification. ``VerificationPlanner`` infers the
6
+ right checks from what changed, ``write_file`` attaches the inferred command to
7
+ its result as ``suggested_verification``, and ``/verify`` runs the plan when a
8
+ human asks for it. Every one of those paths ends with a suggestion. Nothing
9
+ in the loop ever ran the check, read the failure, or refused to let the turn
10
+ finish; the model announced "已完成" and the turn ended, verified or not.
11
+
12
+ That is the whole distance between an agent that writes code and an agent you
13
+ can hand a repository to. The strong coding agents are not better at emitting
14
+ a patch — they are structurally unable to stop while the check is red. The
15
+ loop, not the model, is what holds that line, which is exactly why this belongs
16
+ in the runtime and works the same whether the turn is driven by a 7B local
17
+ model or a frontier one.
18
+
19
+ What it does
20
+ ------------
21
+ The gate arms itself when a turn actually mutates a file on disk, and fires at
22
+ the moment the model stops requesting tools — the point where the loop would
23
+ otherwise ``break`` and report success. It runs the inferred checks; if they
24
+ pass, the turn ends as it always did, now carrying evidence. If they fail, the
25
+ loop gets a repair directive built from the *failing* output — trimmed, with
26
+ ``file:line`` anchors pulled out — and continues, so the model repairs against
27
+ a real signal instead of its own recollection of what it wrote.
28
+
29
+ Three constraints keep it from becoming a tax:
30
+
31
+ - **Read-only turns never pay it.** Arming requires an applied write. A
32
+ market question, a code review, a staged-but-unapplied edit: no checks run.
33
+ - **It is bounded.** After ``max_attempts`` failed rounds the gate stops
34
+ re-arming and the turn ends *honestly* — ``verified: false`` with the
35
+ failing command in the result — rather than looping until the budget dies.
36
+ An unverified answer that says so is useful; an infinite loop is not.
37
+ - **It never invents a sandbox.** Commands go through the caller's own
38
+ runner (the CLI passes ``run_command``, with its policy, permission mode
39
+ and approval path intact), so the gate cannot execute anything the user's
40
+ current mode would not already allow.
41
+ """
42
+
43
+ from __future__ import annotations
44
+
45
+ import inspect
46
+ import hashlib
47
+ import re
48
+ import time
49
+ from dataclasses import dataclass, field, replace
50
+ from pathlib import Path
51
+ from typing import Any, Awaitable, Callable, Dict, Iterable, List, Optional, Sequence, Union
52
+
53
+ __all__ = [
54
+ "AcceptanceGate",
55
+ "AcceptanceReport",
56
+ "CheckResult",
57
+ "DEFAULT_MUTATING_TOOLS",
58
+ "extract_mutated_paths",
59
+ ]
60
+
61
+
62
+ # Tools whose success means bytes changed on disk. ``run_command`` is
63
+ # deliberately absent: it can mutate, but gating on it would re-arm the gate
64
+ # with every check the gate itself runs — the checks would never terminate.
65
+ DEFAULT_MUTATING_TOOLS = frozenset({
66
+ "write_file",
67
+ "edit_file",
68
+ "multi_edit",
69
+ "apply_patch",
70
+ "notebook_edit",
71
+ "str_replace",
72
+ "create_file",
73
+ })
74
+
75
+ # A failing test log is the single most context-hungry payload in a coding
76
+ # turn — a full pytest run can exceed the window on its own. Head carries the
77
+ # collection error, tail carries the assertion and the summary line; the middle
78
+ # is almost always repeated passing output.
79
+ _HEAD_LINES = 20
80
+ _TAIL_LINES = 45
81
+ _MAX_CHARS = 6000
82
+
83
+ # ``File "x.py", line 12`` (Python), ``x.ts:12:5`` (tsc/eslint/jest).
84
+ _PY_ANCHOR = re.compile(r'File "([^"]+)", line (\d+)')
85
+ _COLON_ANCHOR = re.compile(r"(?m)^\s*([\w./\\-]+\.[A-Za-z]{1,4}):(\d+)(?::\d+)?")
86
+
87
+
88
+ def _as_dict(value: Any) -> Dict[str, Any]:
89
+ return value if isinstance(value, dict) else {}
90
+
91
+
92
+ def extract_mutated_paths(
93
+ tool: str,
94
+ result: Any,
95
+ *,
96
+ mutating_tools: Iterable[str] = DEFAULT_MUTATING_TOOLS,
97
+ ) -> tuple[str, ...]:
98
+ """Paths this tool result actually wrote to disk.
99
+
100
+ Returns nothing for a failed call or an unapplied staged change. The
101
+ distinction matters: ``write_file`` in review mode returns success with
102
+ ``applied: False`` and the file on disk is untouched, so running the test
103
+ suite would verify the previous state and report a green that means
104
+ nothing.
105
+ """
106
+ canonical = str(tool or "").rsplit("__", 1)[-1]
107
+ if canonical not in set(mutating_tools):
108
+ return ()
109
+
110
+ payload = _as_dict(result)
111
+ if payload.get("success") is False or payload.get("error"):
112
+ return ()
113
+
114
+ data = _as_dict(payload.get("data")) or payload
115
+ if data.get("applied") is False or (
116
+ data.get("staged") is True and data.get("applied") is not True
117
+ ):
118
+ return ()
119
+
120
+ found: List[str] = []
121
+
122
+ def _add(value: Any) -> None:
123
+ text = str(value or "").strip()
124
+ if text and text not in found:
125
+ found.append(text)
126
+
127
+ _add(data.get("path"))
128
+ _add(data.get("file_path"))
129
+ for entry in data.get("paths", ()) or ():
130
+ _add(entry)
131
+ # multi_edit reports per-edit records rather than a single path.
132
+ for entry in data.get("edits", ()) or ():
133
+ _add(_as_dict(entry).get("path"))
134
+
135
+ return tuple(found)
136
+
137
+
138
+ def _trim(text: str) -> str:
139
+ """Head + tail of command output, with the uninformative middle dropped."""
140
+ body = (text or "").strip()
141
+ if not body:
142
+ return ""
143
+ lines = body.splitlines()
144
+ if len(lines) > _HEAD_LINES + _TAIL_LINES:
145
+ omitted = len(lines) - _HEAD_LINES - _TAIL_LINES
146
+ lines = (
147
+ lines[:_HEAD_LINES]
148
+ + [f"… [{omitted} lines omitted] …"]
149
+ + lines[-_TAIL_LINES:]
150
+ )
151
+ joined = "\n".join(lines)
152
+ if len(joined) > _MAX_CHARS:
153
+ keep = _MAX_CHARS // 2
154
+ joined = f"{joined[:keep]}\n… [truncated] …\n{joined[-keep:]}"
155
+ return joined
156
+
157
+
158
+ def _anchors(text: str, limit: int = 5) -> tuple[str, ...]:
159
+ """``file:line`` locations named in a failure, most recent frame last.
160
+
161
+ Handing the model the anchors separately is what turns a wall of log into
162
+ an edit: without them a weaker model tends to rewrite the whole file
163
+ instead of patching the line the traceback already identified.
164
+ """
165
+ out: List[str] = []
166
+ for match in _PY_ANCHOR.finditer(text or ""):
167
+ entry = f"{match.group(1)}:{match.group(2)}"
168
+ if entry not in out:
169
+ out.append(entry)
170
+ for match in _COLON_ANCHOR.finditer(text or ""):
171
+ entry = f"{match.group(1)}:{match.group(2)}"
172
+ if entry not in out:
173
+ out.append(entry)
174
+ # The last frames are the ones inside the code that just changed; the first
175
+ # are usually the runner's own stack.
176
+ return tuple(out[-limit:])
177
+
178
+
179
+ # What a runner prints when the tool itself is missing, as opposed to a test failing:
180
+ # `python3 -m pytest` -> "/opt/homebrew/bin/python3.14: No module named pytest", and
181
+ # a missing program -> "command not found" (shell exit 127). A project's own
182
+ # ModuleNotFoundError inside its tests looks different and stays a failure.
183
+ _RUNNER_MISSING = re.compile(r"(?m)^\S*python[\d.]*: No module named ['\"]?([\w.]+)['\"]?\s*$")
184
+ _PROGRAM_MISSING = re.compile(r"(?m)^(?:\S+: )*(?:([\w.+-]+): (?:command )?not found|command not found: ([\w.+-]+))\s*$")
185
+
186
+
187
+ def unavailable_reason(exit_code: int, output: str, error: str = "") -> str:
188
+ """Why a check could not run at all ("" when it ran, whatever its verdict)."""
189
+ text = f"{output or ''}\n{error or ''}"
190
+ match = _RUNNER_MISSING.search(text)
191
+ if match:
192
+ return f"{match.group(1)} is not installed for this python"
193
+ match = _PROGRAM_MISSING.search(text)
194
+ if match or exit_code == 127:
195
+ name = (match.group(1) or match.group(2)) if match else ""
196
+ return f"{name or 'the command'} is not installed"
197
+ return ""
198
+
199
+
200
+ @dataclass(frozen=True)
201
+ class CheckResult:
202
+ """One verification command, run."""
203
+
204
+ command: str
205
+ exit_code: int
206
+ passed: bool
207
+ output: str = ""
208
+ duration: float = 0.0
209
+ error: str = ""
210
+ # Set from the test baseline when the check failed: whether every failure
211
+ # was already there before the change, and which test ids are which.
212
+ preexisting: bool = False
213
+ new_failures: tuple[str, ...] = ()
214
+ old_failures: tuple[str, ...] = ()
215
+ baseline_note: str = ""
216
+ # Non-empty when the tool needed to run this check is missing. Not a red check:
217
+ # nothing was verified, and asking the model to "fix" it only makes it install things.
218
+ unavailable: str = ""
219
+
220
+ @property
221
+ def anchors(self) -> tuple[str, ...]:
222
+ return () if self.passed else _anchors(self.output)
223
+
224
+ def summary(self) -> dict:
225
+ data = {
226
+ "command": self.command,
227
+ "exit_code": self.exit_code,
228
+ "passed": self.passed,
229
+ "duration": round(self.duration, 3),
230
+ "error": self.error,
231
+ }
232
+ if self.unavailable:
233
+ data["not_run"] = self.unavailable
234
+ if not self.passed and (self.baseline_note or self.new_failures or self.old_failures):
235
+ data.update({"preexisting": self.preexisting, "new_failures": list(self.new_failures),
236
+ "old_failures": list(self.old_failures), "baseline": self.baseline_note})
237
+ return data
238
+
239
+
240
+ @dataclass(frozen=True)
241
+ class AcceptanceReport:
242
+ """The outcome of one pass of the gate."""
243
+
244
+ attempt: int
245
+ checks: tuple[CheckResult, ...] = ()
246
+ reason: str = ""
247
+ paths: tuple[str, ...] = ()
248
+ attempts_remaining: int = 0
249
+ revision_status: str = "not_recorded"
250
+ revision_paths: tuple[tuple[str, str, str], ...] = ()
251
+
252
+ @property
253
+ def ran(self) -> bool:
254
+ return any(not check.unavailable for check in self.checks)
255
+
256
+ @property
257
+ def not_run(self) -> tuple[CheckResult, ...]:
258
+ """Checks whose tool is missing: nothing was verified by them."""
259
+ return tuple(check for check in self.checks if check.unavailable)
260
+
261
+ @property
262
+ def passed(self) -> bool:
263
+ """True only when at least one check ran and every check that could run passed.
264
+
265
+ A gate that reports "verified" without running anything is worse than
266
+ no gate: it launders an unchecked claim into a checked-looking one.
267
+ """
268
+ return (self.revision_status not in {"changed_during_checks", "unavailable"}
269
+ and self.ran and all(check.passed for check in self.checks if not check.unavailable))
270
+
271
+ @property
272
+ def failures(self) -> tuple[CheckResult, ...]:
273
+ return tuple(check for check in self.checks if not check.passed and not check.unavailable)
274
+
275
+ @property
276
+ def regressed(self) -> bool:
277
+ """A check failed that was not already failing before the change."""
278
+ return any(not check.preexisting for check in self.failures)
279
+
280
+ def headline(self) -> str:
281
+ if self.revision_status in {"changed_during_checks", "unavailable"} and not self.failures:
282
+ return "验收未确认:检查期间文件版本变化或无法取得安全的文件指纹"
283
+ if not self.ran:
284
+ if self.not_run:
285
+ first = self.not_run[0]
286
+ return f"验收未执行:`{first.command}` 无法运行({first.unavailable})"
287
+ return "验收未执行:未推断出检查命令"
288
+ if self.passed:
289
+ names = ", ".join(check.command for check in self.checks if not check.unavailable)
290
+ if self.not_run:
291
+ skipped = "; ".join(f"`{c.command}` ({c.unavailable})" for c in self.not_run)
292
+ return f"验收部分通过 ({names});未能运行:{skipped}"
293
+ return f"验收通过 ({names})"
294
+ first = self.failures[0]
295
+ if not self.regressed:
296
+ return f"验收未通过,但失败在改动前就已存在:`{first.command}` exit {first.exit_code}"
297
+ return f"验收失败:`{first.command}` exit {first.exit_code}"
298
+
299
+ def repair_directive(self) -> str:
300
+ """What the model is told when the check came back red.
301
+
302
+ Written as evidence plus one instruction. The failing output is the
303
+ evidence; the instruction exists because the observed failure mode is
304
+ not that the model cannot fix the bug — it is that it re-announces
305
+ completion without having looked at why the command failed.
306
+ """
307
+ if self.revision_status in {"changed_during_checks", "unavailable"}:
308
+ return ("文件内容在检查期间变化,或无法取得安全指纹;当前结果未验证。"
309
+ "先重新读取工作区并确认变更,不要覆盖用户修改。"
310
+ "保留原有权限与审批,通过正常验收流程重新检查。")
311
+ blocks: List[str] = [
312
+ "## 验收未通过 (Acceptance check failed)",
313
+ "",
314
+ "你声明任务已完成,但改动过的文件没有通过自动验收检查。"
315
+ "以下是**实际执行**的命令和真实输出:",
316
+ "",
317
+ ]
318
+ for check in self.failures:
319
+ if check.preexisting:
320
+ continue
321
+ blocks.append(f"### `{check.command}` → exit {check.exit_code}")
322
+ if check.new_failures:
323
+ blocks.append("本次改动新引入的失败:" + ", ".join(f"`{t}`" for t in check.new_failures))
324
+ if check.old_failures:
325
+ blocks.append("以下失败在改动前就存在,与本任务无关,不要修改:"
326
+ + ", ".join(f"`{t}`" for t in check.old_failures))
327
+ if check.error:
328
+ blocks.append(f"(执行错误:{check.error})")
329
+ body = _trim(check.output)
330
+ if body:
331
+ blocks.append(f"```\n{body}\n```")
332
+ if check.anchors:
333
+ blocks.append("定位:" + ", ".join(f"`{a}`" for a in check.anchors))
334
+ blocks.append("")
335
+
336
+ blocks.append(
337
+ "请依次:(1) 读出错位置的代码确认原因,(2) 用 `edit_file` 定点修补"
338
+ "——不要整文件重写,(3) 修好后直接说明修了什么。"
339
+ "修改后验收会自动重跑,你**不需要**自己调用验收命令。"
340
+ )
341
+ if self.attempts_remaining <= 0:
342
+ blocks.append(
343
+ "注意:这是最后一次修复机会。若仍未通过,请如实说明失败原因,"
344
+ "不要声称任务已完成。"
345
+ )
346
+ else:
347
+ blocks.append(f"剩余自动重试次数:{self.attempts_remaining}。")
348
+ return "\n".join(blocks)
349
+
350
+ def summary(self) -> dict:
351
+ return {
352
+ "attempt": self.attempt,
353
+ "passed": self.passed,
354
+ "regressed": self.regressed,
355
+ "ran": self.ran,
356
+ "reason": self.reason,
357
+ "paths": list(self.paths),
358
+ "checks": [check.summary() for check in self.checks],
359
+ "revision_status": self.revision_status,
360
+ "revision_paths": [dict(path=p, state=s, sha256=h or None) for p, s, h in self.revision_paths],
361
+ }
362
+
363
+
364
+ # ``(command) -> result dict`` — sync or async. The result is read loosely
365
+ # because every surface in this codebase wraps command output slightly
366
+ # differently; see ``_read_run_result``.
367
+ CommandRunner = Callable[[str], Union[dict, Awaitable[dict]]]
368
+
369
+
370
+ def _read_run_result(raw: Any) -> tuple[int, str, str]:
371
+ """Normalise a runner result into ``(exit_code, output, error)``.
372
+
373
+ Deliberately permissive. ``tool_run_command`` returns
374
+ ``{"success": True, "data": {"exit_code": .., "stdout": .., "stderr": ..}}``
375
+ on a completed command and ``{"success": False, "error": "…timed out"}``
376
+ when it never completed — and a timeout is a *failed* check, not a passing
377
+ one, so an unreadable result must never be read as exit 0.
378
+ """
379
+ payload = _as_dict(raw)
380
+ if not payload:
381
+ return 1, "", "runner returned no result"
382
+
383
+ if payload.get("success") is False:
384
+ return 1, str(payload.get("output") or ""), str(payload.get("error") or "command failed")
385
+
386
+ data = _as_dict(payload.get("data")) or payload
387
+ for key in ("exit_code", "returncode", "code", "status"):
388
+ if key in data:
389
+ try:
390
+ exit_code = int(data[key])
391
+ break
392
+ except (TypeError, ValueError):
393
+ continue
394
+ else:
395
+ return 1, "", "runner returned no exit status"
396
+
397
+ stdout = str(data.get("stdout") or data.get("output") or "")
398
+ stderr = str(data.get("stderr") or "")
399
+ output = "\n".join(part for part in (stdout, stderr) if part.strip())
400
+ return exit_code, output, ""
401
+
402
+
403
+ class AcceptanceGate:
404
+ """Arms on real writes, fires when the model says it is done."""
405
+
406
+ def __init__(
407
+ self,
408
+ *,
409
+ runner: CommandRunner,
410
+ root: Union[str, Path] = ".",
411
+ planner: Any = None,
412
+ max_attempts: int = 2,
413
+ mutating_tools: Iterable[str] = DEFAULT_MUTATING_TOOLS,
414
+ enabled: bool = True,
415
+ commands: Optional[Sequence[str]] = None,
416
+ baseline: Any = None,
417
+ revision_inputs: Sequence[str] = (),
418
+ ) -> None:
419
+ self.root = Path(root).expanduser()
420
+ # ``runtime.baseline.Baseline``: reruns a failed check on the code as
421
+ # it was before the change, so pre-existing failures are not repaired.
422
+ self.baseline = baseline
423
+ self.runner = runner
424
+ self.max_attempts = max(0, int(max_attempts))
425
+ self.mutating_tools = frozenset(mutating_tools)
426
+ self.enabled = bool(enabled)
427
+ # An explicit command list overrides inference — this is the hook a
428
+ # domain pack or a repo's own config uses to say what "green" means
429
+ # for it (``make check``, ``bazel test //...``), which inference can
430
+ # never guess.
431
+ self.commands = tuple(commands or ())
432
+ self._planner = planner
433
+ self.attempts = 0
434
+ self.reports: List[AcceptanceReport] = []
435
+ self._pending: List[str] = []
436
+ self._all_paths: List[str] = []
437
+ if (not isinstance(revision_inputs, (tuple, list)) or len(revision_inputs) > 64
438
+ or any(not isinstance(p, str) or not p or len(p) > 512 for p in revision_inputs)):
439
+ raise ValueError("revision_inputs must contain at most 64 bounded paths")
440
+ self.revision_inputs = tuple(revision_inputs)
441
+
442
+ def _revision(self, paths: Sequence[str]) -> tuple[tuple[str, str, str], ...] | None:
443
+ """Bounded content snapshots, not an atomic Git/dependency revision."""
444
+ from .task_verification import _read_file, relative_path
445
+ if not paths or len(paths) > 64:
446
+ return None
447
+ snapshots = []
448
+ try:
449
+ root = self.root.resolve(strict=True)
450
+ for value in paths:
451
+ path = Path(value)
452
+ name = relative_path(str(path.relative_to(root)) if path.is_absolute() else value)
453
+ try:
454
+ digest = hashlib.sha256(_read_file(str(root), name)).hexdigest()
455
+ snapshots.append((name, "file", digest))
456
+ except FileNotFoundError:
457
+ snapshots.append((name, "absent", ""))
458
+ except (OSError, ValueError, TypeError):
459
+ return None
460
+ return tuple(snapshots)
461
+
462
+ # ── arming ────────────────────────────────────────────────────────────
463
+
464
+ def record_tool(self, tool: str, result: Any) -> tuple[str, ...]:
465
+ """Note one tool result; arms the gate if it wrote to disk."""
466
+ if not self.enabled:
467
+ return ()
468
+ paths = extract_mutated_paths(tool, result, mutating_tools=self.mutating_tools)
469
+ for path in paths:
470
+ if path not in self._pending:
471
+ self._pending.append(path)
472
+ if path not in self._all_paths:
473
+ self._all_paths.append(path)
474
+ return paths
475
+
476
+ @property
477
+ def armed(self) -> bool:
478
+ return bool(self._pending)
479
+
480
+ @property
481
+ def exhausted(self) -> bool:
482
+ return self.attempts >= self.max_attempts
483
+
484
+ def should_run(self) -> bool:
485
+ return self.enabled and self.armed and not self.exhausted
486
+
487
+ # ── firing ────────────────────────────────────────────────────────────
488
+
489
+ def _plan(self, paths: Sequence[str]) -> tuple[tuple[str, ...], str]:
490
+ if self.commands:
491
+ return self.commands, "configured acceptance commands"
492
+ planner = self._planner
493
+ if planner is None:
494
+ try:
495
+ from aria_code.workspace.verify import VerificationPlanner
496
+ except Exception:
497
+ return (), "verification planner unavailable"
498
+ planner = VerificationPlanner(root=self.root)
499
+ self._planner = planner
500
+ try:
501
+ plan = planner.infer(list(paths))
502
+ except Exception as exc: # a planner fault must not fail the turn
503
+ return (), f"verification planning failed: {exc}"
504
+ return tuple(plan.commands or ()), str(plan.reason or "")
505
+
506
+ async def _run_one(self, command: str) -> CheckResult:
507
+ started = time.time()
508
+ try:
509
+ raw = self.runner(command)
510
+ if inspect.isawaitable(raw):
511
+ raw = await raw
512
+ except Exception as exc:
513
+ return CheckResult(
514
+ command=command,
515
+ exit_code=1,
516
+ passed=False,
517
+ error=str(exc),
518
+ duration=time.time() - started,
519
+ )
520
+ exit_code, output, error = _read_run_result(raw)
521
+ passed = exit_code == 0 and not error
522
+ return CheckResult(
523
+ command=command,
524
+ exit_code=exit_code,
525
+ passed=passed,
526
+ output=output,
527
+ error=error,
528
+ duration=time.time() - started,
529
+ unavailable="" if passed else unavailable_reason(exit_code, output, error),
530
+ )
531
+
532
+ async def _against_baseline(self, check: CheckResult) -> CheckResult:
533
+ if check.passed or check.unavailable:
534
+ return check
535
+ from .baseline import compare
536
+
537
+ try:
538
+ before = await self.baseline.result(check.command)
539
+ except Exception:
540
+ return check
541
+ result = compare(check.output, True, before)
542
+ return replace(check, preexisting=result.preexisting, new_failures=result.new_failures,
543
+ old_failures=result.old_failures, baseline_note=result.note)
544
+
545
+ async def run(self) -> Optional[AcceptanceReport]:
546
+ """Run the inferred checks once. ``None`` when the gate is not armed.
547
+
548
+ Disarms before running: the paths this pass covers are consumed, so a
549
+ turn that fixes nothing cannot re-fire the same checks forever, while
550
+ a repair that writes a file re-arms the gate for the next pass.
551
+ """
552
+ if not self.should_run():
553
+ return None
554
+
555
+ paths = tuple(self._pending)
556
+ self._pending.clear()
557
+ self.attempts += 1
558
+
559
+ commands, reason = self._plan(paths)
560
+ bound_paths = tuple(dict.fromkeys((*paths, *self.revision_inputs)))
561
+ before = self._revision(bound_paths)
562
+ checks: List[CheckResult] = []
563
+ for command in commands:
564
+ check = await self._run_one(command)
565
+ checks.append(check)
566
+ # Stop at the first red. Later checks usually fail for the same
567
+ # cause, and each extra failing log costs context the repair needs.
568
+ # A check that could not run says nothing about the code, so the rest still run.
569
+ if not check.passed and not check.unavailable:
570
+ break
571
+
572
+ if self.baseline is not None:
573
+ checks = [await self._against_baseline(check) for check in checks]
574
+
575
+ after = self._revision(bound_paths)
576
+ revision_status = ("unavailable" if before is None or after is None else
577
+ "current" if before == after else "changed_during_checks")
578
+ report = AcceptanceReport(
579
+ attempt=self.attempts,
580
+ checks=tuple(checks),
581
+ reason=reason,
582
+ paths=paths,
583
+ attempts_remaining=max(0, self.max_attempts - self.attempts),
584
+ revision_status=revision_status,
585
+ revision_paths=after or (),
586
+ )
587
+ self.reports.append(report)
588
+ return report
589
+
590
+ # ── reporting ─────────────────────────────────────────────────────────
591
+
592
+ def summary(self) -> dict:
593
+ """What the turn result carries so a caller can prove the claim.
594
+
595
+ ``verified`` is tri-state on purpose. ``True`` means checks ran green,
596
+ ``False`` means they ran red, and ``None`` means nothing was verified —
597
+ a read-only turn, or a workspace with no inferable check. Collapsing
598
+ the last two into ``False`` would make every analysis turn look failed;
599
+ collapsing it into ``True`` would be the exact lie this module exists
600
+ to prevent.
601
+ """
602
+ last = self.reports[-1] if self.reports else None
603
+ freshness = "not_checked"
604
+ if last is not None:
605
+ if last.revision_status != "current":
606
+ freshness = last.revision_status
607
+ else:
608
+ current = self._revision(tuple(p for p, _, _ in last.revision_paths))
609
+ freshness = ("unavailable" if current is None else
610
+ "current" if current == last.revision_paths else "stale")
611
+ verified: Optional[bool] = None
612
+ if last is not None and last.ran:
613
+ verified = last.passed and not self.armed
614
+ if verified and last.not_run:
615
+ verified = None # what could run passed, but part of the plan did not run
616
+ if freshness != "current" and not last.failures:
617
+ verified = None
618
+ return {
619
+ "verified": verified,
620
+ # False when the checks are red only where they were red before
621
+ # the change; None when nothing ran or nothing failed.
622
+ "regressions": (last.regressed if last is not None and last.ran and not last.passed else None),
623
+ "attempts": self.attempts,
624
+ "paths": list(self._all_paths),
625
+ "reports": [report.summary() for report in self.reports],
626
+ "pending_paths": list(self._pending),
627
+ "revision_freshness": freshness,
628
+ "revision_scope": "latest_check_paths_and_host_inputs_content_only",
629
+ "headline": ("改动后尚未重新验收" if self.armed else
630
+ "文件内容变化或指纹不可用,需重新验收" if freshness not in {"current", "not_checked"} and not last.failures else
631
+ last.headline() if last is not None else ""),
632
+ }