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,213 @@
1
+ """按用户的**实际环境**生成 providers.yaml,而不是发一份通用模板。
2
+
3
+ 为什么不是写死一份文档让用户照抄:通用模板对每个人都是"差不多但不对"——
4
+ 装了 Ollama 的人不需要被告知怎么配 OpenAI,配了 DEEPSEEK_API_KEY 的人不该看到
5
+ 一堆用不上的占位符,而真正卡住他的(本地服务没起来 / key 名字拼错)模板里
6
+ 一个字都不会提。
7
+
8
+ 这里的做法是先探测再生成:
9
+ - 本地推理服务(Ollama / LM Studio)是否在跑、跑着哪些模型
10
+ - 哪些 provider 的环境变量已经设了
11
+ - 用户已有的配置文件里声明过什么
12
+
13
+ 然后产出一份**只包含这台机器上真的能用的东西**的配置,并把"还差什么、
14
+ 去哪拿"作为注释写进同一个文件——用户不必在文档和配置之间来回对照。
15
+
16
+ 探测全部是只读的:不发请求到任何云端 provider(那需要消耗用户的额度,也会
17
+ 把 key 泄给一次纯粹的探活),只查本地端口和环境变量。云端 provider 的判定
18
+ 标准就是"环境变量在不在",这跟 registry 实际取 key 的方式完全一致。
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import os
25
+ import socket
26
+ import urllib.error
27
+ import urllib.request
28
+ from dataclasses import dataclass, field
29
+ from typing import Dict, List, Optional
30
+ from urllib.parse import urlparse
31
+
32
+ __all__ = ["Finding", "probe_environment", "render_providers_yaml", "suggest_default_chain"]
33
+
34
+ # (provider id, 环境变量, 默认模型, 去哪拿 key)
35
+ _CLOUD_PROVIDERS: List[tuple] = [
36
+ ("deepseek", "DEEPSEEK_API_KEY", "deepseek-chat", "https://platform.deepseek.com/api_keys"),
37
+ ("siliconflow", "SILICONFLOW_API_KEY", "deepseek-ai/DeepSeek-V3", "https://cloud.siliconflow.cn/account/ak"),
38
+ ("dashscope", "DASHSCOPE_API_KEY", "qwen-plus", "https://bailian.console.aliyun.com/"),
39
+ ("moonshot", "MOONSHOT_API_KEY", "moonshot-v1-8k", "https://platform.moonshot.cn/console/api-keys"),
40
+ ("zhipu", "ZHIPUAI_API_KEY", "glm-4-flash", "https://open.bigmodel.cn/usercenter/apikeys"),
41
+ ("openai", "OPENAI_API_KEY", "gpt-4o-mini", "https://platform.openai.com/api-keys"),
42
+ ("anthropic", "ANTHROPIC_API_KEY", "claude-3-5-haiku-latest", "https://console.anthropic.com/settings/keys"),
43
+ ("groq", "GROQ_API_KEY", "llama-3.3-70b-versatile", "https://console.groq.com/keys"),
44
+ ("together", "TOGETHER_API_KEY", "meta-llama/Llama-3.3-70B-Instruct-Turbo", "https://api.together.xyz/settings/api-keys"),
45
+ ]
46
+
47
+ # 本地推理服务:(provider id, 默认地址, 列模型的路径)
48
+ _LOCAL_PROVIDERS: List[tuple] = [
49
+ ("ollama", os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434"), "/api/tags"),
50
+ ("lmstudio", os.environ.get("LMSTUDIO_BASE_URL", "http://localhost:1234"), "/v1/models"),
51
+ ]
52
+
53
+
54
+ @dataclass
55
+ class Finding:
56
+ """一个 provider 的探测结果。"""
57
+ provider: str
58
+ kind: str # "local" | "cloud"
59
+ available: bool
60
+ detail: str = ""
61
+ models: List[str] = field(default_factory=list)
62
+ env_key: Optional[str] = None
63
+ signup_url: str = ""
64
+ base_url: str = ""
65
+
66
+
67
+ def _port_open(url: str, timeout: float = 0.4) -> bool:
68
+ """只做 TCP 探活。比发 HTTP 请求快得多,且本地服务没起来时能立刻返回,
69
+ 不会让整个探测卡在连接超时上。"""
70
+ parsed = urlparse(url)
71
+ host = parsed.hostname or "localhost"
72
+ port = parsed.port or (443 if parsed.scheme == "https" else 80)
73
+ try:
74
+ with socket.create_connection((host, port), timeout=timeout):
75
+ return True
76
+ except (OSError, ValueError):
77
+ return False
78
+
79
+
80
+ def _fetch_json(url: str, timeout: float = 1.5) -> Optional[dict]:
81
+ try:
82
+ with urllib.request.urlopen(url, timeout=timeout) as resp:
83
+ return json.loads(resp.read())
84
+ except (urllib.error.URLError, OSError, ValueError, json.JSONDecodeError):
85
+ return None
86
+
87
+
88
+ def _local_models(provider: str, base_url: str, path: str) -> List[str]:
89
+ payload = _fetch_json(base_url.rstrip("/") + path)
90
+ if not payload:
91
+ return []
92
+ if provider == "ollama":
93
+ return [m.get("name", "") for m in payload.get("models", []) if m.get("name")]
94
+ return [m.get("id", "") for m in payload.get("data", []) if m.get("id")]
95
+
96
+
97
+ def probe_environment(*, check_local: bool = True) -> List[Finding]:
98
+ """探测这台机器上有什么。只读、不消耗任何额度。"""
99
+ findings: List[Finding] = []
100
+
101
+ if check_local:
102
+ for provider, base_url, path in _LOCAL_PROVIDERS:
103
+ if not _port_open(base_url):
104
+ findings.append(Finding(
105
+ provider=provider, kind="local", available=False,
106
+ base_url=base_url,
107
+ detail=f"{base_url} 未监听(服务没启动,或端口不是默认值)",
108
+ ))
109
+ continue
110
+ models = _local_models(provider, base_url, path)
111
+ findings.append(Finding(
112
+ provider=provider, kind="local", available=bool(models),
113
+ base_url=base_url, models=models,
114
+ detail=(f"在跑,{len(models)} 个模型" if models
115
+ else "端口通但没列出模型(可能还没 pull 过任何模型)"),
116
+ ))
117
+
118
+ for provider, env_key, _model, signup in _CLOUD_PROVIDERS:
119
+ has_key = bool(os.environ.get(env_key, "").strip())
120
+ findings.append(Finding(
121
+ provider=provider, kind="cloud", available=has_key,
122
+ env_key=env_key, signup_url=signup,
123
+ detail=(f"{env_key} 已设置" if has_key else f"{env_key} 未设置"),
124
+ ))
125
+
126
+ return findings
127
+
128
+
129
+ def suggest_default_chain(findings: List[Finding]) -> tuple[Optional[str], List[str]]:
130
+ """按探测结果给出 default 与 fallback 链。
131
+
132
+ 排序原则:本地优先(零成本、不出网、隐私最好),其次是已配好 key 的云端。
133
+ 没配 key 的一律不进链——把用不了的东西写进 fallback 只会在真正需要兜底时
134
+ 连续失败几次才走到能用的那个。
135
+ """
136
+ local_ready = [f for f in findings if f.kind == "local" and f.available]
137
+ cloud_ready = [f for f in findings if f.kind == "cloud" and f.available]
138
+
139
+ chain: List[str] = []
140
+ for f in local_ready:
141
+ model = f.models[0] if f.models else ""
142
+ chain.append(f"{f.provider}/{model}" if model else f.provider)
143
+
144
+ cloud_default = {p: m for p, _e, m, _s in _CLOUD_PROVIDERS}
145
+ for f in cloud_ready:
146
+ chain.append(f"{f.provider}/{cloud_default.get(f.provider, '')}".rstrip("/"))
147
+
148
+ return (chain[0] if chain else None), chain[1:]
149
+
150
+
151
+ def render_providers_yaml(findings: List[Finding]) -> str:
152
+ """生成配置文本。缺什么、去哪拿,作为注释写在同一个文件里。"""
153
+ default, fallback = suggest_default_chain(findings)
154
+ lines: List[str] = [
155
+ "# ~/.aria/providers.yaml",
156
+ "# 由 `aria-code /providers init` 按本机实际环境生成。",
157
+ "# 密钥一律不写在这里——只写环境变量名,值放 ~/.aria/.env。",
158
+ "",
159
+ ]
160
+
161
+ if not default:
162
+ lines += [
163
+ "# ⚠️ 这台机器上暂时没有可用的模型来源。最快的两条路:",
164
+ "# 1. 本地(免费、离线可用):",
165
+ "# brew install ollama && ollama serve && ollama pull qwen2.5:7b",
166
+ "# 2. 云端:拿一个 key 写进 ~/.aria/.env,然后重跑 /providers init",
167
+ "",
168
+ "llm:",
169
+ " default: ollama/qwen2.5:7b # 装好 Ollama 后即可用",
170
+ "",
171
+ ]
172
+ else:
173
+ lines += ["llm:", f" default: {default}"]
174
+ if fallback:
175
+ lines.append(" fallback:")
176
+ lines += [f" - {item}" for item in fallback]
177
+ else:
178
+ lines += [
179
+ " # 只探测到一个可用来源,暂无 fallback。多配一个 key 可以让",
180
+ " # 默认来源故障时自动切换。",
181
+ ]
182
+ lines.append("")
183
+
184
+ ready_local = [f for f in findings if f.kind == "local" and f.available]
185
+ if ready_local:
186
+ lines.append("# ── 本机检测到的本地模型 ─────────────────────────────")
187
+ for f in ready_local:
188
+ preview = ", ".join(f.models[:6]) + (" …" if len(f.models) > 6 else "")
189
+ lines.append(f"# {f.provider} @ {f.base_url} → {preview}")
190
+ lines.append("")
191
+
192
+ missing = [f for f in findings if f.kind == "cloud" and not f.available]
193
+ if missing:
194
+ lines.append("# ── 还没配的云端 provider(想用哪个就取哪个 key)────────")
195
+ lines.append("# 把值写进 ~/.aria/.env,格式 KEY=值(不要加引号)")
196
+ for f in missing:
197
+ lines.append(f"# {f.env_key:<22} {f.signup_url}")
198
+ lines.append("")
199
+
200
+ lines += [
201
+ "# ── 接入未列出的服务(自建 vLLM / 内网网关 / 任意 OpenAI 兼容端点)──",
202
+ "# 取消注释并改成你自己的地址即可;之后 mycorp/<model> 就能用在上面的",
203
+ "# default 和 fallback 里。",
204
+ "#",
205
+ "# model_providers:",
206
+ "# mycorp:",
207
+ "# base_url: http://192.168.1.50:8000/v1",
208
+ "# env_key: MYCORP_LLM_TOKEN # 只写变量名,不写值",
209
+ "# env_key_instructions: 找基础架构组申请",
210
+ "# model: qwen-72b",
211
+ "",
212
+ ]
213
+ return "\n".join(lines)
@@ -0,0 +1,139 @@
1
+ """
2
+ providers/llm/base.py — LLM Provider 统一抽象基类
3
+ ==================================================
4
+ 所有 provider(本地/云端)实现同一接口,上层代码无需关心具体后端。
5
+
6
+ 事件类型 (stream yields):
7
+ {"type": "token", "text": "..."} # 文本增量
8
+ {"type": "thinking", "text": "..."} # 思考过程 (Claude/DeepSeek-R1)
9
+ {"type": "tool_call", "name": "...", "arguments": {...}} # 工具调用
10
+ {"type": "done", "text": "完整响应"} # 流结束
11
+ {"type": "error", "message": "..."} # 错误
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ from abc import ABC, abstractmethod
18
+ from dataclasses import dataclass, field
19
+ from typing import Any, AsyncIterator, Dict, List, Optional
20
+
21
+
22
+ @dataclass
23
+ class Message:
24
+ role: str # "system" | "user" | "assistant" | "tool"
25
+ content: str
26
+ name: Optional[str] = None # tool name (for role=tool)
27
+ tool_call_id: Optional[str] = None
28
+
29
+
30
+ @dataclass
31
+ class ProviderConfig:
32
+ """可由 providers.yaml / 环境变量 / CLI 参数覆盖"""
33
+ name: str
34
+ api_key: Optional[str] = None
35
+ base_url: Optional[str] = None
36
+ model: Optional[str] = None
37
+ temperature: float = 0.3
38
+ max_tokens: int = 4096
39
+ timeout: int = 120
40
+ # 扩展字段(各 provider 可自定义)
41
+ extra: Dict[str, Any] = field(default_factory=dict)
42
+
43
+ @classmethod
44
+ def from_env(cls, name: str, **defaults) -> "ProviderConfig":
45
+ """从环境变量自动读取 API Key(DEEPSEEK_API_KEY / OPENAI_API_KEY 等)"""
46
+ key_map = {
47
+ "deepseek": "DEEPSEEK_API_KEY",
48
+ "openai": "OPENAI_API_KEY",
49
+ "anthropic": "ANTHROPIC_API_KEY",
50
+ "groq": "GROQ_API_KEY",
51
+ "together": "TOGETHER_API_KEY",
52
+ "dashscope": "DASHSCOPE_API_KEY",
53
+ "siliconflow": "SILICONFLOW_API_KEY",
54
+ "moonshot": "MOONSHOT_API_KEY",
55
+ "zhipu": "ZHIPUAI_API_KEY",
56
+ }
57
+ env_var = key_map.get(name.lower())
58
+ api_key = os.getenv(env_var, "") if env_var else ""
59
+ return cls(name=name, api_key=api_key or None, **defaults)
60
+
61
+ def is_configured(self) -> bool:
62
+ """判断 provider 是否可用(本地 provider 无需 api_key)"""
63
+ _local = {"ollama", "lmstudio", "vllm", "llamacpp", "jan"}
64
+ if self.name.lower() in _local:
65
+ return True
66
+ return bool(self.api_key)
67
+
68
+
69
+ class BaseLLMProvider(ABC):
70
+ """
71
+ 所有 LLM provider 的统一基类。
72
+
73
+ 子类只需实现 `stream()` 方法;`complete()` 会自动聚合流结果。
74
+ """
75
+
76
+ # 子类声明这些属性
77
+ provider_name: str = "base"
78
+ supports_tools: bool = False
79
+ supports_thinking: bool = False
80
+ local: bool = False # True = 本地运行,不需要 api_key
81
+
82
+ def __init__(self, config: ProviderConfig):
83
+ self.config = config
84
+
85
+ # ── 必须实现 ──────────────────────────────────────────────────────────────
86
+
87
+ @abstractmethod
88
+ async def stream(
89
+ self,
90
+ messages: List[Message],
91
+ tools: Optional[List[Dict]] = None,
92
+ temperature: Optional[float] = None,
93
+ max_tokens: Optional[int] = None,
94
+ cancel_event=None,
95
+ ) -> AsyncIterator[Dict[str, Any]]:
96
+ """
97
+ 流式生成 token。
98
+
99
+ 每次 yield 一个事件 dict(见模块文档中的事件类型)。
100
+ """
101
+ ...
102
+ yield {} # 让 Python 识别为 async generator
103
+
104
+ # ── 默认实现(子类可覆盖)────────────────────────────────────────────────
105
+
106
+ async def complete(
107
+ self,
108
+ messages: List[Message],
109
+ tools: Optional[List[Dict]] = None,
110
+ temperature: Optional[float] = None,
111
+ max_tokens: Optional[int] = None,
112
+ ) -> Dict[str, Any]:
113
+ """聚合 stream() 事件,返回完整响应 dict。"""
114
+ full_text = ""
115
+ tool_calls = []
116
+ async for event in self.stream(
117
+ messages, tools=tools,
118
+ temperature=temperature, max_tokens=max_tokens,
119
+ ):
120
+ t = event.get("type")
121
+ if t == "token":
122
+ full_text += event.get("text", "")
123
+ elif t == "tool_call":
124
+ tool_calls.append({
125
+ "name": event.get("name"),
126
+ "arguments": event.get("arguments", {}),
127
+ })
128
+ elif t == "error":
129
+ return {"success": False, "error": event.get("message"),
130
+ "response": full_text, "tool_calls": tool_calls}
131
+ return {"success": True, "response": full_text, "tool_calls": tool_calls}
132
+
133
+ async def is_available(self) -> bool:
134
+ """检查 provider 是否在线/可用(子类覆盖以做实际探测)"""
135
+ return self.config.is_configured()
136
+
137
+ def __repr__(self) -> str:
138
+ model = self.config.model or "default"
139
+ return f"{self.__class__.__name__}(model={model})"
@@ -0,0 +1,158 @@
1
+ """声明式自定义 provider —— 用户只写配置文件,不写 Python 代码。
2
+
3
+ 背景:registry.py 里内置了 12 个 provider,但它们的名字、base_url、环境变量
4
+ 都是**硬编码**的。用户要接一个未列出的服务(自建 vLLM、公司内网网关、
5
+ Arthera 自己的云端 API、任何 OpenAI 兼容端点),此前唯一的办法是写一个
6
+ BaseLLMProvider 子类再调 register_provider()——对"只想填个地址和 key"的
7
+ 用户门槛太高。
8
+
9
+ 设计对标 codex 的 `model_providers`(codex-rs/model-provider-info/src/lib.rs):
10
+ 配置里**只写环境变量名,不写密钥值**。codex 那边同时提供了明文
11
+ `experimental_bearer_token` 字段,但源码注释明确写着 "Use of this config is
12
+ discouraged in favor of `env_key` for security reasons"——这里不提供明文字段,
13
+ 只认 env_key,理由见下面 build_custom_provider 的说明。
14
+
15
+ 用户配置示例(~/.aria/providers.yaml 或 ~/.arthera/providers.json):
16
+
17
+ llm:
18
+ default: mycorp/qwen-72b
19
+
20
+ model_providers:
21
+ mycorp:
22
+ name: 公司内网推理网关
23
+ base_url: https://llm.internal.example.com/v1
24
+ env_key: MYCORP_LLM_TOKEN
25
+ env_key_instructions: 找基础架构组申请,写进 ~/.aria/.env
26
+ model: qwen-72b
27
+ http_headers:
28
+ X-Tenant: research
29
+ env_http_headers:
30
+ X-Trace-Id: MYCORP_TRACE_ID
31
+
32
+ arthera-cloud:
33
+ name: Arthera 云端(Cloud Run)
34
+ base_url: https://api.arthera.example/api/v2
35
+ env_key: ARTHERA_API_TOKEN
36
+
37
+ 声明后即可像内置 provider 一样使用:default / fallback / code_tasks 里都能写
38
+ `mycorp/<model>`。
39
+ """
40
+
41
+ from __future__ import annotations
42
+
43
+ import logging
44
+ import os
45
+ from typing import Any, Dict, List, Optional
46
+
47
+ from .base import ProviderConfig
48
+ from .openai_compat import OpenAICompatProvider
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+ __all__ = ["CustomProviderSpec", "parse_custom_providers", "build_custom_provider"]
53
+
54
+ # 配置里出现这些键一律拒绝:它们意味着用户把密钥明文写进了配置文件。
55
+ # 配置文件常被连同项目一起备份、同步、甚至误提交,明文密钥的暴露面比环境
56
+ # 变量大一个量级。codex 提供了明文字段但自己在注释里劝退;这里直接不提供,
57
+ # 并在检测到时给出可操作的替代方案,而不是静默忽略——静默忽略会让用户以为
58
+ # 配好了,实际请求全部 401,排查成本更高。
59
+ _FORBIDDEN_INLINE_SECRET_KEYS = ("api_key", "apikey", "token", "bearer_token", "secret")
60
+
61
+
62
+ class CustomProviderSpec:
63
+ """一个用户声明的 provider。"""
64
+
65
+ __slots__ = ("id", "name", "base_url", "env_key", "env_key_instructions",
66
+ "model", "http_headers", "env_http_headers", "timeout")
67
+
68
+ def __init__(self, provider_id: str, raw: Dict[str, Any]):
69
+ self.id = provider_id
70
+ self.name = str(raw.get("name") or provider_id)
71
+ self.base_url = str(raw.get("base_url") or "").rstrip("/")
72
+ self.env_key = raw.get("env_key") or None
73
+ self.env_key_instructions = raw.get("env_key_instructions") or ""
74
+ self.model = raw.get("model") or None
75
+ self.http_headers = dict(raw.get("http_headers") or {})
76
+ self.env_http_headers = dict(raw.get("env_http_headers") or {})
77
+ self.timeout = int(raw.get("timeout") or 120)
78
+
79
+ def resolved_headers(self) -> Dict[str, str]:
80
+ """静态头 + 从环境变量取值的头。环境变量缺失时**不发**该头,
81
+ 而不是发一个空值——空值头在很多网关那里会被当成"显式声明为空",
82
+ 比缺失更难排查。"""
83
+ headers = dict(self.http_headers)
84
+ for header_name, env_name in self.env_http_headers.items():
85
+ value = os.environ.get(str(env_name), "").strip()
86
+ if value:
87
+ headers[str(header_name)] = value
88
+ return headers
89
+
90
+ def api_key(self) -> str:
91
+ return os.environ.get(str(self.env_key), "").strip() if self.env_key else ""
92
+
93
+ def missing_key_hint(self) -> str:
94
+ base = f"provider '{self.id}' 需要环境变量 {self.env_key},当前未设置或为空。"
95
+ return f"{base} {self.env_key_instructions}".strip()
96
+
97
+
98
+ def parse_custom_providers(cfg: Dict[str, Any]) -> Dict[str, CustomProviderSpec]:
99
+ """从用户配置解析 model_providers 段。
100
+
101
+ 配置有问题时记录 warning 并跳过该条,不抛异常——一个写错的自定义 provider
102
+ 不该让整个 CLI 起不来,其余 provider 应当照常可用。
103
+ """
104
+ raw_section = cfg.get("model_providers") if isinstance(cfg, dict) else None
105
+ if not isinstance(raw_section, dict):
106
+ return {}
107
+
108
+ specs: Dict[str, CustomProviderSpec] = {}
109
+ for provider_id, raw in raw_section.items():
110
+ pid = str(provider_id).strip().lower()
111
+ if not pid or not isinstance(raw, dict):
112
+ logger.warning("model_providers 中跳过无效条目: %r", provider_id)
113
+ continue
114
+
115
+ inline = [k for k in raw if str(k).lower() in _FORBIDDEN_INLINE_SECRET_KEYS]
116
+ if inline:
117
+ logger.warning(
118
+ "model_providers['%s'] 含明文密钥字段 %s —— 已忽略该 provider。"
119
+ "请改用 env_key 指向环境变量名,把值写进 ~/.aria/.env:"
120
+ "\n %s:\n base_url: ...\n env_key: %s_API_KEY",
121
+ pid, inline, pid, pid.upper().replace("-", "_"),
122
+ )
123
+ continue
124
+
125
+ if not raw.get("base_url"):
126
+ logger.warning("model_providers['%s'] 缺少 base_url —— 已跳过", pid)
127
+ continue
128
+
129
+ specs[pid] = CustomProviderSpec(pid, raw)
130
+
131
+ if specs:
132
+ logger.info("✓ 已加载 %d 个自定义 provider: %s", len(specs), ", ".join(sorted(specs)))
133
+ return specs
134
+
135
+
136
+ def build_custom_provider(spec: CustomProviderSpec, model: Optional[str] = None):
137
+ """按 spec 构造一个 OpenAI 兼容 provider 实例。
138
+
139
+ 复用 OpenAICompatProvider 而不是新写一套 HTTP 客户端:绝大多数第三方与
140
+ 自建推理服务(vLLM / LM Studio / Ollama 的 OpenAI 兼容层 / 各家云厂商网关)
141
+ 都实现了 /chat/completions,重写一遍只会多一处要维护的重试与流式解析。
142
+ """
143
+ config = ProviderConfig(
144
+ name=spec.id,
145
+ api_key=spec.api_key() or None,
146
+ base_url=spec.base_url,
147
+ model=model or spec.model,
148
+ timeout=spec.timeout,
149
+ extra={"http_headers": spec.resolved_headers(), "custom": True},
150
+ )
151
+
152
+ class _DeclaredProvider(OpenAICompatProvider):
153
+ provider_name = spec.id
154
+ DEFAULT_BASE_URL = spec.base_url
155
+ DEFAULT_MODEL = spec.model or ""
156
+
157
+ _DeclaredProvider.__name__ = f"Declared_{spec.id.replace('-', '_')}"
158
+ return _DeclaredProvider(config)
@@ -0,0 +1,137 @@
1
+ """
2
+ providers/llm/ollama.py — Ollama 本地 LLM Provider
3
+ ====================================================
4
+ 连接本地运行的 Ollama 服务,支持工具调用(native + text-based fallback)。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ from typing import Any, AsyncIterator, Dict, List, Optional
12
+
13
+ from .base import BaseLLMProvider, Message, ProviderConfig
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class OllamaProvider(BaseLLMProvider):
19
+
20
+ provider_name = "ollama"
21
+ supports_tools = True
22
+ supports_thinking = False
23
+ local = True
24
+
25
+ DEFAULT_URL = "http://localhost:11434"
26
+
27
+ def __init__(self, config: ProviderConfig):
28
+ super().__init__(config)
29
+ from aria_code.providers.ollama_models import ollama_base_url
30
+ self.base_url = ollama_base_url({"ollama_base_url": config.base_url})
31
+ self.model = config.model or "qwen2.5:7b"
32
+
33
+ async def is_available(self) -> bool:
34
+ """探测 Ollama 服务是否在线"""
35
+ import urllib.request
36
+ for url in [self.base_url,
37
+ self.base_url.replace("localhost", "127.0.0.1")]:
38
+ try:
39
+ urllib.request.urlopen(f"{url}/api/tags", timeout=2).close()
40
+ return True
41
+ except Exception:
42
+ continue
43
+ return False
44
+
45
+ async def list_models(self) -> List[str]:
46
+ """返回已安装的模型列表"""
47
+ import urllib.request
48
+ import json as _json
49
+ try:
50
+ with urllib.request.urlopen(f"{self.base_url}/api/tags", timeout=3) as r:
51
+ data = _json.loads(r.read())
52
+ return [m["name"] for m in data.get("models", [])]
53
+ except Exception:
54
+ return []
55
+
56
+ async def stream(
57
+ self,
58
+ messages: List[Message],
59
+ tools: Optional[List[Dict]] = None,
60
+ temperature: Optional[float] = None,
61
+ max_tokens: Optional[int] = None,
62
+ cancel_event=None,
63
+ ) -> AsyncIterator[Dict[str, Any]]:
64
+ import aiohttp
65
+
66
+ from aria_code.providers.ollama_models import resolve_model_async
67
+ try:
68
+ model = await resolve_model_async(self.base_url, self.model)
69
+ except ValueError as exc:
70
+ yield {"type": "error", "message": str(exc)}
71
+ return
72
+
73
+ temp = temperature if temperature is not None else self.config.temperature
74
+ n_tokens = max_tokens if max_tokens is not None else self.config.max_tokens
75
+
76
+ payload = {
77
+ "model": model,
78
+ "messages": [{"role": m.role, "content": m.content} for m in messages],
79
+ "stream": True,
80
+ "options": {"temperature": temp, "num_predict": n_tokens, "num_ctx": 32768},
81
+ }
82
+ if tools:
83
+ # 只有支持 native tool call 的模型才注入(其他走 text-based 解析)
84
+ payload["tools"] = tools
85
+
86
+ url = f"{self.base_url}/api/chat"
87
+ try:
88
+ async with aiohttp.ClientSession(trust_env=True) as sess:
89
+ async with sess.post(
90
+ url, json=payload,
91
+ timeout=aiohttp.ClientTimeout(total=self.config.timeout)
92
+ ) as resp:
93
+ if resp.status != 200:
94
+ body = await resp.text()
95
+ yield {"type": "error",
96
+ "message": f"Ollama HTTP {resp.status}: {body[:200]}"}
97
+ return
98
+
99
+ async for raw in resp.content:
100
+ if cancel_event and cancel_event.is_set():
101
+ return
102
+ line = raw.decode("utf-8", errors="ignore").strip()
103
+ if not line:
104
+ continue
105
+ try:
106
+ data = json.loads(line)
107
+ except json.JSONDecodeError:
108
+ continue
109
+
110
+ # Native tool calls
111
+ tc_list = (data.get("message") or {}).get("tool_calls") or []
112
+ for tc in tc_list:
113
+ fn = tc.get("function") or {}
114
+ args = fn.get("arguments", {})
115
+ if isinstance(args, str):
116
+ try:
117
+ args = json.loads(args)
118
+ except json.JSONDecodeError:
119
+ args = {"_raw": args}
120
+ yield {"type": "tool_call",
121
+ "name": fn.get("name", ""),
122
+ "arguments": args}
123
+
124
+ # Text token
125
+ token = (data.get("message") or {}).get("content", "")
126
+ if token:
127
+ yield {"type": "token", "text": token}
128
+
129
+ if data.get("done"):
130
+ yield {"type": "done"}
131
+ return
132
+
133
+ except aiohttp.ClientConnectorError as e:
134
+ yield {"type": "error",
135
+ "message": f"Ollama 连接失败 ({self.base_url}): {e}"}
136
+ except Exception as e:
137
+ yield {"type": "error", "message": f"Ollama 错误: {e}"}