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,75 @@
1
+ """Domain-neutral task roles for the existing Aria runtime.
2
+
3
+ Profiles narrow a task's instructions and available tools. They do not provide
4
+ credentials, install integrations, choose another model, or grant permissions.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class AgentProfile:
13
+ name: str
14
+ description: str
15
+ instructions: str
16
+ tools: frozenset[str] | None = None
17
+ writable: bool = False
18
+ max_rounds: int = 20
19
+ timeout_seconds: int = 300
20
+
21
+
22
+ READ = frozenset({"read_file", "list_files", "search_code", "glob", "analyze_file", "notebook_read", "lsp_diagnostics"})
23
+ RESEARCH = READ | {"web_search", "web_fetch"}
24
+ WRITE = READ | {"write_file", "edit_file", "multi_edit", "apply_patch", "notebook_edit", "run_command"}
25
+
26
+ PROFILES = {
27
+ p.name: p for p in (
28
+ AgentProfile("general", "General-purpose fallback for tasks that do not fit a narrower role.",
29
+ "Complete the delegated goal using available tools. State missing capabilities and evidence explicitly.",
30
+ writable=True, max_rounds=30),
31
+ AgentProfile("explorer", "Find and explain files, architecture and execution paths without edits.",
32
+ "Read targeted sources, trace the actual execution path, and cite files and symbols. Do not implement changes.", READ),
33
+ AgentProfile("planner", "Turn a goal into an evidence-based plan, dependencies and acceptance criteria.",
34
+ "Inspect the relevant context. Return a concrete plan, dependencies, assumptions and observable acceptance criteria. Do not implement it.", RESEARCH),
35
+ AgentProfile("researcher", "Research technical, product or business questions with source evidence.",
36
+ "Search and read primary sources when available. Separate sourced facts, inferences and unknowns; include source locations and dates for time-sensitive claims. If search access is absent, say so.", RESEARCH),
37
+ AgentProfile("implementer", "Implement and test a bounded software change in an isolated workspace.",
38
+ "Read relevant code before editing. Implement the requested scope and run appropriate checks. Report changed files, actual commands and failures. Never push, publish or deploy.", WRITE, writable=True, max_rounds=30),
39
+ AgentProfile("reviewer", "Independently inspect correctness, security and missing validation without edits.",
40
+ "Review the actual sources and available evidence. Report actionable findings with file locations, severity and reasoning. Distinguish static review from executed tests; no findings does not prove correctness.", READ),
41
+ AgentProfile("data_analyst", "Analyze datasets, validate quality and produce reproducible calculations across domains.",
42
+ "Inspect supplied data and its grain, schema and quality. Use verified tool outputs for calculations; never invent computed totals. Use command execution only under inherited host policy. Write outputs only when workspace-write was requested. If no computation tool is available, return a reproducible method and the limitation instead of pretending to execute it.", WRITE, writable=True),
43
+ AgentProfile("writer", "Draft and revise documents, specifications and content grounded in supplied sources.",
44
+ "Use authorized context and source files. Preserve audience, voice and factual provenance. Write requested files only in the permitted workspace and read them back. Return drafts for review; never send messages or publish content.", WRITE, writable=True),
45
+ )
46
+ }
47
+
48
+
49
+ def get_profile(name: str = "general") -> AgentProfile:
50
+ try:
51
+ return PROFILES[name]
52
+ except KeyError:
53
+ raise ValueError(f"Unknown agent profile: {name}. Use list_agents to discover supported roles.") from None
54
+
55
+
56
+ def tool_list_agents(params: dict) -> dict:
57
+ return {"success": True, "agents": [
58
+ {"name": p.name, "description": p.description,
59
+ "modes": ["read-only", "workspace-write"] if p.writable else ["read-only"],
60
+ "tool_policy": "inherit parent minus delegation" if p.tools is None else sorted(p.tools),
61
+ "max_rounds": p.max_rounds, "timeout_seconds": p.timeout_seconds}
62
+ for p in PROFILES.values()
63
+ ], "note": "Profiles use the existing Aria model/runtime. Tools are intersected with the host's actual tool registry; listed roles do not imply connected services. Command execution remains subject to the host permission policy."}
64
+
65
+
66
+ DELEGATION_GUIDANCE = """General task delegation:
67
+ - Aria handles software, research, data inspection, documents and other authorized tasks across domains.
68
+ - Built-in roles: explorer (source exploration), planner (plans), researcher (sourced research), implementer (software changes), reviewer (independent review), data_analyst (datasets), writer (documents); general is the fallback.
69
+ - Use list_agents to discover reusable roles; select one by its description and the task context, not a keyword router. Use spawn_task(agent=..., prompt=..., success_criteria=...) for a bounded independent task when delegation is useful. Keep simple/dependent work in the main conversation unless the user explicitly requests a delegate. Honor explicit delegation requests: do not replace a requested independent writer/researcher task with a draft produced in the parent conversation.
70
+ - Discover relevant project skill/memory descriptions with list_task_context(agent=target_role), then pass only needed IDs in spawn_task.context_refs. Only explicit project auto entries load by default; no global memory scan occurs. Context provenance records source hashes, not proof of current facts. Never copy unrelated personal context into a delegate.
71
+ - Give the delegate its goal, relevant source context and observable acceptance criteria. Inherit the current model and permissions; never delegate to bypass a denial or gain access.
72
+ - Declare observable checks in the spawn_task checks argument when the goal permits artifact, tool or command predicates. Describing these checks in prompt/context does not declare them. For a file-based research task, use checks=[{"kind":"tool","tool":"read_file","path":"brief.md"},{"kind":"artifact","path":"brief.md","format":"text","min_bytes":1}] with the actual requested file. File checks read actual bounded workspace bytes; command checks require a zero exit code from the exact observed command and never execute additional commands. Checks cover only declared predicates, not semantic correctness.
73
+ - Retrieve task_result before relying on a delegate. verified=true means the declared predicates passed; verified=null means no checks were requested: explicitly report that machine acceptance was not performed and never say those checks passed. Never call either a done status or a VERIFICATION heading independent acceptance. A spawned or done task is not proof that the user's goal was verified. Check the reported evidence, artifacts and blockers; disclose missing tools or failed checks.
74
+ - Specialized financial and warehouse capabilities remain optional domain extensions. Do not impose stock symbols, trading signals or financial-evidence requirements on unrelated tasks.
75
+ """
@@ -0,0 +1,71 @@
1
+ """Approval decisions for tools that require user consent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class ApprovalDecision:
10
+ """Structured result from a tool approval prompt."""
11
+
12
+ approved: bool
13
+ policy: str | None = None
14
+ user_approved: bool = False
15
+ upgrade_policy: bool = False
16
+ auto_approve_session: bool = False
17
+ tool_scope: str = ""
18
+ command_prefix: tuple[str, ...] = ()
19
+ reason: str = ""
20
+ # What the user said instead of approving. A denial with feedback does
21
+ # not end the turn: the call is skipped and the model reads this.
22
+ feedback: str = ""
23
+
24
+ @classmethod
25
+ def allow(
26
+ cls,
27
+ *,
28
+ policy: str | None = None,
29
+ user_approved: bool = False,
30
+ upgrade_policy: bool = False,
31
+ auto_approve_session: bool = False,
32
+ tool_scope: str = "",
33
+ command_prefix: tuple[str, ...] = (),
34
+ reason: str = "",
35
+ ) -> "ApprovalDecision":
36
+ return cls(
37
+ approved=True,
38
+ policy=policy,
39
+ user_approved=user_approved,
40
+ upgrade_policy=upgrade_policy,
41
+ auto_approve_session=auto_approve_session,
42
+ tool_scope=tool_scope,
43
+ command_prefix=command_prefix,
44
+ reason=reason,
45
+ )
46
+
47
+ @classmethod
48
+ def deny(cls, reason: str = "", *, feedback: str = "") -> "ApprovalDecision":
49
+ return cls(approved=False, reason=reason, feedback=feedback.strip())
50
+
51
+ def as_declined_result(self) -> dict:
52
+ """What the model reads in place of a call the user declined with feedback."""
53
+ return {
54
+ "success": False,
55
+ "error": (
56
+ "The user declined this call and said: "
57
+ f"\"{self.feedback}\". Do what they asked instead; do not retry the same call."
58
+ ),
59
+ "declined_by_user": True,
60
+ }
61
+
62
+
63
+ def apply_approval_decision(params: dict, decision: ApprovalDecision) -> dict:
64
+ """Apply execution-facing approval fields to tool params."""
65
+ if decision.policy is not None:
66
+ params["policy"] = decision.policy
67
+ if decision.user_approved:
68
+ params["user_approved"] = True
69
+ if decision.upgrade_policy:
70
+ params["_upgrade_policy"] = True
71
+ return params
@@ -0,0 +1,219 @@
1
+ """Test baseline: was this check already failing before the change?
2
+
3
+ A red check sends the model back to repair. When the test was failing before
4
+ the task touched anything, that sends it to "fix" code unrelated to the
5
+ request — or to give up on a task that was actually done. The baseline runs
6
+ the failed command once more on the code as it was before the change and
7
+ compares:
8
+
9
+ * pytest: by test id (``FAILED tests/x.py::test_y``). Failures that also
10
+ fail on the baseline are pre-existing; the rest are the change's. The
11
+ baseline run continues past collection errors (see ``_keep_collecting``).
12
+ * anything else: by exit status. A command that fails on the baseline too
13
+ is pre-existing as a whole.
14
+
15
+ "Before the change" is the task's starting snapshot when the turn runs in a
16
+ task worktree. Otherwise it is the working tree now with this turn's edits
17
+ undone from their checkpoints — edits a shell command made are not
18
+ recorded, so they are in the baseline too. Outside a git repository the
19
+ working tree is copied instead of checked out, when it is small enough
20
+ (``_COPY_MAX_FILES``/``_COPY_MAX_BYTES``); without a baseline every failure
21
+ counts as the change's, and the model is sent to "fix" unrelated code.
22
+
23
+ It runs only after a failure, in a scratch worktree removed straight after,
24
+ and each command at most once per turn.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import inspect
30
+ import logging
31
+ import os
32
+ import re
33
+ import shutil
34
+ import uuid
35
+ from dataclasses import dataclass
36
+ from pathlib import Path
37
+ from typing import Any, Awaitable, Callable, Optional, Union
38
+
39
+ from .task_worktree import TaskWorktreeError, checkout, remove_checkout, repository_root, snapshot
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ _PYTEST_FAILURE = re.compile(r"^(?:FAILED|ERROR)\s+(\S+?)(?:\s+-\s|$)", re.MULTILINE)
44
+
45
+ # A workspace outside git is copied for its baseline only up to this size; a
46
+ # turn started in a home directory must not copy the home directory.
47
+ _COPY_MAX_FILES = 5_000
48
+ _COPY_MAX_BYTES = 100 * 1024 * 1024
49
+ _COPY_SKIPPED = frozenset({
50
+ ".git", ".hg", ".svn", "node_modules", ".venv", "venv", "__pycache__",
51
+ ".mypy_cache", ".pytest_cache", ".ruff_cache", ".tox", ".nox",
52
+ })
53
+
54
+ # ``(command, cwd) -> run result dict``, as the acceptance gate's runner returns.
55
+ BaselineRunner = Callable[[str, str], Union[dict, Awaitable[dict]]]
56
+
57
+
58
+ def failing_tests(output: str) -> frozenset[str]:
59
+ """pytest's failing test ids, from its short summary lines."""
60
+ return frozenset(match.group(1) for match in _PYTEST_FAILURE.finditer(output or ""))
61
+
62
+
63
+ @dataclass(frozen=True)
64
+ class Comparison:
65
+ preexisting: bool # every failure was already there
66
+ new_failures: tuple[str, ...] = () # test ids failing only after the change
67
+ old_failures: tuple[str, ...] = () # test ids failing before it too
68
+ note: str = ""
69
+
70
+
71
+ def compare(after_output: str, after_failed: bool, before: Optional[tuple[int, str]]) -> Comparison:
72
+ """Classify a failed check against its baseline run ``(exit_code, output)``."""
73
+ if before is None or not after_failed:
74
+ return Comparison(preexisting=False)
75
+ before_code, before_output = before
76
+ if before_code == 0:
77
+ return Comparison(preexisting=False, note="passed before this change")
78
+ after_ids, before_ids = failing_tests(after_output), failing_tests(before_output)
79
+ if after_ids:
80
+ new = tuple(sorted(after_ids - before_ids))
81
+ old = tuple(sorted(after_ids & before_ids))
82
+ return Comparison(preexisting=not new, new_failures=new, old_failures=old,
83
+ note="failing before this change" if not new else "")
84
+ return Comparison(preexisting=True, note="failing before this change")
85
+
86
+
87
+ _PYTEST_COMMAND = re.compile(r"(?:^|[\s/])(?:py\.test|pytest)(?:\s|$)")
88
+
89
+
90
+ def _keep_collecting(command: str) -> str:
91
+ """Let a pytest baseline run past collection errors.
92
+
93
+ Before the change a test file often cannot even be imported — it tests the
94
+ function the task is about to add — and pytest then stops at collection,
95
+ running nothing else. A test that was already red elsewhere is missing from
96
+ that baseline, so after the change it would look new and be "repaired".
97
+ """
98
+ if (not _PYTEST_COMMAND.search(command) or "--continue-on-collection-errors" in command
99
+ or re.search(r"[|;&<>`$]", command)):
100
+ return command
101
+ return f"{command} --continue-on-collection-errors"
102
+
103
+
104
+ class Baseline:
105
+ def __init__(
106
+ self,
107
+ workspace: Path | str,
108
+ *,
109
+ run: BaselineRunner,
110
+ base_commit: str = "",
111
+ undo_since: Optional[int] = None,
112
+ session_id: str = "",
113
+ scratch_root: Path | str,
114
+ ) -> None:
115
+ self.workspace = Path(workspace).expanduser().resolve()
116
+ self.run = run
117
+ self.base_commit = base_commit
118
+ self.undo_since = undo_since
119
+ self.session_id = session_id
120
+ self.scratch_root = Path(scratch_root).expanduser()
121
+ self._results: dict[str, Optional[tuple[int, str]]] = {}
122
+
123
+ async def result(self, command: str) -> Optional[tuple[int, str]]:
124
+ """``(exit_code, output)`` of ``command`` before the change; None if unknown."""
125
+ if command not in self._results:
126
+ try:
127
+ self._results[command] = await self._run(_keep_collecting(command))
128
+ except Exception as exc:
129
+ logger.debug("baseline run failed: %s", exc)
130
+ self._results[command] = None
131
+ return self._results[command]
132
+
133
+ async def _run(self, command: str) -> Optional[tuple[int, str]]:
134
+ repo = repository_root(self.workspace)
135
+ destination = (self.scratch_root / f"baseline-{uuid.uuid4().hex[:8]}").resolve()
136
+ if repo is None:
137
+ if self.base_commit or not self._copy(destination):
138
+ return None
139
+ try:
140
+ self._undo_turn(self.workspace, destination)
141
+ raw = self.run(command, str(destination))
142
+ if inspect.isawaitable(raw):
143
+ raw = await raw
144
+ finally:
145
+ shutil.rmtree(destination, ignore_errors=True)
146
+ return self._result(raw)
147
+ commit = self.base_commit or snapshot(repo)[0]
148
+ linked = checkout(repo, commit, destination)
149
+ try:
150
+ if not self.base_commit:
151
+ self._undo_turn(repo, destination)
152
+ inside = self.workspace.relative_to(repo) if self.workspace.is_relative_to(repo) else Path()
153
+ cwd = destination / inside
154
+ cwd.mkdir(parents=True, exist_ok=True)
155
+ raw = self.run(command, str(cwd))
156
+ if inspect.isawaitable(raw):
157
+ raw = await raw
158
+ finally:
159
+ remove_checkout(repo, destination, linked)
160
+ return self._result(raw)
161
+
162
+ @staticmethod
163
+ def _result(raw: Any) -> tuple[int, str]:
164
+ from .acceptance import _read_run_result
165
+
166
+ code, output, error = _read_run_result(raw)
167
+ return (code if not error else 1, output)
168
+
169
+ def _copy(self, destination: Path) -> bool:
170
+ """Copy the workspace to ``destination``; False (and nothing left) when too big."""
171
+ files: list[tuple[Path, Path]] = []
172
+ total = 0
173
+ for directory, dirnames, filenames in os.walk(self.workspace):
174
+ dirnames[:] = [name for name in dirnames if name not in _COPY_SKIPPED]
175
+ for name in filenames:
176
+ source = Path(directory) / name
177
+ if source.is_symlink():
178
+ pass # copied as a link: it may point outside the workspace
179
+ elif source.is_file():
180
+ total += source.stat().st_size
181
+ else:
182
+ continue
183
+ files.append((source, destination / source.relative_to(self.workspace)))
184
+ if len(files) > _COPY_MAX_FILES or total > _COPY_MAX_BYTES:
185
+ return False
186
+ try:
187
+ for source, target in files:
188
+ target.parent.mkdir(parents=True, exist_ok=True)
189
+ shutil.copy2(source, target, follow_symlinks=False)
190
+ except OSError:
191
+ shutil.rmtree(destination, ignore_errors=True)
192
+ raise
193
+ destination.mkdir(parents=True, exist_ok=True)
194
+ return True
195
+
196
+ def _undo_turn(self, repo: Path, destination: Path) -> None:
197
+ """Put back what this turn's checkpointed edits replaced."""
198
+ if self.undo_since is None:
199
+ return
200
+ from .checkpoints import CheckpointStore
201
+
202
+ earliest: dict[str, Any] = {}
203
+ for record in reversed(CheckpointStore().since(self.undo_since, session_id=self.session_id or None)):
204
+ for file in record.files:
205
+ earliest.setdefault(file.path, file) # oldest change holds the true "before"
206
+ for path, file in earliest.items():
207
+ try:
208
+ relative = Path(path).resolve().relative_to(repo)
209
+ except ValueError:
210
+ continue
211
+ target = destination / relative
212
+ if file.existed_before:
213
+ target.parent.mkdir(parents=True, exist_ok=True)
214
+ target.write_text(file.before_content, encoding="utf-8")
215
+ elif target.exists():
216
+ target.unlink()
217
+
218
+
219
+ __all__ = ["Baseline", "Comparison", "compare", "failing_tests", "TaskWorktreeError"]
@@ -0,0 +1,232 @@
1
+ """Token / 成本预算:给能自主跑多轮的 agent 一个花费上限。
2
+
3
+ 为什么需要:run_agent() 默认可以跑 30 轮,每轮都可能调云端模型;
4
+ agents/team.py 还会并行拉起多个 agent。这些循环在无人看管时(定时任务、
5
+ 飞书 bot、后台 subagent)一旦进入一个"工具失败→重试→再失败"的死循环,
6
+ 会持续消耗真金白银,而现有的唯一护栏是轮数上限——轮数管不住单轮消耗,
7
+ 一轮塞进 200k token 的上下文和一轮塞进 2k,成本差两个数量级。
8
+
9
+ 设计要点:
10
+
11
+ 1. **本地模型不计费**。ollama / lmstudio / local 的边际成本是零,把它们计入
12
+ 预算只会让本地用户莫名其妙被打断。这跟 /cost 命令已有的判断保持一致。
13
+
14
+ 2. **超限是暂停,不是抛异常**。异常会让调用方拿不到已经产出的中间结果;
15
+ 返回一个明确的"已暂停"状态,调用方可以决定是展示给用户确认后继续,
16
+ 还是就此收尾。这也是 pause/resume 语义能成立的前提。
17
+
18
+ 3. **预检查而非事后补记**。在发起下一轮之前判断"这一轮预计会花多少",
19
+ 而不是花完了才发现超了——后者每次都会超支一轮。
20
+
21
+ 4. **默认值保守但不碍事**。默认 2.0 美元/会话,够正常交互用很久,又能在
22
+ 死循环烧掉几十美元之前叫停。设成 0 表示不限制(显式选择,不是默认)。
23
+
24
+ 价格表按 2026-08 的公开价格,只用于**估算**:真实账单以各家为准。宁可估高
25
+ 不估低——估低会让预算形同虚设。
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import os
31
+ from dataclasses import dataclass, field
32
+ from typing import Dict, Optional, Tuple
33
+
34
+ __all__ = [
35
+ "BudgetConfig", "BudgetState", "BudgetTracker",
36
+ "BudgetExceeded", "estimate_cost_usd", "is_local_provider",
37
+ ]
38
+
39
+ # 零边际成本的 provider —— 与 /cost 命令的判断保持一致
40
+ _LOCAL_PROVIDERS = frozenset({"ollama", "ollama_cache", "local", "lmstudio"})
41
+
42
+ # (输入, 输出) 美元 / 每百万 token。取各家公开价格的较高档,宁可估高。
43
+ _PRICE_TABLE: Dict[str, Tuple[float, float]] = {
44
+ "openai": (2.50, 10.00),
45
+ "anthropic": (3.00, 15.00),
46
+ "deepseek": (0.27, 1.10),
47
+ "groq": (0.59, 0.79),
48
+ "siliconflow": (0.27, 1.10),
49
+ "dashscope": (0.40, 1.20),
50
+ "moonshot": (1.70, 1.70),
51
+ "zhipu": (0.10, 0.10),
52
+ "together": (0.88, 0.88),
53
+ }
54
+ _DEFAULT_PRICE = (2.00, 8.00) # 未知 provider(含用户自定义的)按较贵档估
55
+
56
+
57
+ def is_local_provider(provider: Optional[str]) -> bool:
58
+ return (provider or "").strip().lower() in _LOCAL_PROVIDERS
59
+
60
+
61
+ def estimate_cost_usd(provider: Optional[str], input_tokens: int, output_tokens: int) -> float:
62
+ """估算一次调用的美元成本。本地 provider 恒为 0。"""
63
+ if is_local_provider(provider):
64
+ return 0.0
65
+ price_in, price_out = _PRICE_TABLE.get((provider or "").strip().lower(), _DEFAULT_PRICE)
66
+ return (max(0, input_tokens) * price_in + max(0, output_tokens) * price_out) / 1_000_000
67
+
68
+
69
+ @dataclass(frozen=True)
70
+ class BudgetConfig:
71
+ """预算上限。任一项设为 0 表示该项不限制。"""
72
+ max_usd: float = 2.0
73
+ max_tokens: int = 0
74
+ max_rounds: int = 0
75
+
76
+ @classmethod
77
+ def from_env(cls) -> "BudgetConfig":
78
+ """环境变量覆盖默认值,便于定时任务/容器里单独收紧或放开。"""
79
+ def _num(name: str, default: float) -> float:
80
+ raw = os.environ.get(name, "").strip()
81
+ if not raw:
82
+ return default
83
+ try:
84
+ return max(0.0, float(raw))
85
+ except ValueError:
86
+ return default
87
+
88
+ return cls(
89
+ max_usd=_num("ARIA_BUDGET_MAX_USD", 2.0),
90
+ max_tokens=int(_num("ARIA_BUDGET_MAX_TOKENS", 0)),
91
+ max_rounds=int(_num("ARIA_BUDGET_MAX_ROUNDS", 0)),
92
+ )
93
+
94
+ @property
95
+ def unlimited(self) -> bool:
96
+ return not (self.max_usd or self.max_tokens or self.max_rounds)
97
+
98
+
99
+ @dataclass
100
+ class BudgetState:
101
+ spent_usd: float = 0.0
102
+ input_tokens: int = 0
103
+ output_tokens: int = 0
104
+ rounds: int = 0
105
+ billable_calls: int = 0 # 计费调用次数(本地调用不计)
106
+ per_provider: Dict[str, float] = field(default_factory=dict)
107
+
108
+ @property
109
+ def total_tokens(self) -> int:
110
+ return self.input_tokens + self.output_tokens
111
+
112
+
113
+ class BudgetExceeded(RuntimeError):
114
+ """仅供确实需要硬中断的调用方使用。默认路径不抛这个——见模块文档第 2 点。"""
115
+
116
+ def __init__(self, reason: str, state: BudgetState):
117
+ super().__init__(reason)
118
+ self.reason = reason
119
+ self.state = state
120
+
121
+
122
+ class BudgetTracker:
123
+ """累计消耗并回答"还能不能再跑一轮"。
124
+
125
+ 刻意不持有任何 provider 或循环对象:它只接收数字、返回判断,因此可以在
126
+ CLI 会话、后台 subagent、agents.team 并行编排里用同一套逻辑,也容易测试。
127
+ """
128
+
129
+ def __init__(self, config: Optional[BudgetConfig] = None):
130
+ self.config = config or BudgetConfig.from_env()
131
+ self.state = BudgetState()
132
+ self._paused_reason: Optional[str] = None
133
+
134
+ # ── 记账 ──────────────────────────────────────────────────────────
135
+ def record(self, provider: Optional[str], input_tokens: int, output_tokens: int) -> float:
136
+ """记录一次模型调用,返回本次估算成本。"""
137
+ cost = estimate_cost_usd(provider, input_tokens, output_tokens)
138
+ self.state.input_tokens += max(0, input_tokens)
139
+ self.state.output_tokens += max(0, output_tokens)
140
+ self.state.spent_usd += cost
141
+ if cost > 0:
142
+ self.state.billable_calls += 1
143
+ key = (provider or "unknown").strip().lower()
144
+ self.state.per_provider[key] = self.state.per_provider.get(key, 0.0) + cost
145
+ return cost
146
+
147
+ def record_round(self) -> None:
148
+ self.state.rounds += 1
149
+
150
+ def projected_next_round_usd(self) -> float:
151
+ """按已观测到的平均单轮成本,预测下一轮会花多少。
152
+
153
+ 没有这个预测,闸门只能事后止损:$1 的预算实测会花到 $1.275——超支的
154
+ 正是最后那一轮,而它恰恰可能是上下文最满、最贵的一轮。用历史均值做
155
+ 预测,能在**发起调用之前**就拦住。
156
+
157
+ 还没有任何计费轮次时返回 0(没有依据就不猜,第一轮总是放行)。
158
+
159
+ 因此**第一轮永远无法被预算拦住**——预算比单轮成本还低时会超支一次。
160
+ 这是有意的:宁可放行第一轮,也不要因为一个凭空的猜测把正常会话
161
+ 堵死在起点。真要限制到单轮以下,应该用更小的模型或更短的上下文,
162
+ 而不是指望预算闸门。
163
+ """
164
+ if self.state.rounds <= 0 or self.state.spent_usd <= 0:
165
+ return 0.0
166
+ return self.state.spent_usd / self.state.rounds
167
+
168
+ # ── 判断 ──────────────────────────────────────────────────────────
169
+ def check(self, *, projected_usd: float = 0.0, projected_tokens: int = 0) -> Optional[str]:
170
+ """返回超限原因;未超限返回 None。
171
+
172
+ projected_* 是"下一轮预计消耗"。传入它就变成**预检查**——在花掉之前
173
+ 拦住,而不是花完才发现超了(后者每次都会超支一轮)。
174
+ """
175
+ cfg = self.config
176
+ if cfg.unlimited:
177
+ return None
178
+
179
+ if cfg.max_usd:
180
+ projected = self.state.spent_usd + max(0.0, projected_usd)
181
+ if projected >= cfg.max_usd:
182
+ return (f"预算上限 ${cfg.max_usd:.2f} 已达到"
183
+ f"(已用 ${self.state.spent_usd:.4f}"
184
+ f"{f',本轮预计 ${projected_usd:.4f}' if projected_usd else ''})")
185
+
186
+ if cfg.max_tokens:
187
+ projected_tok = self.state.total_tokens + max(0, projected_tokens)
188
+ if projected_tok >= cfg.max_tokens:
189
+ return (f"token 上限 {cfg.max_tokens:,} 已达到"
190
+ f"(已用 {self.state.total_tokens:,})")
191
+
192
+ if cfg.max_rounds and self.state.rounds >= cfg.max_rounds:
193
+ return f"轮数上限 {cfg.max_rounds} 已达到"
194
+
195
+ return None
196
+
197
+ def should_continue(self, *, projected_usd: float = 0.0, projected_tokens: int = 0) -> bool:
198
+ reason = self.check(projected_usd=projected_usd, projected_tokens=projected_tokens)
199
+ if reason:
200
+ self._paused_reason = reason
201
+ return reason is None
202
+
203
+ # ── 状态 ──────────────────────────────────────────────────────────
204
+ @property
205
+ def paused(self) -> bool:
206
+ return self._paused_reason is not None
207
+
208
+ @property
209
+ def paused_reason(self) -> Optional[str]:
210
+ return self._paused_reason
211
+
212
+ def resume(self, *, additional_usd: float = 0.0) -> None:
213
+ """用户确认后继续。可选地追加额度——不追加就会在下一次检查时再次暂停,
214
+ 这是刻意的:确认一次只放行一次,避免"确认后无限继续"。
215
+ """
216
+ self._paused_reason = None
217
+ if additional_usd > 0:
218
+ self.config = BudgetConfig(
219
+ max_usd=self.config.max_usd + additional_usd,
220
+ max_tokens=self.config.max_tokens,
221
+ max_rounds=self.config.max_rounds,
222
+ )
223
+
224
+ def summary(self) -> str:
225
+ s = self.state
226
+ parts = [f"${s.spent_usd:.4f}", f"{s.total_tokens:,} tokens", f"{s.rounds} 轮"]
227
+ if self.config.max_usd:
228
+ pct = (s.spent_usd / self.config.max_usd * 100) if self.config.max_usd else 0
229
+ parts.append(f"用量 {pct:.0f}% / ${self.config.max_usd:.2f}")
230
+ if not s.billable_calls and s.total_tokens:
231
+ parts.append("(全部走本地模型,零成本)")
232
+ return " · ".join(parts)