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,522 @@
1
+ """SQLite-backed run and event persistence for the Aria agent runtime."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import re
8
+ import socket
9
+ import sqlite3
10
+ import time
11
+ import uuid
12
+ from dataclasses import dataclass, field
13
+ from pathlib import Path
14
+ from typing import Any, Dict, Iterable, Optional
15
+
16
+ from .run_state import (
17
+ ACTIVE_RUN_STATUSES,
18
+ RunStatus,
19
+ is_terminal,
20
+ normalize_run_status,
21
+ require_transition,
22
+ )
23
+ from aria_code.packages.aria_core.paths import aria_home
24
+ from .task_brief import TaskBrief, brief_digest
25
+
26
+
27
+ # Compared with every non-alphanumeric character removed and lowercased, so
28
+ # apiKey, api-key and API_KEY are all the same field.
29
+ _SECRET_KEYS = {
30
+ "apikey",
31
+ "accesstoken",
32
+ "authtoken",
33
+ "refreshtoken",
34
+ "authorization",
35
+ "cookie",
36
+ "password",
37
+ "passwd",
38
+ "privatekey",
39
+ "secret",
40
+ "clientsecret",
41
+ "token",
42
+ }
43
+
44
+ # Credentials inside free text: prompts, errors, tool output, commands. The
45
+ # shapes are those exec_events.py already masks on screen and in CI logs.
46
+ _SECRET_TEXT = (
47
+ (re.compile(r"(?i)\b(api[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|client[_-]?secret"
48
+ r"|token|password|passwd|secret)(\s*[=:]\s*)[\"']?[^\s'\",;]+"), r"\1\2[REDACTED]"),
49
+ (re.compile(r"(?i)\b(bearer|basic)(\s+)[A-Za-z0-9._~+/=-]+"), r"\1\2[REDACTED]"),
50
+ (re.compile(r"(?i)\b([a-z][a-z0-9+.-]*://)[^\s/:@]+:[^\s/@]+@"), r"\1[REDACTED]@"),
51
+ (re.compile(r"\b(?:sk|pk|rk)-[A-Za-z0-9_-]{8,}|\bgh[pousr]_[A-Za-z0-9]{12,}"
52
+ r"|\bAIza[0-9A-Za-z_-]{20,}|\bya29\.[0-9A-Za-z_-]+"), "[REDACTED]"),
53
+ )
54
+
55
+
56
+ def _redact_text(value: str) -> str:
57
+ for pattern, replacement in _SECRET_TEXT:
58
+ value = pattern.sub(replacement, value)
59
+ return value
60
+
61
+
62
+ def _default_database_path() -> Path:
63
+ configured = os.getenv("ARIA_HOME")
64
+ if configured:
65
+ root = Path(configured).expanduser()
66
+ else:
67
+ legacy = aria_home()
68
+ root = legacy if legacy.exists() else Path.home() / ".aria-code"
69
+ return root / "runtime" / "runs.sqlite3"
70
+
71
+
72
+ def _redact(value: Any) -> Any:
73
+ if isinstance(value, dict):
74
+ result = {}
75
+ for key, item in value.items():
76
+ normalized = re.sub(r"[^a-z0-9]", "", str(key).lower())
77
+ result[key] = "[REDACTED]" if normalized in _SECRET_KEYS else _redact(item)
78
+ return result
79
+ if isinstance(value, (list, tuple)):
80
+ return [_redact(item) for item in value]
81
+ if isinstance(value, str):
82
+ return _redact_text(value)
83
+ return value
84
+
85
+
86
+ def _json_dumps(value: Any) -> str:
87
+ return json.dumps(_redact(value), ensure_ascii=False, default=str, separators=(",", ":"))
88
+
89
+
90
+ def _json_loads(value: str | None) -> Dict[str, Any]:
91
+ if not value:
92
+ return {}
93
+ try:
94
+ loaded = json.loads(value)
95
+ return loaded if isinstance(loaded, dict) else {"value": loaded}
96
+ except (TypeError, json.JSONDecodeError):
97
+ return {}
98
+
99
+
100
+ @dataclass(frozen=True)
101
+ class RunRecord:
102
+ run_id: str
103
+ session_id: str
104
+ status: RunStatus
105
+ prompt: str
106
+ workspace: str
107
+ provider: str
108
+ parent_run_id: Optional[str]
109
+ owner_pid: int
110
+ owner_host: str
111
+ created_at: float
112
+ updated_at: float
113
+ started_at: Optional[float]
114
+ finished_at: Optional[float]
115
+ error: str
116
+ metadata: Dict[str, Any] = field(default_factory=dict)
117
+
118
+
119
+ @dataclass(frozen=True)
120
+ class RunEventRecord:
121
+ event_id: str
122
+ run_id: str
123
+ sequence: int
124
+ event_type: str
125
+ timestamp: float
126
+ data: Dict[str, Any] = field(default_factory=dict)
127
+
128
+
129
+ class RunNotFoundError(KeyError):
130
+ """Raised when a run identifier is not present in the durable store."""
131
+
132
+
133
+ class RunStore:
134
+ """Durable source of truth for runs and their append-only event streams."""
135
+
136
+ def __init__(self, database_path: Path | str | None = None) -> None:
137
+ self.database_path = Path(database_path or _default_database_path()).expanduser()
138
+ self.database_path.parent.mkdir(parents=True, exist_ok=True)
139
+ self._initialize()
140
+
141
+ def _connect(self) -> sqlite3.Connection:
142
+ connection = sqlite3.connect(str(self.database_path), timeout=10.0)
143
+ connection.row_factory = sqlite3.Row
144
+ connection.execute("PRAGMA foreign_keys = ON")
145
+ connection.execute("PRAGMA busy_timeout = 10000")
146
+ return connection
147
+
148
+ def _initialize(self) -> None:
149
+ with self._connect() as connection:
150
+ connection.execute("PRAGMA journal_mode = WAL")
151
+ connection.execute("PRAGMA synchronous = NORMAL")
152
+ connection.executescript(
153
+ """
154
+ CREATE TABLE IF NOT EXISTS runs (
155
+ run_id TEXT PRIMARY KEY,
156
+ session_id TEXT NOT NULL,
157
+ parent_run_id TEXT,
158
+ status TEXT NOT NULL,
159
+ prompt TEXT NOT NULL,
160
+ workspace TEXT NOT NULL,
161
+ provider TEXT NOT NULL DEFAULT '',
162
+ owner_pid INTEGER NOT NULL,
163
+ owner_host TEXT NOT NULL,
164
+ created_at REAL NOT NULL,
165
+ updated_at REAL NOT NULL,
166
+ started_at REAL,
167
+ finished_at REAL,
168
+ error TEXT NOT NULL DEFAULT '',
169
+ metadata_json TEXT NOT NULL DEFAULT '{}',
170
+ FOREIGN KEY(parent_run_id) REFERENCES runs(run_id)
171
+ );
172
+
173
+ CREATE TABLE IF NOT EXISTS run_events (
174
+ event_id TEXT PRIMARY KEY,
175
+ run_id TEXT NOT NULL,
176
+ sequence INTEGER NOT NULL,
177
+ event_type TEXT NOT NULL,
178
+ timestamp REAL NOT NULL,
179
+ data_json TEXT NOT NULL DEFAULT '{}',
180
+ UNIQUE(run_id, sequence),
181
+ FOREIGN KEY(run_id) REFERENCES runs(run_id) ON DELETE CASCADE
182
+ );
183
+
184
+ CREATE INDEX IF NOT EXISTS idx_runs_session_updated
185
+ ON runs(session_id, updated_at DESC);
186
+ CREATE INDEX IF NOT EXISTS idx_runs_status_updated
187
+ ON runs(status, updated_at DESC);
188
+ CREATE INDEX IF NOT EXISTS idx_run_events_run_sequence
189
+ ON run_events(run_id, sequence);
190
+
191
+ CREATE TABLE IF NOT EXISTS run_briefs (
192
+ run_id TEXT PRIMARY KEY REFERENCES runs(run_id) ON DELETE CASCADE,
193
+ brief_json TEXT NOT NULL,
194
+ sha256 TEXT NOT NULL
195
+ );
196
+ """
197
+ )
198
+
199
+ @staticmethod
200
+ def _row_to_run(row: sqlite3.Row) -> RunRecord:
201
+ return RunRecord(
202
+ run_id=row["run_id"],
203
+ session_id=row["session_id"],
204
+ status=RunStatus(row["status"]),
205
+ prompt=row["prompt"],
206
+ workspace=row["workspace"],
207
+ provider=row["provider"],
208
+ parent_run_id=row["parent_run_id"],
209
+ owner_pid=int(row["owner_pid"]),
210
+ owner_host=row["owner_host"],
211
+ created_at=float(row["created_at"]),
212
+ updated_at=float(row["updated_at"]),
213
+ started_at=float(row["started_at"]) if row["started_at"] is not None else None,
214
+ finished_at=float(row["finished_at"]) if row["finished_at"] is not None else None,
215
+ error=row["error"],
216
+ metadata=_json_loads(row["metadata_json"]),
217
+ )
218
+
219
+ @staticmethod
220
+ def _row_to_event(row: sqlite3.Row) -> RunEventRecord:
221
+ return RunEventRecord(
222
+ event_id=row["event_id"],
223
+ run_id=row["run_id"],
224
+ sequence=int(row["sequence"]),
225
+ event_type=row["event_type"],
226
+ timestamp=float(row["timestamp"]),
227
+ data=_json_loads(row["data_json"]),
228
+ )
229
+
230
+ @staticmethod
231
+ def _append_event(
232
+ connection: sqlite3.Connection,
233
+ run_id: str,
234
+ event_type: str,
235
+ data: Dict[str, Any] | None = None,
236
+ *,
237
+ event_id: str | None = None,
238
+ timestamp: float | None = None,
239
+ ) -> RunEventRecord:
240
+ sequence = int(connection.execute(
241
+ "SELECT COALESCE(MAX(sequence), 0) + 1 FROM run_events WHERE run_id = ?",
242
+ (run_id,),
243
+ ).fetchone()[0])
244
+ record = RunEventRecord(
245
+ event_id=event_id or uuid.uuid4().hex,
246
+ run_id=run_id,
247
+ sequence=sequence,
248
+ event_type=event_type,
249
+ timestamp=timestamp or time.time(),
250
+ data=dict(data or {}),
251
+ )
252
+ connection.execute(
253
+ """INSERT INTO run_events
254
+ (event_id, run_id, sequence, event_type, timestamp, data_json)
255
+ VALUES (?, ?, ?, ?, ?, ?)""",
256
+ (
257
+ record.event_id,
258
+ record.run_id,
259
+ record.sequence,
260
+ record.event_type,
261
+ record.timestamp,
262
+ _json_dumps(record.data),
263
+ ),
264
+ )
265
+ connection.execute(
266
+ "UPDATE runs SET updated_at = ? WHERE run_id = ?",
267
+ (record.timestamp, run_id),
268
+ )
269
+ return record
270
+
271
+ def create_run(
272
+ self,
273
+ *,
274
+ session_id: str,
275
+ prompt: str,
276
+ workspace: str,
277
+ provider: str = "",
278
+ parent_run_id: str | None = None,
279
+ metadata: Dict[str, Any] | None = None,
280
+ run_id: str | None = None,
281
+ owner_pid: int | None = None,
282
+ owner_host: str | None = None,
283
+ task_brief: TaskBrief | None = None,
284
+ ) -> RunRecord:
285
+ if task_brief is not None and not isinstance(task_brief, TaskBrief):
286
+ raise TypeError("task_brief must be a validated TaskBrief")
287
+ # Existing CLI callers automatically retain their initial goal. Preserve
288
+ # compatibility for empty/oversize legacy prompts without inventing one.
289
+ if task_brief is None and prompt.strip() and len(prompt.encode()) <= 65536:
290
+ task_brief = TaskBrief(goal=prompt)
291
+ brief_json = _json_dumps(task_brief.to_dict()) if task_brief is not None else None
292
+ digest = brief_digest(json.loads(brief_json)) if brief_json is not None else None
293
+ now = time.time()
294
+ identifier = run_id or uuid.uuid4().hex[:16]
295
+ pid = int(owner_pid if owner_pid is not None else os.getpid())
296
+ host = owner_host or socket.gethostname()
297
+ with self._connect() as connection:
298
+ connection.execute("BEGIN IMMEDIATE")
299
+ connection.execute(
300
+ """INSERT INTO runs
301
+ (run_id, session_id, parent_run_id, status, prompt, workspace,
302
+ provider, owner_pid, owner_host, created_at, updated_at,
303
+ started_at, finished_at, error, metadata_json)
304
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, '', ?)""",
305
+ (
306
+ identifier,
307
+ session_id,
308
+ parent_run_id,
309
+ RunStatus.QUEUED.value,
310
+ _redact_text(prompt),
311
+ workspace,
312
+ provider,
313
+ pid,
314
+ host,
315
+ now,
316
+ now,
317
+ _json_dumps(metadata or {}),
318
+ ),
319
+ )
320
+ if brief_json is not None:
321
+ connection.execute("INSERT INTO run_briefs VALUES (?, ?, ?)",
322
+ (identifier, brief_json, digest))
323
+ self._append_event(connection, identifier, "run_created", {
324
+ "status": RunStatus.QUEUED.value,
325
+ "provider": provider,
326
+ "workspace": workspace,
327
+ "brief_sha256": digest,
328
+ }, timestamp=now)
329
+ record = self.get_run(identifier)
330
+ assert record is not None
331
+ return record
332
+
333
+ def get_task_brief(self, run_id: str) -> dict | None:
334
+ """Read immutable intent; callers must apply their existing run access checks.
335
+
336
+ Missing brief means legacy/unrecorded intent, never inferred completion.
337
+ Hash checking detects corruption, not an adversary with database access.
338
+ """
339
+ with self._connect() as connection:
340
+ row = connection.execute(
341
+ """SELECT r.run_id, b.brief_json, b.sha256 FROM runs r
342
+ LEFT JOIN run_briefs b ON r.run_id=b.run_id WHERE r.run_id=?""",
343
+ (run_id,),
344
+ ).fetchone()
345
+ if row is None:
346
+ raise RunNotFoundError(run_id)
347
+ if row["brief_json"] is None:
348
+ return None
349
+ try:
350
+ value = json.loads(row["brief_json"])
351
+ brief = TaskBrief.from_dict(value)
352
+ if brief_digest(value) != row["sha256"]:
353
+ raise ValueError("Digest mismatch")
354
+ except (TypeError, ValueError, UnicodeError) as exc:
355
+ raise ValueError("Stored task brief is invalid") from exc
356
+ return {"brief": brief.to_dict(), "sha256": row["sha256"],
357
+ "acceptance_defined": bool(brief.acceptance),
358
+ "verification_state": "unverified"}
359
+
360
+ def get_run(self, run_id: str) -> Optional[RunRecord]:
361
+ with self._connect() as connection:
362
+ row = connection.execute(
363
+ "SELECT * FROM runs WHERE run_id = ?", (run_id,)
364
+ ).fetchone()
365
+ return self._row_to_run(row) if row is not None else None
366
+
367
+ def transition(
368
+ self,
369
+ run_id: str,
370
+ target: RunStatus | str,
371
+ *,
372
+ reason: str = "",
373
+ error: str | None = None,
374
+ provider: str | None = None,
375
+ data: Dict[str, Any] | None = None,
376
+ ) -> RunRecord:
377
+ destination = normalize_run_status(target)
378
+ now = time.time()
379
+ with self._connect() as connection:
380
+ connection.execute("BEGIN IMMEDIATE")
381
+ row = connection.execute(
382
+ "SELECT * FROM runs WHERE run_id = ?", (run_id,)
383
+ ).fetchone()
384
+ if row is None:
385
+ raise RunNotFoundError(run_id)
386
+ current = RunStatus(row["status"])
387
+ require_transition(current, destination)
388
+ if current == destination:
389
+ return self._row_to_run(row)
390
+
391
+ started_at = row["started_at"]
392
+ if started_at is None and destination in {RunStatus.PLANNING, RunStatus.RUNNING}:
393
+ started_at = now
394
+ finished_at = now if is_terminal(destination) else None
395
+ if error is None and current is RunStatus.INTERRUPTED and destination in {
396
+ RunStatus.PLANNING,
397
+ RunStatus.RUNNING,
398
+ }:
399
+ next_error = ""
400
+ else:
401
+ next_error = row["error"] if error is None else _redact_text(str(error))
402
+ next_provider = row["provider"] if provider is None else str(provider)
403
+ connection.execute(
404
+ """UPDATE runs
405
+ SET status = ?, provider = ?, updated_at = ?, started_at = ?,
406
+ finished_at = ?, error = ?
407
+ WHERE run_id = ?""",
408
+ (
409
+ destination.value,
410
+ next_provider,
411
+ now,
412
+ started_at,
413
+ finished_at,
414
+ next_error,
415
+ run_id,
416
+ ),
417
+ )
418
+ event_data = {
419
+ "from": current.value,
420
+ "to": destination.value,
421
+ "reason": reason,
422
+ }
423
+ if data:
424
+ event_data.update(data)
425
+ self._append_event(connection, run_id, "run_state_changed", event_data, timestamp=now)
426
+ updated = connection.execute(
427
+ "SELECT * FROM runs WHERE run_id = ?", (run_id,)
428
+ ).fetchone()
429
+ return self._row_to_run(updated)
430
+
431
+ def append_event(
432
+ self,
433
+ run_id: str,
434
+ event_type: str,
435
+ data: Dict[str, Any] | None = None,
436
+ *,
437
+ event_id: str | None = None,
438
+ timestamp: float | None = None,
439
+ ) -> RunEventRecord:
440
+ with self._connect() as connection:
441
+ connection.execute("BEGIN IMMEDIATE")
442
+ exists = connection.execute(
443
+ "SELECT 1 FROM runs WHERE run_id = ?", (run_id,)
444
+ ).fetchone()
445
+ if exists is None:
446
+ raise RunNotFoundError(run_id)
447
+ return self._append_event(
448
+ connection,
449
+ run_id,
450
+ event_type,
451
+ data,
452
+ event_id=event_id,
453
+ timestamp=timestamp,
454
+ )
455
+
456
+ def events(self, run_id: str) -> list[RunEventRecord]:
457
+ with self._connect() as connection:
458
+ rows = connection.execute(
459
+ "SELECT * FROM run_events WHERE run_id = ? ORDER BY sequence",
460
+ (run_id,),
461
+ ).fetchall()
462
+ return [self._row_to_event(row) for row in rows]
463
+
464
+ def list_runs(
465
+ self,
466
+ *,
467
+ session_id: str | None = None,
468
+ statuses: Iterable[RunStatus | str] | None = None,
469
+ limit: int = 50,
470
+ ) -> list[RunRecord]:
471
+ clauses = []
472
+ values: list[Any] = []
473
+ if session_id:
474
+ clauses.append("session_id = ?")
475
+ values.append(session_id)
476
+ normalized = [normalize_run_status(status).value for status in (statuses or [])]
477
+ if normalized:
478
+ clauses.append(f"status IN ({','.join('?' for _ in normalized)})")
479
+ values.extend(normalized)
480
+ where = f" WHERE {' AND '.join(clauses)}" if clauses else ""
481
+ values.append(max(1, int(limit)))
482
+ with self._connect() as connection:
483
+ rows = connection.execute(
484
+ f"SELECT * FROM runs{where} ORDER BY updated_at DESC LIMIT ?",
485
+ values,
486
+ ).fetchall()
487
+ return [self._row_to_run(row) for row in rows]
488
+
489
+ @staticmethod
490
+ def _pid_is_alive(pid: int) -> bool:
491
+ if pid <= 0:
492
+ return False
493
+ try:
494
+ os.kill(pid, 0)
495
+ except ProcessLookupError:
496
+ return False
497
+ except PermissionError:
498
+ return True
499
+ return True
500
+
501
+ def recover_orphaned_runs(self) -> list[str]:
502
+ """Mark active runs from dead local processes as interrupted."""
503
+ host = socket.gethostname()
504
+ active_values = [status.value for status in ACTIVE_RUN_STATUSES]
505
+ placeholders = ",".join("?" for _ in active_values)
506
+ with self._connect() as connection:
507
+ rows = connection.execute(
508
+ f"SELECT run_id, owner_pid FROM runs "
509
+ f"WHERE owner_host = ? AND status IN ({placeholders})",
510
+ [host, *active_values],
511
+ ).fetchall()
512
+ recovered = []
513
+ for row in rows:
514
+ if not self._pid_is_alive(int(row["owner_pid"])):
515
+ self.transition(
516
+ row["run_id"],
517
+ RunStatus.INTERRUPTED,
518
+ reason="owner_process_missing",
519
+ error="The process ended before the run reached a terminal state.",
520
+ )
521
+ recovered.append(row["run_id"])
522
+ return recovered
@@ -0,0 +1,113 @@
1
+ """Host-bound task reads on the existing RunStore, not a network auth service."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+
7
+ from .run_store import RunNotFoundError, RunStore
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class RunGrant:
12
+ """Construct only after host authentication and project/session authorization.
13
+
14
+ Never deserialize this grant from model arguments, HTTP bodies or headers.
15
+ Direct access to the underlying RunStore remains a trusted-host capability.
16
+ """
17
+ organization: str
18
+ project: str
19
+ subject: str
20
+ session: str
21
+ workspace: str
22
+
23
+ def __post_init__(self):
24
+ for value in (self.organization, self.project, self.subject, self.session):
25
+ if not isinstance(value, str) or not value.strip() or len(value) > 128:
26
+ raise ValueError('Invalid host scope')
27
+ path = Path(self.workspace).resolve(strict=True)
28
+ if not path.is_dir():
29
+ raise ValueError('Workspace must be a directory')
30
+ object.__setattr__(self, 'workspace', str(path))
31
+
32
+ def values(self):
33
+ return (self.organization, self.project, self.subject, self.session, self.workspace)
34
+
35
+
36
+ class ScopedRuns:
37
+ """A session-owner-only adapter; does not execute or resume queued records.
38
+
39
+ Missing and out-of-scope IDs share one error. Bindings are immutable. Legacy
40
+ runs with no binding are denied, even when their metadata claims ownership.
41
+ """
42
+ def __init__(self, store: RunStore, grant: RunGrant):
43
+ self._store = store
44
+ self._grant = grant
45
+ with store._connect() as connection:
46
+ connection.execute('''CREATE TABLE IF NOT EXISTS run_access (
47
+ run_id TEXT PRIMARY KEY REFERENCES runs(run_id) ON DELETE CASCADE,
48
+ organization TEXT NOT NULL, project TEXT NOT NULL,
49
+ subject TEXT NOT NULL, session TEXT NOT NULL, workspace TEXT NOT NULL
50
+ )''')
51
+ connection.execute('''CREATE INDEX IF NOT EXISTS idx_run_access_scope
52
+ ON run_access(organization, project, subject, session, workspace)''')
53
+
54
+ def create(self, prompt: str) -> dict:
55
+ if not isinstance(prompt, str) or not prompt.strip() or len(prompt.encode()) > 65536:
56
+ raise ValueError('Prompt must be 1..65536 UTF-8 bytes')
57
+ run = self._store.create_run(session_id=self._grant.session, prompt=prompt,
58
+ workspace=self._grant.workspace)
59
+ # A failure between these commits leaves an unbound record, which this
60
+ # adapter denies. Never infer a binding from existing run metadata.
61
+ with self._store._connect() as connection:
62
+ connection.execute('INSERT INTO run_access VALUES (?, ?, ?, ?, ?, ?)',
63
+ (run.run_id, *self._grant.values()))
64
+ return self.get(run.run_id)
65
+
66
+ def _require(self, run_id):
67
+ if not isinstance(run_id, str) or not run_id or len(run_id) > 128:
68
+ raise RunNotFoundError('Task not found')
69
+ with self._store._connect() as connection:
70
+ row = connection.execute('''SELECT run_id FROM run_access WHERE run_id=?
71
+ AND organization=? AND project=? AND subject=? AND session=? AND workspace=?''',
72
+ (run_id, *self._grant.values())).fetchone()
73
+ if row is None:
74
+ raise RunNotFoundError('Task not found')
75
+
76
+ @staticmethod
77
+ def _view(run):
78
+ return {'version': 1, 'run_id': run.run_id, 'execution_state': run.status.value,
79
+ 'verification_state': 'unverified', 'created_at': run.created_at,
80
+ 'updated_at': run.updated_at, 'finished_at': run.finished_at}
81
+
82
+ def get(self, run_id: str) -> dict:
83
+ self._require(run_id)
84
+ record = self._store.get_run(run_id)
85
+ if record is None:
86
+ raise RunNotFoundError('Task not found')
87
+ return self._view(record)
88
+
89
+ @staticmethod
90
+ def _limit(limit):
91
+ if type(limit) is not int or not 1 <= limit <= 200:
92
+ raise ValueError('Limit must be an integer from 1 to 200')
93
+ return limit
94
+
95
+ def list(self, *, limit: int = 50) -> list[dict]:
96
+ self._limit(limit)
97
+ with self._store._connect() as connection:
98
+ rows = connection.execute('''SELECT r.* FROM runs r JOIN run_access a ON r.run_id=a.run_id
99
+ WHERE a.organization=? AND a.project=? AND a.subject=? AND a.session=? AND a.workspace=?
100
+ ORDER BY r.updated_at DESC, r.run_id LIMIT ?''',
101
+ (*self._grant.values(), limit)).fetchall()
102
+ return [self._view(self._store._row_to_run(row)) for row in rows]
103
+
104
+ def events(self, run_id: str, *, after: int = 0, limit: int = 50) -> list[dict]:
105
+ self._require(run_id)
106
+ self._limit(limit)
107
+ if type(after) is not int or after < 0:
108
+ raise ValueError('Cursor must be a nonnegative integer')
109
+ with self._store._connect() as connection:
110
+ rows = connection.execute('''SELECT sequence, event_type, timestamp FROM run_events
111
+ WHERE run_id=? AND sequence>? ORDER BY sequence LIMIT ?''',
112
+ (run_id, after, limit)).fetchall()
113
+ return [dict(row) for row in rows]