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,329 @@
1
+ """Tool execution layer for Aria Code runtimes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import re
7
+ import time
8
+ from pathlib import Path
9
+ from typing import Any, Awaitable, Callable, Dict, Mapping, Optional
10
+
11
+ from .approval import ApprovalDecision, apply_approval_decision
12
+ from .events import RuntimeTrace, ToolCallRecord
13
+
14
+ ToolHandler = Callable[[dict], dict]
15
+ RemoteExecutor = Callable[[str, dict], Awaitable[dict]]
16
+ Hook = Callable[[str, str, dict, Optional[dict]], None]
17
+ ExecutionContextProvider = Callable[[], Mapping[str, Any]]
18
+
19
+
20
+ class ToolExecutor:
21
+ """Execute local/remote tools with hooks, policy injection, and trace records."""
22
+
23
+ def __init__(
24
+ self,
25
+ local_tools: Mapping[str, tuple],
26
+ *,
27
+ remote_executor: RemoteExecutor | None = None,
28
+ hook: Hook | None = None,
29
+ trace: RuntimeTrace | None = None,
30
+ config: Dict[str, Any] | None = None,
31
+ execution_context: ExecutionContextProvider | None = None,
32
+ ) -> None:
33
+ self.local_tools = local_tools
34
+ self.remote_executor = remote_executor
35
+ self.hook = hook
36
+ self.trace = trace or RuntimeTrace()
37
+ self.config = config or {}
38
+ self.execution_context = execution_context
39
+
40
+ def execute_local(
41
+ self, tool_name: str, params: dict, *, approval: ApprovalDecision | None = None
42
+ ) -> dict:
43
+ """Execute a local tool synchronously."""
44
+ if "_agent_allowed_tools" in self.config and tool_name not in self.config["_agent_allowed_tools"]:
45
+ return {"success": False, "error": "Tool is outside this agent role’s allowed capabilities."}
46
+ if self.config.get("_conversation_only"):
47
+ return {"success": False, "error": "This is a standalone conversational request. Reply directly without tools or file inspection."}
48
+ if tool_name not in self.local_tools:
49
+ return {"success": False, "error": f"Unknown local tool: {tool_name}"}
50
+ if approval is not None and not approval.approved:
51
+ reason = approval.reason or "Tool approval denied."
52
+ self.trace.emit("tool_denied", {"tool": tool_name, "reason": reason})
53
+ return {"success": False, "error": reason}
54
+ handler = self.local_tools[tool_name][0]
55
+ params = self._prepare_params(
56
+ tool_name,
57
+ params,
58
+ include_execution_context=True,
59
+ bind_research_context=True,
60
+ approval=approval,
61
+ )
62
+ context_error = params.pop("_execution_context_error", None)
63
+ if context_error:
64
+ result = {"success": False, "error": context_error}
65
+ self.trace.emit("tool_denied", {"tool": tool_name, "reason": context_error})
66
+ return result
67
+ return self._call_with_trace(tool_name, params, lambda: handler(params))
68
+
69
+ async def execute(self, tool_name: str, params: dict) -> dict:
70
+ """Execute a tool asynchronously, using remote executor when needed."""
71
+ if "_agent_allowed_tools" in self.config and tool_name not in self.config["_agent_allowed_tools"]:
72
+ return {"success": False, "error": "Tool is outside this agent role’s allowed capabilities."}
73
+ if self.config.get("_conversation_only"):
74
+ return {"success": False, "error": "This is a standalone conversational request. Reply directly without tools or file inspection."}
75
+ if tool_name in self.local_tools:
76
+ # Scheduler operations must remain on the active event loop. A worker
77
+ # thread cannot create a durable background coroutine on this loop.
78
+ if tool_name in {"spawn_task", "task_cancel", "task_status", "task_result", "task_list", "list_agents"}:
79
+ return self.execute_local(tool_name, params)
80
+ loop = asyncio.get_event_loop()
81
+ return await loop.run_in_executor(None, self.execute_local, tool_name, params)
82
+ if self.remote_executor is None:
83
+ return {"success": False, "error": f"Unknown tool: {tool_name}"}
84
+ params = self._prepare_params(tool_name, params, bind_research_context=True)
85
+ start = time.time()
86
+ self._run_hook("pre_tool", tool_name, params)
87
+ self.trace.emit("tool_call", {"tool": tool_name, "params": params})
88
+ try:
89
+ result = await self.remote_executor(tool_name, params)
90
+ except Exception as exc:
91
+ result = {"success": False, "error": str(exc)}
92
+ observable = {key: value for key, value in result.items() if key != "_vision_image"}
93
+ self._run_hook("post_tool", tool_name, params, observable)
94
+ end = time.time()
95
+ self.trace.add_tool_call(ToolCallRecord(
96
+ tool=tool_name,
97
+ params=params,
98
+ result=observable,
99
+ elapsed_ms=(end - start) * 1000,
100
+ started_at=start,
101
+ ended_at=end,
102
+ ))
103
+ return result
104
+
105
+ def _call_with_trace(self, tool_name: str, params: dict, fn: Callable[[], dict]) -> dict:
106
+ start = time.time()
107
+ self._run_hook("pre_tool", tool_name, params)
108
+ self.trace.emit("tool_call", {"tool": tool_name, "params": params})
109
+ try:
110
+ result = fn()
111
+ except Exception as exc:
112
+ result = {"success": False, "error": str(exc)}
113
+ observable = {key: value for key, value in result.items() if key != "_vision_image"}
114
+ self._run_hook("post_tool", tool_name, params, observable)
115
+ end = time.time()
116
+ self.trace.add_tool_call(ToolCallRecord(
117
+ tool=tool_name,
118
+ params=params,
119
+ result=observable,
120
+ elapsed_ms=(end - start) * 1000,
121
+ started_at=start,
122
+ ended_at=end,
123
+ ))
124
+ return result
125
+
126
+ def _prepare_params(
127
+ self,
128
+ tool_name: str,
129
+ params: dict,
130
+ *,
131
+ include_execution_context: bool = False,
132
+ bind_research_context: bool = False,
133
+ approval: ApprovalDecision | None = None,
134
+ ) -> dict:
135
+ prepared = dict(params or {})
136
+ # A model cannot grant itself directories or replace the host workspace.
137
+ for key in tuple(prepared):
138
+ if key.startswith("_"):
139
+ prepared.pop(key)
140
+ if tool_name == "analyze_financial_statements":
141
+ prepared["network_enabled"] = bool(self.config.get("network_enabled", True))
142
+ if tool_name == "run_command":
143
+ # Tool arguments come from the model. Only the host configuration and
144
+ # a typed approval decision may set execution controls.
145
+ for key in (
146
+ "policy", "permission_mode", "network_enabled",
147
+ "user_approved", "_upgrade_policy", "sandbox", "os_sandbox",
148
+ ):
149
+ prepared.pop(key, None)
150
+ workspace_tools = {"read_file", "write_file", "edit_file", "multi_edit", "list_files",
151
+ "search_code", "glob", "analyze_file", "notebook_read", "notebook_edit",
152
+ "apply_patch", "run_command", "github", "spawn_task", "list_task_context"}
153
+ context = {
154
+ "_workspace": self.config.get("_session_workspace_root") or self.config.get("workspace_root") or str(Path.cwd()),
155
+ "_allowed_read_roots": [*(self.config.get("read_roots") or ()), *(self.config.get("_session_read_roots") or ())],
156
+ "_allowed_write_roots": [*(self.config.get("write_roots") or ()), *(self.config.get("_session_write_roots") or ())],
157
+ "_permission_mode": self.config.get("permission_mode", "workspace-write"),
158
+ } if tool_name in workspace_tools else {}
159
+ if self.execution_context is not None and (
160
+ include_execution_context or bind_research_context
161
+ ):
162
+ try:
163
+ context.update(dict(self.execution_context() or {}))
164
+ if bind_research_context:
165
+ self._bind_research_run(tool_name, prepared, context)
166
+ except Exception as exc:
167
+ if include_execution_context:
168
+ prepared["_execution_context_error"] = (
169
+ f"Execution context unavailable: {exc}"
170
+ )
171
+ if include_execution_context:
172
+ for key, value in context.items():
173
+ if key.startswith("_") and value is not None:
174
+ prepared[key] = value
175
+ self._bind_workspace(tool_name, prepared, context)
176
+ self._check_file_permission(tool_name, prepared)
177
+ if tool_name in {"write_file", "edit_file", "multi_edit", "notebook_edit"}:
178
+ if approval is not None and approval.approved:
179
+ prepared["_skip_confirm"] = True
180
+ if tool_name in {"spawn_task", "list_task_context"}:
181
+ prepared["_task_context_enabled"] = bool(self.config.get("task_context_enabled", True))
182
+ prepared["_session_id"] = str(context.get("_session_id") or self.config.get("last_session_id") or "")
183
+ if tool_name == "spawn_task":
184
+ prepared["_parent_permission_mode"] = self.config.get("permission_mode", "workspace-write")
185
+ if tool_name == "warehouse_task":
186
+ # Tool arguments cannot select another conversation or permission mode.
187
+ session = context.get("_session_id") or self.config.get("last_session_id")
188
+ prepared["_warehouse_scope"] = str(session or "")
189
+ prepared["_warehouse_read_only"] = self.config.get("permission_mode") in {"read-only", "readonly", "read_only", "plan"}
190
+ if tool_name == "run_command":
191
+ prepared["policy"] = self.config.get("command_policy", "safe")
192
+ prepared["permission_mode"] = self.config.get("permission_mode", "workspace-write")
193
+ prepared["network_enabled"] = bool(self.config.get("network_enabled", True))
194
+ prepared["sandbox"] = bool(self.config.get("command_sandbox", False))
195
+ prepared["os_sandbox"] = self.config.get("os_sandbox", "auto")
196
+ if approval is not None and approval.approved:
197
+ apply_approval_decision(prepared, approval)
198
+ return prepared
199
+
200
+ def _check_file_permission(self, tool_name: str, prepared: dict) -> None:
201
+ if prepared.get("_execution_context_error"):
202
+ return
203
+ from aria_code.workspace.files import WorkspaceSecurity
204
+ write_tools = {"write_file", "edit_file", "multi_edit", "apply_patch", "notebook_edit"}
205
+ read_tools = {"read_file", "list_files", "search_code", "glob", "analyze_file", "notebook_read"}
206
+ canonical = tool_name.rsplit("__", 1)[-1]
207
+ mode = str(self.config.get("permission_mode", "workspace-write"))
208
+ if canonical in write_tools and mode in {"read-only", "readonly", "read_only", "plan"}:
209
+ prepared["_execution_context_error"] = "Writes are blocked in read-only mode."
210
+ return
211
+ if canonical not in write_tools | read_tools or mode == "full-access":
212
+ return
213
+ security = WorkspaceSecurity.from_tool_params(prepared)
214
+ try:
215
+ security.require_safe(
216
+ prepared.get("root" if canonical == "glob" else "path") or ".",
217
+ write=canonical in write_tools,
218
+ )
219
+ except PermissionError as exc:
220
+ prepared["_execution_context_error"] = (
221
+ f"{exc}. Add --add-dir for writes or --read-dir for reads."
222
+ )
223
+
224
+ @staticmethod
225
+ def _bind_research_run(
226
+ tool_name: str,
227
+ prepared: dict,
228
+ context: Mapping[str, Any],
229
+ ) -> None:
230
+ """Correlate an institutional research run with its upstream Aria run."""
231
+ canonical_name = str(tool_name).rsplit("__", 1)[-1]
232
+ if canonical_name != "research_run_create":
233
+ return
234
+ control_run_id = context.get("_run_id")
235
+ trace_id = context.get("_trace_id") or control_run_id
236
+ if control_run_id:
237
+ prepared.setdefault("control_run_id", str(control_run_id))
238
+ if trace_id:
239
+ prepared.setdefault("trace_id", str(trace_id))
240
+
241
+ @staticmethod
242
+ def _bind_workspace(tool_name: str, prepared: dict, context: Mapping[str, Any]) -> None:
243
+ workspace_value = context.get("_workspace")
244
+ if not workspace_value:
245
+ return
246
+ workspace = Path(str(workspace_value)).expanduser().resolve()
247
+ restricted = bool(context.get("_workspace_restricted", False))
248
+ # A task worktree stands in for the repository it was made from. The
249
+ # model still sees that repository's paths — in the project context,
250
+ # in earlier turns — so a path into it is taken to mean the same file
251
+ # in the worktree, and the user's own copy is never written.
252
+ origins = _origins(context.get("_workspace_origin"), workspace)
253
+ path_tools = {
254
+ "read_file",
255
+ "write_file",
256
+ "edit_file",
257
+ "multi_edit",
258
+ "list_files",
259
+ "search_code",
260
+ "glob",
261
+ "analyze_file",
262
+ "notebook_read",
263
+ "notebook_edit",
264
+ }
265
+ if tool_name in path_tools:
266
+ path_key = "root" if tool_name == "glob" else "path"
267
+ raw_path = str(prepared.get(path_key) or ".")
268
+ target = Path(raw_path).expanduser()
269
+ if not target.is_absolute():
270
+ target = workspace / target
271
+ target = _into_workspace(target.resolve(), origins, workspace)
272
+ if restricted and not target.is_relative_to(workspace):
273
+ prepared["_execution_context_error"] = (
274
+ f"Tool path is outside the isolated workspace: {target}"
275
+ )
276
+ return
277
+ prepared[path_key] = str(target)
278
+ if tool_name in {"run_command", "github"}:
279
+ raw_cwd = str(prepared.get("cwd") or workspace)
280
+ cwd = Path(raw_cwd).expanduser()
281
+ if not cwd.is_absolute():
282
+ cwd = workspace / cwd
283
+ cwd = _into_workspace(cwd.resolve(), origins, workspace)
284
+ if origins and prepared.get("command"):
285
+ prepared["command"] = _rebase_command(str(prepared["command"]), origins, workspace)
286
+ if restricted and not cwd.is_relative_to(workspace):
287
+ prepared["_execution_context_error"] = (
288
+ f"Command cwd is outside the isolated workspace: {cwd}"
289
+ )
290
+ return
291
+ prepared["cwd"] = str(cwd)
292
+
293
+ def _run_hook(self, hook_type: str, tool_name: str, params: dict, result: dict | None = None) -> None:
294
+ if self.hook is None:
295
+ return
296
+ try:
297
+ self.hook(hook_type, tool_name, params, result)
298
+ except Exception:
299
+ pass
300
+
301
+
302
+ def _origins(value: Any, workspace: Path) -> tuple[Path, ...]:
303
+ """The origin repository as written and as resolved, unless it is the workspace."""
304
+ if not value:
305
+ return ()
306
+ raw = Path(str(value)).expanduser()
307
+ found = []
308
+ for candidate in (raw, raw.resolve()):
309
+ if candidate != workspace and candidate not in found:
310
+ found.append(candidate)
311
+ return tuple(found)
312
+
313
+
314
+ def _into_workspace(target: Path, origins: tuple[Path, ...], workspace: Path) -> Path:
315
+ if target.is_relative_to(workspace):
316
+ return target
317
+ for origin in origins:
318
+ if target.is_relative_to(origin):
319
+ return workspace / target.relative_to(origin)
320
+ return target
321
+
322
+
323
+ def _rebase_command(command: str, origins: tuple[Path, ...], workspace: Path) -> str:
324
+ """Point absolute paths into the origin at the worktree: ``cd /repo && …``."""
325
+ for origin in sorted(origins, key=lambda path: len(str(path)), reverse=True):
326
+ pattern = re.escape(str(origin)) + r"(?=[/\s'\"`;:)|&]|$)"
327
+ command = re.sub(pattern, lambda _match: str(workspace), command)
328
+ return command
329
+
@@ -0,0 +1,107 @@
1
+ """Persistent per-tool execution policy: allowlist, denylist, ask-always.
2
+
3
+ Stores policy in ~/.arthera/tool_policy.json.
4
+ Checked in _confirm_tool_execution_decision() before any user prompt.
5
+
6
+ Usage:
7
+ from runtime.tool_policy import check_tool_policy, add_to_policy
8
+
9
+ verdict = check_tool_policy("write_file") # "allow" | "deny" | "ask" | "default"
10
+ add_to_policy("read_file", "allow") # permanently auto-approve
11
+ add_to_policy("run_command", "deny") # permanently block
12
+ add_to_policy("edit_file", "ask") # always prompt
13
+ remove_from_policy("read_file") # remove from all lists
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ from pathlib import Path
20
+ from typing import Literal
21
+ from aria_code.packages.aria_core.paths import aria_home
22
+
23
+ PolicyVerdict = Literal["allow", "deny", "ask", "default"]
24
+
25
+ _DEFAULT_POLICY: dict = {
26
+ "allowed": [], # auto-approve without prompt
27
+ "denied": [], # always block, never execute
28
+ "ask_always": [], # always prompt even for non-CONFIRM_TOOLS
29
+ }
30
+
31
+
32
+ def _policy_file() -> Path:
33
+ return aria_home() / "tool_policy.json"
34
+
35
+
36
+ def load_tool_policy() -> dict:
37
+ """Load policy from disk; returns defaults if missing or corrupt."""
38
+ f = _policy_file()
39
+ if f.exists():
40
+ try:
41
+ raw = json.loads(f.read_text(encoding="utf-8"))
42
+ return {
43
+ "allowed": list(raw.get("allowed", [])),
44
+ "denied": list(raw.get("denied", [])),
45
+ "ask_always": list(raw.get("ask_always", [])),
46
+ }
47
+ except Exception:
48
+ pass
49
+ return {k: list(v) for k, v in _DEFAULT_POLICY.items()}
50
+
51
+
52
+ def save_tool_policy(policy: dict) -> None:
53
+ f = _policy_file()
54
+ f.parent.mkdir(parents=True, exist_ok=True)
55
+ f.write_text(json.dumps(policy, indent=2, ensure_ascii=False), encoding="utf-8")
56
+
57
+
58
+ def check_tool_policy(tool_name: str) -> PolicyVerdict:
59
+ """Return the persistent verdict for *tool_name*.
60
+
61
+ "allow" → auto-approve, skip confirmation prompt
62
+ "deny" → block, never execute
63
+ "ask" → always prompt (overrides session auto-allow)
64
+ "default" → no override, fall through to normal flow
65
+ """
66
+ policy = load_tool_policy()
67
+ if tool_name in policy.get("denied", []):
68
+ return "deny"
69
+ if tool_name in policy.get("allowed", []):
70
+ return "allow"
71
+ if tool_name in policy.get("ask_always", []):
72
+ return "ask"
73
+ return "default"
74
+
75
+
76
+ def add_to_policy(tool_name: str, verdict: Literal["allow", "deny", "ask"]) -> None:
77
+ """Add *tool_name* to the given policy list, removing it from any other list first."""
78
+ policy = load_tool_policy()
79
+ for key in ("allowed", "denied", "ask_always"):
80
+ policy.setdefault(key, [])
81
+ if tool_name in policy[key]:
82
+ policy[key].remove(tool_name)
83
+ if verdict == "allow":
84
+ policy["allowed"].append(tool_name)
85
+ elif verdict == "deny":
86
+ policy["denied"].append(tool_name)
87
+ elif verdict == "ask":
88
+ policy["ask_always"].append(tool_name)
89
+ save_tool_policy(policy)
90
+
91
+
92
+ def remove_from_policy(tool_name: str) -> bool:
93
+ """Remove *tool_name* from all lists. Returns True if it was present."""
94
+ policy = load_tool_policy()
95
+ changed = False
96
+ for key in ("allowed", "denied", "ask_always"):
97
+ if tool_name in policy.get(key, []):
98
+ policy[key].remove(tool_name)
99
+ changed = True
100
+ if changed:
101
+ save_tool_policy(policy)
102
+ return changed
103
+
104
+
105
+ def policy_summary() -> dict:
106
+ """Return current policy as a human-readable dict."""
107
+ return load_tool_policy()
@@ -0,0 +1,216 @@
1
+ """Transaction points: the whole session state before each turn.
2
+
3
+ ``/rewind`` used to restore files, and ``/rewind both`` then dropped the last
4
+ exchange, so rewinding three turns of edits left the conversation one turn
5
+ back and every approval granted since still in force. A transaction point
6
+ records, before each turn, everything that turn could change:
7
+
8
+ * the conversation, in full;
9
+ * the task list the model was keeping;
10
+ * the approvals in force (allow-all, per-tool, per-command-prefix);
11
+ * the newest file checkpoint, so every edit after it can be undone;
12
+ * whether the code at that point had passed its checks;
13
+ * the open task worktree and its unapplied diff.
14
+
15
+ Rewinding to a point undoes every file change recorded after it, then puts
16
+ the rest back as it was. Points live in ``<root>/<session_id>.jsonl``, the
17
+ newest ``keep_per_session`` kept, each storing only the messages its turn's
18
+ predecessor did not have.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import os
25
+ import time
26
+ import uuid
27
+ from dataclasses import asdict, dataclass, field
28
+ from pathlib import Path
29
+ from typing import Any, Optional
30
+
31
+ TRANSACTION_SCHEMA = "aria.transaction_point.v1"
32
+ DEFAULT_KEEP_PER_SESSION = 50
33
+ DEFAULT_MAX_SNAPSHOT_BYTES = 2 * 1024 * 1024
34
+
35
+ # What the code was known to be at a point: checks ran green, ran red, files
36
+ # changed with nothing to check them, or nothing has changed yet.
37
+ PASSED, FAILED, UNVERIFIED, UNCHANGED = "passed", "failed", "unverified", ""
38
+ # Red, but only where it was red before the change (runtime/baseline.py).
39
+ PREEXISTING = "preexisting"
40
+
41
+
42
+ @dataclass
43
+ class TransactionPoint:
44
+ point_id: str
45
+ session_id: str
46
+ turn: int
47
+ prompt: str # the message the turn after this point answered
48
+ created_at: float
49
+ messages: list = field(default_factory=list)
50
+ todos: list = field(default_factory=list)
51
+ approvals: dict = field(default_factory=dict)
52
+ checkpoint_sequence: int = 0
53
+ verdict: str = UNCHANGED
54
+ task: Optional[dict] = None # {task_id, repository, path, patch}
55
+ truncated: bool = False
56
+
57
+ def to_dict(self) -> dict:
58
+ return {"schema": TRANSACTION_SCHEMA, **asdict(self)}
59
+
60
+ @classmethod
61
+ def from_dict(cls, data: dict) -> "TransactionPoint":
62
+ fields = cls.__dataclass_fields__
63
+ return cls(**{key: value for key, value in data.items() if key in fields})
64
+
65
+
66
+ def verdict_from_acceptance(acceptance: Any, previous: str) -> str:
67
+ """The code's state after a turn, from the acceptance summary it carried.
68
+
69
+ A turn that changed nothing leaves the previous verdict standing.
70
+ """
71
+ if not isinstance(acceptance, dict) or not acceptance.get("paths"):
72
+ return previous
73
+ verified = acceptance.get("verified")
74
+ if verified is True:
75
+ return PASSED
76
+ if verified is False:
77
+ return PREEXISTING if acceptance.get("regressions") is False else FAILED
78
+ return UNVERIFIED
79
+
80
+
81
+ class TransactionStore:
82
+ """Points per session, appended one line per turn.
83
+
84
+ Consecutive points usually share the conversation up to the newer one's
85
+ last few messages, so a point whose conversation extends the previous
86
+ one's stores only the messages added since (``delta``). A compaction or a
87
+ rewind breaks the chain and the next point is stored in full. The file is
88
+ rewritten only to drop old points, once it holds twice as many as kept.
89
+ """
90
+
91
+ def __init__(self, root: Path | str, *, keep_per_session: int = DEFAULT_KEEP_PER_SESSION,
92
+ max_snapshot_bytes: int = DEFAULT_MAX_SNAPSHOT_BYTES) -> None:
93
+ self.root = Path(root).expanduser()
94
+ self.keep_per_session = max(1, int(keep_per_session))
95
+ self.max_snapshot_bytes = max(64 * 1024, int(max_snapshot_bytes))
96
+
97
+ def _path(self, session_id: str) -> Path:
98
+ safe = "".join(ch for ch in str(session_id) if ch.isalnum() or ch in "-_") or "default"
99
+ return self.root / f"{safe}.jsonl"
100
+
101
+ def _lines(self, session_id: str) -> list[dict]:
102
+ try:
103
+ raw = self._path(session_id).read_text(encoding="utf-8").splitlines()
104
+ except OSError:
105
+ return []
106
+ records = []
107
+ for line in raw:
108
+ try:
109
+ data = json.loads(line)
110
+ except ValueError:
111
+ continue
112
+ if isinstance(data, dict) and data.get("schema") == TRANSACTION_SCHEMA:
113
+ records.append(data)
114
+ return records
115
+
116
+ def _read(self, session_id: str) -> list[TransactionPoint]:
117
+ """Oldest first, each with its whole conversation."""
118
+ points: list[TransactionPoint] = []
119
+ for data in self._lines(session_id):
120
+ delta = data.pop("delta", None)
121
+ try:
122
+ point = TransactionPoint.from_dict(data)
123
+ except TypeError:
124
+ continue
125
+ if delta is not None:
126
+ if not points or points[-1].point_id != delta.get("base"):
127
+ continue # its base was dropped: unrecoverable, skip it
128
+ prefix = points[-1].messages[: int(delta.get("start") or 0)]
129
+ point.messages = prefix + list(delta.get("messages") or [])
130
+ point.truncated = point.truncated or points[-1].truncated
131
+ points.append(point)
132
+ return points
133
+
134
+ @staticmethod
135
+ def _encode(point: TransactionPoint, previous: Optional[TransactionPoint]) -> dict:
136
+ data = point.to_dict()
137
+ if previous is not None:
138
+ start = len(previous.messages)
139
+ if start and point.messages[:start] == previous.messages:
140
+ data.pop("messages")
141
+ data["delta"] = {"base": previous.point_id, "start": start,
142
+ "messages": point.messages[start:]}
143
+ return data
144
+
145
+ def _rewrite(self, session_id: str, points: list[TransactionPoint]) -> None:
146
+ path = self._path(session_id)
147
+ path.parent.mkdir(parents=True, exist_ok=True)
148
+ temp = path.with_suffix(".tmp")
149
+ previous = None
150
+ with temp.open("w", encoding="utf-8") as handle:
151
+ for point in points[-self.keep_per_session:]:
152
+ handle.write(json.dumps(self._encode(point, previous), ensure_ascii=False, default=str) + "\n")
153
+ previous = point
154
+ os.replace(temp, path)
155
+
156
+ def _fit(self, point: TransactionPoint) -> TransactionPoint:
157
+ """Drop the oldest messages until the snapshot is under the byte cap."""
158
+ messages = list(point.messages)
159
+ while messages and len(json.dumps(messages, ensure_ascii=False, default=str)) > self.max_snapshot_bytes:
160
+ messages.pop(0)
161
+ point.truncated = True
162
+ point.messages = messages
163
+ return point
164
+
165
+ def record(self, point: TransactionPoint) -> TransactionPoint:
166
+ # Round-trip through JSON so the stored and the compared forms agree.
167
+ point.messages = json.loads(json.dumps(point.messages, ensure_ascii=False, default=str))
168
+ point = self._fit(point)
169
+ points = self._read(point.session_id)
170
+ if len(points) + 1 > 2 * self.keep_per_session:
171
+ self._rewrite(point.session_id, points + [point])
172
+ return point
173
+ path = self._path(point.session_id)
174
+ path.parent.mkdir(parents=True, exist_ok=True)
175
+ line = json.dumps(self._encode(point, points[-1] if points else None), ensure_ascii=False, default=str)
176
+ with path.open("a", encoding="utf-8") as handle:
177
+ handle.write(line + "\n")
178
+ return point
179
+
180
+ def list(self, session_id: str) -> list[TransactionPoint]:
181
+ """Newest first, at most ``keep_per_session``."""
182
+ return list(reversed(self._read(session_id)[-self.keep_per_session:]))
183
+
184
+ def find(self, session_id: str, ref: str) -> Optional[TransactionPoint]:
185
+ """By id (or its prefix), or by count: ``"1"`` is the point before the last turn."""
186
+ points = self.list(session_id)
187
+ ref = str(ref or "1").strip()
188
+ if ref.isdigit() and len(ref) <= 3:
189
+ index = int(ref) - 1
190
+ return points[index] if 0 <= index < len(points) else None
191
+ matches = [point for point in points if point.point_id.startswith(ref)]
192
+ return matches[0] if len(matches) == 1 else None
193
+
194
+ def latest_green(self, session_id: str) -> Optional[TransactionPoint]:
195
+ return next((point for point in self.list(session_id) if point.verdict == PASSED), None)
196
+
197
+ def drop_from(self, point: TransactionPoint) -> None:
198
+ """Forget ``point`` and every later one: after a rewind they are not history."""
199
+ kept = []
200
+ for candidate in self._read(point.session_id):
201
+ if candidate.point_id == point.point_id:
202
+ break
203
+ kept.append(candidate)
204
+ self._rewrite(point.session_id, kept)
205
+
206
+
207
+ def new_point(*, session_id: str, turn: int, prompt: str, **state: Any) -> TransactionPoint:
208
+ return TransactionPoint(point_id=uuid.uuid4().hex[:10], session_id=session_id, turn=turn,
209
+ prompt=" ".join(str(prompt or "").split())[:120],
210
+ created_at=time.time(), **state)
211
+
212
+
213
+ def default_transaction_store() -> TransactionStore:
214
+ from ..packages.aria_core.paths import aria_home
215
+
216
+ return TransactionStore(aria_home() / "transactions")