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,153 @@
1
+ """Project-graph imports and Python definitions from ``aria-native index``.
2
+
3
+ Parsing every Python file twice — ``repo_map`` for its definitions,
4
+ ``project_graph`` for its imports, each an ``ast.parse`` and a walk — is most
5
+ of the time a graph build takes. The Rust ``aria-graph`` crate does both in
6
+ parallel; the callers ask it first and keep the Python implementation for
7
+ everything it does not answer:
8
+
9
+ * no binary — ``ARIA_NATIVE_BINARY`` or ``aria-native`` on ``PATH`` — or
10
+ ``ARIA_NATIVE_GRAPH=off``;
11
+ * too few files to be worth a process (``_MIN_FILES``);
12
+ * the binary failing, timing out or answering out of shape;
13
+ * a file its parser rejects or cannot read (``fallback``), which Python then
14
+ handles itself.
15
+
16
+ The two implementations must agree; ``tests/test_native_index.py`` holds them
17
+ to it on this repository and on edge cases.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import shutil
25
+ import subprocess
26
+ import sys
27
+ from pathlib import Path
28
+ from typing import Optional, Sequence
29
+
30
+ _MIN_FILES = 32
31
+ _TIMEOUT = 120
32
+
33
+
34
+ def native_binary() -> Optional[str]:
35
+ """``ARIA_NATIVE_BINARY``, else the copy bundled with a native build or a
36
+ platform wheel, else ``PATH``."""
37
+ configured = os.environ.get("ARIA_NATIVE_BINARY", "").strip()
38
+ if configured:
39
+ return configured if Path(configured).is_file() else None
40
+ name = "aria-native.exe" if sys.platform == "win32" else "aria-native"
41
+ if getattr(sys, "frozen", False):
42
+ # go/buildtools puts it in the PyInstaller contents
43
+ # folder (_internal/), which is sys._MEIPASS at run time.
44
+ bundled = Path(getattr(sys, "_MEIPASS", Path(sys.executable).parent)) / name
45
+ if bundled.is_file():
46
+ return str(bundled)
47
+ # A platform wheel (scripts/platform_wheels.py) carries it, with the Go
48
+ # engine beside it, in aria_code/_bin/.
49
+ packaged = Path(__file__).resolve().parents[1] / "_bin" / name
50
+ if packaged.is_file() and (sys.platform == "win32" or os.access(packaged, os.X_OK)):
51
+ return str(packaged)
52
+ return shutil.which("aria-native")
53
+
54
+
55
+ def enabled() -> bool:
56
+ return os.environ.get("ARIA_NATIVE_GRAPH", "").strip().lower() not in ("0", "off", "false", "no")
57
+
58
+
59
+ def _call(command: str, payload: dict, wanted: Sequence[str], key: str,
60
+ minimum: Optional[int]) -> Optional[tuple[dict, list[str]]]:
61
+ """``(answers by path, paths left to Python)`` from ``aria-native index <command>``, or None."""
62
+ if len(wanted) < (_MIN_FILES if minimum is None else minimum) or not enabled():
63
+ return None
64
+ binary = native_binary()
65
+ if not binary:
66
+ return None
67
+ try:
68
+ done = subprocess.run([binary, "index", command], input=json.dumps(payload), capture_output=True,
69
+ text=True, encoding="utf-8", timeout=_TIMEOUT, check=False)
70
+ if done.returncode != 0:
71
+ return None
72
+ data = json.loads(done.stdout)
73
+ except (OSError, ValueError, subprocess.SubprocessError):
74
+ return None
75
+ answers, fallback = data.get(key), data.get("fallback")
76
+ if not isinstance(answers, dict) or not isinstance(fallback, list):
77
+ return None
78
+ paths = set(wanted)
79
+ if not set(answers) | set(fallback) >= paths: # every file answered one way or the other
80
+ return None
81
+ return ({path: answer for path, answer in answers.items() if path in paths},
82
+ [path for path in fallback if path in paths])
83
+
84
+
85
+ def resolve_imports(root: Path, files: Sequence[tuple[str, str]], parse: Sequence[str],
86
+ *, minimum: Optional[int] = None) -> Optional[tuple[dict[str, list[str]], list[str]]]:
87
+ """``(imports by path, paths to parse in Python)``, or None to do it all in Python."""
88
+ payload = {"root": str(root), "files": [list(f) for f in files], "parse": list(parse)}
89
+ result = _call("imports", payload, parse, "imports", minimum)
90
+ if result is None:
91
+ return None
92
+ imports, fallback = result
93
+ return {path: list(found) for path, found in imports.items()}, fallback
94
+
95
+
96
+ def python_symbols(root: Path, parse: Sequence[str], *, minimum: Optional[int] = None,
97
+ ) -> Optional[tuple[dict[str, list[tuple[str, str, int, str]]], list[str]]]:
98
+ """``(definitions by path as (name, kind, line, parent), paths for Python)``, or None."""
99
+ result = _call("symbols", {"root": str(root), "parse": list(parse)}, parse, "symbols", minimum)
100
+ if result is None:
101
+ return None
102
+ symbols, fallback = result
103
+ try:
104
+ return ({path: [(str(n), str(k), int(line), str(p)) for n, k, line, p in found]
105
+ for path, found in symbols.items()}, fallback)
106
+ except (TypeError, ValueError):
107
+ return None
108
+
109
+
110
+ UNAVAILABLE = object()
111
+
112
+
113
+ def _raw(command: str, payload: dict) -> Optional[dict]:
114
+ """JSON from ``aria-native index <command>``, or None when it cannot answer."""
115
+ if not enabled():
116
+ return None
117
+ binary = native_binary()
118
+ if not binary:
119
+ return None
120
+ try:
121
+ done = subprocess.run(
122
+ [binary, "index", command], input=json.dumps(payload), capture_output=True,
123
+ text=True, encoding="utf-8", timeout=_TIMEOUT, check=False,
124
+ )
125
+ if done.returncode != 0:
126
+ return None
127
+ data = json.loads(done.stdout)
128
+ except (OSError, ValueError, subprocess.SubprocessError):
129
+ return None
130
+ return data if isinstance(data, dict) else None
131
+
132
+
133
+ def reverse_apply(after: str, diff: str):
134
+ """The text *diff* was made from, None when it does not fit, or UNAVAILABLE."""
135
+ data = _raw("changes", {"op": "reverse", "after": after, "diff": diff})
136
+ if data is None or "applied" not in data:
137
+ return UNAVAILABLE
138
+ if not data.get("applied"):
139
+ return None
140
+ text = data.get("text")
141
+ return text if isinstance(text, str) else UNAVAILABLE
142
+
143
+
144
+ def symbol_changes(before: str, after: str, language: str) -> Optional[list[tuple[str, str, str]]]:
145
+ """``(kind, qualified name, symbol kind)`` rows, or None to decide in Python."""
146
+ data = _raw("changes", {"op": "changes", "before": before, "after": after, "language": language})
147
+ rows = data.get("changes") if isinstance(data, dict) else None
148
+ if not isinstance(rows, list):
149
+ return None
150
+ try:
151
+ return [(str(row["kind"]), str(row["name"]), str(row["symbol_kind"])) for row in rows]
152
+ except (KeyError, TypeError):
153
+ return None
@@ -0,0 +1,55 @@
1
+ from typing import List, Dict, Any
2
+ import json
3
+ import logging
4
+ from aria_code.agents.registry import get_registry
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ async def dynamic_agent_orchestration(user_query: str, provider: Any) -> Dict[str, Any]:
9
+ """
10
+ Dynamic routing to pick the best agents for the user's query.
11
+ """
12
+ registry = get_registry()
13
+ agents = registry.list()
14
+
15
+ # Filter out orchestrator or core infrastructure agents that shouldn't be dynamically routed
16
+ agents = [a for a in agents if a["name"] not in {"orchestrator", "supervisor"}]
17
+
18
+ agents_info = "\n".join([f"- {a['name']}: {a.get('description', '')}" for a in agents])
19
+
20
+ prompt = (
21
+ f"你是一个高级的智能体编排中心 (Orchestrator)。\n"
22
+ f"用户请求:\n{user_query}\n\n"
23
+ f"可用智能体库:\n{agents_info}\n\n"
24
+ f"请直接输出一段合法的 JSON,选择最合适的智能体来解决用户请求(最多选3个)。\n"
25
+ f"JSON 结构必须是:\n"
26
+ f"{{\n"
27
+ f" \"plan\": \"解释为什么选择这些智能体\",\n"
28
+ f" \"agents\": [\"agent_name_1\", \"agent_name_2\"]\n"
29
+ f"}}\n"
30
+ )
31
+
32
+ try:
33
+ # We assume provider is an async function or object that can generate text
34
+ # But we'll just try to use a simple completion if available
35
+ messages = [{"role": "user", "content": prompt}]
36
+
37
+ # Use provider to generate
38
+ full_response = ""
39
+ async for chunk in provider.stream(messages=messages, tools=[]):
40
+ if hasattr(chunk, 'text') and chunk.text:
41
+ full_response += chunk.text
42
+
43
+ # Parse JSON
44
+ start_idx = full_response.find("{")
45
+ end_idx = full_response.rfind("}")
46
+ if start_idx != -1 and end_idx != -1:
47
+ json_str = full_response[start_idx:end_idx+1]
48
+ return json.loads(json_str)
49
+ else:
50
+ return {"plan": "未能解析 JSON", "agents": ["technical"]}
51
+ except Exception as e:
52
+ logger.error(f"Orchestration failed: {e}")
53
+ # Default fallback
54
+ return {"plan": "降级路由", "agents": ["technical", "fundamental"]}
55
+
@@ -0,0 +1,343 @@
1
+ """Long-running commands: start one, read its output later, send it input, stop it.
2
+
3
+ run_command waited for a command to finish, so a dev server, a test watcher
4
+ or anything interactive either blocked the turn until the timeout or could
5
+ not be used at all: there was no way to start a server and then test against
6
+ it. ``run_command`` with ``background: true`` starts the process here, under
7
+ the same approval and sandbox as any command, and the ``process`` tool reads
8
+ what it has printed since the last look, writes to its stdin, or stops it.
9
+
10
+ Output goes through pipes, not a terminal, so a program that insists on a TTY
11
+ behaves as it does when piped. Every process gets its own process group, so
12
+ stopping it stops what it started; all of them are stopped when Aria exits.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import atexit
18
+ import itertools
19
+ import os
20
+ import re
21
+ import signal
22
+ import subprocess
23
+ import threading
24
+ import time
25
+ from dataclasses import dataclass, field
26
+ from pathlib import Path
27
+ from typing import Sequence
28
+
29
+ MAX_RUNNING = 8
30
+ MAX_BUFFER = 1_000_000 # characters kept per process; older output is dropped
31
+ MAX_READ = 8_000 # characters returned by one read
32
+ MAX_WAIT = 30.0
33
+
34
+ _ids = itertools.count(1)
35
+ _lock = threading.Lock()
36
+
37
+
38
+ @dataclass
39
+ class _Process:
40
+ id: str
41
+ command: str
42
+ cwd: str
43
+ popen: subprocess.Popen
44
+ started: float = field(default_factory=time.time)
45
+ text: str = "" # the kept tail of everything printed
46
+ dropped: int = 0 # characters dropped from the front of `text`
47
+ read_upto: int = 0 # absolute position the caller has read to
48
+ done: bool = False # exited, and everything it printed has been read in
49
+ changed: threading.Condition = field(default_factory=threading.Condition)
50
+ stop_lock: threading.Lock = field(default_factory=threading.Lock)
51
+ group_cleaned: bool = False
52
+ windows_job: object | None = None
53
+
54
+ @property
55
+ def running(self) -> bool:
56
+ return _group_running(self)
57
+
58
+ def end(self) -> int:
59
+ return self.dropped + len(self.text)
60
+
61
+
62
+ _processes: dict[str, _Process] = {}
63
+
64
+
65
+ def _group_running(proc: _Process) -> bool:
66
+ """The group may outlive its leader. Zombies have already stopped.
67
+
68
+ Linux CI's PID 1 may not reap orphan zombies promptly; killpg(..., 0)
69
+ alone therefore cannot tell whether a command is still executing.
70
+ """
71
+ if proc.group_cleaned:
72
+ return False
73
+ proc.popen.poll() # reap our own child even while its children hold stdout
74
+ if os.name == "nt":
75
+ if proc.windows_job is not None:
76
+ active = proc.windows_job.running()
77
+ if not active:
78
+ proc.windows_job.close()
79
+ proc.group_cleaned = True
80
+ return active
81
+ return proc.popen.returncode is None
82
+ try:
83
+ os.killpg(proc.popen.pid, 0)
84
+ except ProcessLookupError:
85
+ proc.group_cleaned = True
86
+ return False
87
+ except PermissionError:
88
+ return True
89
+ if Path("/proc/self/stat").exists():
90
+ seen = False
91
+ for entry in Path("/proc").iterdir():
92
+ if not entry.name.isdecimal():
93
+ continue
94
+ try:
95
+ fields = (entry / "stat").read_text().rsplit(")", 1)[1].split()
96
+ if int(fields[2]) != proc.popen.pid:
97
+ continue
98
+ seen = True
99
+ if fields[0] not in ("Z", "X"):
100
+ return True
101
+ except (OSError, ValueError, IndexError):
102
+ continue
103
+ if seen:
104
+ proc.group_cleaned = True
105
+ return False
106
+ return True
107
+
108
+
109
+ def _wait_group(proc: _Process, seconds: float) -> bool:
110
+ deadline = time.monotonic() + max(0.0, seconds)
111
+ while _group_running(proc):
112
+ remaining = deadline - time.monotonic()
113
+ if remaining <= 0:
114
+ return False
115
+ time.sleep(min(0.05, remaining))
116
+ return True
117
+
118
+
119
+ def _pump(proc: _Process) -> None:
120
+ stream = proc.popen.stdout
121
+ try:
122
+ while True:
123
+ chunk = stream.read1(4096) if hasattr(stream, "read1") else stream.read(4096)
124
+ if not chunk:
125
+ break
126
+ text = chunk.decode("utf-8", errors="replace")
127
+ with proc.changed:
128
+ proc.text += text
129
+ if len(proc.text) > MAX_BUFFER:
130
+ cut = len(proc.text) - MAX_BUFFER
131
+ proc.text = proc.text[cut:]
132
+ proc.dropped += cut
133
+ proc.changed.notify_all()
134
+ except (OSError, ValueError):
135
+ pass
136
+ finally:
137
+ proc.popen.wait()
138
+ stream.close()
139
+ with proc.changed:
140
+ proc.done = True
141
+ proc.changed.notify_all()
142
+
143
+
144
+ def start(argv: str | Sequence[str], *, shell: bool, cwd: str | None, label: str,
145
+ wait: float = 3.0, until: str | None = None) -> dict:
146
+ with _lock:
147
+ running = [p for p in _processes.values() if p.running]
148
+ if len(running) >= MAX_RUNNING:
149
+ ids = ", ".join(p.id for p in running)
150
+ return {"success": False, "error": f"{MAX_RUNNING} background processes are already running "
151
+ f"({ids}). Stop one with the process tool first."}
152
+ popen = subprocess.Popen(
153
+ argv, shell=shell, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
154
+ stderr=subprocess.STDOUT, start_new_session=True,
155
+ # The command must not spawn children before the Job owns it.
156
+ creationflags=0x4 if os.name == "nt" else 0, # CREATE_SUSPENDED
157
+ )
158
+ proc = _Process(id=f"p{next(_ids)}", command=label, cwd=cwd or os.getcwd(), popen=popen)
159
+ if os.name == "nt":
160
+ from .windows_job import WindowsJob
161
+ try:
162
+ proc.windows_job = WindowsJob(popen)
163
+ proc.windows_job.resume(popen.pid)
164
+ except OSError as exc:
165
+ if proc.windows_job is not None:
166
+ proc.windows_job.close()
167
+ popen.kill()
168
+ popen.communicate(timeout=5)
169
+ return {"success": False, "error": f"Cannot manage the background process tree: {exc}"}
170
+ _processes[proc.id] = proc
171
+ threading.Thread(target=_pump, args=(proc,), daemon=True, name=f"aria-{proc.id}").start()
172
+ return {"success": True, "data": read(proc.id, wait=wait, until=until)["data"] | {"background": True}}
173
+
174
+
175
+ def _get(process_id: str) -> _Process | None:
176
+ return _processes.get(str(process_id or "").strip())
177
+
178
+
179
+ def _unknown(process_id: str) -> dict:
180
+ known = ", ".join(_processes) or "none"
181
+ return {"success": False, "error": f"No background process '{process_id}' (known: {known})."}
182
+
183
+
184
+ def read(process_id: str, *, wait: float = 0.0, until: str | None = None) -> dict:
185
+ """Output printed since the last read.
186
+
187
+ Waits up to ``wait`` seconds, returning early when the process exits or,
188
+ with ``until``, when that regular expression appears in the new output (a
189
+ server's "Listening on"). Returning at the first byte gave half a line
190
+ and a process that had not yet exited.
191
+ """
192
+ proc = _get(process_id)
193
+ if proc is None:
194
+ return _unknown(process_id)
195
+ pattern = None
196
+ if until:
197
+ try:
198
+ pattern = re.compile(until)
199
+ except re.error as exc:
200
+ return {"success": False, "error": f"Invalid 'until' pattern: {exc}"}
201
+ deadline = time.monotonic() + max(0.0, min(float(wait or 0), MAX_WAIT))
202
+
203
+ def ready() -> bool:
204
+ if proc.done:
205
+ return True
206
+ return bool(pattern and pattern.search(proc.text[max(0, proc.read_upto - proc.dropped):]))
207
+
208
+ with proc.changed:
209
+ while not ready():
210
+ left = deadline - time.monotonic()
211
+ if left <= 0:
212
+ break
213
+ proc.changed.wait(left)
214
+ start_at = max(proc.read_upto, proc.dropped)
215
+ missed = start_at - proc.read_upto
216
+ new = proc.text[start_at - proc.dropped:]
217
+ proc.read_upto = proc.end()
218
+ clipped = len(new) > MAX_READ
219
+ data = {
220
+ "process_id": proc.id,
221
+ "command": proc.command,
222
+ "running": proc.running,
223
+ "exit_code": proc.popen.returncode,
224
+ "output": new[-MAX_READ:],
225
+ }
226
+ if clipped or missed:
227
+ data["output_dropped_chars"] = missed + (len(new) - MAX_READ if clipped else 0)
228
+ if pattern is not None:
229
+ data["matched"] = bool(pattern.search(new))
230
+ return {"success": True, "data": data}
231
+
232
+
233
+ def write(process_id: str, text: str, *, wait: float = 1.0) -> dict:
234
+ proc = _get(process_id)
235
+ if proc is None:
236
+ return _unknown(process_id)
237
+ if not proc.running:
238
+ return {"success": False, "error": f"{proc.id} has exited (code {proc.popen.returncode})."}
239
+ try:
240
+ proc.popen.stdin.write(str(text).encode("utf-8"))
241
+ proc.popen.stdin.flush()
242
+ except (BrokenPipeError, OSError) as exc:
243
+ return {"success": False, "error": f"Could not write to {proc.id}: {exc}"}
244
+ return read(proc.id, wait=wait)
245
+
246
+
247
+ def stop(process_id: str, *, grace: float = 3.0) -> dict:
248
+ proc = _get(process_id)
249
+ if proc is None:
250
+ return _unknown(process_id)
251
+ error = ""
252
+ with proc.stop_lock:
253
+ if os.name == "nt" and proc.running:
254
+ try:
255
+ proc.windows_job.terminate()
256
+ _wait_group(proc, 2.0)
257
+ except OSError as exc:
258
+ error = str(exc)
259
+ elif os.name != "nt":
260
+ for sig, pause in ((signal.SIGTERM, min(max(float(grace), 0), 30)),
261
+ (signal.SIGKILL, 2.0)):
262
+ if not proc.running:
263
+ break
264
+ try:
265
+ os.killpg(proc.popen.pid, sig)
266
+ except ProcessLookupError:
267
+ proc.group_cleaned = True
268
+ break
269
+ except PermissionError as exc:
270
+ error = str(exc)
271
+ break
272
+ if _wait_group(proc, pause):
273
+ break
274
+ if proc.popen.poll() is not None and proc.popen.stdin:
275
+ proc.popen.stdin.close()
276
+ result = read(proc.id, wait=0.5)
277
+ result["data"]["stopped"] = not proc.running
278
+ if error or proc.running:
279
+ result.update(success=False, error=error or "The process group did not stop within the deadline.")
280
+ return result
281
+
282
+
283
+ def listing() -> dict:
284
+ rows = [{
285
+ "process_id": p.id, "command": p.command, "cwd": p.cwd, "running": p.running,
286
+ "exit_code": p.popen.returncode, "seconds": round(time.time() - p.started, 1),
287
+ "unread_chars": max(0, p.end() - max(p.read_upto, p.dropped)),
288
+ } for p in _processes.values()]
289
+ return {"success": True, "data": {"processes": rows}}
290
+
291
+
292
+ def stop_all() -> None:
293
+ for proc in list(_processes.values()):
294
+ if proc.running:
295
+ stop(proc.id, grace=1.0)
296
+
297
+
298
+ atexit.register(stop_all)
299
+
300
+
301
+ def tool_process(params: dict) -> dict:
302
+ """The ``process`` tool: output | input | stop | list."""
303
+ action = str(params.get("action") or "output").strip().lower()
304
+ pid = params.get("process_id", "")
305
+ if action == "list":
306
+ return listing()
307
+ if action == "output":
308
+ return read(pid, wait=params.get("wait_seconds", 2), until=params.get("until"))
309
+ if action == "input":
310
+ if "text" not in params:
311
+ return {"success": False, "error": "input needs 'text' (include \\n to press Enter)."}
312
+ return write(pid, params["text"], wait=params.get("wait_seconds", 1))
313
+ if action == "stop":
314
+ return stop(pid)
315
+ return {"success": False, "error": f"Unknown action '{action}': use output, input, stop or list."}
316
+
317
+
318
+ PROCESS_SCHEMA = {
319
+ "type": "function",
320
+ "function": {
321
+ "name": "process",
322
+ "description": (
323
+ "Manage a command started with run_command background=true (a dev server, a watcher, an "
324
+ "interactive program). action=output returns what it printed since the last read, "
325
+ "waiting up to wait_seconds, or until a regex `until` appears; action=input writes `text` "
326
+ "to its stdin (include \\n for Enter); action=stop ends it and everything it started; "
327
+ "action=list shows all background processes. Stop servers when you are done with them."
328
+ ),
329
+ "parameters": {
330
+ "type": "object",
331
+ "properties": {
332
+ "action": {"type": "string", "enum": ["output", "input", "stop", "list"]},
333
+ "process_id": {"type": "string", "description": "The id run_command returned, e.g. p1"},
334
+ "text": {"type": "string", "description": "For input: the text to send"},
335
+ "wait_seconds": {"type": "number", "description": "How long to wait for output (max 30)"},
336
+ "until": {"type": "string", "description": "For output: a regex to wait for, e.g. 'Listening on'"},
337
+ },
338
+ "required": ["action"],
339
+ },
340
+ },
341
+ }
342
+
343
+ __all__ = ["start", "read", "write", "stop", "listing", "stop_all", "tool_process", "PROCESS_SCHEMA"]