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,183 @@
1
+ """A real-message test for Prelude's intent routing, kept on this computer.
2
+
3
+ Hand-written test messages only show that a model learned its author's style. Real
4
+ messages are the check that matters, and they are private, so this tool never writes them
5
+ into a repository and the person who owns them does the reading and the labelling:
6
+
7
+ python -m aria_code.training.prelude_real extract --source DIR_OR_FILE
8
+ python -m aria_code.training.prelude_real label
9
+ python -m aria_code.training.prelude_real import --source FILE # label<TAB>message
10
+ python -m aria_code.training.prelude_real score --adapter ADAPTER
11
+
12
+ ``extract`` collects candidate messages from a directory of ``*.json`` interaction logs
13
+ (the ``instruction`` field) or a text file with one message per line, drops duplicates,
14
+ very short messages and anything that looks like a secret, an email address or a phone
15
+ number, and writes them to ``~/.aria/prelude/`` with owner-only permissions. ``label``
16
+ shows each message and asks for its label. ``score`` runs a model over the labelled
17
+ messages and prints counts only: accuracy and an interval, never a message.
18
+
19
+ Nothing here is ever committed; ``~/.aria/prelude`` is outside every repository.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import argparse
25
+ import json
26
+ import os
27
+ import re
28
+ import sys
29
+ from pathlib import Path
30
+ from typing import Iterable, List, Optional
31
+
32
+ from aria_code.evals.scorecard import wilson
33
+ from aria_code.training import prelude_eval as P
34
+
35
+ HOME = Path(os.environ.get("ARIA_PRELUDE_HOME") or Path.home() / ".aria" / "prelude")
36
+ CANDIDATES = HOME / "real_candidates.jsonl"
37
+ LABELLED = HOME / "real_test.jsonl"
38
+ KEYS = {"c": "coding", "a": "analysis", "r": "realtime", "g": "general", "f": "finance"}
39
+ MIN_CHARS = 6
40
+
41
+ _PRIVATE = [
42
+ re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+"), # email address
43
+ re.compile(r"(?<!\d)(?:\+?\d[\d\s-]{8,}\d)(?!\d)"), # phone or long account number
44
+ re.compile(r"\b(?:sk|pk|ghp|gho|AIza|AKIA|xox[bap])[-_A-Za-z0-9]{12,}"), # API keys and tokens
45
+ re.compile(r"\b[A-Za-z0-9_-]{32,}\b"), # any long opaque string
46
+ re.compile(r"(?i)\b(?:password|passwd|secret|token|api[_-]?key)\b\s*[:=]"),
47
+ ]
48
+
49
+
50
+ def looks_private(text: str) -> bool:
51
+ return any(pattern.search(text) for pattern in _PRIVATE)
52
+
53
+
54
+ def read_source(source: Path) -> Iterable[str]:
55
+ if source.is_dir():
56
+ for path in sorted(source.rglob("*.json")):
57
+ try:
58
+ record = json.loads(path.read_text(encoding="utf-8"))
59
+ except (OSError, ValueError):
60
+ continue
61
+ text = record.get("instruction") if isinstance(record, dict) else None
62
+ if isinstance(text, str):
63
+ yield text
64
+ else:
65
+ for line in source.read_text(encoding="utf-8").splitlines():
66
+ yield line
67
+
68
+
69
+ def candidates(texts: Iterable[str]) -> List[str]:
70
+ seen, out = set(), []
71
+ for text in texts:
72
+ text = " ".join(text.split())
73
+ if len(text) < MIN_CHARS or text in seen or looks_private(text):
74
+ continue
75
+ seen.add(text)
76
+ out.append(text)
77
+ return out
78
+
79
+
80
+ def _write_private(path: Path, rows: List[dict]) -> None:
81
+ HOME.mkdir(parents=True, exist_ok=True)
82
+ os.chmod(HOME, 0o700)
83
+ path.write_text("".join(json.dumps(r, ensure_ascii=False) + "\n" for r in rows), encoding="utf-8")
84
+ os.chmod(path, 0o600)
85
+
86
+
87
+ def extract(source: Path) -> dict:
88
+ kept = candidates(read_source(source))
89
+ _write_private(CANDIDATES, [{"text": t} for t in kept])
90
+ return {"candidates": len(kept), "written_to": str(CANDIDATES)}
91
+
92
+
93
+ def _load(path: Path) -> List[dict]:
94
+ if not path.is_file():
95
+ return []
96
+ return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()]
97
+
98
+
99
+ def label(ask=input, show=print) -> dict:
100
+ """Walk through unlabelled candidates; resumable, and a skipped message stays out."""
101
+ done = {r["text"] for r in _load(LABELLED)}
102
+ rows = _load(LABELLED)
103
+ todo = [r["text"] for r in _load(CANDIDATES) if r["text"] not in done]
104
+ show("c=coding a=analysis r=realtime g=general f=finance s=skip q=quit")
105
+ for text in todo:
106
+ show(f"\n{text}")
107
+ while True:
108
+ answer = ask("> ").strip().lower()
109
+ if answer == "q":
110
+ _write_private(LABELLED, rows)
111
+ return {"labelled": len(rows)}
112
+ if answer == "s" or answer in KEYS:
113
+ break
114
+ if answer in KEYS:
115
+ rows.append({"text": text, "label": KEYS[answer]})
116
+ _write_private(LABELLED, rows)
117
+ return {"labelled": len(rows)}
118
+
119
+
120
+ def import_labelled(source: Path) -> dict:
121
+ """Load ``label<TAB>message`` lines written by the owner, replacing any earlier labels."""
122
+ valid = set(P.INTENT_LABELS)
123
+ rows, skipped = [], 0
124
+ for line in source.read_text(encoding="utf-8").splitlines():
125
+ label_name, _, text = line.partition("\t")
126
+ label_name, text = label_name.strip().lower(), " ".join(text.split())
127
+ if label_name in valid and len(text) >= 2:
128
+ rows.append({"text": text, "label": label_name})
129
+ elif line.strip():
130
+ skipped += 1
131
+ _write_private(LABELLED, rows)
132
+ per_label = {name: sum(1 for r in rows if r["label"] == name) for name in P.INTENT_LABELS}
133
+ return {"labelled": len(rows), "skipped_lines": skipped, "per_label": per_label}
134
+
135
+
136
+ def score(adapter: Optional[Path], model: Optional[str]) -> dict:
137
+ """Counts only. A message never leaves this function."""
138
+ from aria_code.training import prelude_train as T
139
+ from mlx_lm import generate, load
140
+
141
+ labelled = _load(LABELLED)
142
+ if not labelled:
143
+ raise SystemExit(f"Nothing labelled yet in {LABELLED}. Run `label` first.")
144
+ network, tokenizer = load(T.base_model(model), adapter_path=str(adapter) if adapter else None)
145
+ right = unparsable = 0
146
+ for row in labelled:
147
+ prompt = tokenizer.apply_chat_template(
148
+ [{"role": "system", "content": P.INTENT_SYSTEM}, {"role": "user", "content": row["text"]}],
149
+ add_generation_prompt=True, tokenize=False)
150
+ prediction = P.parse_prediction("intent", generate(network, tokenizer, prompt=prompt, max_tokens=6))
151
+ unparsable += prediction is None
152
+ right += prediction == row["label"]
153
+ low, high = wilson(right, len(labelled))
154
+ return {"adapter": str(adapter) if adapter else None, "n": len(labelled), "correct": right,
155
+ "accuracy": round(right / len(labelled), 4), "ci95": [round(low, 4), round(high, 4)],
156
+ "unparsable": unparsable}
157
+
158
+
159
+ def main(argv: Optional[List[str]] = None) -> int:
160
+ parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
161
+ sub = parser.add_subparsers(dest="command", required=True)
162
+ e = sub.add_parser("extract")
163
+ e.add_argument("--source", required=True, help="a directory of *.json interaction logs, or a text file")
164
+ sub.add_parser("label")
165
+ i = sub.add_parser("import", help="load label<TAB>message lines you wrote yourself")
166
+ i.add_argument("--source", required=True)
167
+ s = sub.add_parser("score")
168
+ s.add_argument("--adapter")
169
+ s.add_argument("--model")
170
+ args = parser.parse_args(argv)
171
+ if args.command == "extract":
172
+ print(json.dumps(extract(Path(args.source).expanduser())))
173
+ elif args.command == "label":
174
+ print(json.dumps(label()))
175
+ elif args.command == "import":
176
+ print(json.dumps(import_labelled(Path(args.source).expanduser())))
177
+ else:
178
+ print(json.dumps(score(Path(args.adapter) if args.adapter else None, args.model), indent=2))
179
+ return 0
180
+
181
+
182
+ if __name__ == "__main__":
183
+ sys.exit(main())
@@ -0,0 +1,248 @@
1
+ """Train and score Prelude's risk gate with MLX LoRA on a Mac.
2
+
3
+ Reproduces the experiment end to end from files in this repository:
4
+
5
+ python -m aria_code.training.prelude_train data --out DIR [--task intent]
6
+ python -m aria_code.training.prelude_train train --data DIR --adapter DIR/adapter
7
+ python -m aria_code.training.prelude_train pick --log DIR/train.log --adapter DIR/adapter
8
+ python -m aria_code.training.prelude_train eval --adapter DIR/adapter
9
+
10
+ ``data`` uses only train-side splits (``dev`` and ``extra``). Variants of those commands
11
+ are generated by swapping arguments and wrapping them (``cd x &&``, ``time``, a pipe to
12
+ ``tail``), labelled by ``safety.risk``, and a command that also appears in a test split
13
+ is dropped. Levels 3 and 4 are repeated so the loss weighs the dangerous cases. Risk
14
+ ``data`` needs the locked sets from aria-evals-holdout (``ARIA_PRELUDE_HOLDOUT``) so it can
15
+ drop their families too. ``pick`` chooses a checkpoint by validation loss only. ``eval``
16
+ reports every split it can load; read ``test2`` as a score and never as a list of
17
+ mistakes to fix.
18
+
19
+ Needs ``mlx-lm`` (Apple Silicon); it is imported only by ``train`` and ``eval``.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import argparse
25
+ import hashlib
26
+ import json
27
+ import random
28
+ import re
29
+ import shutil
30
+ import subprocess
31
+ import sys
32
+ from pathlib import Path
33
+ from typing import Dict, List, Optional, Tuple
34
+
35
+ from aria_code.training import prelude_eval as P
36
+
37
+ FILES = ["app.py", "src/main.rs", "README.md", "config.yaml", "docs/guide.md", "build/out.js", "tests/test_x.py",
38
+ "data/prices.csv", "notes.txt", "src/index.ts", "lib/util.go", "scripts/run.sh", "output/report.pdf",
39
+ "tmp/cache.bin", "web/app.css"]
40
+ PACKAGES = ["left-pad", "requests", "numpy", "zod", "serde", "rich", "pandas", "express", "tokio", "axios"]
41
+ BRANCHES = ["main", "dev", "feature/login", "fix/crash", "release/1.2"]
42
+ HOSTS = ["https://api.example.com/v1", "https://example.org/data.json", "https://files.test.io/pkg.tgz",
43
+ "http://localhost:8080/health"]
44
+ WRAPPERS = [
45
+ lambda c: c, lambda c: f"cd project && {c}", lambda c: f"time {c}", lambda c: f"{c} 2>&1",
46
+ lambda c: f"{c} | tail -20", lambda c: f"cd src && {c}", lambda c: f"FOO=1 {c}", lambda c: f"{c} | head -5",
47
+ ]
48
+ WEIGHT = {3: 3, 4: 2} # how many times a level appears in the training file
49
+ VARIANTS_PER_FAMILY = 14
50
+ SEED = 7
51
+ MODEL_ENV = "ARIA_PRELUDE_BASE"
52
+
53
+
54
+ def vary(command: str, rng: random.Random) -> str:
55
+ tokens = command.split(" ")
56
+ for i, token in enumerate(tokens):
57
+ if not i:
58
+ continue
59
+ if re.search(r"\.\w{1,4}$|/", token) and not token.startswith(("http", "-", "/dev", "~/.ssh", ".env")) \
60
+ and ".pem" not in token and "credentials" not in token:
61
+ tokens[i] = rng.choice(FILES)
62
+ elif token in PACKAGES:
63
+ tokens[i] = rng.choice(PACKAGES)
64
+ elif token in BRANCHES:
65
+ tokens[i] = rng.choice(BRANCHES)
66
+ elif token.startswith("http") and "|" not in command:
67
+ tokens[i] = rng.choice(HOSTS)
68
+ return " ".join(tokens)
69
+
70
+
71
+ def record(command: str, level, system: str = P.RISK_SYSTEM) -> dict:
72
+ return {"messages": [{"role": "system", "content": system}, {"role": "user", "content": command},
73
+ {"role": "assistant", "content": str(level)}]}
74
+
75
+
76
+ def is_validation(family: str) -> bool:
77
+ return int(hashlib.sha256(family.encode()).hexdigest(), 16) % 10 == 3
78
+
79
+
80
+ def build_training_data(require_holdout: bool = True) -> Tuple[List[dict], List[dict], dict]:
81
+ """(train, validation, facts) from train-side splits only.
82
+
83
+ Generated variants can land in a locked family, and only the locked sets say which
84
+ families those are, so without them this refuses rather than risk training on one.
85
+ """
86
+ from aria_code.safety.risk import assess_command
87
+
88
+ if require_holdout and not P.holdout_available("risk"):
89
+ raise SystemExit(f"The locked risk sets are not at {P.HOLDOUT}. Clone aria-evals-holdout "
90
+ "next to this checkout or set ARIA_PRELUDE_HOLDOUT to its prelude/ directory.")
91
+ rng = random.Random(SEED)
92
+ rows = P.load("risk")
93
+ train_rows = [r for r in rows if r["split"] in ("dev", "extra", "extra2")]
94
+ held_out = {r["input"] for r in rows if r["split"] in ("test", "test2", "test3")}
95
+ held_families = {r["family"] for r in rows if r["split"] in ("test", "test2", "test3")}
96
+ bases: Dict[str, str] = {}
97
+ for r in train_rows:
98
+ bases.setdefault(re.sub(r"^(cd project && |time )", "", r["input"]), r["family"])
99
+ variants: Dict[str, str] = {}
100
+ counts: Dict[str, int] = {}
101
+ for base, fam in bases.items():
102
+ for _ in range(40):
103
+ command = rng.choice(WRAPPERS)(vary(base, rng))
104
+ if "\n" in command or command in variants:
105
+ continue
106
+ variants[command] = fam
107
+ counts[fam] = counts.get(fam, 0) + 1
108
+ if counts[fam] >= VARIANTS_PER_FAMILY:
109
+ break
110
+ pool = [(c, assess_command(c).level, f) for c, f in variants.items()]
111
+ pool += [(r["input"], r["label"], r["family"]) for r in train_rows]
112
+ seen, distinct = set(), []
113
+ for command, level, fam in pool:
114
+ if command in seen or command in held_out or fam in held_families or P.family(command) in held_families:
115
+ continue
116
+ seen.add(command)
117
+ distinct.append((command, level, fam))
118
+ train, valid = [], []
119
+ for command, level, fam in distinct:
120
+ if is_validation(fam):
121
+ valid.append(record(command, level))
122
+ else:
123
+ train.extend(record(command, level) for _ in range(WEIGHT.get(level, 1)))
124
+ rng.shuffle(train)
125
+ return train, valid, {"distinct": len(distinct), "train_lines": len(train), "validation_lines": len(valid)}
126
+
127
+
128
+ def build_intent_data() -> Tuple[List[dict], List[dict], dict]:
129
+ """Train and validation records for intent routing, from the ``dev`` split only.
130
+
131
+ Messages are hand-written and independent, so each is its own family. A fixed share of
132
+ ``dev`` is held back for choosing a checkpoint; ``test`` is never read here.
133
+ """
134
+ rng = random.Random(SEED)
135
+ rows = [r for r in P.load("intent") if r["split"] == "dev"]
136
+ train, valid = [], []
137
+ for r in rows:
138
+ (valid if is_validation(r["input"]) else train).append(record(r["input"], r["label"], P.INTENT_SYSTEM))
139
+ # A short run over ~150 messages underfits; repeat so the step count means something.
140
+ train = train * 4
141
+ rng.shuffle(train)
142
+ return train, valid, {"distinct": len(rows), "train_lines": len(train), "validation_lines": len(valid)}
143
+
144
+
145
+ def write_data(out: Path, task: str = "risk") -> dict:
146
+ train, valid, facts = build_intent_data() if task == "intent" else build_training_data()
147
+ out.mkdir(parents=True, exist_ok=True)
148
+ for name, data in (("train", train), ("valid", valid)):
149
+ (out / f"{name}.jsonl").write_text("".join(json.dumps(x, ensure_ascii=False) + "\n" for x in data),
150
+ encoding="utf-8")
151
+ return facts
152
+
153
+
154
+ def base_model(explicit: Optional[str]) -> str:
155
+ import os
156
+
157
+ value = explicit or os.environ.get(MODEL_ENV)
158
+ if value:
159
+ return value
160
+ cache = Path.home() / ".cache" / "huggingface" / "hub" / "models--Qwen--Qwen2.5-1.5B-Instruct" / "snapshots"
161
+ found = sorted(cache.glob("*")) if cache.is_dir() else []
162
+ if not found:
163
+ raise SystemExit(f"Pass --model, or set {MODEL_ENV}, to a Qwen2.5-1.5B-Instruct directory or Hugging Face id.")
164
+ return str(found[-1])
165
+
166
+
167
+ def train(data: Path, adapter: Path, model: Optional[str], iters: int, rate: float, layers: int) -> int:
168
+ command = [sys.executable, "-m", "mlx_lm", "lora", "--model", base_model(model), "--train", "--data", str(data),
169
+ "--adapter-path", str(adapter), "--iters", str(iters), "--batch-size", "4", "--num-layers", str(layers),
170
+ "--learning-rate", str(rate), "--steps-per-eval", "100", "--val-batches", "42", "--save-every", "100",
171
+ "--mask-prompt"]
172
+ return subprocess.call(command)
173
+
174
+
175
+ def validation_losses(log: str) -> Dict[int, float]:
176
+ text = re.sub(r"\x1b\[[0-9;]*m", "", log).replace("\r", "\n")
177
+ return {int(m.group(1)): float(m.group(2)) for m in re.finditer(r"^\s*(\d+)\s+val\s+([\d.]+)", text, re.M)
178
+ if int(m.group(1)) > 1}
179
+
180
+
181
+ def pick(log: Path, adapter: Path) -> int:
182
+ losses = validation_losses(log.read_text(encoding="utf-8", errors="replace"))
183
+ if not losses:
184
+ raise SystemExit("No validation losses in the log.")
185
+ step = min(losses, key=losses.get)
186
+ checkpoint = adapter / f"{step:07d}_adapters.safetensors"
187
+ if not checkpoint.is_file():
188
+ raise SystemExit(f"Checkpoint for step {step} is missing: {checkpoint}")
189
+ chosen = adapter.with_name(adapter.name + f"-best-{step}")
190
+ chosen.mkdir(exist_ok=True)
191
+ shutil.copy(adapter / "adapter_config.json", chosen / "adapter_config.json")
192
+ shutil.copy(checkpoint, chosen / "adapters.safetensors")
193
+ print(json.dumps({"step": step, "validation_loss": losses[step], "adapter": str(chosen)}))
194
+ return 0
195
+
196
+
197
+ def evaluate(adapter: Optional[Path], model: Optional[str], task: str = "risk") -> dict:
198
+ from mlx_lm import generate, load
199
+
200
+ network, tokenizer = load(base_model(model), adapter_path=str(adapter) if adapter else None)
201
+ rows = P.load(task)
202
+ system = P.RISK_SYSTEM if task == "risk" else P.INTENT_SYSTEM
203
+ predictions = {}
204
+ for row in rows:
205
+ prompt = tokenizer.apply_chat_template(
206
+ [{"role": "system", "content": system}, {"role": "user", "content": row["input"]}],
207
+ add_generation_prompt=True, tokenize=False)
208
+ predictions[row["id"]] = P.parse_prediction(task, generate(network, tokenizer, prompt=prompt, max_tokens=6))
209
+ report = P.score(task, rows, predictions)
210
+ report.pop("confusion", None)
211
+ return {"adapter": str(adapter) if adapter else None, **report}
212
+
213
+
214
+ def main(argv: Optional[List[str]] = None) -> int:
215
+ parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
216
+ sub = parser.add_subparsers(dest="command", required=True)
217
+ d = sub.add_parser("data")
218
+ d.add_argument("--out", required=True)
219
+ d.add_argument("--task", choices=("risk", "intent"), default="risk")
220
+ t = sub.add_parser("train")
221
+ t.add_argument("--data", required=True)
222
+ t.add_argument("--adapter", required=True)
223
+ t.add_argument("--model")
224
+ t.add_argument("--iters", type=int, default=1000)
225
+ t.add_argument("--rate", type=float, default=5e-5)
226
+ t.add_argument("--layers", type=int, default=8)
227
+ k = sub.add_parser("pick")
228
+ k.add_argument("--log", required=True)
229
+ k.add_argument("--adapter", required=True)
230
+ e = sub.add_parser("eval")
231
+ e.add_argument("--task", choices=("risk", "intent"), default="risk")
232
+ e.add_argument("--adapter")
233
+ e.add_argument("--model")
234
+ args = parser.parse_args(argv)
235
+ if args.command == "data":
236
+ print(json.dumps(write_data(Path(args.out), args.task)))
237
+ return 0
238
+ if args.command == "train":
239
+ return train(Path(args.data), Path(args.adapter), args.model, args.iters, args.rate, args.layers)
240
+ if args.command == "pick":
241
+ return pick(Path(args.log), Path(args.adapter))
242
+ print(json.dumps(evaluate(Path(args.adapter) if args.adapter else None, args.model, args.task),
243
+ ensure_ascii=False, indent=2))
244
+ return 0
245
+
246
+
247
+ if __name__ == "__main__":
248
+ sys.exit(main())
@@ -0,0 +1,230 @@
1
+ """Eval trajectories -> a supervised fine-tuning set, built the way a quant builds a backtest.
2
+
3
+ The rules (docs/training-protocol.md) are enforced here, in code, not by care:
4
+
5
+ - **No look-ahead.** Tasks in the locked holdout suites (``hard`` by default)
6
+ never produce an example, and a trajectory that touched a grader file is
7
+ dropped: a model trained on the answer key measures nothing.
8
+ - **Split by task, never by attempt.** Two attempts at one task are near
9
+ copies; one in train and one in validation is leakage. The split is a
10
+ stable hash of the task id, so it does not move when data is added.
11
+ - **No survivorship of lucky runs.** Only attempts the grader passed *and*
12
+ whose own acceptance check did not fail become examples.
13
+ - **Exposure is reported.** Examples per domain and split, so a set that is
14
+ 90% one domain is visible before it trains a lopsided model.
15
+ - **Provenance.** The manifest records each input file's sha256, the rules
16
+ and the counts, so a tuned model can be traced to exactly what it saw.
17
+
18
+ Output is the Vertex AI Gemini supervised-tuning format: one JSON object per
19
+ line with ``systemInstruction`` and ``contents``, tool use as
20
+ ``functionCall`` / ``functionResponse`` parts.
21
+
22
+ python -m aria_code.training.sft_dataset trajectories/ --suites evals/suites --out sft/
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import fnmatch
29
+ import hashlib
30
+ import json
31
+ from collections import Counter, defaultdict
32
+ from dataclasses import dataclass, field
33
+ from pathlib import Path
34
+ from typing import Iterable
35
+
36
+ DEFAULT_HOLDOUT = ("hard",)
37
+ DOMAINS = ("software", "finance", "payments", "logistics")
38
+ RESULT_CHARS = 6_000 # one tool result in an example; long outputs are cut, not dropped
39
+
40
+
41
+ @dataclass
42
+ class Trajectory:
43
+ path: Path
44
+ suite: str
45
+ task_id: str
46
+ attempt: int
47
+ model: str
48
+ prompt: str
49
+ events: list[dict] = field(default_factory=list)
50
+ outcome: dict = field(default_factory=dict)
51
+
52
+ @property
53
+ def final(self) -> dict:
54
+ return next((e for e in reversed(self.events) if e.get("type") == "turn.completed"), {})
55
+
56
+
57
+ @dataclass
58
+ class TaskInfo:
59
+ suite: str
60
+ tags: tuple[str, ...]
61
+ hidden: tuple[str, ...]
62
+
63
+
64
+ def load_trajectories(root: Path) -> list[Trajectory]:
65
+ out = []
66
+ for path in sorted(Path(root).rglob("*.jsonl")):
67
+ lines = [json.loads(l) for l in path.read_text(encoding="utf-8").splitlines() if l.strip().startswith("{")]
68
+ if not lines or lines[0].get("type") != "eval.task":
69
+ continue
70
+ head = lines[0]
71
+ outcome: dict = next((l for l in reversed(lines) if l.get("type") == "eval.outcome"), {})
72
+ events = [l for l in lines[1:] if l.get("type") not in ("eval.task", "eval.outcome")]
73
+ out.append(Trajectory(path=path, suite=path.parent.name, task_id=str(head.get("task_id")),
74
+ attempt=int(head.get("attempt") or 1), model=str(head.get("model") or ""),
75
+ prompt=str(head.get("prompt") or ""), events=events, outcome=outcome))
76
+ return out
77
+
78
+
79
+ def load_tasks(suites_dir: Path) -> dict[str, TaskInfo]:
80
+ import yaml
81
+
82
+ tasks = {}
83
+ for suite_file in sorted(Path(suites_dir).glob("*.yaml")):
84
+ doc = yaml.safe_load(suite_file.read_text(encoding="utf-8")) or {}
85
+ for t in doc.get("tasks") or []:
86
+ tasks[str(t["id"])] = TaskInfo(suite=str(doc.get("suite") or suite_file.stem),
87
+ tags=tuple(t.get("tags") or ()),
88
+ hidden=tuple(t.get("hidden") or ()))
89
+ return tasks
90
+
91
+
92
+ def split_of(task_id: str, validation_share: float = 0.2) -> str:
93
+ """"train" or "validation", fixed by the task id alone."""
94
+ bucket = int(hashlib.sha256(task_id.encode()).hexdigest()[:8], 16) / 0xFFFFFFFF
95
+ return "validation" if bucket < validation_share else "train"
96
+
97
+
98
+ def domain_of(tags: Iterable[str]) -> str:
99
+ tags = set(tags)
100
+ for d in DOMAINS:
101
+ if d in tags:
102
+ return "finance" if d == "payments" else d
103
+ return "other"
104
+
105
+
106
+ def why_excluded(t: Trajectory, info: TaskInfo | None, holdout: tuple[str, ...]) -> str | None:
107
+ if info is None:
108
+ return "task not in any suite"
109
+ if info.suite in holdout or t.suite in holdout:
110
+ return "locked holdout"
111
+ if t.outcome.get("outcome") != "pass":
112
+ return f"outcome {t.outcome.get('outcome') or 'missing'}"
113
+ final = t.final
114
+ if not final:
115
+ return "no turn.completed"
116
+ acceptance = final.get("acceptance") or {}
117
+ if isinstance(acceptance, dict) and acceptance.get("verified") is False:
118
+ return "its own checks failed"
119
+ text = json.dumps(t.events, ensure_ascii=False)
120
+ graders = set(info.hidden) | {"test_*_hidden.py"}
121
+ for event in t.events:
122
+ for value in (event.get("params") or {}).values():
123
+ name = Path(str(value)).name
124
+ if any(fnmatch.fnmatch(name, g) for g in graders):
125
+ return "touched a grader"
126
+ if "eval.outcome" in text or "reward.json" in text:
127
+ return "grader output in the trajectory"
128
+ return None
129
+
130
+
131
+ def to_example(t: Trajectory, system: str) -> dict:
132
+ """One Vertex Gemini SFT record from one trajectory."""
133
+ contents: list[dict] = [{"role": "user", "parts": [{"text": t.prompt}]}]
134
+ pending: list[dict] = []
135
+ for event in t.events:
136
+ kind = event.get("type")
137
+ if kind == "tool.started":
138
+ call = {"functionCall": {"name": event.get("tool"), "args": event.get("params") or {}}}
139
+ if contents[-1]["role"] == "model" and not pending:
140
+ contents[-1]["parts"].append(call)
141
+ else:
142
+ contents.append({"role": "model", "parts": [call]})
143
+ pending.append(event)
144
+ elif kind == "tool.completed" and pending:
145
+ pending.pop(0)
146
+ result = event.get("result")
147
+ if result is None:
148
+ result = {"success": event.get("success"), "error": event.get("error", "")}
149
+ body = json.dumps(result, ensure_ascii=False)
150
+ if len(body) > RESULT_CHARS:
151
+ result = {"truncated": True, "head": body[:RESULT_CHARS]}
152
+ part = {"functionResponse": {"name": event.get("tool"), "response": result}}
153
+ if contents[-1]["role"] == "user" and "functionResponse" in contents[-1]["parts"][0]:
154
+ contents[-1]["parts"].append(part)
155
+ else:
156
+ contents.append({"role": "user", "parts": [part]})
157
+ final = str(t.final.get("response") or "").strip()
158
+ if final:
159
+ contents.append({"role": "model", "parts": [{"text": final}]})
160
+ return {"systemInstruction": {"role": "system", "parts": [{"text": system}]}, "contents": contents}
161
+
162
+
163
+ def build(trajectories: Path, suites: Path, out: Path, *, holdout=DEFAULT_HOLDOUT,
164
+ validation_share: float = 0.2, system: str = "") -> dict:
165
+ tasks = load_tasks(suites)
166
+ trajs = load_trajectories(trajectories)
167
+ out.mkdir(parents=True, exist_ok=True)
168
+ system = system or ("You are Aria, an AI agent for coding, financial analysis and logistics "
169
+ "operations. Read the workspace first, compute every number with code from "
170
+ "named data, keep each client's data apart, and check your work before you finish.")
171
+ split_files = {s: (out / f"{s}.jsonl").open("w", encoding="utf-8") for s in ("train", "validation")}
172
+ excluded: Counter = Counter()
173
+ exposure: dict[str, Counter] = defaultdict(Counter)
174
+ seen_tasks: dict[str, set[str]] = defaultdict(set)
175
+ fingerprints: set[str] = set()
176
+ try:
177
+ for t in trajs:
178
+ info = tasks.get(t.task_id)
179
+ reason = why_excluded(t, info, tuple(holdout))
180
+ if reason:
181
+ excluded[reason] += 1
182
+ continue
183
+ example = to_example(t, system)
184
+ fp = hashlib.sha256(json.dumps(example["contents"], sort_keys=True).encode()).hexdigest()
185
+ if fp in fingerprints:
186
+ excluded["duplicate"] += 1
187
+ continue
188
+ fingerprints.add(fp)
189
+ split = split_of(t.task_id, validation_share)
190
+ seen_tasks[split].add(t.task_id)
191
+ exposure[split][domain_of(info.tags)] += 1
192
+ split_files[split].write(json.dumps(example, ensure_ascii=False) + "\n")
193
+ finally:
194
+ for fh in split_files.values():
195
+ fh.close()
196
+
197
+ overlap = seen_tasks["train"] & seen_tasks["validation"]
198
+ assert not overlap, f"task in two splits: {sorted(overlap)}"
199
+ holdout_tasks = sorted(tid for tid, info in tasks.items() if info.suite in holdout)
200
+ manifest = {
201
+ "rules": {"holdout_suites": list(holdout), "split": "sha256(task_id)", "validation_share": validation_share,
202
+ "eligible": "grader PASS and acceptance not failed; no grader file touched"},
203
+ "inputs": {str(t.path): hashlib.sha256(t.path.read_bytes()).hexdigest() for t in trajs},
204
+ "models": sorted({t.model for t in trajs}),
205
+ "examples": {s: sum(c.values()) for s, c in exposure.items()},
206
+ "tasks": {s: sorted(v) for s, v in seen_tasks.items()},
207
+ "exposure_by_domain": {s: dict(c) for s, c in exposure.items()},
208
+ "excluded": dict(excluded),
209
+ "holdout_tasks": holdout_tasks,
210
+ }
211
+ (out / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
212
+ return manifest
213
+
214
+
215
+ def main(argv: list[str] | None = None) -> int:
216
+ ap = argparse.ArgumentParser(description="Build a Vertex Gemini SFT set from eval trajectories.")
217
+ ap.add_argument("trajectories", type=Path)
218
+ ap.add_argument("--suites", type=Path, default=Path("evals/suites"))
219
+ ap.add_argument("--out", type=Path, required=True)
220
+ ap.add_argument("--holdout", nargs="*", default=list(DEFAULT_HOLDOUT))
221
+ ap.add_argument("--validation-share", type=float, default=0.2)
222
+ args = ap.parse_args(argv)
223
+ m = build(args.trajectories, args.suites, args.out, holdout=tuple(args.holdout),
224
+ validation_share=args.validation_share)
225
+ print(json.dumps({k: m[k] for k in ("examples", "exposure_by_domain", "excluded")}, ensure_ascii=False, indent=2))
226
+ return 0
227
+
228
+
229
+ if __name__ == "__main__":
230
+ raise SystemExit(main())