aria-code 0.52.0__py3-none-any.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 (478) hide show
  1. aria_code/__init__.py +42 -0
  2. aria_code/_version.py +20 -0
  3. aria_code/adk_apps/__init__.py +1 -0
  4. aria_code/adk_apps/aria_code_review/__init__.py +1 -0
  5. aria_code/adk_apps/aria_code_review/agent.py +32 -0
  6. aria_code/adk_apps/aria_research/__init__.py +1 -0
  7. aria_code/adk_apps/aria_research/agent.py +31 -0
  8. aria_code/agents/__init__.py +34 -0
  9. aria_code/agents/base.py +318 -0
  10. aria_code/agents/code_review.py +200 -0
  11. aria_code/agents/deep/__init__.py +37 -0
  12. aria_code/agents/deep/calibration_loop.py +144 -0
  13. aria_code/agents/deep/critic.py +125 -0
  14. aria_code/agents/deep/deepen.py +193 -0
  15. aria_code/agents/deep/models.py +149 -0
  16. aria_code/agents/deep/pipeline.py +164 -0
  17. aria_code/agents/deep/quant_fusion.py +192 -0
  18. aria_code/agents/deep/themes.py +95 -0
  19. aria_code/agents/deep/tiers.py +106 -0
  20. aria_code/agents/engineering/__init__.py +14 -0
  21. aria_code/agents/engineering/coder.py +222 -0
  22. aria_code/agents/engineering/tester.py +145 -0
  23. aria_code/agents/financial/__init__.py +21 -0
  24. aria_code/agents/financial/cashflow_burn.py +119 -0
  25. aria_code/agents/financial/catalyst.py +279 -0
  26. aria_code/agents/financial/corporate_finance.py +175 -0
  27. aria_code/agents/financial/debate.py +224 -0
  28. aria_code/agents/financial/earnings.py +303 -0
  29. aria_code/agents/financial/fundamental.py +191 -0
  30. aria_code/agents/financial/macro.py +99 -0
  31. aria_code/agents/financial/news.py +207 -0
  32. aria_code/agents/financial/risk.py +165 -0
  33. aria_code/agents/financial/sector.py +279 -0
  34. aria_code/agents/financial/strategist.py +121 -0
  35. aria_code/agents/financial/stripe_revenue.py +127 -0
  36. aria_code/agents/financial/synthesis.py +274 -0
  37. aria_code/agents/financial/technical.py +258 -0
  38. aria_code/agents/orchestrator.py +44 -0
  39. aria_code/agents/portfolio_agent.py +363 -0
  40. aria_code/agents/realty/__init__.py +62 -0
  41. aria_code/agents/realty/asset_diagnosis.py +152 -0
  42. aria_code/agents/realty/business_match.py +166 -0
  43. aria_code/agents/realty/cashflow_verify.py +209 -0
  44. aria_code/agents/realty/contract_rules.py +210 -0
  45. aria_code/agents/realty/energy_anomaly.py +189 -0
  46. aria_code/agents/realty/exit_settlement.py +208 -0
  47. aria_code/agents/realty/fulfillment_risk.py +206 -0
  48. aria_code/agents/realty/ops_optimize.py +160 -0
  49. aria_code/agents/realty/revenue_share.py +215 -0
  50. aria_code/agents/registry.py +158 -0
  51. aria_code/agents/signal_scheme.py +111 -0
  52. aria_code/agents/sports/__init__.py +0 -0
  53. aria_code/agents/sports/football_agent.py +197 -0
  54. aria_code/agents/supervisor.py +113 -0
  55. aria_code/agents/team.py +492 -0
  56. aria_code/agents/warehouse/__init__.py +25 -0
  57. aria_code/agents/warehouse/contracts.py +26 -0
  58. aria_code/agents/warehouse/dashboard.py +155 -0
  59. aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
  60. aria_code/agents/warehouse/inbound_exceptions.py +25 -0
  61. aria_code/agents/warehouse/inventory_health.py +24 -0
  62. aria_code/agents/warehouse/local_run.py +71 -0
  63. aria_code/agents/warehouse/local_snapshot.py +132 -0
  64. aria_code/agents/warehouse/logistics_cost.py +84 -0
  65. aria_code/agents/warehouse/logistics_sync.py +21 -0
  66. aria_code/agents/warehouse/workflow.py +31 -0
  67. aria_code/aliyun_data_client.py +4 -0
  68. aria_code/apps/README.md +12 -0
  69. aria_code/apps/__init__.py +2 -0
  70. aria_code/apps/channels/README.md +15 -0
  71. aria_code/apps/channels/__init__.py +17 -0
  72. aria_code/apps/channels/intake.py +92 -0
  73. aria_code/apps/channels/registry.py +95 -0
  74. aria_code/apps/channels/tradingview.py +94 -0
  75. aria_code/apps/cli/README.md +13 -0
  76. aria_code/apps/cli/__init__.py +2 -0
  77. aria_code/apps/cli/_optional.py +120 -0
  78. aria_code/apps/cli/bootstrap.py +145 -0
  79. aria_code/apps/cli/broker_render.py +206 -0
  80. aria_code/apps/cli/codegen_paths.py +29 -0
  81. aria_code/apps/cli/commands/__init__.py +16 -0
  82. aria_code/apps/cli/commands/_business_render.py +78 -0
  83. aria_code/apps/cli/commands/_ui.py +71 -0
  84. aria_code/apps/cli/commands/analysis_cmds.py +369 -0
  85. aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
  86. aria_code/apps/cli/commands/auth_cmds.py +239 -0
  87. aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
  88. aria_code/apps/cli/commands/broker_cmds.py +1234 -0
  89. aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
  90. aria_code/apps/cli/commands/canvas_cmds.py +77 -0
  91. aria_code/apps/cli/commands/catalog.py +87 -0
  92. aria_code/apps/cli/commands/core_cmds.py +2520 -0
  93. aria_code/apps/cli/commands/data_cmds.py +457 -0
  94. aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
  95. aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
  96. aria_code/apps/cli/commands/file_cmds.py +312 -0
  97. aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
  98. aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
  99. aria_code/apps/cli/commands/market.py +434 -0
  100. aria_code/apps/cli/commands/market_cmds.py +1381 -0
  101. aria_code/apps/cli/commands/market_context.py +425 -0
  102. aria_code/apps/cli/commands/market_render.py +7 -0
  103. aria_code/apps/cli/commands/model_cmds.py +2153 -0
  104. aria_code/apps/cli/commands/ops_cmds.py +721 -0
  105. aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
  106. aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
  107. aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
  108. aria_code/apps/cli/commands/report.py +437 -0
  109. aria_code/apps/cli/commands/scaffold_templates.py +617 -0
  110. aria_code/apps/cli/commands/session_cmds.py +236 -0
  111. aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
  112. aria_code/apps/cli/commands/team.py +669 -0
  113. aria_code/apps/cli/commands/team_render.py +8 -0
  114. aria_code/apps/cli/commands/ui_cmds.py +401 -0
  115. aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
  116. aria_code/apps/cli/commands/workflow_cmds.py +480 -0
  117. aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
  118. aria_code/apps/cli/config_paths.py +73 -0
  119. aria_code/apps/cli/config_store.py +78 -0
  120. aria_code/apps/cli/constants.py +88 -0
  121. aria_code/apps/cli/context.py +34 -0
  122. aria_code/apps/cli/deterministic.py +191 -0
  123. aria_code/apps/cli/direct.py +48 -0
  124. aria_code/apps/cli/finance_service_catalog.py +111 -0
  125. aria_code/apps/cli/football_reports.py +231 -0
  126. aria_code/apps/cli/github_app_auth.py +135 -0
  127. aria_code/apps/cli/google_login.py +196 -0
  128. aria_code/apps/cli/handlers/__init__.py +11 -0
  129. aria_code/apps/cli/handlers/broker_handlers.py +122 -0
  130. aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
  131. aria_code/apps/cli/handlers/market_handlers.py +2513 -0
  132. aria_code/apps/cli/handlers/realty_handlers.py +114 -0
  133. aria_code/apps/cli/handlers/sports_handlers.py +22 -0
  134. aria_code/apps/cli/handlers/strategy_advice.py +82 -0
  135. aria_code/apps/cli/helpers.py +302 -0
  136. aria_code/apps/cli/hooks.py +180 -0
  137. aria_code/apps/cli/i18n.py +297 -0
  138. aria_code/apps/cli/intent.py +136 -0
  139. aria_code/apps/cli/intent_router.py +276 -0
  140. aria_code/apps/cli/intent_signals.py +344 -0
  141. aria_code/apps/cli/lifecycle_hooks.py +48 -0
  142. aria_code/apps/cli/local_tool_schemas.py +536 -0
  143. aria_code/apps/cli/main.py +29 -0
  144. aria_code/apps/cli/market_metadata.py +135 -0
  145. aria_code/apps/cli/market_universe.py +487 -0
  146. aria_code/apps/cli/message_processing.py +310 -0
  147. aria_code/apps/cli/model_catalog.py +620 -0
  148. aria_code/apps/cli/pdf_report.py +977 -0
  149. aria_code/apps/cli/plan_mode.py +139 -0
  150. aria_code/apps/cli/plotly_html.py +15 -0
  151. aria_code/apps/cli/prediction_feedback.py +202 -0
  152. aria_code/apps/cli/preflight.py +502 -0
  153. aria_code/apps/cli/project_aria.py +60 -0
  154. aria_code/apps/cli/prompt_assembly.py +59 -0
  155. aria_code/apps/cli/prompts/__init__.py +0 -0
  156. aria_code/apps/cli/prompts/coding.py +53 -0
  157. aria_code/apps/cli/prompts/select.py +142 -0
  158. aria_code/apps/cli/prompts/system_prompts.py +552 -0
  159. aria_code/apps/cli/prompts/ui.py +436 -0
  160. aria_code/apps/cli/provider_endpoints.py +237 -0
  161. aria_code/apps/cli/provider_keys.py +73 -0
  162. aria_code/apps/cli/providers/__init__.py +1 -0
  163. aria_code/apps/cli/providers/base.py +521 -0
  164. aria_code/apps/cli/providers/chat_routing.py +128 -0
  165. aria_code/apps/cli/providers/collaboration.py +98 -0
  166. aria_code/apps/cli/providers/llm/__init__.py +1 -0
  167. aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
  168. aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
  169. aria_code/apps/cli/providers/llm/response_cache.py +60 -0
  170. aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
  171. aria_code/apps/cli/providers/runtime_bridge.py +353 -0
  172. aria_code/apps/cli/providers/vertexai_stream.py +316 -0
  173. aria_code/apps/cli/runtime_consumer.py +657 -0
  174. aria_code/apps/cli/sandbox.py +32 -0
  175. aria_code/apps/cli/session_export.py +120 -0
  176. aria_code/apps/cli/session_jsonl.py +208 -0
  177. aria_code/apps/cli/session_store.py +112 -0
  178. aria_code/apps/cli/skills_catalog.py +273 -0
  179. aria_code/apps/cli/todo_tracker.py +190 -0
  180. aria_code/apps/cli/tool_executor.py +823 -0
  181. aria_code/apps/cli/tool_registry.py +34 -0
  182. aria_code/apps/cli/tool_scope.py +106 -0
  183. aria_code/apps/cli/tools/__init__.py +40 -0
  184. aria_code/apps/cli/tools/context.py +46 -0
  185. aria_code/apps/cli/tools/file_tools.py +180 -0
  186. aria_code/apps/cli/tools/market_tools.py +620 -0
  187. aria_code/apps/cli/tools/notebook_tools.py +111 -0
  188. aria_code/apps/cli/tools/system_tools.py +726 -0
  189. aria_code/apps/cli/tools/write_tools.py +845 -0
  190. aria_code/apps/cli/tradingview_bridge.py +529 -0
  191. aria_code/apps/cli/turn_planning.py +137 -0
  192. aria_code/apps/cli/update_check.py +153 -0
  193. aria_code/apps/cli/utils/__init__.py +0 -0
  194. aria_code/apps/cli/utils/market_detect.py +1597 -0
  195. aria_code/apps/daemon/README.md +14 -0
  196. aria_code/apps/vscode/README.md +115 -0
  197. aria_code/apps/vscode/package.json +70 -0
  198. aria_code/aria_cli.py +6743 -0
  199. aria_code/aria_daemon.py +1398 -0
  200. aria_code/aria_feishu_bot.py +1423 -0
  201. aria_code/aria_mcp_server.py +7 -0
  202. aria_code/aria_relay_client.py +4 -0
  203. aria_code/aria_relay_server.py +490 -0
  204. aria_code/aria_telegram_bot.py +202 -0
  205. aria_code/ariarc.py +385 -0
  206. aria_code/artifacts.py +581 -0
  207. aria_code/backtest_engine.py +4 -0
  208. aria_code/backtest_report.py +4 -0
  209. aria_code/brokers/__init__.py +78 -0
  210. aria_code/brokers/automation.py +193 -0
  211. aria_code/brokers/base.py +231 -0
  212. aria_code/brokers/capabilities.py +264 -0
  213. aria_code/brokers/cn/__init__.py +10 -0
  214. aria_code/brokers/cn/easytrader_broker.py +193 -0
  215. aria_code/brokers/cn/futu_broker.py +194 -0
  216. aria_code/brokers/cn/longbridge_broker.py +190 -0
  217. aria_code/brokers/cn/tiger_broker.py +196 -0
  218. aria_code/brokers/cn/xtquant_broker.py +225 -0
  219. aria_code/brokers/config.py +414 -0
  220. aria_code/brokers/intl/__init__.py +5 -0
  221. aria_code/brokers/intl/alpaca_broker.py +183 -0
  222. aria_code/brokers/intl/ibkr_broker.py +215 -0
  223. aria_code/brokers/intl/trading212_broker.py +183 -0
  224. aria_code/brokers/intl/webull_broker.py +156 -0
  225. aria_code/brokers/paper_broker.py +266 -0
  226. aria_code/brokers/planning.py +296 -0
  227. aria_code/brokers/registry.py +213 -0
  228. aria_code/brokers/trading.py +267 -0
  229. aria_code/canva_client.py +4 -0
  230. aria_code/change_store.py +127 -0
  231. aria_code/clients/__init__.py +0 -0
  232. aria_code/clients/aliyun_data_client.py +660 -0
  233. aria_code/clients/aria_relay_client.py +182 -0
  234. aria_code/clients/canva_client.py +284 -0
  235. aria_code/clients/figma_client.py +100 -0
  236. aria_code/clients/football_data_client.py +1671 -0
  237. aria_code/clients/kling_video_client.py +182 -0
  238. aria_code/clients/market_data_client.py +1976 -0
  239. aria_code/clients/openai_image_client.py +242 -0
  240. aria_code/clients/runway_video_client.py +157 -0
  241. aria_code/clients/warehouse_erp_client.py +105 -0
  242. aria_code/cloud_memory.py +181 -0
  243. aria_code/command_safety.py +19 -0
  244. aria_code/computer_use_tools.py +4 -0
  245. aria_code/dashboard_generator.py +579 -0
  246. aria_code/data_analysis_tools.py +4 -0
  247. aria_code/data_cleaner.py +483 -0
  248. aria_code/data_service.py +513 -0
  249. aria_code/datasources/__init__.py +23 -0
  250. aria_code/datasources/base.py +166 -0
  251. aria_code/datasources/router.py +253 -0
  252. aria_code/datasources/sources/__init__.py +15 -0
  253. aria_code/datasources/sources/akshare_source.py +269 -0
  254. aria_code/datasources/sources/alpha_vantage_source.py +203 -0
  255. aria_code/datasources/sources/edgar_source.py +219 -0
  256. aria_code/datasources/sources/finnhub_source.py +198 -0
  257. aria_code/datasources/sources/fred_source.py +223 -0
  258. aria_code/datasources/sources/tushare_source.py +143 -0
  259. aria_code/datasources/sources/web_scraper_source.py +278 -0
  260. aria_code/datasources/sources/world_bank_source.py +206 -0
  261. aria_code/datasources/sources/yfinance_source.py +152 -0
  262. aria_code/demo_player.py +207 -0
  263. aria_code/doctor.py +813 -0
  264. aria_code/domain/__init__.py +0 -0
  265. aria_code/domain/backtest_engine.py +354 -0
  266. aria_code/domain/backtest_report.py +472 -0
  267. aria_code/domain/finance_formulas.py +389 -0
  268. aria_code/domain/portfolio_ledger.py +307 -0
  269. aria_code/domain/strategy_vault.py +421 -0
  270. aria_code/evals/__init__.py +37 -0
  271. aria_code/evals/harness.py +598 -0
  272. aria_code/evals/runner.py +238 -0
  273. aria_code/external_agent_runner.py +115 -0
  274. aria_code/figma_client.py +4 -0
  275. aria_code/file_analysis_tools.py +4 -0
  276. aria_code/finance_formulas.py +4 -0
  277. aria_code/football_data_client.py +4 -0
  278. aria_code/image_gen_tools.py +4 -0
  279. aria_code/intent_classifier.py +386 -0
  280. aria_code/kling_video_client.py +4 -0
  281. aria_code/licensing.py +151 -0
  282. aria_code/local_finance_tools.py +4 -0
  283. aria_code/local_image_provider.py +4 -0
  284. aria_code/local_llm_provider.py +4 -0
  285. aria_code/macro_tools.py +4 -0
  286. aria_code/markdown_pdf.py +289 -0
  287. aria_code/market_data_client.py +4 -0
  288. aria_code/mcp_client.py +639 -0
  289. aria_code/memory_manager.py +246 -0
  290. aria_code/model_capability.py +486 -0
  291. aria_code/notification_tools.py +4 -0
  292. aria_code/openai_image_client.py +4 -0
  293. aria_code/packages/__init__.py +23 -0
  294. aria_code/packages/adk_bridge/__init__.py +11 -0
  295. aria_code/packages/adk_bridge/code_review_tools.py +49 -0
  296. aria_code/packages/adk_bridge/market_tools.py +125 -0
  297. aria_code/packages/aria_agents/__init__.py +5 -0
  298. aria_code/packages/aria_agents/manifest.py +78 -0
  299. aria_code/packages/aria_core/__init__.py +34 -0
  300. aria_code/packages/aria_core/architecture.py +269 -0
  301. aria_code/packages/aria_core/export.py +147 -0
  302. aria_code/packages/aria_core/manifest.py +65 -0
  303. aria_code/packages/aria_core/paths.py +57 -0
  304. aria_code/packages/aria_core/secure_file.py +68 -0
  305. aria_code/packages/aria_infra/__init__.py +15 -0
  306. aria_code/packages/aria_infra/arthera.py +52 -0
  307. aria_code/packages/aria_infra/doctor.py +246 -0
  308. aria_code/packages/aria_infra/product.py +40 -0
  309. aria_code/packages/aria_mcp/__init__.py +25 -0
  310. aria_code/packages/aria_mcp/bridge.py +201 -0
  311. aria_code/packages/aria_mcp/circuit.py +82 -0
  312. aria_code/packages/aria_mcp/config.py +111 -0
  313. aria_code/packages/aria_mcp/installer.py +95 -0
  314. aria_code/packages/aria_mcp/server.py +1550 -0
  315. aria_code/packages/aria_mcp/tools.py +81 -0
  316. aria_code/packages/aria_sdk/__init__.py +19 -0
  317. aria_code/packages/aria_sdk/client.py +396 -0
  318. aria_code/packages/aria_sdk/providers.py +70 -0
  319. aria_code/packages/aria_sdk/streaming.py +79 -0
  320. aria_code/packages/aria_sdk/types.py +86 -0
  321. aria_code/packages/aria_services/__init__.py +92 -0
  322. aria_code/packages/aria_services/cache.py +60 -0
  323. aria_code/packages/aria_services/context.py +356 -0
  324. aria_code/packages/aria_services/context_checkpoints.py +157 -0
  325. aria_code/packages/aria_services/data.py +11 -0
  326. aria_code/packages/aria_services/provider_health.py +268 -0
  327. aria_code/packages/aria_services/references.py +247 -0
  328. aria_code/packages/aria_services/registry.py +249 -0
  329. aria_code/packages/aria_services/research_protocol.py +57 -0
  330. aria_code/packages/aria_services/research_quality.py +186 -0
  331. aria_code/packages/aria_services/settings.py +157 -0
  332. aria_code/packages/aria_services/usage.py +151 -0
  333. aria_code/packages/aria_skills/__init__.py +46 -0
  334. aria_code/packages/aria_skills/catalog.py +149 -0
  335. aria_code/packages/aria_skills/loader.py +455 -0
  336. aria_code/packages/aria_skills/registry.py +84 -0
  337. aria_code/packages/aria_tools/__init__.py +5 -0
  338. aria_code/packages/aria_tools/financial/__init__.py +8 -0
  339. aria_code/packages/aria_tools/financial/_paths.py +130 -0
  340. aria_code/packages/aria_tools/financial/compliance.py +31 -0
  341. aria_code/packages/aria_tools/financial/factors.py +33 -0
  342. aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
  343. aria_code/packages/aria_tools/financial/strategy.py +31 -0
  344. aria_code/packages/aria_tools/registry.py +128 -0
  345. aria_code/packages/quant_engine/__init__.py +34 -0
  346. aria_code/packages/quant_engine/_namespace.py +62 -0
  347. aria_code/packages/quant_engine/backtest/__init__.py +14 -0
  348. aria_code/packages/quant_engine/backtest/core.py +53 -0
  349. aria_code/packages/quant_engine/backtest/engine.py +96 -0
  350. aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
  351. aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
  352. aria_code/packages/quant_engine/sports/__init__.py +80 -0
  353. aria_code/packages/quant_engine/sports/calibrator.py +354 -0
  354. aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
  355. aria_code/packages/quant_engine/sports/elo.py +300 -0
  356. aria_code/packages/quant_engine/sports/form.py +188 -0
  357. aria_code/packages/quant_engine/sports/h2h.py +195 -0
  358. aria_code/packages/quant_engine/sports/ml_model.py +377 -0
  359. aria_code/packages/quant_engine/sports/predictor.py +312 -0
  360. aria_code/packages/quant_engine/sports/tracker.py +665 -0
  361. aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
  362. aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
  363. aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
  364. aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
  365. aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
  366. aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
  367. aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
  368. aria_code/packs/__init__.py +85 -0
  369. aria_code/packs/base.py +168 -0
  370. aria_code/packs/finance/__init__.py +250 -0
  371. aria_code/packs/logistics/__init__.py +169 -0
  372. aria_code/packs/payments/__init__.py +139 -0
  373. aria_code/packs/realty/__init__.py +190 -0
  374. aria_code/packs/registry.py +202 -0
  375. aria_code/packs/rules.py +90 -0
  376. aria_code/plan_utils.py +194 -0
  377. aria_code/plugin_loader.py +328 -0
  378. aria_code/portfolio_ledger.py +4 -0
  379. aria_code/preview_server.py +449 -0
  380. aria_code/privacy/__init__.py +5 -0
  381. aria_code/privacy/feedback.py +123 -0
  382. aria_code/project_review.py +278 -0
  383. aria_code/project_review_api.py +235 -0
  384. aria_code/project_review_server.py +18 -0
  385. aria_code/project_tools.py +4 -0
  386. aria_code/providers/__init__.py +30 -0
  387. aria_code/providers/llm/__init__.py +19 -0
  388. aria_code/providers/llm/anthropic.py +184 -0
  389. aria_code/providers/llm/autoconfig.py +213 -0
  390. aria_code/providers/llm/base.py +139 -0
  391. aria_code/providers/llm/custom.py +158 -0
  392. aria_code/providers/llm/ollama.py +129 -0
  393. aria_code/providers/llm/openai_compat.py +313 -0
  394. aria_code/providers/llm/registry.py +444 -0
  395. aria_code/providers/local_image_provider.py +202 -0
  396. aria_code/providers/local_llm_provider.py +589 -0
  397. aria_code/realty_data_tools.py +4 -0
  398. aria_code/report_exporters.py +150 -0
  399. aria_code/report_generator.py +1764 -0
  400. aria_code/runtime/__init__.py +169 -0
  401. aria_code/runtime/acceptance.py +481 -0
  402. aria_code/runtime/agent_loop.py +1520 -0
  403. aria_code/runtime/approval.py +57 -0
  404. aria_code/runtime/budget.py +232 -0
  405. aria_code/runtime/checkpoints.py +432 -0
  406. aria_code/runtime/crash_report.py +174 -0
  407. aria_code/runtime/events.py +113 -0
  408. aria_code/runtime/gateway.py +150 -0
  409. aria_code/runtime/lsp.py +484 -0
  410. aria_code/runtime/orchestrator.py +55 -0
  411. aria_code/runtime/repo_map.py +700 -0
  412. aria_code/runtime/run_state.py +127 -0
  413. aria_code/runtime/run_store.py +450 -0
  414. aria_code/runtime/self_healing.py +422 -0
  415. aria_code/runtime/subagent.py +547 -0
  416. aria_code/runtime/task_ledger.py +86 -0
  417. aria_code/runtime/task_orchestrator.py +90 -0
  418. aria_code/runtime/tool_executor.py +217 -0
  419. aria_code/runtime/tool_policy.py +107 -0
  420. aria_code/runtime/worktrees.py +215 -0
  421. aria_code/runway_video_client.py +4 -0
  422. aria_code/safety/__init__.py +23 -0
  423. aria_code/safety/permissions.py +306 -0
  424. aria_code/safety/service.py +102 -0
  425. aria_code/setup_wizard.py +673 -0
  426. aria_code/spreadsheet_tools.py +4 -0
  427. aria_code/strategy_vault.py +4 -0
  428. aria_code/tools/__init__.py +0 -0
  429. aria_code/tools/artifact_tools.py +252 -0
  430. aria_code/tools/broker_tools.py +92 -0
  431. aria_code/tools/build_quant_engine.py +97 -0
  432. aria_code/tools/code_audit_tools.py +192 -0
  433. aria_code/tools/computer_use_tools.py +504 -0
  434. aria_code/tools/data_analysis_tools.py +809 -0
  435. aria_code/tools/enterprise_finance_tools.py +156 -0
  436. aria_code/tools/extended_tools.py +240 -0
  437. aria_code/tools/file_analysis_tools.py +885 -0
  438. aria_code/tools/image_gen_tools.py +114 -0
  439. aria_code/tools/local_finance_tools.py +3417 -0
  440. aria_code/tools/logistics_tools.py +135 -0
  441. aria_code/tools/macro_tools.py +369 -0
  442. aria_code/tools/notification_tools.py +249 -0
  443. aria_code/tools/project_tools.py +525 -0
  444. aria_code/tools/realty_data_tools.py +659 -0
  445. aria_code/tools/spreadsheet_tools.py +388 -0
  446. aria_code/tools/stripe_tools.py +115 -0
  447. aria_code/ui/__init__.py +105 -0
  448. aria_code/ui/banner.py +508 -0
  449. aria_code/ui/completer.py +501 -0
  450. aria_code/ui/console.py +281 -0
  451. aria_code/ui/image_render.py +243 -0
  452. aria_code/ui/input_box.py +488 -0
  453. aria_code/ui/picker.py +201 -0
  454. aria_code/ui/render/__init__.py +11 -0
  455. aria_code/ui/render/finance.py +1705 -0
  456. aria_code/ui/render/market.py +225 -0
  457. aria_code/ui/render/output.py +775 -0
  458. aria_code/ui/render/responsive.py +75 -0
  459. aria_code/ui/render/team.py +354 -0
  460. aria_code/ui/robot.py +235 -0
  461. aria_code/ui/startup_dashboard.py +109 -0
  462. aria_code/utils/vscode_uri.py +37 -0
  463. aria_code/video_analysis.py +147 -0
  464. aria_code/video_editor.py +271 -0
  465. aria_code/workspace/__init__.py +6 -0
  466. aria_code/workspace/files.py +193 -0
  467. aria_code/workspace/verify.py +113 -0
  468. aria_code/workspace_changes.py +199 -0
  469. aria_code/workspace_context.py +233 -0
  470. aria_code/workspace_service.py +196 -0
  471. aria_code/workspace_tools.py +150 -0
  472. aria_code-0.52.0.dist-info/METADATA +237 -0
  473. aria_code-0.52.0.dist-info/RECORD +478 -0
  474. aria_code-0.52.0.dist-info/WHEEL +5 -0
  475. aria_code-0.52.0.dist-info/entry_points.txt +3 -0
  476. aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
  477. aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
  478. aria_code-0.52.0.dist-info/top_level.txt +1 -0
@@ -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,129 @@
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
+ self.base_url = config.base_url or self.DEFAULT_URL
30
+ self.model = config.model or "qwen2.5:7b"
31
+
32
+ async def is_available(self) -> bool:
33
+ """探测 Ollama 服务是否在线"""
34
+ import urllib.request
35
+ for url in [self.base_url,
36
+ self.base_url.replace("localhost", "127.0.0.1")]:
37
+ try:
38
+ urllib.request.urlopen(f"{url}/api/tags", timeout=2).close()
39
+ return True
40
+ except Exception:
41
+ continue
42
+ return False
43
+
44
+ async def list_models(self) -> List[str]:
45
+ """返回已安装的模型列表"""
46
+ import urllib.request
47
+ import json as _json
48
+ try:
49
+ with urllib.request.urlopen(f"{self.base_url}/api/tags", timeout=3) as r:
50
+ data = _json.loads(r.read())
51
+ return [m["name"] for m in data.get("models", [])]
52
+ except Exception:
53
+ return []
54
+
55
+ async def stream(
56
+ self,
57
+ messages: List[Message],
58
+ tools: Optional[List[Dict]] = None,
59
+ temperature: Optional[float] = None,
60
+ max_tokens: Optional[int] = None,
61
+ cancel_event=None,
62
+ ) -> AsyncIterator[Dict[str, Any]]:
63
+ import aiohttp
64
+
65
+ temp = temperature if temperature is not None else self.config.temperature
66
+ n_tokens = max_tokens if max_tokens is not None else self.config.max_tokens
67
+
68
+ payload = {
69
+ "model": self.model,
70
+ "messages": [{"role": m.role, "content": m.content} for m in messages],
71
+ "stream": True,
72
+ "options": {"temperature": temp, "num_predict": n_tokens, "num_ctx": 32768},
73
+ }
74
+ if tools:
75
+ # 只有支持 native tool call 的模型才注入(其他走 text-based 解析)
76
+ payload["tools"] = tools
77
+
78
+ url = f"{self.base_url}/api/chat"
79
+ try:
80
+ async with aiohttp.ClientSession() as sess:
81
+ async with sess.post(
82
+ url, json=payload,
83
+ timeout=aiohttp.ClientTimeout(total=self.config.timeout)
84
+ ) as resp:
85
+ if resp.status != 200:
86
+ body = await resp.text()
87
+ yield {"type": "error",
88
+ "message": f"Ollama HTTP {resp.status}: {body[:200]}"}
89
+ return
90
+
91
+ async for raw in resp.content:
92
+ if cancel_event and cancel_event.is_set():
93
+ return
94
+ line = raw.decode("utf-8", errors="ignore").strip()
95
+ if not line:
96
+ continue
97
+ try:
98
+ data = json.loads(line)
99
+ except json.JSONDecodeError:
100
+ continue
101
+
102
+ # Native tool calls
103
+ tc_list = (data.get("message") or {}).get("tool_calls") or []
104
+ for tc in tc_list:
105
+ fn = tc.get("function") or {}
106
+ args = fn.get("arguments", {})
107
+ if isinstance(args, str):
108
+ try:
109
+ args = json.loads(args)
110
+ except json.JSONDecodeError:
111
+ args = {"_raw": args}
112
+ yield {"type": "tool_call",
113
+ "name": fn.get("name", ""),
114
+ "arguments": args}
115
+
116
+ # Text token
117
+ token = (data.get("message") or {}).get("content", "")
118
+ if token:
119
+ yield {"type": "token", "text": token}
120
+
121
+ if data.get("done"):
122
+ yield {"type": "done"}
123
+ return
124
+
125
+ except aiohttp.ClientConnectorError as e:
126
+ yield {"type": "error",
127
+ "message": f"Ollama 连接失败 ({self.base_url}): {e}"}
128
+ except Exception as e:
129
+ yield {"type": "error", "message": f"Ollama 错误: {e}"}
@@ -0,0 +1,313 @@
1
+ """
2
+ providers/llm/openai_compat.py — OpenAI 兼容协议通用 Provider
3
+ ==============================================================
4
+ DeepSeek / OpenAI / Groq / Together / LM Studio / vLLM / llama.cpp
5
+ 全部走同一套 /v1/chat/completions SSE 协议。
6
+
7
+ 各 provider 只需继承并声明 DEFAULT_BASE_URL 和 DEFAULT_MODEL。
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import logging
14
+ import os
15
+ import re
16
+ from typing import Any, AsyncIterator, Dict, List, Optional
17
+
18
+ from .base import BaseLLMProvider, Message, ProviderConfig
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ def chat_completions_url(base_url: str) -> str:
24
+ """Join an OpenAI-compatible base URL without duplicating its version."""
25
+ base = base_url.rstrip("/")
26
+ if re.search(r"/v\d+(?:beta)?$", base):
27
+ return f"{base}/chat/completions"
28
+ return f"{base}/v1/chat/completions"
29
+
30
+
31
+ class OpenAICompatProvider(BaseLLMProvider):
32
+ """
33
+ 通用 OpenAI 兼容 Provider。
34
+ 子类覆盖 DEFAULT_BASE_URL / DEFAULT_MODEL / provider_name。
35
+ """
36
+
37
+ provider_name = "openai_compat"
38
+ supports_tools = True
39
+ supports_thinking = False
40
+ local = False
41
+
42
+ DEFAULT_BASE_URL = "https://api.openai.com"
43
+ DEFAULT_MODEL = "gpt-4o-mini"
44
+
45
+ def __init__(self, config: ProviderConfig):
46
+ super().__init__(config)
47
+ self.base_url = (config.base_url or self.DEFAULT_BASE_URL).rstrip("/")
48
+ self.model = config.model or self.DEFAULT_MODEL
49
+ self.api_key = config.api_key or ""
50
+
51
+ async def is_available(self) -> bool:
52
+ return bool(self.api_key)
53
+
54
+ async def stream(
55
+ self,
56
+ messages: List[Message],
57
+ tools: Optional[List[Dict]] = None,
58
+ temperature: Optional[float] = None,
59
+ max_tokens: Optional[int] = None,
60
+ cancel_event=None,
61
+ ) -> AsyncIterator[Dict[str, Any]]:
62
+ import aiohttp
63
+
64
+ temp = temperature if temperature is not None else self.config.temperature
65
+ n_tokens = max_tokens if max_tokens is not None else self.config.max_tokens
66
+
67
+ headers = {
68
+ "Authorization": f"Bearer {self.api_key}",
69
+ "Content-Type": "application/json",
70
+ }
71
+ payload: Dict[str, Any] = {
72
+ "model": self.model,
73
+ "messages": [{"role": m.role, "content": m.content} for m in messages],
74
+ "temperature": temp,
75
+ "max_tokens": n_tokens,
76
+ "stream": True,
77
+ }
78
+ if tools:
79
+ payload["tools"] = [
80
+ {"type": "function", "function": t} for t in tools
81
+ ]
82
+ payload["tool_choice"] = "auto"
83
+
84
+ # Some compatible endpoints already include their API version
85
+ # (Moonshot /v1, ZhiPu /v4). Avoid generating /v1/v1 or /v4/v1.
86
+ url = chat_completions_url(self.base_url)
87
+ # aiohttp 不自动读系统代理,需显式传入
88
+ proxy = (os.getenv("HTTPS_PROXY") or os.getenv("https_proxy")
89
+ or os.getenv("HTTP_PROXY") or os.getenv("http_proxy"))
90
+
91
+ try:
92
+ async with aiohttp.ClientSession() as sess:
93
+ async with sess.post(
94
+ url, json=payload, headers=headers,
95
+ proxy=proxy,
96
+ timeout=aiohttp.ClientTimeout(total=self.config.timeout)
97
+ ) as resp:
98
+ if resp.status != 200:
99
+ body = await resp.text()
100
+ yield {"type": "error",
101
+ "message": f"HTTP {resp.status}: {body[:300]}"}
102
+ return
103
+
104
+ pending_tool: Dict = {}
105
+ async for raw in resp.content:
106
+ if cancel_event and cancel_event.is_set():
107
+ return
108
+
109
+ line = raw.decode("utf-8", errors="ignore").strip()
110
+ if not line or line == "data: [DONE]":
111
+ continue
112
+ if not line.startswith("data: "):
113
+ continue
114
+
115
+ try:
116
+ data = json.loads(line[6:])
117
+ except json.JSONDecodeError:
118
+ continue
119
+
120
+ # 处理 thinking tokens(DeepSeek-R1 等)
121
+ reasoning = (
122
+ ((data.get("choices") or [{}])[0]
123
+ .get("delta") or {})
124
+ .get("reasoning_content")
125
+ )
126
+ if reasoning:
127
+ yield {"type": "thinking", "text": reasoning}
128
+
129
+ # 普通 token
130
+ delta = ((data.get("choices") or [{}])[0].get("delta") or {})
131
+ token = delta.get("content") or ""
132
+ if token:
133
+ yield {"type": "token", "text": token}
134
+
135
+ # 工具调用(SSE 增量拼接)
136
+ for tc in delta.get("tool_calls") or []:
137
+ fn = tc.get("function") or {}
138
+ idx = tc.get("index", 0)
139
+ name = fn.get("name", "")
140
+ args_chunk = fn.get("arguments", "")
141
+
142
+ if name:
143
+ if pending_tool:
144
+ # emit previous tool
145
+ try:
146
+ args = json.loads(pending_tool["args"])
147
+ except Exception:
148
+ args = {"_raw": pending_tool["args"]}
149
+ yield {"type": "tool_call",
150
+ "name": pending_tool["name"],
151
+ "arguments": args}
152
+ pending_tool = {"name": name, "args": "", "idx": idx}
153
+ if args_chunk:
154
+ pending_tool["args"] = pending_tool.get("args", "") + args_chunk
155
+
156
+ # finish reason
157
+ finish = ((data.get("choices") or [{}])[0].get("finish_reason"))
158
+ if finish in ("stop", "tool_calls", "length"):
159
+ if pending_tool:
160
+ try:
161
+ args = json.loads(pending_tool["args"])
162
+ except Exception:
163
+ args = {"_raw": pending_tool["args"]}
164
+ yield {"type": "tool_call",
165
+ "name": pending_tool["name"],
166
+ "arguments": args}
167
+ pending_tool = {}
168
+ yield {"type": "done"}
169
+ return
170
+
171
+ except aiohttp.ClientConnectorError as e:
172
+ yield {"type": "error", "message": f"连接 {self.base_url} 失败: {e}"}
173
+ except Exception as e:
174
+ yield {"type": "error", "message": f"Provider 错误: {e}"}
175
+
176
+
177
+ # ── 具体 Provider 子类(只需声明几个属性)────────────────────────────────────
178
+
179
+ class DeepSeekProvider(OpenAICompatProvider):
180
+ provider_name = "deepseek"
181
+ DEFAULT_BASE_URL = "https://api.deepseek.com"
182
+ DEFAULT_MODEL = "deepseek-chat"
183
+ supports_thinking = True # deepseek-reasoner 支持
184
+
185
+ def __init__(self, config: ProviderConfig):
186
+ if not config.api_key:
187
+ config.api_key = os.getenv("DEEPSEEK_API_KEY", "")
188
+ super().__init__(config)
189
+ # 思考模型别名
190
+ if self.model in ("deepseek-reasoner", "deepseek-r1"):
191
+ self.supports_thinking = True
192
+
193
+
194
+ class OpenAIProvider(OpenAICompatProvider):
195
+ provider_name = "openai"
196
+ DEFAULT_BASE_URL = "https://api.openai.com"
197
+ DEFAULT_MODEL = "gpt-4o-mini"
198
+
199
+ def __init__(self, config: ProviderConfig):
200
+ if not config.api_key:
201
+ config.api_key = os.getenv("OPENAI_API_KEY", "")
202
+ super().__init__(config)
203
+
204
+
205
+ class GroqProvider(OpenAICompatProvider):
206
+ provider_name = "groq"
207
+ DEFAULT_BASE_URL = "https://api.groq.com/openai"
208
+ DEFAULT_MODEL = "llama-3.3-70b-versatile"
209
+
210
+ def __init__(self, config: ProviderConfig):
211
+ if not config.api_key:
212
+ config.api_key = os.getenv("GROQ_API_KEY", "")
213
+ super().__init__(config)
214
+
215
+
216
+ class GoogleProvider(OpenAICompatProvider):
217
+ """Gemini through Google's OpenAI-compatible endpoint.
218
+
219
+ The registry previously had no Google entry at all, so Gemini — the default
220
+ model in the shipped config — could not be reached through the provider
221
+ chain and never appeared in fallback. Vertex AI (service-account / ADC) is
222
+ handled separately by apps/cli/providers/vertexai_stream.py; this covers the
223
+ API-key path.
224
+ """
225
+
226
+ provider_name = "google"
227
+ DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai"
228
+ DEFAULT_MODEL = "gemini-2.5-flash"
229
+
230
+ def __init__(self, config: ProviderConfig):
231
+ if not config.api_key:
232
+ config.api_key = os.getenv("GEMINI_API_KEY", "") or os.getenv("GOOGLE_API_KEY", "")
233
+ super().__init__(config)
234
+
235
+
236
+ class TogetherProvider(OpenAICompatProvider):
237
+ provider_name = "together"
238
+ DEFAULT_BASE_URL = "https://api.together.xyz"
239
+ DEFAULT_MODEL = "meta-llama/Llama-3.3-70B-Instruct-Turbo"
240
+
241
+ def __init__(self, config: ProviderConfig):
242
+ if not config.api_key:
243
+ config.api_key = os.getenv("TOGETHER_API_KEY", "")
244
+ super().__init__(config)
245
+
246
+
247
+ class DashScopeProvider(OpenAICompatProvider):
248
+ """阿里云通义(OpenAI 兼容端点)"""
249
+ provider_name = "dashscope"
250
+ DEFAULT_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode"
251
+ DEFAULT_MODEL = "qwen-plus"
252
+
253
+ def __init__(self, config: ProviderConfig):
254
+ if not config.api_key:
255
+ config.api_key = os.getenv("DASHSCOPE_API_KEY", "")
256
+ super().__init__(config)
257
+
258
+
259
+ class LMStudioProvider(OpenAICompatProvider):
260
+ """LM Studio 本地服务"""
261
+ provider_name = "lmstudio"
262
+ DEFAULT_BASE_URL = "http://localhost:1234"
263
+ DEFAULT_MODEL = "loaded-model"
264
+ local = True
265
+
266
+ async def is_available(self) -> bool:
267
+ import urllib.request
268
+ try:
269
+ urllib.request.urlopen(
270
+ f"{self.base_url}/v1/models", timeout=2
271
+ ).close()
272
+ return True
273
+ except Exception:
274
+ return False
275
+
276
+
277
+ # ── 国内可访问 Provider(OpenAI 兼容协议)────────────────────────────────────
278
+
279
+ class SiliconFlowProvider(OpenAICompatProvider):
280
+ """硅基流动 — 中国大陆可直连,支持 DeepSeek-V3/R1、Qwen 等主流模型"""
281
+ provider_name = "siliconflow"
282
+ DEFAULT_BASE_URL = "https://api.siliconflow.cn"
283
+ DEFAULT_MODEL = "deepseek-ai/DeepSeek-V3"
284
+ supports_thinking = True # DeepSeek-R1 在此运行
285
+
286
+ def __init__(self, config: ProviderConfig):
287
+ if not config.api_key:
288
+ config.api_key = os.getenv("SILICONFLOW_API_KEY", "")
289
+ super().__init__(config)
290
+
291
+
292
+ class MoonshotProvider(OpenAICompatProvider):
293
+ """Moonshot / Kimi — 中国大陆可直连"""
294
+ provider_name = "moonshot"
295
+ DEFAULT_BASE_URL = "https://api.moonshot.cn/v1"
296
+ DEFAULT_MODEL = "moonshot-v1-8k"
297
+
298
+ def __init__(self, config: ProviderConfig):
299
+ if not config.api_key:
300
+ config.api_key = os.getenv("MOONSHOT_API_KEY", "")
301
+ super().__init__(config)
302
+
303
+
304
+ class ZhiPuProvider(OpenAICompatProvider):
305
+ """智谱 GLM — 中国大陆可直连"""
306
+ provider_name = "zhipu"
307
+ DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4"
308
+ DEFAULT_MODEL = "glm-4-flash"
309
+
310
+ def __init__(self, config: ProviderConfig):
311
+ if not config.api_key:
312
+ config.api_key = os.getenv("ZHIPUAI_API_KEY", "")
313
+ super().__init__(config)