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,172 @@
1
+ """/earnings SYMBOL: the next report, the last four against estimates, and the quarterly numbers.
2
+
3
+ /earnings handed off to /report, which wrote a general technical-analysis
4
+ report: price, moving averages, RSI. Nothing about earnings. This shows
5
+ what the command names, from yfinance: the next report date with the
6
+ consensus range, reported EPS against the estimate for recent quarters, and
7
+ revenue, net income and diluted EPS by quarter. `/earnings SYMBOL --report`
8
+ still writes the Markdown report.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import math
14
+ from typing import Any, Optional
15
+
16
+
17
+ def _num(value: Any) -> Optional[float]:
18
+ try:
19
+ number = float(value)
20
+ except (TypeError, ValueError):
21
+ return None
22
+ return None if math.isnan(number) or math.isinf(number) else number
23
+
24
+
25
+ def fetch_earnings(symbol: str, ticker: Any = None) -> dict:
26
+ """Earnings data for ``symbol`` from yfinance (or the ``ticker`` object given)."""
27
+ import logging
28
+
29
+ # yfinance logs "HTTP Error 404 …" straight to the terminal for a symbol
30
+ # without earnings; the answer below says so in a sentence instead.
31
+ yf_log = logging.getLogger("yfinance")
32
+ previous = yf_log.level
33
+ yf_log.setLevel(logging.CRITICAL)
34
+ try:
35
+ return _fetch_earnings(symbol, ticker)
36
+ finally:
37
+ yf_log.setLevel(previous)
38
+
39
+
40
+ def _fetch_earnings(symbol: str, ticker: Any = None) -> dict:
41
+ if ticker is None:
42
+ try:
43
+ import yfinance as yf
44
+ except ImportError:
45
+ return {"success": False, "error": "yfinance is not installed"}
46
+ ticker = yf.Ticker(symbol)
47
+ out: dict = {"success": True, "symbol": symbol.upper(), "history": [], "quarters": [], "next": {}}
48
+
49
+ try:
50
+ dates = ticker.earnings_dates
51
+ except Exception:
52
+ dates = None
53
+ if dates is not None and not getattr(dates, "empty", True):
54
+ for when, row in dates.sort_index(ascending=False).iterrows():
55
+ reported = _num(row.get("Reported EPS"))
56
+ estimate = _num(row.get("EPS Estimate"))
57
+ if reported is None:
58
+ continue
59
+ surprise = _num(row.get("Surprise(%)"))
60
+ if surprise is None and estimate:
61
+ surprise = (reported - estimate) / abs(estimate) * 100
62
+ out["history"].append({"date": str(when)[:10], "estimate": estimate, "reported": reported,
63
+ "surprise_pct": surprise})
64
+ if len(out["history"]) == 4:
65
+ break
66
+
67
+ try:
68
+ calendar = ticker.calendar or {}
69
+ except Exception:
70
+ calendar = {}
71
+ if isinstance(calendar, dict) and calendar:
72
+ upcoming = calendar.get("Earnings Date") or []
73
+ out["next"] = {
74
+ "date": str(upcoming[0]) if upcoming else None,
75
+ "eps_avg": _num(calendar.get("Earnings Average")),
76
+ "eps_low": _num(calendar.get("Earnings Low")),
77
+ "eps_high": _num(calendar.get("Earnings High")),
78
+ "revenue_avg": _num(calendar.get("Revenue Average")),
79
+ }
80
+
81
+ try:
82
+ income = ticker.quarterly_income_stmt
83
+ except Exception:
84
+ income = None
85
+ if income is not None and not getattr(income, "empty", True):
86
+ for column in list(income.columns)[:5]:
87
+ def field(name: str) -> Optional[float]:
88
+ return _num(income.at[name, column]) if name in income.index else None
89
+ revenue, net = field("Total Revenue"), field("Net Income")
90
+ out["quarters"].append({
91
+ "period": str(column)[:10], "revenue": revenue, "net_income": net,
92
+ "eps": field("Diluted EPS"),
93
+ "net_margin": net / revenue * 100 if revenue and net is not None else None,
94
+ })
95
+
96
+ if not (out["history"] or out["quarters"] or out["next"]):
97
+ return {"success": False, "symbol": symbol.upper(),
98
+ "error": f"No earnings data for {symbol.upper()} (ETFs, indices and some non-US listings have none)"}
99
+ return out
100
+
101
+
102
+ def _money(value: Optional[float]) -> str:
103
+ if value is None:
104
+ return "—"
105
+ for size, unit in ((1e12, "T"), (1e9, "B"), (1e6, "M")):
106
+ if abs(value) >= size:
107
+ return f"{value / size:.2f}{unit}"
108
+ return f"{value:,.0f}"
109
+
110
+
111
+ def render_earnings(data: dict, console, lang: str = "en") -> None:
112
+ from rich.padding import Padding
113
+ from rich.table import Table
114
+
115
+ zh = str(lang).lower().startswith("zh")
116
+ T = (lambda a, b: a) if zh else (lambda a, b: b)
117
+ symbol = data.get("symbol", "")
118
+ console.print()
119
+ console.print(f" [bold]{symbol} {T('财报', 'earnings')}[/bold] [dim]yfinance[/dim]")
120
+
121
+ nxt = data.get("next") or {}
122
+ if nxt.get("date"):
123
+ parts = [f"{T('下次财报', 'Next report')} {nxt['date']}"]
124
+ if nxt.get("eps_avg") is not None:
125
+ band = (f" ({nxt['eps_low']:.2f}–{nxt['eps_high']:.2f})"
126
+ if nxt.get("eps_low") is not None and nxt.get("eps_high") is not None else "")
127
+ parts.append(f"{T('EPS 一致预期', 'EPS consensus')} {nxt['eps_avg']:.2f}{band}")
128
+ if nxt.get("revenue_avg"):
129
+ parts.append(f"{T('营收预期', 'revenue consensus')} {_money(nxt['revenue_avg'])}")
130
+ console.print(" [dim]" + " · ".join(parts) + "[/dim]")
131
+
132
+ history = data.get("history") or []
133
+ if history:
134
+ console.print()
135
+ table = Table(box=None, show_header=True, header_style="bold", padding=(0, 2))
136
+ table.add_column(T("公布日", "Reported"))
137
+ table.add_column(T("EPS 预期", "EPS est."), justify="right")
138
+ table.add_column(T("EPS 实际", "EPS actual"), justify="right")
139
+ table.add_column(T("超预期", "Surprise"), justify="right")
140
+ for row in history:
141
+ surprise = row.get("surprise_pct")
142
+ colour = "green" if (surprise or 0) > 0 else "red" if (surprise or 0) < 0 else "dim"
143
+ table.add_row(row["date"], f"{row['estimate']:.2f}" if row.get("estimate") is not None else "—",
144
+ f"{row['reported']:.2f}",
145
+ f"[{colour}]{surprise:+.1f}%[/{colour}]" if surprise is not None else "—")
146
+ console.print(Padding(table, (0, 0, 0, 2)))
147
+ beats = sum(1 for r in history if (r.get("surprise_pct") or 0) > 0)
148
+ console.print(f" [dim]{T(f'近 {len(history)} 次中 {beats} 次超预期', f'Beat the estimate in {beats} of the last {len(history)}')}[/dim]")
149
+
150
+ quarters = data.get("quarters") or []
151
+ if quarters:
152
+ console.print()
153
+ table = Table(box=None, show_header=True, header_style="bold", padding=(0, 2))
154
+ table.add_column(T("季度末", "Quarter"))
155
+ table.add_column(T("营收", "Revenue"), justify="right")
156
+ table.add_column(T("净利润", "Net income"), justify="right")
157
+ table.add_column(T("净利率", "Net margin"), justify="right")
158
+ table.add_column(T("稀释 EPS (GAAP)", "Diluted EPS (GAAP)"), justify="right")
159
+ for q in quarters:
160
+ table.add_row(q["period"], _money(q.get("revenue")), _money(q.get("net_income")),
161
+ f"{q['net_margin']:.1f}%" if q.get("net_margin") is not None else "—",
162
+ f"{q['eps']:.2f}" if q.get("eps") is not None else "—")
163
+ console.print(Padding(table, (0, 0, 0, 2)))
164
+ console.print(f" [dim]{T('上表 EPS 为公司公布的调整后口径,此处为 GAAP 稀释口径,两者可能不同', 'EPS above is as reported against estimates (adjusted); here it is GAAP diluted, which can differ')}[/dim]")
165
+ if len(quarters) == 5 and quarters[0].get("revenue") and quarters[4].get("revenue"):
166
+ yoy = quarters[0]["revenue"] / quarters[4]["revenue"] * 100 - 100
167
+ console.print(f" [dim]{T('最近一季营收同比', 'Latest quarter revenue year on year')} {yoy:+.1f}%[/dim]")
168
+ console.print(f" [dim]{T('完整报告:', 'Full report: ')}/earnings {symbol} --report[/dim]")
169
+ console.print()
170
+
171
+
172
+ __all__ = ["fetch_earnings", "render_earnings"]
@@ -0,0 +1,64 @@
1
+ """The server an install talks to, and the old default that stranded it on localhost.
2
+
3
+ ``default_config()`` used to save ``api_url = http://localhost:8000``. That
4
+ looked like a default but was written into every user's config.json on first
5
+ run, where it became indistinguishable from a choice. Anyone who installed
6
+ from GitHub then had every backend call, and Google sign-in, aimed at a
7
+ developer backend on their own machine: a refused connection, or on a machine
8
+ that happened to run one, a page reading ``{"detail":"Not Found"}``. Fixing the
9
+ default in code cannot reach a config that already holds the old value, so the
10
+ old default is recognised here and replaced once, written back and announced,
11
+ the same way a retired model is (see model_retirement).
12
+
13
+ What counts as a choice and is left alone:
14
+
15
+ * ``ARTHERA_API_URL`` in the environment, which now also overrides a saved value
16
+ (in memory only), so a developer with a real local backend sets it once;
17
+ * any ``api_url`` other than the exact old default, such as a staging server;
18
+ * ``api_url_pinned: true``, an escape hatch for someone who wants localhost.
19
+
20
+ ``local_mode`` is not touched: choosing a local model is a different decision
21
+ from where the backend lives.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import os
27
+ from aria_code.service_endpoints import API_URL, current_url
28
+
29
+ PRODUCTION_API_URL = API_URL
30
+ LEGACY_DEFAULT_API_URL = "http://localhost:8000"
31
+ # The product moved from arthera.finance to arthera.xyz and the old domain no
32
+ # longer answers, so a config that was migrated to (or installed with) the old
33
+ # production address points at nothing. It is replaced the same way the
34
+ # localhost default is.
35
+ RETIRED_API_URLS = ("http://localhost:8000", "https://api.arthera.finance")
36
+
37
+
38
+ def _norm(url: object) -> str:
39
+ return str(url or "").strip().rstrip("/").lower()
40
+
41
+
42
+ def migrate_config(config: dict) -> list[tuple[str, str, str]]:
43
+ """Move the old localhost default to production in place; return (key, old, new)."""
44
+ old = config.get("api_url")
45
+ retired = bool(old) and current_url(str(old)) != str(old).strip().rstrip('/')
46
+ env = os.getenv("ARTHERA_API_URL", "").strip()
47
+ if env:
48
+ # An explicit environment choice wins over the file for this run only;
49
+ # nothing is rewritten, so unsetting the variable restores the file.
50
+ config["api_url"] = current_url(env)
51
+ return []
52
+ if retired:
53
+ config["api_url"] = PRODUCTION_API_URL
54
+ return [("api_url", str(old), PRODUCTION_API_URL)]
55
+ if config.get("api_url_pinned"):
56
+ return []
57
+ old = config.get("api_url")
58
+ if _norm(old) not in {LEGACY_DEFAULT_API_URL, "https://api.arthera.finance", "https://cn.arthera.finance"}:
59
+ return []
60
+ config["api_url"] = PRODUCTION_API_URL
61
+ return [("api_url", str(old), PRODUCTION_API_URL)]
62
+
63
+
64
+ __all__ = ["LEGACY_DEFAULT_API_URL", "PRODUCTION_API_URL", "RETIRED_API_URLS", "migrate_config"]
@@ -0,0 +1,255 @@
1
+ """JSON events for `aria-code -p … --format jsonl`, one per line, as the turn runs.
2
+
3
+ `-p --json` printed one document at the end, so a CI job saw nothing until the
4
+ turn was over and could not tell which tool ran, how long it took or where
5
+ it failed. With jsonl each step is a line on stdout as it happens:
6
+
7
+ {"type": "turn.started", "prompt": "...", "model": "...", "ts": ...}
8
+ {"type": "tool.started", "tool": "run_command", "params": {...}, "ts": ...}
9
+ {"type": "tool.completed", "tool": "run_command", "success": true, "elapsed_s": 1.2,
10
+ "error": "", "ts": ...}
11
+ {"type": "turn.completed", "success": true, "response": "...", "tools_used": [...], ...}
12
+
13
+ Tool parameters are shortened and secrets masked: a written file's contents
14
+ or a command's token have no place in a CI log.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ import re
21
+ import time
22
+ from typing import Any, TextIO
23
+
24
+ from aria_code.apps.cli.runtime_consumer import MEASURED_ELAPSED_KEY, _redact_activity_text
25
+
26
+ PARAM_CHARS = 300
27
+
28
+
29
+ def json_safe(value: Any) -> Any:
30
+ """``value`` with anything json cannot write turned into text."""
31
+ return json.loads(json.dumps(value, ensure_ascii=False, default=str))
32
+
33
+
34
+ RESULT_CHARS = 20_000
35
+
36
+
37
+ def _full() -> bool:
38
+ """ARIA_EVENTS_FULL=1: keep whole parameters and tool results (eval trajectories).
39
+
40
+ The default view is for logs and CI: short, file bodies by size. A
41
+ trajectory to learn from needs what was written and what came back.
42
+ """
43
+ import os
44
+
45
+ return os.environ.get("ARIA_EVENTS_FULL", "").strip() in ("1", "true", "yes")
46
+
47
+
48
+ _SECRET = re.compile(
49
+ r"(?i)\b(api[_-]?key|token|password|passwd|secret)(\s*[=:]\s*)[^\s'\"]+"
50
+ r"|\b(bearer|basic)(\s+)[A-Za-z0-9._~+/=-]+"
51
+ r"|\b(?:sk|pk|rk)-[A-Za-z0-9_-]{8,}|\bgh[pousr]_[A-Za-z0-9]{12,}|\bAIza[0-9A-Za-z_-]{20,}"
52
+ r"|\bya29\.[0-9A-Za-z_-]+"
53
+ )
54
+
55
+
56
+ def _mask_text(text: str) -> str:
57
+ """Secret-shaped values masked; whitespace, indentation and newlines kept."""
58
+ def repl(match: "re.Match") -> str:
59
+ if match.group(1):
60
+ return f"{match.group(1)}{match.group(2)}***"
61
+ if match.group(3):
62
+ return f"{match.group(3)}{match.group(4)}***"
63
+ return "***"
64
+ return _SECRET.sub(repl, str(text))
65
+
66
+
67
+ def _mask_value(value: Any) -> Any:
68
+ if isinstance(value, str):
69
+ return _mask_text(value)
70
+ if isinstance(value, dict):
71
+ return {k: _mask_value(v) for k, v in value.items() if not str(k).startswith("_")}
72
+ if isinstance(value, list):
73
+ return [_mask_value(v) for v in value]
74
+ return value
75
+
76
+
77
+ def _param_view(params: dict) -> dict:
78
+ if _full():
79
+ return _mask_value(json_safe(dict(params or {})))
80
+ view = {}
81
+ for key, value in (params or {}).items():
82
+ if str(key).startswith("_"):
83
+ continue # execution context the host added
84
+ if isinstance(value, str):
85
+ # A file's contents is not a parameter worth a log line; its size is.
86
+ view[key] = (f"<{len(value)} chars>" if len(value) > 2000
87
+ else _redact_activity_text(value, limit=PARAM_CHARS))
88
+ elif isinstance(value, (int, float, bool)) or value is None:
89
+ view[key] = value
90
+ else:
91
+ view[key] = _redact_activity_text(json.dumps(value, ensure_ascii=False, default=str),
92
+ limit=PARAM_CHARS)
93
+ return view
94
+
95
+
96
+ class ExecEvents:
97
+ """Writes events to ``out``; does nothing when ``out`` is None."""
98
+
99
+ def __init__(self, out: TextIO | None):
100
+ self.out = out
101
+ # Preserve the established JSONL contract unless a streaming consumer
102
+ # opts in. Never emit provider reasoning; only visible answer tokens.
103
+ import os
104
+ self.streaming = out is not None and os.environ.get("ARIA_EVENTS_STREAM", "").strip().lower() in (
105
+ "1", "true", "yes",
106
+ )
107
+
108
+ def text_delta(self, text: str) -> None:
109
+ if self.streaming and text:
110
+ self.emit("answer.delta", text=text)
111
+
112
+ def status(self, state: str, message: str) -> None:
113
+ if self.streaming:
114
+ self.emit("turn.status", state=_redact_activity_text(state, limit=80),
115
+ message=_redact_activity_text(message, limit=PARAM_CHARS))
116
+
117
+ def emit(self, event_type: str, **fields: Any) -> None:
118
+ if self.out is None:
119
+ return
120
+ record = {"type": event_type, **json_safe(fields), "ts": round(time.time(), 3)}
121
+ try:
122
+ self.out.write(json.dumps(record, ensure_ascii=False) + "\n")
123
+ self.out.flush()
124
+ except (OSError, ValueError):
125
+ self.out = None # the reader went away; stop writing
126
+
127
+ def tool_started(self, tool: str, params: dict) -> None:
128
+ self.emit("tool.started", tool=tool, params=_param_view(params))
129
+
130
+ def tool_completed(self, tool: str, result: dict) -> None:
131
+ result = result if isinstance(result, dict) else {"success": bool(result)}
132
+ fields: dict[str, Any] = {"tool": tool, "success": bool(result.get("success", True))}
133
+ if isinstance(result.get(MEASURED_ELAPSED_KEY), (int, float)):
134
+ fields["elapsed_s"] = round(float(result[MEASURED_ELAPSED_KEY]), 3)
135
+ if result.get("error"):
136
+ fields["error"] = _redact_activity_text(result["error"], limit=PARAM_CHARS)
137
+ data = result.get("data") if isinstance(result.get("data"), dict) else {}
138
+ if result.get("reused") is True:
139
+ fields["reused"] = True
140
+ # Counts describe the returned data, never inferred model prose.
141
+ if tool == "list_files" and isinstance(data.get("items"), list):
142
+ fields["item_count"] = len(data["items"])
143
+ for key in ("exit_code", "path", "process_id", "change_id"):
144
+ if key in data:
145
+ fields[key] = data[key]
146
+ if _full():
147
+ masked = _mask_value(json_safe(result))
148
+ body = json.dumps(masked, ensure_ascii=False)
149
+ fields["result"] = masked if len(body) <= RESULT_CHARS else body[:RESULT_CHARS] + "…"
150
+ brief = _brief(tool, data)
151
+ if brief:
152
+ fields["brief"] = brief
153
+ self.emit("tool.completed", **fields)
154
+
155
+
156
+ def _tool_name(tool: str) -> str:
157
+ return str(tool or "").rsplit("__", 1)[-1]
158
+
159
+
160
+ def _brief_bodies(data: dict) -> list[dict]:
161
+ bodies = [data]
162
+ nested = data.get("data")
163
+ if isinstance(nested, dict):
164
+ bodies.append(nested)
165
+ metrics = data.get("metrics")
166
+ if isinstance(metrics, dict):
167
+ bodies.append(metrics)
168
+ content = data.get("content")
169
+ if isinstance(content, str) and content.lstrip().startswith("{"):
170
+ try:
171
+ inner = json.loads(content)
172
+ except json.JSONDecodeError:
173
+ inner = None
174
+ if isinstance(inner, dict):
175
+ bodies.append(inner)
176
+ if isinstance(inner.get("data"), dict):
177
+ bodies.append(inner["data"])
178
+ if isinstance(inner.get("metrics"), dict):
179
+ bodies.append(inner["metrics"])
180
+ return bodies
181
+
182
+
183
+ def _brief_num(body: dict, *keys: str) -> float | None:
184
+ for key in keys:
185
+ value = body.get(key)
186
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
187
+ continue
188
+ if value != value or value in (float("inf"), float("-inf")):
189
+ continue
190
+ return float(value)
191
+ return None
192
+
193
+
194
+ def _brief_text(body: dict, *keys: str) -> str:
195
+ for key in keys:
196
+ value = body.get(key)
197
+ if not isinstance(value, str):
198
+ continue
199
+ text = " ".join(value.split())
200
+ if text:
201
+ return text[:24]
202
+ return ""
203
+
204
+
205
+ def _brief_percent(body: dict, fraction_key: str, pct_key: str) -> float | None:
206
+ direct = _brief_num(body, pct_key)
207
+ if direct is not None:
208
+ return round(direct, 2)
209
+ fraction = _brief_num(body, fraction_key)
210
+ if fraction is None:
211
+ return None
212
+ return round(fraction * 100, 2)
213
+
214
+
215
+ def _brief(tool: str, data: dict) -> dict | None:
216
+ """One terminal line of numbers the tool returned. Missing fields stay out."""
217
+ if not isinstance(data, dict) or not data:
218
+ return None
219
+ bodies = _brief_bodies(data)
220
+ for body in bodies:
221
+ diff = body.get("diff")
222
+ if isinstance(diff, str) and diff:
223
+ added = sum(1 for line in diff.splitlines() if line.startswith("+") and not line.startswith("+++"))
224
+ removed = sum(1 for line in diff.splitlines() if line.startswith("-") and not line.startswith("---"))
225
+ return {"kind": "edit", "added": added, "removed": removed}
226
+ name = _tool_name(tool)
227
+ if name in {"get_market_data", "get_crypto_data", "get_forex_data", "financial_quote"}:
228
+ for body in bodies:
229
+ price = _brief_num(body, "price", "latest_close", "current_price")
230
+ if price is None:
231
+ continue
232
+ brief: dict[str, Any] = {"kind": "quote", "price": price}
233
+ label = _brief_text(body, "name", "symbol")
234
+ if label:
235
+ brief["name"] = label
236
+ change = _brief_num(body, "change_pct", "change_pct_24h", "changePercent")
237
+ if change is not None:
238
+ brief["change_pct"] = change
239
+ if isinstance(body.get("stale"), bool):
240
+ brief["stale"] = body["stale"]
241
+ return brief
242
+ if name in {"backtest_strategy", "cloud_backtest", "run_portfolio_backtest", "financial_backtest"}:
243
+ for body in bodies:
244
+ returned = _brief_percent(body, "total_return", "total_return_pct")
245
+ if returned is None:
246
+ continue
247
+ brief = {"kind": "backtest", "return_pct": returned}
248
+ drawdown = _brief_percent(body, "max_drawdown", "max_drawdown_pct")
249
+ if drawdown is not None:
250
+ brief["drawdown_pct"] = round(abs(drawdown), 2)
251
+ return brief
252
+ return None
253
+
254
+
255
+ __all__ = ["ExecEvents", "json_safe"]
@@ -0,0 +1,155 @@
1
+ """Candidates for an `@` file reference, the way Claude Code and Codex offer them.
2
+
3
+ Typing `@` in a prompt names a file or folder. The old completion listed one
4
+ directory at a time, like a shell, which makes a file three levels down take
5
+ three Tabs. This searches the whole workspace instead: `@auth` finds
6
+ `src/api/auth.py`, `@rdme` finds `README.md`, and `@src/` lists what is in
7
+ `src/`. Files the project ignores (`.gitignore`) and build clutter are left out.
8
+
9
+ The result is a list of whole replacement texts: the prompt as typed, with the
10
+ `@token` replaced by one candidate. That is the shape the Go runtime has always
11
+ answered with, so the frontend has one way to read both.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import subprocess
18
+ import time
19
+ from pathlib import Path
20
+ from typing import Dict, List, Optional, Tuple
21
+
22
+ #: How many candidates a request returns.
23
+ LIMIT = 8
24
+
25
+ _SKIP_DIRS = {
26
+ ".git", "node_modules", "__pycache__", ".venv", "venv", "dist", "build", "target",
27
+ ".mypy_cache", ".pytest_cache", ".ruff_cache", ".next", ".cache", "site-packages",
28
+ }
29
+ _MAX_FILES = 20000
30
+ _TTL_SECONDS = 10.0
31
+ _cache: Dict[str, Tuple[float, List[str]]] = {}
32
+
33
+
34
+ def _git_files(root: Path) -> Optional[List[str]]:
35
+ if not (root / ".git").exists():
36
+ return None
37
+ try:
38
+ out = subprocess.run(
39
+ ["git", "-C", str(root), "ls-files", "-co", "--exclude-standard", "-z"],
40
+ capture_output=True, timeout=3, check=True,
41
+ ).stdout
42
+ except (OSError, subprocess.SubprocessError):
43
+ return None
44
+ return [p for p in out.decode("utf-8", "replace").split("\0") if p][:_MAX_FILES]
45
+
46
+
47
+ def _walk_files(root: Path) -> List[str]:
48
+ found: List[str] = []
49
+ for current, dirs, names in os.walk(root):
50
+ dirs[:] = sorted(d for d in dirs if d not in _SKIP_DIRS and not d.startswith("."))
51
+ base = Path(current).relative_to(root)
52
+ for name in sorted(names):
53
+ if name.startswith(".") and name not in (".gitignore", ".env.example"):
54
+ continue
55
+ found.append((base / name).as_posix())
56
+ if len(found) >= _MAX_FILES:
57
+ return found
58
+ return found
59
+
60
+
61
+ def workspace_files(root: Path, now: Optional[float] = None) -> List[str]:
62
+ """Every file in the workspace (relative, `/`-separated), cached for a few seconds."""
63
+ key = str(root)
64
+ stamp = time.monotonic() if now is None else now
65
+ hit = _cache.get(key)
66
+ if hit and stamp - hit[0] < _TTL_SECONDS:
67
+ return hit[1]
68
+ files = _git_files(root)
69
+ if files is None:
70
+ files = _walk_files(root)
71
+ _cache[key] = (stamp, files)
72
+ return files
73
+
74
+
75
+ def _token(text: str) -> Optional[Tuple[int, str]]:
76
+ """Where the `@token` starts and what has been typed of it, or None."""
77
+ start = text.rfind("@")
78
+ if start < 0 or (start > 0 and text[start - 1] not in " \t\n"):
79
+ return None
80
+ token = text[start + 1:]
81
+ if token.startswith("file:"):
82
+ token = token[5:]
83
+ token = token.lstrip('"')
84
+ if any(c in token for c in "\n\r\t"):
85
+ return None
86
+ return start, token
87
+
88
+
89
+ def _is_subsequence(needle: str, hay: str) -> bool:
90
+ it = iter(hay)
91
+ return all(c in it for c in needle)
92
+
93
+
94
+ def _children(files: List[str], prefix: str) -> List[str]:
95
+ """What sits directly inside `prefix` ('' for the top level): folders end in `/`."""
96
+ seen: Dict[str, None] = {}
97
+ for path in files:
98
+ if not path.startswith(prefix):
99
+ continue
100
+ rest = path[len(prefix):]
101
+ if not rest:
102
+ continue
103
+ head, sep, _ = rest.partition("/")
104
+ seen[prefix + head + ("/" if sep else "")] = None
105
+ entries = list(seen)
106
+ return sorted(entries, key=lambda e: (not e.endswith("/"), e.lower()))
107
+
108
+
109
+ def _search(files: List[str], query: str) -> List[str]:
110
+ q = query.lower()
111
+ dirs: Dict[str, None] = {}
112
+ for path in files:
113
+ parts = path.split("/")
114
+ for i in range(1, len(parts)):
115
+ dirs["/".join(parts[:i]) + "/"] = None
116
+ scored: List[Tuple[int, int, str]] = []
117
+ for path in [*files, *dirs]:
118
+ low = path.lower()
119
+ bare = low.rstrip("/")
120
+ base = bare.rsplit("/", 1)[-1]
121
+ if base.startswith(q):
122
+ tier = 0
123
+ elif low.startswith(q):
124
+ tier = 1
125
+ elif q in base:
126
+ tier = 2
127
+ elif q in low:
128
+ tier = 3
129
+ elif _is_subsequence(q, base):
130
+ tier = 4
131
+ elif _is_subsequence(q, low):
132
+ tier = 5
133
+ else:
134
+ continue
135
+ scored.append((tier, len(path), path))
136
+ scored.sort()
137
+ return [path for _, _, path in scored]
138
+
139
+
140
+ def reference_candidates(text: str, root: Path, limit: int = LIMIT) -> List[str]:
141
+ """Replacement prompts for the `@token` at the end of `text`, best first."""
142
+ found = _token(text)
143
+ if found is None:
144
+ return []
145
+ start, token = found
146
+ files = workspace_files(root)
147
+ if token == "" or token.endswith("/"):
148
+ paths = _children(files, token)
149
+ else:
150
+ paths = _search(files, token)
151
+ out: List[str] = []
152
+ for path in paths[:limit]:
153
+ shown = f'"{path}"' if " " in path else path
154
+ out.append(f"{text[:start]}@{shown}")
155
+ return out