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,156 @@
1
+ """The logistics tools as an MCP server, so the Go engine can use them.
2
+
3
+ aria-logistics-mcp [--data-dir DIR]
4
+
5
+ Speaks MCP over stdio (newline-delimited JSON-RPC 2.0). Three read-only
6
+ tools: analyze_logistics_data, score_carriers, plan_inventory_policy.
7
+
8
+ Shipper scope is not the model's choice. The server reads ARIA_OWNER_SCOPE
9
+ from its own environment (the engine passes it down from the bot that started
10
+ the turn) and every tool goes through logistics.tenancy, which fails closed.
11
+
12
+ A `file_path` argument is read only from inside the data folder
13
+ (`--data-dir`, else ARIA_LOGISTICS_DATA_DIR). With no data folder, files are
14
+ refused and the tools take inline records only: a chat must not be able to
15
+ name any file on the host.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import argparse
20
+ import json
21
+ import os
22
+ import sys
23
+ from pathlib import Path
24
+ from typing import Any, Callable, Dict, Optional, TextIO
25
+
26
+ from .carriers import SCHEMA as CARRIER_SCHEMA, tool_score_carriers
27
+ from .freight import tool_analyze_logistics_data
28
+ from .inventory import SCHEMA as INVENTORY_SCHEMA, tool_plan_inventory_policy
29
+ from .tenancy import OWNER_SCOPE_ENV, owner_params_schema
30
+
31
+ PROTOCOL_VERSION = "2024-11-05"
32
+ DATA_DIR_ENV = "ARIA_LOGISTICS_DATA_DIR"
33
+
34
+ FREIGHT_SCHEMA = {
35
+ "name": "analyze_logistics_data",
36
+ "description": "Analyze actual waybills from supplied records, a CSV/JSON file, or an existing local database",
37
+ "parameters": {
38
+ "type": "object",
39
+ "properties": {
40
+ "file_path": {"type": "string", "description": "CSV or JSON waybill file path"},
41
+ "waybills": {"type": "array", "description": "Waybill records with total_cost"},
42
+ **owner_params_schema(),
43
+ },
44
+ },
45
+ }
46
+
47
+ TOOLS: Dict[str, tuple[Callable[[Dict[str, Any]], Dict[str, Any]], Dict[str, Any]]] = {
48
+ "analyze_logistics_data": (tool_analyze_logistics_data, FREIGHT_SCHEMA),
49
+ "score_carriers": (tool_score_carriers, CARRIER_SCHEMA),
50
+ "plan_inventory_policy": (tool_plan_inventory_policy, INVENTORY_SCHEMA),
51
+ }
52
+
53
+
54
+ def tool_list() -> list[Dict[str, Any]]:
55
+ return [
56
+ {
57
+ "name": name,
58
+ "description": schema["description"],
59
+ "inputSchema": schema.get("parameters") or {"type": "object", "properties": {}},
60
+ "annotations": {"readOnlyHint": True, "openWorldHint": False},
61
+ }
62
+ for name, (_, schema) in TOOLS.items()
63
+ ]
64
+
65
+
66
+ def confine(arguments: Dict[str, Any], data_dir: Optional[Path]) -> Dict[str, Any]:
67
+ """Resolve file_path inside the data folder, or refuse it."""
68
+ file_path = arguments.get("file_path")
69
+ if not file_path:
70
+ return arguments
71
+ if data_dir is None:
72
+ raise ValueError(f"Files are not available here; set {DATA_DIR_ENV} or pass records inline")
73
+ root = data_dir.resolve()
74
+ candidate = Path(str(file_path)).expanduser()
75
+ path = (candidate if candidate.is_absolute() else root / candidate).resolve()
76
+ if path != root and root not in path.parents:
77
+ raise ValueError("file_path must be inside the logistics data folder")
78
+ return {**arguments, "file_path": str(path)}
79
+
80
+
81
+ def call_tool(name: str, arguments: Any, data_dir: Optional[Path]) -> Dict[str, Any]:
82
+ entry = TOOLS.get(name)
83
+ if entry is None:
84
+ return {"content": [{"type": "text", "text": f"Unknown tool: {name}"}], "isError": True}
85
+ if not isinstance(arguments, dict):
86
+ arguments = {}
87
+ try:
88
+ result = entry[0](confine(arguments, data_dir))
89
+ except ValueError as exc:
90
+ result = {"success": False, "error": str(exc)}
91
+ except Exception as exc: # a tool bug must not take the server down
92
+ result = {"success": False, "error": f"{type(exc).__name__}: {exc}"}
93
+ failed = isinstance(result, dict) and result.get("success") is False
94
+ text = json.dumps(result, ensure_ascii=False, default=str)
95
+ return {"content": [{"type": "text", "text": text}], "isError": failed}
96
+
97
+
98
+ def handle(message: Dict[str, Any], data_dir: Optional[Path]) -> Optional[Dict[str, Any]]:
99
+ method = message.get("method")
100
+ if "id" not in message:
101
+ return None # a notification
102
+ reply: Dict[str, Any] = {"jsonrpc": "2.0", "id": message["id"]}
103
+ params = message.get("params") or {}
104
+ if method == "initialize":
105
+ scope = os.environ.get(OWNER_SCOPE_ENV, "").strip()
106
+ reply["result"] = {
107
+ "protocolVersion": PROTOCOL_VERSION,
108
+ "capabilities": {"tools": {}},
109
+ "serverInfo": {"name": "aria-logistics", "version": "0.1.0"},
110
+ "instructions": "Logistics analyses scoped to one shipper." if scope else
111
+ "Logistics analyses; data spanning shippers needs owner_id or all_owners.",
112
+ }
113
+ elif method == "ping":
114
+ reply["result"] = {}
115
+ elif method == "tools/list":
116
+ reply["result"] = {"tools": tool_list()}
117
+ elif method == "tools/call":
118
+ reply["result"] = call_tool(str(params.get("name", "")), params.get("arguments"), data_dir)
119
+ else:
120
+ reply["error"] = {"code": -32601, "message": f"Method not found: {method}"}
121
+ return reply
122
+
123
+
124
+ def serve(stdin: TextIO, stdout: TextIO, data_dir: Optional[Path]) -> None:
125
+ for line in stdin:
126
+ line = line.strip()
127
+ if not line:
128
+ continue
129
+ try:
130
+ message = json.loads(line)
131
+ except json.JSONDecodeError:
132
+ reply: Optional[Dict[str, Any]] = {"jsonrpc": "2.0", "id": None,
133
+ "error": {"code": -32700, "message": "Parse error"}}
134
+ else:
135
+ reply = handle(message, data_dir) if isinstance(message, dict) else None
136
+ if reply is not None:
137
+ stdout.write(json.dumps(reply, ensure_ascii=False) + "\n")
138
+ stdout.flush()
139
+
140
+
141
+ def main(argv: Optional[list[str]] = None) -> int:
142
+ parser = argparse.ArgumentParser(prog="aria-logistics-mcp", description=__doc__.splitlines()[0])
143
+ parser.add_argument("--data-dir", default=os.environ.get(DATA_DIR_ENV) or None,
144
+ help=f"folder file_path is read from (default ${DATA_DIR_ENV}; none: inline records only)")
145
+ args = parser.parse_args(argv)
146
+ data_dir = Path(args.data_dir).expanduser() if args.data_dir else None
147
+ # MCP is UTF-8 JSON lines. Windows' default (cp1252, CRLF) would crash on
148
+ # the first non-ASCII description and add \r to every line.
149
+ for stream in (sys.stdin, sys.stdout):
150
+ stream.reconfigure(encoding="utf-8", newline="\n") # type: ignore[union-attr]
151
+ serve(sys.stdin, sys.stdout, data_dir)
152
+ return 0
153
+
154
+
155
+ if __name__ == "__main__":
156
+ raise SystemExit(main())
@@ -0,0 +1,119 @@
1
+ """Input loading and field validation shared by the logistics analyses.
2
+
3
+ Every analysis here reports figures a 3PL may bill or negotiate on, so the
4
+ rules are strict: a value that cannot be read is an error naming the row,
5
+ never a silent zero, and an empty input is an error, never a sample dataset.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import csv
11
+ import json
12
+ import math
13
+ import pathlib
14
+ from typing import Any
15
+
16
+
17
+ def load_records(params: dict[str, Any], key: str) -> tuple[list[dict[str, Any]], str]:
18
+ """Records from params[key] or a CSV/JSON file, and a label for where they came from."""
19
+ inline = params.get(key)
20
+ file_path = params.get("file_path")
21
+ if inline is not None and file_path:
22
+ raise ValueError(f"Provide either file_path or {key}, not both")
23
+ if file_path:
24
+ path = pathlib.Path(str(file_path)).expanduser().resolve()
25
+ if not path.is_file():
26
+ # The OSError read "[Errno 2] No such file or directory:
27
+ # '/private/var/…/shipments.csv'". Say which files are there.
28
+ here = sorted(p.name for p in path.parent.glob("*") if p.suffix.lower() in (".csv", ".json"))[:6]
29
+ hint = f" CSV/JSON files in {path.parent.name or path.parent}: {', '.join(here)}" if here else ""
30
+ raise ValueError(f"No such file: {file_path}.{hint}")
31
+ suffix = path.suffix.lower()
32
+ if suffix == ".json":
33
+ content = json.loads(path.read_text(encoding="utf-8"))
34
+ records = content.get(key) if isinstance(content, dict) else content
35
+ elif suffix == ".csv":
36
+ with path.open(encoding="utf-8-sig", newline="") as handle:
37
+ records = list(csv.DictReader(handle))
38
+ else:
39
+ raise ValueError("Only CSV and JSON files are supported")
40
+ source = f"file:{path.name}"
41
+ else:
42
+ records = inline
43
+ source = "caller-supplied records"
44
+ if not isinstance(records, list) or not records:
45
+ raise ValueError(f"No {key} records supplied")
46
+ for row, record in enumerate(records, 1):
47
+ if not isinstance(record, dict):
48
+ raise ValueError(f"Row {row}: each record must be an object")
49
+ return records, source
50
+
51
+
52
+ def number(record: dict[str, Any], field: str, row: int, *, required: bool = False,
53
+ positive: bool = False) -> float | None:
54
+ """A finite, non-negative number, or None when absent and optional."""
55
+ value = record.get(field)
56
+ if value is None or (isinstance(value, str) and not value.strip()):
57
+ if required:
58
+ raise ValueError(f"Row {row}: {field} is required")
59
+ return None
60
+ if isinstance(value, bool):
61
+ raise ValueError(f"Row {row}: {field} must be a number")
62
+ try:
63
+ result = float(value)
64
+ except (TypeError, ValueError) as exc:
65
+ raise ValueError(f"Row {row}: {field} must be a number") from exc
66
+ if not math.isfinite(result) or result < 0:
67
+ raise ValueError(f"Row {row}: {field} must be finite and non-negative")
68
+ if positive and result == 0:
69
+ raise ValueError(f"Row {row}: {field} must be greater than zero")
70
+ return result
71
+
72
+
73
+ def flag(record: dict[str, Any], field: str, row: int) -> bool | None:
74
+ """A yes/no field, accepting the spellings spreadsheets produce."""
75
+ value = record.get(field)
76
+ if value is None or (isinstance(value, str) and not value.strip()):
77
+ return None
78
+ if isinstance(value, bool):
79
+ return value
80
+ if value in (0, 1):
81
+ return bool(value)
82
+ if isinstance(value, str):
83
+ normalized = value.strip().lower()
84
+ if normalized in {"true", "yes", "y", "1", "是"}:
85
+ return True
86
+ if normalized in {"false", "no", "n", "0", "否"}:
87
+ return False
88
+ raise ValueError(f"Row {row}: {field} must be true/false")
89
+
90
+
91
+ def series(record: dict[str, Any], field: str, row: int) -> list[float] | None:
92
+ """A list of non-negative numbers, from a JSON array or a CSV cell like "3;5;2"."""
93
+ value = record.get(field)
94
+ if value is None or (isinstance(value, str) and not value.strip()):
95
+ return None
96
+ if isinstance(value, str):
97
+ parts = [p for p in value.replace(",", ";").replace(" ", ";").split(";") if p]
98
+ elif isinstance(value, list):
99
+ parts = value
100
+ else:
101
+ raise ValueError(f"Row {row}: {field} must be a list of numbers")
102
+ out: list[float] = []
103
+ for index, part in enumerate(parts, 1):
104
+ try:
105
+ item = float(part)
106
+ except (TypeError, ValueError) as exc:
107
+ raise ValueError(f"Row {row}: {field} item {index} must be a number") from exc
108
+ if not math.isfinite(item) or item < 0:
109
+ raise ValueError(f"Row {row}: {field} item {index} must be finite and non-negative")
110
+ out.append(item)
111
+ return out
112
+
113
+
114
+ def text(record: dict[str, Any], field: str, row: int, *, required: bool = False) -> str:
115
+ value = record.get(field)
116
+ result = "" if value is None else str(value).strip()
117
+ if required and not result:
118
+ raise ValueError(f"Row {row}: {field} is required")
119
+ return result
@@ -0,0 +1,152 @@
1
+ """Shipper (货主) isolation for third-party-logistics analyses.
2
+
3
+ A 3PL holds many shippers' inventory and waybills side by side. An analysis
4
+ that sums them — an average cost per kg, a carrier ranking, a reorder list —
5
+ is computed from one client's commercial data and handed to another. That is
6
+ a data leak whether or not anyone notices, so the analyses do not decide it
7
+ case by case: every one of them goes through `scope_records` first, and it
8
+ fails closed.
9
+
10
+ - Records that carry no owner_id at all are single-tenant data, and pass.
11
+ - Records that all belong to one shipper pass.
12
+ - Records that span shippers are refused unless the caller names one
13
+ (`owner_id`, a client-facing analysis) or explicitly asks for the 3PL's
14
+ internal cross-shipper view (`all_owners=True`), which is marked as not
15
+ for client distribution.
16
+ - A mix of records with and without owner_id is refused, because there is
17
+ no safe way to attribute the unlabelled ones.
18
+
19
+ What an error message says is part of the guarantee: it may say how many
20
+ shippers the data spans, but never which, so a refusal does not itself
21
+ disclose another client's name.
22
+
23
+ Conversation scope
24
+ ------------------
25
+ A chat bound to one shipper (a 3PL usually keeps one group per client) sets
26
+ ARIA_OWNER_SCOPE for every turn it runs. Then, whatever the model asks for:
27
+ - owner_id defaults to that shipper, and naming another is refused;
28
+ - all_owners is refused — the internal view has no place in a client chat;
29
+ - records without owner_id are refused, because nothing shows they are this
30
+ shipper's (a file on the host could be anyone's).
31
+ This is enforced here rather than in a prompt, so it holds for the CLI, the
32
+ MCP server and every chat channel alike, and does not depend on the model
33
+ choosing to comply.
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import os
39
+ from typing import Any, Iterable
40
+
41
+ OWNER_FIELD = "owner_id"
42
+ OWNER_SCOPE_ENV = "ARIA_OWNER_SCOPE"
43
+
44
+ INTERNAL_MARKER = "INTERNAL — cross-shipper view; not for client distribution"
45
+
46
+
47
+ class TenancyError(ValueError):
48
+ """The records cannot be analysed without mixing shippers."""
49
+
50
+
51
+ def active_owner_scope() -> str:
52
+ """The shipper this process is confined to, or "" when unconfined."""
53
+ return os.environ.get(OWNER_SCOPE_ENV, "").strip()
54
+
55
+
56
+ def _owner_of(record: dict[str, Any]) -> str:
57
+ value = record.get(OWNER_FIELD)
58
+ return "" if value is None else str(value).strip()
59
+
60
+
61
+ def scope_records(
62
+ records: Iterable[dict[str, Any]],
63
+ owner_id: str | None = None,
64
+ *,
65
+ all_owners: bool = False,
66
+ ) -> tuple[list[dict[str, Any]], dict[str, Any]]:
67
+ """Return the records an analysis may use, and a description of the scope.
68
+
69
+ The scope dict is copied into every result, so a reader can always tell
70
+ whose data a number came from and whether it may be shown to a client.
71
+ """
72
+ records = list(records)
73
+ wanted = (owner_id or "").strip()
74
+ if wanted and all_owners:
75
+ raise TenancyError("Pass owner_id or all_owners, not both")
76
+
77
+ scope = active_owner_scope()
78
+ if scope:
79
+ if all_owners:
80
+ raise TenancyError(
81
+ "This conversation is confined to one shipper; the cross-shipper view "
82
+ "is not available here"
83
+ )
84
+ if wanted and wanted != scope:
85
+ raise TenancyError("This conversation is confined to one shipper and cannot analyse another")
86
+ wanted = scope
87
+
88
+ labelled = [r for r in records if _owner_of(r)]
89
+ unlabelled = len(records) - len(labelled)
90
+
91
+ if not labelled:
92
+ if scope:
93
+ raise TenancyError(
94
+ f"This conversation is confined to one shipper, so every record must carry "
95
+ f"{OWNER_FIELD} to show it is theirs; these records have none"
96
+ )
97
+ if wanted:
98
+ raise TenancyError(
99
+ f"owner_id {wanted!r} was requested, but the records carry no {OWNER_FIELD}"
100
+ )
101
+ return records, {"mode": "single_tenant", "client_facing": True}
102
+
103
+ if unlabelled:
104
+ raise TenancyError(
105
+ f"{unlabelled} of {len(records)} records have no {OWNER_FIELD}; they cannot "
106
+ f"be attributed to a shipper, so they cannot be analysed alongside records "
107
+ f"that can"
108
+ )
109
+
110
+ owners = {_owner_of(r) for r in labelled}
111
+
112
+ if wanted:
113
+ in_scope = [r for r in labelled if _owner_of(r) == wanted]
114
+ if not in_scope:
115
+ # Deliberately does not list the owners that *are* present.
116
+ raise TenancyError(f"No records for owner_id {wanted!r}")
117
+ result_scope = {"mode": "single_owner", "owner_id": wanted, "client_facing": True}
118
+ if scope:
119
+ result_scope["conversation_scoped"] = True
120
+ return in_scope, result_scope
121
+
122
+ if len(owners) == 1:
123
+ (only,) = owners
124
+ return labelled, {"mode": "single_owner", "owner_id": only, "client_facing": True}
125
+
126
+ if all_owners:
127
+ return labelled, {
128
+ "mode": "all_owners",
129
+ "shipper_count": len(owners),
130
+ "client_facing": False,
131
+ "marker": INTERNAL_MARKER,
132
+ }
133
+
134
+ raise TenancyError(
135
+ f"These records belong to {len(owners)} different shippers. Pass owner_id to "
136
+ f"analyse one shipper (safe to share with that client), or all_owners=true for "
137
+ f"the internal cross-shipper view (not for client distribution)."
138
+ )
139
+
140
+
141
+ def owner_params_schema() -> dict[str, Any]:
142
+ """JSON-schema properties every tenant-aware tool accepts."""
143
+ return {
144
+ "owner_id": {
145
+ "type": "string",
146
+ "description": "Shipper (货主) to analyse. Required when records span several shippers.",
147
+ },
148
+ "all_owners": {
149
+ "type": "boolean",
150
+ "description": "Internal 3PL view across all shippers. Output is marked not for client distribution.",
151
+ },
152
+ }
aria_bots/market.py ADDED
@@ -0,0 +1,91 @@
1
+ """Market commands for the bots, answered by `aria-runtime daemon`.
2
+
3
+ The bots used to import the Python daemon's internals (its database path,
4
+ price fetcher and brief builders). Now they run the Go daemon's commands:
5
+
6
+ aria-runtime daemon quote SYMBOL --json
7
+ aria-runtime daemon once morning-brief --json
8
+ aria-runtime daemon alert add SYMBOL CONDITION VALUE
9
+ aria-runtime daemon alert list
10
+ aria-runtime daemon status
11
+
12
+ Quotes come from financial-service; alerts land in the same daemon.db the
13
+ running daemon watches (ARIA_DAEMON_DIR, else ~/.aria).
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import asyncio
18
+ import json
19
+ from typing import Optional
20
+
21
+ from . import engine
22
+
23
+ CONDITIONS = ("pct_change_above", "pct_change_below", "price_above", "price_below")
24
+
25
+
26
+ class MarketError(RuntimeError):
27
+ """The daemon command failed; the message is safe to show in a chat."""
28
+
29
+
30
+ async def daemon(*args: str, timeout: float = 60) -> str:
31
+ runtime = engine.find_engine()
32
+ if not runtime:
33
+ raise MarketError("未找到 aria-runtime:请安装,或用 ARIA_RUNTIME 指向它。")
34
+ proc = await asyncio.create_subprocess_exec(
35
+ runtime, "daemon", *args,
36
+ stdin=asyncio.subprocess.DEVNULL,
37
+ stdout=asyncio.subprocess.PIPE,
38
+ stderr=asyncio.subprocess.PIPE,
39
+ )
40
+ try:
41
+ stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
42
+ except asyncio.TimeoutError:
43
+ proc.kill()
44
+ await proc.wait()
45
+ raise MarketError(f"aria-runtime daemon {args[0]} 超时(>{int(timeout)}s)") from None
46
+ if proc.returncode != 0:
47
+ detail = stderr.decode("utf-8", errors="replace").strip()[-300:] or f"exit {proc.returncode}"
48
+ raise MarketError(detail)
49
+ return stdout.decode("utf-8", errors="replace").strip()
50
+
51
+
52
+ async def quote(symbol: str) -> dict:
53
+ """{symbol, price, currency, source[, change_pct]}."""
54
+ return json.loads(await daemon("quote", symbol, "--json"))
55
+
56
+
57
+ async def brief(command: str = "morning-brief") -> tuple[str, str]:
58
+ """(title, body) of a brief: morning-brief, evening-brief or weekly-recap."""
59
+ data = json.loads(await daemon("once", command, "--json", timeout=120))
60
+ return data["title"], data["body"]
61
+
62
+
63
+ async def add_alert(symbol: str, condition: str, value: str) -> str:
64
+ if condition not in CONDITIONS:
65
+ raise MarketError("条件必须是 " + " / ".join(CONDITIONS))
66
+ return await daemon("alert", "add", symbol, condition, value)
67
+
68
+
69
+ async def list_alerts() -> str:
70
+ return await daemon("alert", "list")
71
+
72
+
73
+ async def status() -> str:
74
+ return await daemon("status")
75
+
76
+
77
+ def price_card(data: dict) -> tuple[str, str, str]:
78
+ """(title, body, color) for a quote card. Red is up, as in Chinese markets."""
79
+ symbol, price = data["symbol"], float(data["price"])
80
+ mark = {"CNY": "¥", "RMB": "¥", "USD": "$", "HKD": "HK$"}.get(str(data.get("currency") or "").upper(), "")
81
+ change: Optional[float] = data.get("change_pct")
82
+ lines = [f"**当前价** {mark}{price:,.3f}"]
83
+ if change is None:
84
+ color, arrow = "blue", "📈"
85
+ else:
86
+ lines.append(f"**涨跌幅** {change:+.2f}%")
87
+ color = "red" if change > 0 else "green" if change < 0 else "blue"
88
+ arrow = "📈" if change >= 0 else "📉"
89
+ if data.get("source"):
90
+ lines.append(f"**来源** {data['source']}")
91
+ return f"{arrow} {symbol}", "\n".join(lines), color