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,484 @@
1
+ """Minimal Language Server Protocol (LSP) client for on-demand diagnostics.
2
+
3
+ This is the "biggest gap" vs Claude Code's architecture: real diagnostics from
4
+ a language server (type errors, undefined names, unused imports) rather than
5
+ just a syntax compile check.
6
+
7
+ Design — deliberately one-shot, not a persistent server:
8
+ spawn language server → initialize → didOpen → collect publishDiagnostics →
9
+ shutdown. Each call is self-contained with strict timeouts so it never hangs
10
+ the REPL, and degrades gracefully (returns []) when no server is installed.
11
+
12
+ Supported servers (auto-detected on PATH):
13
+ Python → pylsp (pip install python-lsp-server)
14
+ TS / JS → typescript-language-server --stdio (npm i -g …)
15
+
16
+ Exposed to the LLM as the `lsp_diagnostics` tool and to users via /lsp.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import os
23
+ import queue
24
+ import shutil
25
+ import subprocess
26
+ import threading
27
+ import time
28
+ from pathlib import Path
29
+ from typing import Optional
30
+
31
+ # ── Server registry ──────────────────────────────────────────────────────────
32
+ # suffix → (command argv, LSP languageId)
33
+ _SERVERS: dict[str, tuple[list[str], str]] = {
34
+ ".py": (["pylsp"], "python"),
35
+ ".ts": (["typescript-language-server", "--stdio"], "typescript"),
36
+ ".tsx": (["typescript-language-server", "--stdio"], "typescriptreact"),
37
+ ".js": (["typescript-language-server", "--stdio"], "javascript"),
38
+ ".jsx": (["typescript-language-server", "--stdio"], "javascriptreact"),
39
+ ".mjs": (["typescript-language-server", "--stdio"], "javascript"),
40
+ ".cjs": (["typescript-language-server", "--stdio"], "javascript"),
41
+ }
42
+
43
+ _SEVERITY = {1: "error", 2: "warning", 3: "info", 4: "hint"}
44
+
45
+ # Cache PATH lookups so repeated edits don't re-stat the filesystem each time.
46
+ _AVAILABILITY: dict[str, bool] = {}
47
+
48
+
49
+ def server_for(path) -> Optional[tuple[list[str], str]]:
50
+ """Return (argv, languageId) if a language server is installed for this
51
+ file's type, else None."""
52
+ suffix = Path(path).suffix.lower()
53
+ entry = _SERVERS.get(suffix)
54
+ if not entry:
55
+ return None
56
+ cmd, lang = entry
57
+ exe = cmd[0]
58
+ if exe not in _AVAILABILITY:
59
+ _AVAILABILITY[exe] = shutil.which(exe) is not None
60
+ if not _AVAILABILITY[exe]:
61
+ return None
62
+ return cmd, lang
63
+
64
+
65
+ def available_servers() -> dict[str, bool]:
66
+ """Report which known language servers are installed (for /lsp status)."""
67
+ out: dict[str, bool] = {}
68
+ for cmd, _ in _SERVERS.values():
69
+ exe = cmd[0]
70
+ if exe not in out:
71
+ out[exe] = shutil.which(exe) is not None
72
+ return out
73
+
74
+
75
+ # ── JSON-RPC framing ──────────────────────────────────────────────────────────
76
+
77
+ def _encode(msg: dict) -> bytes:
78
+ body = json.dumps(msg).encode("utf-8")
79
+ return f"Content-Length: {len(body)}\r\n\r\n".encode("ascii") + body
80
+
81
+
82
+ def _read_message(stdout) -> Optional[dict]:
83
+ """Read one LSP message (headers + body) from a blocking stream."""
84
+ headers: dict[bytes, bytes] = {}
85
+ while True:
86
+ line = stdout.readline()
87
+ if not line:
88
+ return None
89
+ line = line.strip()
90
+ if not line:
91
+ break # blank line terminates headers
92
+ if b":" in line:
93
+ k, v = line.split(b":", 1)
94
+ headers[k.strip().lower()] = v.strip()
95
+ length = int(headers.get(b"content-length", b"0") or 0)
96
+ if length <= 0:
97
+ return None
98
+ body = stdout.read(length)
99
+ if not body:
100
+ return None
101
+ try:
102
+ return json.loads(body.decode("utf-8"))
103
+ except Exception:
104
+ return None
105
+
106
+
107
+ def _format_diagnostics(raw: list) -> list[dict]:
108
+ out = []
109
+ for d in raw or []:
110
+ start = (d.get("range") or {}).get("start") or {}
111
+ code = d.get("code", "")
112
+ out.append({
113
+ "line": int(start.get("line", 0)) + 1, # LSP is 0-based
114
+ "col": int(start.get("character", 0)) + 1,
115
+ "severity": _SEVERITY.get(d.get("severity", 1), "info"),
116
+ "message": str(d.get("message", "")).strip(),
117
+ "source": d.get("source", "") or "",
118
+ "code": str(code) if code != "" else "",
119
+ })
120
+ out.sort(key=lambda x: (x["line"], x["col"]))
121
+ return out
122
+
123
+
124
+ # ── Core: one-shot diagnostics ────────────────────────────────────────────────
125
+
126
+ def get_diagnostics(path, timeout: float = 8.0) -> list[dict]:
127
+ """Spawn a language server, open `path`, and return its diagnostics.
128
+
129
+ Returns [] if no server is available, the file can't be read, or the
130
+ handshake times out. Never raises.
131
+ """
132
+ resolved = server_for(path)
133
+ if not resolved:
134
+ return []
135
+ cmd, lang_id = resolved
136
+
137
+ p = Path(path).expanduser().resolve()
138
+ try:
139
+ text = p.read_text(errors="replace")
140
+ except Exception:
141
+ return []
142
+
143
+ try:
144
+ proc = subprocess.Popen(
145
+ cmd,
146
+ stdin=subprocess.PIPE,
147
+ stdout=subprocess.PIPE,
148
+ stderr=subprocess.DEVNULL,
149
+ cwd=str(p.parent),
150
+ )
151
+ except Exception:
152
+ return []
153
+
154
+ msg_queue: "queue.Queue[dict]" = queue.Queue()
155
+
156
+ def _reader():
157
+ try:
158
+ while True:
159
+ msg = _read_message(proc.stdout)
160
+ if msg is None:
161
+ break
162
+ msg_queue.put(msg)
163
+ except Exception:
164
+ pass
165
+
166
+ reader = threading.Thread(target=_reader, daemon=True)
167
+ reader.start()
168
+
169
+ def _send(msg: dict) -> None:
170
+ try:
171
+ proc.stdin.write(_encode(msg))
172
+ proc.stdin.flush()
173
+ except Exception:
174
+ pass
175
+
176
+ def _cleanup() -> None:
177
+ try:
178
+ _send({"jsonrpc": "2.0", "id": 9999, "method": "shutdown", "params": None})
179
+ _send({"jsonrpc": "2.0", "method": "exit"})
180
+ except Exception:
181
+ pass
182
+ try:
183
+ proc.terminate()
184
+ proc.wait(timeout=1.0)
185
+ except Exception:
186
+ try:
187
+ proc.kill()
188
+ except Exception:
189
+ pass
190
+
191
+ file_uri = p.as_uri()
192
+ deadline = time.time() + timeout
193
+
194
+ # 1) initialize
195
+ _send({
196
+ "jsonrpc": "2.0", "id": 1, "method": "initialize",
197
+ "params": {
198
+ "processId": os.getpid(),
199
+ "rootUri": p.parent.as_uri(),
200
+ "workspaceFolders": [{"uri": p.parent.as_uri(), "name": p.parent.name}],
201
+ "capabilities": {
202
+ "textDocument": {
203
+ "publishDiagnostics": {"relatedInformation": True},
204
+ "synchronization": {"didSave": True},
205
+ },
206
+ },
207
+ },
208
+ })
209
+
210
+ initialized = False
211
+ while time.time() < deadline:
212
+ try:
213
+ msg = msg_queue.get(timeout=0.2)
214
+ except queue.Empty:
215
+ if proc.poll() is not None:
216
+ _cleanup()
217
+ return []
218
+ continue
219
+ if msg.get("id") == 1 and "result" in msg:
220
+ initialized = True
221
+ break
222
+ if not initialized:
223
+ _cleanup()
224
+ return []
225
+
226
+ # 2) initialized + didOpen
227
+ _send({"jsonrpc": "2.0", "method": "initialized", "params": {}})
228
+ _send({
229
+ "jsonrpc": "2.0", "method": "textDocument/didOpen",
230
+ "params": {
231
+ "textDocument": {
232
+ "uri": file_uri, "languageId": lang_id,
233
+ "version": 1, "text": text,
234
+ },
235
+ },
236
+ })
237
+
238
+ # 3) collect publishDiagnostics for our file. Some servers emit an empty
239
+ # set first, then a populated one after analysis — so once we see a
240
+ # matching notification we keep a short grace window for a better one.
241
+ diagnostics: list = []
242
+ got_one = False
243
+ grace_deadline = None
244
+ while time.time() < deadline:
245
+ remaining = deadline - time.time()
246
+ if grace_deadline is not None:
247
+ remaining = min(remaining, grace_deadline - time.time())
248
+ if remaining <= 0:
249
+ break
250
+ try:
251
+ msg = msg_queue.get(timeout=max(0.05, min(0.2, remaining)))
252
+ except queue.Empty:
253
+ if proc.poll() is not None:
254
+ break
255
+ continue
256
+ if msg.get("method") == "textDocument/publishDiagnostics":
257
+ params = msg.get("params", {})
258
+ if _same_uri(params.get("uri", ""), file_uri, p):
259
+ diags = params.get("diagnostics", [])
260
+ if diags:
261
+ diagnostics = diags
262
+ got_one = True
263
+ break # populated result — done
264
+ if not got_one:
265
+ diagnostics = diags # remember the empty result
266
+ got_one = True
267
+ grace_deadline = time.time() + 1.5 # wait briefly for more
268
+
269
+ _cleanup()
270
+ return _format_diagnostics(diagnostics)
271
+
272
+
273
+ def _same_uri(a: str, b: str, path: Path) -> bool:
274
+ if not a:
275
+ return False
276
+ if a == b:
277
+ return True
278
+ # Tolerate trailing-slash / encoding differences by comparing resolved paths
279
+ try:
280
+ return Path(a.replace("file://", "")).resolve() == path
281
+ except Exception:
282
+ return False
283
+
284
+
285
+ # ── Tool wrapper ──────────────────────────────────────────────────────────────
286
+
287
+ def tool_lsp_diagnostics(params: dict) -> dict:
288
+ """LLM-callable: run language-server diagnostics on a single file."""
289
+ path = params.get("path", "")
290
+ if not path:
291
+ return {"success": False, "error": "Missing 'path' parameter"}
292
+ p = Path(path).expanduser()
293
+ if not p.exists():
294
+ return {"success": False, "error": f"File not found: {p}"}
295
+
296
+ resolved = server_for(p)
297
+ if not resolved:
298
+ return {"success": True, "data": {
299
+ "path": str(p), "diagnostics": [], "available": False,
300
+ "note": f"No language server installed for '{p.suffix}' files. "
301
+ f"Python: pip install 'python-lsp-server[all]' (the [all] extra "
302
+ f"pulls in pyflakes/pycodestyle — without it pylsp reports nothing) · "
303
+ f"TS/JS: npm i -g typescript-language-server typescript",
304
+ }}
305
+
306
+ cmd, _ = resolved
307
+ diags = get_diagnostics(p)
308
+ errors = sum(1 for d in diags if d["severity"] == "error")
309
+ warnings = sum(1 for d in diags if d["severity"] == "warning")
310
+ return {"success": True, "data": {
311
+ "path": str(p),
312
+ "server": cmd[0],
313
+ "available": True,
314
+ "diagnostics": diags,
315
+ "errors": errors,
316
+ "warnings": warnings,
317
+ "total": len(diags),
318
+ }}
319
+
320
+
321
+ # ── Registry (merged into LOCAL_TOOLS in aria_cli.py) ─────────────────────────
322
+
323
+ LSP_TOOLS = {
324
+ "lsp_diagnostics": (tool_lsp_diagnostics,
325
+ "Run language-server diagnostics (errors/warnings) on a code file"),
326
+ }
327
+
328
+ LSP_SCHEMAS = [
329
+ {
330
+ "name": "lsp_diagnostics",
331
+ "description": (
332
+ "Run a language server (pylsp / typescript-language-server) on a single "
333
+ "file and return its diagnostics: type errors, undefined names, unused "
334
+ "imports, lint warnings. Use this after editing code to catch problems a "
335
+ "plain syntax check misses. Returns [] if no server is installed for the "
336
+ "file type."
337
+ ),
338
+ "parameters": {
339
+ "type": "object",
340
+ "properties": {
341
+ "path": {"type": "string", "description": "Path to the code file to analyze"},
342
+ },
343
+ "required": ["path"],
344
+ },
345
+ },
346
+ ]
347
+
348
+ def _lsp_query(path: str, method: str, params: dict, timeout: float = 6.0) -> dict | None:
349
+ resolved = server_for(path)
350
+ if not resolved: return None
351
+ cmd, lang_id = resolved
352
+ p = Path(path).expanduser().resolve()
353
+ try: text_content = p.read_text(errors="replace")
354
+ except Exception: return None
355
+ try:
356
+ proc = subprocess.Popen(
357
+ cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, cwd=str(p.parent)
358
+ )
359
+ except Exception: return None
360
+
361
+ msg_queue = queue.Queue()
362
+ def _reader():
363
+ try:
364
+ while True:
365
+ m = _read_message(proc.stdout)
366
+ if not m: break
367
+ msg_queue.put(m)
368
+ except Exception: pass
369
+ t = threading.Thread(target=_reader, daemon=True)
370
+ t.start()
371
+
372
+ def _send(m):
373
+ try:
374
+ proc.stdin.write(_encode(m))
375
+ proc.stdin.flush()
376
+ except Exception: pass
377
+
378
+ def _cleanup():
379
+ try:
380
+ _send({"jsonrpc": "2.0", "id": 99, "method": "shutdown", "params": None})
381
+ _send({"jsonrpc": "2.0", "method": "exit"})
382
+ except Exception: pass
383
+ try: proc.terminate(); proc.wait(1.0)
384
+ except Exception: pass
385
+
386
+ file_uri = p.as_uri()
387
+ deadline = time.time() + timeout
388
+ _send({
389
+ "jsonrpc": "2.0", "id": 1, "method": "initialize",
390
+ "params": {
391
+ "processId": os.getpid(),
392
+ "rootUri": p.parent.as_uri(),
393
+ "capabilities": {}
394
+ }
395
+ })
396
+
397
+ initialized = False
398
+ while time.time() < deadline:
399
+ try:
400
+ m = msg_queue.get(timeout=0.2)
401
+ if m.get("id") == 1 and "result" in m:
402
+ initialized = True
403
+ break
404
+ except queue.Empty:
405
+ if proc.poll() is not None:
406
+ _cleanup()
407
+ return None
408
+
409
+ if not initialized:
410
+ _cleanup()
411
+ return None
412
+
413
+ _send({"jsonrpc": "2.0", "method": "initialized", "params": {}})
414
+ _send({
415
+ "jsonrpc": "2.0", "method": "textDocument/didOpen",
416
+ "params": {"textDocument": {"uri": file_uri, "languageId": lang_id, "version": 1, "text": text_content}}
417
+ })
418
+
419
+ req_id = 2
420
+ params["textDocument"] = {"uri": file_uri}
421
+ _send({"jsonrpc": "2.0", "id": req_id, "method": method, "params": params})
422
+
423
+ result = None
424
+ while time.time() < deadline:
425
+ try:
426
+ m = msg_queue.get(timeout=0.2)
427
+ if m.get("id") == req_id:
428
+ if "result" in m:
429
+ result = m["result"]
430
+ break
431
+ except queue.Empty:
432
+ if proc.poll() is not None:
433
+ break
434
+
435
+ _cleanup()
436
+ return result
437
+
438
+
439
+ def get_hover(path: str, line: int, col: int) -> str | None:
440
+ res = _lsp_query(path, "textDocument/hover", {"position": {"line": line - 1, "character": col - 1}})
441
+ if not res or not res.get("contents"):
442
+ return None
443
+ contents = res["contents"]
444
+ if isinstance(contents, dict) and "value" in contents:
445
+ return contents["value"]
446
+ if isinstance(contents, list):
447
+ return "\n".join(c.get("value", c) if isinstance(c, dict) else c for c in contents)
448
+ return str(contents)
449
+
450
+
451
+ def get_definition(path: str, line: int, col: int) -> list[dict]:
452
+ res = _lsp_query(path, "textDocument/definition", {"position": {"line": line - 1, "character": col - 1}})
453
+ if not res: return []
454
+ if isinstance(res, dict): res = [res]
455
+ out = []
456
+ for loc in res:
457
+ uri = loc.get("uri") or loc.get("targetUri")
458
+ if not uri: continue
459
+ rng = loc.get("range") or loc.get("targetRange") or {}
460
+ st = rng.get("start", {})
461
+ if str(uri).startswith("file://"):
462
+ from urllib.parse import unquote
463
+ file_path = unquote(str(uri)[7:])
464
+ out.append({"path": file_path, "line": st.get("line", 0) + 1, "col": st.get("character", 0) + 1})
465
+ return out
466
+
467
+
468
+ def get_references(path: str, line: int, col: int) -> list[dict]:
469
+ res = _lsp_query(path, "textDocument/references", {
470
+ "position": {"line": line - 1, "character": col - 1},
471
+ "context": {"includeDeclaration": True}
472
+ })
473
+ if not res: return []
474
+ out = []
475
+ for loc in res:
476
+ uri = loc.get("uri")
477
+ if not uri: continue
478
+ rng = loc.get("range", {})
479
+ st = rng.get("start", {})
480
+ if str(uri).startswith("file://"):
481
+ from urllib.parse import unquote
482
+ file_path = unquote(str(uri)[7:])
483
+ out.append({"path": file_path, "line": st.get("line", 0) + 1, "col": st.get("character", 0) + 1})
484
+ return out
@@ -0,0 +1,55 @@
1
+ from typing import List, Dict, Any
2
+ import json
3
+ import logging
4
+ from aria_code.agents.registry import get_registry
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ async def dynamic_agent_orchestration(user_query: str, provider: Any) -> Dict[str, Any]:
9
+ """
10
+ Dynamic routing to pick the best agents for the user's query.
11
+ """
12
+ registry = get_registry()
13
+ agents = registry.list()
14
+
15
+ # Filter out orchestrator or core infrastructure agents that shouldn't be dynamically routed
16
+ agents = [a for a in agents if a["name"] not in {"orchestrator", "supervisor"}]
17
+
18
+ agents_info = "\n".join([f"- {a['name']}: {a.get('description', '')}" for a in agents])
19
+
20
+ prompt = (
21
+ f"你是一个高级的智能体编排中心 (Orchestrator)。\n"
22
+ f"用户请求:\n{user_query}\n\n"
23
+ f"可用智能体库:\n{agents_info}\n\n"
24
+ f"请直接输出一段合法的 JSON,选择最合适的智能体来解决用户请求(最多选3个)。\n"
25
+ f"JSON 结构必须是:\n"
26
+ f"{{\n"
27
+ f" \"plan\": \"解释为什么选择这些智能体\",\n"
28
+ f" \"agents\": [\"agent_name_1\", \"agent_name_2\"]\n"
29
+ f"}}\n"
30
+ )
31
+
32
+ try:
33
+ # We assume provider is an async function or object that can generate text
34
+ # But we'll just try to use a simple completion if available
35
+ messages = [{"role": "user", "content": prompt}]
36
+
37
+ # Use provider to generate
38
+ full_response = ""
39
+ async for chunk in provider.stream(messages=messages, tools=[]):
40
+ if hasattr(chunk, 'text') and chunk.text:
41
+ full_response += chunk.text
42
+
43
+ # Parse JSON
44
+ start_idx = full_response.find("{")
45
+ end_idx = full_response.rfind("}")
46
+ if start_idx != -1 and end_idx != -1:
47
+ json_str = full_response[start_idx:end_idx+1]
48
+ return json.loads(json_str)
49
+ else:
50
+ return {"plan": "未能解析 JSON", "agents": ["technical"]}
51
+ except Exception as e:
52
+ logger.error(f"Orchestration failed: {e}")
53
+ # Default fallback
54
+ return {"plan": "降级路由", "agents": ["technical", "fundamental"]}
55
+