aria-code 4.1.3__tar.gz → 4.1.7__tar.gz

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 (397) hide show
  1. {aria_code-4.1.3 → aria_code-4.1.7}/PKG-INFO +81 -8
  2. {aria_code-4.1.3 → aria_code-4.1.7}/README.md +75 -6
  3. aria_code-4.1.7/apps/channels/__init__.py +17 -0
  4. aria_code-4.1.7/apps/channels/intake.py +92 -0
  5. aria_code-4.1.7/apps/channels/registry.py +95 -0
  6. aria_code-4.1.7/apps/channels/tradingview.py +94 -0
  7. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/bootstrap.py +2 -0
  8. aria_code-4.1.7/apps/cli/commands/auth_cmds.py +135 -0
  9. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/backtest_cmds.py +565 -0
  10. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/broker_cmds.py +19 -2
  11. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/diagnostic_ops_cmds.py +12 -0
  12. aria_code-4.1.7/apps/cli/commands/file_cmds.py +267 -0
  13. aria_code-4.1.7/apps/cli/commands/fx_commodity_cmds.py +87 -0
  14. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market.py +10 -3
  15. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/model_cmds.py +154 -23
  16. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/portfolio_cmds.py +92 -0
  17. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/session_cmds.py +28 -0
  18. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/session_ux_cmds.py +40 -0
  19. aria_code-4.1.7/apps/cli/config_store.py +66 -0
  20. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/deterministic.py +8 -2
  21. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/i18n.py +4 -0
  22. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/market_universe.py +19 -2
  23. aria_code-4.1.7/apps/cli/prompt_assembly.py +59 -0
  24. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/system_prompts.py +4 -3
  25. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/base.py +195 -4
  26. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/chat_routing.py +26 -16
  27. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/llm/ollama_stream.py +229 -51
  28. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/runtime_bridge.py +40 -14
  29. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/runtime_consumer.py +96 -14
  30. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/session_export.py +6 -0
  31. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/market_tools.py +54 -12
  32. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/system_tools.py +19 -4
  33. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tradingview_bridge.py +100 -5
  34. aria_code-4.1.7/apps/cli/turn_planning.py +62 -0
  35. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/utils/market_detect.py +5 -0
  36. {aria_code-4.1.3 → aria_code-4.1.7}/aria_cli.py +888 -1138
  37. {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/PKG-INFO +81 -8
  38. {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/SOURCES.txt +42 -0
  39. {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/requires.txt +8 -1
  40. {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/top_level.txt +2 -0
  41. {aria_code-4.1.3 → aria_code-4.1.7}/aria_daemon.py +67 -2
  42. aria_code-4.1.7/backtest_engine.py +354 -0
  43. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/__init__.py +6 -0
  44. aria_code-4.1.7/brokers/automation.py +193 -0
  45. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/base.py +24 -0
  46. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/paper_broker.py +7 -0
  47. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/registry.py +32 -1
  48. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/trading.py +18 -0
  49. {aria_code-4.1.3 → aria_code-4.1.7}/doctor.py +79 -0
  50. {aria_code-4.1.3 → aria_code-4.1.7}/file_analysis_tools.py +124 -0
  51. aria_code-4.1.7/licensing.py +150 -0
  52. {aria_code-4.1.3 → aria_code-4.1.7}/local_finance_tools.py +113 -0
  53. {aria_code-4.1.3 → aria_code-4.1.7}/local_llm_provider.py +40 -3
  54. {aria_code-4.1.3 → aria_code-4.1.7}/mcp_client.py +106 -23
  55. {aria_code-4.1.3 → aria_code-4.1.7}/model_capability.py +4 -4
  56. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/architecture.py +18 -16
  57. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/export.py +23 -0
  58. aria_code-4.1.7/packages/aria_mcp/circuit.py +82 -0
  59. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/config.py +19 -5
  60. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/tools.py +22 -4
  61. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/streaming.py +9 -3
  62. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/__init__.py +20 -0
  63. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/context.py +11 -0
  64. aria_code-4.1.7/packages/aria_services/context_checkpoints.py +156 -0
  65. aria_code-4.1.7/packages/aria_services/references.py +247 -0
  66. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/registry.py +14 -0
  67. aria_code-4.1.7/packages/aria_services/settings.py +146 -0
  68. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/usage.py +8 -0
  69. aria_code-4.1.7/packages/quant_engine/__init__.py +24 -0
  70. {aria_code-4.1.3 → aria_code-4.1.7}/portfolio_ledger.py +44 -0
  71. {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/openai_compat.py +12 -1
  72. {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/registry.py +18 -14
  73. {aria_code-4.1.3 → aria_code-4.1.7}/pyproject.toml +7 -2
  74. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/agent_loop.py +166 -13
  75. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/gateway.py +10 -1
  76. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/tool_executor.py +69 -3
  77. {aria_code-4.1.3 → aria_code-4.1.7}/safety/__init__.py +2 -0
  78. aria_code-4.1.7/safety/service.py +86 -0
  79. aria_code-4.1.7/tests/test_analyze_file_tool.py +73 -0
  80. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_architecture_report.py +3 -2
  81. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_aria_cli_core.py +66 -0
  82. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_aria_sdk.py +69 -0
  83. aria_code-4.1.7/tests/test_backtest_cmds.py +184 -0
  84. aria_code-4.1.7/tests/test_backtest_engine.py +146 -0
  85. aria_code-4.1.7/tests/test_broker_automation.py +133 -0
  86. aria_code-4.1.7/tests/test_broker_safety.py +96 -0
  87. aria_code-4.1.7/tests/test_channel_intake.py +73 -0
  88. aria_code-4.1.7/tests/test_channels.py +102 -0
  89. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_chat_routing.py +13 -4
  90. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_app_split.py +4 -1
  91. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_runtime_consumer.py +59 -2
  92. aria_code-4.1.7/tests/test_configured_provider.py +102 -0
  93. aria_code-4.1.7/tests/test_context_checkpoints.py +130 -0
  94. aria_code-4.1.7/tests/test_context_references.py +177 -0
  95. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_doctor.py +79 -2
  96. aria_code-4.1.7/tests/test_finance_renderers.py +66 -0
  97. aria_code-4.1.7/tests/test_licensing.py +89 -0
  98. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_market_history_tool.py +51 -0
  99. aria_code-4.1.7/tests/test_market_symbol_extraction.py +72 -0
  100. aria_code-4.1.7/tests/test_mcp_circuit.py +170 -0
  101. aria_code-4.1.7/tests/test_mcp_client.py +64 -0
  102. aria_code-4.1.7/tests/test_model_selection_state.py +51 -0
  103. aria_code-4.1.7/tests/test_ollama_stream_tools.py +57 -0
  104. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_packages_facade.py +26 -0
  105. aria_code-4.1.7/tests/test_pick_best_installed_model.py +63 -0
  106. aria_code-4.1.7/tests/test_portfolio_ledger.py +89 -0
  107. aria_code-4.1.7/tests/test_prompt_assembly.py +70 -0
  108. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_agent_loop.py +67 -1
  109. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_bridge.py +56 -1
  110. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_bridge_fallback.py +2 -2
  111. aria_code-4.1.7/tests/test_runtime_tool_executor.py +137 -0
  112. aria_code-4.1.7/tests/test_safety_service.py +100 -0
  113. aria_code-4.1.7/tests/test_settings_service.py +108 -0
  114. aria_code-4.1.7/tests/test_startup_dashboard.py +122 -0
  115. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_tradingview_bridge.py +44 -0
  116. aria_code-4.1.7/tests/test_turn_planning.py +58 -0
  117. aria_code-4.1.7/tests/test_ui_completer_references.py +79 -0
  118. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_ui_input_box.py +93 -1
  119. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_ui_robot_banner.py +7 -6
  120. {aria_code-4.1.3 → aria_code-4.1.7}/ui/__init__.py +7 -2
  121. {aria_code-4.1.3 → aria_code-4.1.7}/ui/banner.py +220 -65
  122. {aria_code-4.1.3 → aria_code-4.1.7}/ui/completer.py +132 -22
  123. {aria_code-4.1.3 → aria_code-4.1.7}/ui/console.py +3 -1
  124. {aria_code-4.1.3 → aria_code-4.1.7}/ui/input_box.py +134 -32
  125. {aria_code-4.1.3 → aria_code-4.1.7}/ui/picker.py +9 -5
  126. {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/finance.py +91 -0
  127. {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/output.py +2 -2
  128. aria_code-4.1.7/ui/startup_dashboard.py +109 -0
  129. aria_code-4.1.3/apps/cli/config_store.py +0 -61
  130. aria_code-4.1.3/packages/quant_engine/__init__.py +0 -6
  131. aria_code-4.1.3/tests/test_backtest_cmds.py +0 -96
  132. aria_code-4.1.3/tests/test_runtime_tool_executor.py +0 -63
  133. {aria_code-4.1.3 → aria_code-4.1.7}/LICENSE +0 -0
  134. {aria_code-4.1.3 → aria_code-4.1.7}/agents/__init__.py +0 -0
  135. {aria_code-4.1.3 → aria_code-4.1.7}/agents/base.py +0 -0
  136. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/__init__.py +0 -0
  137. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/calibration_loop.py +0 -0
  138. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/critic.py +0 -0
  139. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/deepen.py +0 -0
  140. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/models.py +0 -0
  141. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/pipeline.py +0 -0
  142. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/quant_fusion.py +0 -0
  143. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/themes.py +0 -0
  144. {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/tiers.py +0 -0
  145. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/__init__.py +0 -0
  146. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/catalyst.py +0 -0
  147. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/debate.py +0 -0
  148. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/earnings.py +0 -0
  149. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/fundamental.py +0 -0
  150. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/macro.py +0 -0
  151. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/news.py +0 -0
  152. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/risk.py +0 -0
  153. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/sector.py +0 -0
  154. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/synthesis.py +0 -0
  155. {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/technical.py +0 -0
  156. {aria_code-4.1.3 → aria_code-4.1.7}/agents/portfolio_agent.py +0 -0
  157. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/__init__.py +0 -0
  158. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/asset_diagnosis.py +0 -0
  159. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/business_match.py +0 -0
  160. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/cashflow_verify.py +0 -0
  161. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/contract_rules.py +0 -0
  162. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/energy_anomaly.py +0 -0
  163. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/exit_settlement.py +0 -0
  164. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/fulfillment_risk.py +0 -0
  165. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/ops_optimize.py +0 -0
  166. {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/revenue_share.py +0 -0
  167. {aria_code-4.1.3 → aria_code-4.1.7}/agents/registry.py +0 -0
  168. {aria_code-4.1.3 → aria_code-4.1.7}/agents/sports/__init__.py +0 -0
  169. {aria_code-4.1.3 → aria_code-4.1.7}/agents/sports/football_agent.py +0 -0
  170. {aria_code-4.1.3 → aria_code-4.1.7}/agents/team.py +0 -0
  171. {aria_code-4.1.3 → aria_code-4.1.7}/aliyun_data_client.py +0 -0
  172. {aria_code-4.1.3 → aria_code-4.1.7}/apps/README.md +0 -0
  173. {aria_code-4.1.3 → aria_code-4.1.7}/apps/__init__.py +0 -0
  174. {aria_code-4.1.3 → aria_code-4.1.7}/apps/channels/README.md +0 -0
  175. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/README.md +0 -0
  176. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/__init__.py +0 -0
  177. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/codegen_paths.py +0 -0
  178. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/__init__.py +0 -0
  179. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/analysis_cmds.py +0 -0
  180. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/business_workflow_cmds.py +0 -0
  181. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/catalog.py +0 -0
  182. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/data_cmds.py +0 -0
  183. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/diagnostic_cmds.py +0 -0
  184. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/finance_render.py +0 -0
  185. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market_cmds.py +0 -0
  186. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market_context.py +0 -0
  187. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market_render.py +0 -0
  188. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/ops_cmds.py +0 -0
  189. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/report.py +0 -0
  190. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/scaffold_templates.py +0 -0
  191. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/team.py +0 -0
  192. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/team_render.py +0 -0
  193. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/ui_cmds.py +0 -0
  194. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/workflow_cmds.py +0 -0
  195. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/workspace_cmds.py +0 -0
  196. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/config_paths.py +0 -0
  197. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/direct.py +0 -0
  198. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/github_app_auth.py +0 -0
  199. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/__init__.py +0 -0
  200. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/broker_handlers.py +0 -0
  201. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/chart_handlers.py +0 -0
  202. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/market_handlers.py +0 -0
  203. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/realty_handlers.py +0 -0
  204. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/strategy_advice.py +0 -0
  205. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/hooks.py +0 -0
  206. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/intent.py +0 -0
  207. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/intent_router.py +0 -0
  208. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/lifecycle_hooks.py +0 -0
  209. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/main.py +0 -0
  210. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/market_metadata.py +0 -0
  211. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/message_processing.py +0 -0
  212. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/plan_mode.py +0 -0
  213. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/plotly_html.py +0 -0
  214. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prediction_feedback.py +0 -0
  215. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/preflight.py +0 -0
  216. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/project_aria.py +0 -0
  217. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/__init__.py +0 -0
  218. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/coding.py +0 -0
  219. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/ui.py +0 -0
  220. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/__init__.py +0 -0
  221. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/llm/__init__.py +0 -0
  222. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/llm/sse_stream.py +0 -0
  223. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/session_jsonl.py +0 -0
  224. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/session_store.py +0 -0
  225. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/todo_tracker.py +0 -0
  226. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/__init__.py +0 -0
  227. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/context.py +0 -0
  228. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/file_tools.py +0 -0
  229. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/notebook_tools.py +0 -0
  230. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/write_tools.py +0 -0
  231. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/update_check.py +0 -0
  232. {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/utils/__init__.py +0 -0
  233. {aria_code-4.1.3 → aria_code-4.1.7}/apps/daemon/README.md +0 -0
  234. {aria_code-4.1.3 → aria_code-4.1.7}/apps/vscode/README.md +0 -0
  235. {aria_code-4.1.3 → aria_code-4.1.7}/apps/vscode/package.json +0 -0
  236. {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/dependency_links.txt +0 -0
  237. {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/entry_points.txt +0 -0
  238. {aria_code-4.1.3 → aria_code-4.1.7}/aria_feishu_bot.py +0 -0
  239. {aria_code-4.1.3 → aria_code-4.1.7}/aria_relay_client.py +0 -0
  240. {aria_code-4.1.3 → aria_code-4.1.7}/aria_relay_server.py +0 -0
  241. {aria_code-4.1.3 → aria_code-4.1.7}/aria_telegram_bot.py +0 -0
  242. {aria_code-4.1.3 → aria_code-4.1.7}/ariarc.py +0 -0
  243. {aria_code-4.1.3 → aria_code-4.1.7}/artifacts.py +0 -0
  244. {aria_code-4.1.3 → aria_code-4.1.7}/backtest_report.py +0 -0
  245. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/capabilities.py +0 -0
  246. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/__init__.py +0 -0
  247. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/easytrader_broker.py +0 -0
  248. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/futu_broker.py +0 -0
  249. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/longbridge_broker.py +0 -0
  250. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/tiger_broker.py +0 -0
  251. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/xtquant_broker.py +0 -0
  252. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/config.py +0 -0
  253. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/__init__.py +0 -0
  254. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/alpaca_broker.py +0 -0
  255. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/ibkr_broker.py +0 -0
  256. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/webull_broker.py +0 -0
  257. {aria_code-4.1.3 → aria_code-4.1.7}/brokers/planning.py +0 -0
  258. {aria_code-4.1.3 → aria_code-4.1.7}/change_store.py +0 -0
  259. {aria_code-4.1.3 → aria_code-4.1.7}/command_safety.py +0 -0
  260. {aria_code-4.1.3 → aria_code-4.1.7}/computer_use_tools.py +0 -0
  261. {aria_code-4.1.3 → aria_code-4.1.7}/dashboard_generator.py +0 -0
  262. {aria_code-4.1.3 → aria_code-4.1.7}/data_analysis_tools.py +0 -0
  263. {aria_code-4.1.3 → aria_code-4.1.7}/data_cleaner.py +0 -0
  264. {aria_code-4.1.3 → aria_code-4.1.7}/data_service.py +0 -0
  265. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/__init__.py +0 -0
  266. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/base.py +0 -0
  267. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/router.py +0 -0
  268. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/__init__.py +0 -0
  269. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/akshare_source.py +0 -0
  270. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/alpha_vantage_source.py +0 -0
  271. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/edgar_source.py +0 -0
  272. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/finnhub_source.py +0 -0
  273. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/fred_source.py +0 -0
  274. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/tushare_source.py +0 -0
  275. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/web_scraper_source.py +0 -0
  276. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/world_bank_source.py +0 -0
  277. {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/yfinance_source.py +0 -0
  278. {aria_code-4.1.3 → aria_code-4.1.7}/demo_player.py +0 -0
  279. {aria_code-4.1.3 → aria_code-4.1.7}/finance_formulas.py +0 -0
  280. {aria_code-4.1.3 → aria_code-4.1.7}/football_data_client.py +0 -0
  281. {aria_code-4.1.3 → aria_code-4.1.7}/intent_classifier.py +0 -0
  282. {aria_code-4.1.3 → aria_code-4.1.7}/macro_tools.py +0 -0
  283. {aria_code-4.1.3 → aria_code-4.1.7}/market_data_client.py +0 -0
  284. {aria_code-4.1.3 → aria_code-4.1.7}/memory_manager.py +0 -0
  285. {aria_code-4.1.3 → aria_code-4.1.7}/notification_tools.py +0 -0
  286. {aria_code-4.1.3 → aria_code-4.1.7}/packages/__init__.py +0 -0
  287. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_agents/__init__.py +0 -0
  288. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_agents/manifest.py +0 -0
  289. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/__init__.py +0 -0
  290. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/manifest.py +0 -0
  291. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/__init__.py +0 -0
  292. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/arthera.py +0 -0
  293. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/doctor.py +0 -0
  294. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/product.py +0 -0
  295. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/__init__.py +0 -0
  296. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/bridge.py +0 -0
  297. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/__init__.py +0 -0
  298. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/client.py +0 -0
  299. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/providers.py +0 -0
  300. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/types.py +0 -0
  301. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/data.py +0 -0
  302. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/provider_health.py +0 -0
  303. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_skills/__init__.py +0 -0
  304. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_skills/registry.py +0 -0
  305. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_tools/__init__.py +0 -0
  306. {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_tools/registry.py +0 -0
  307. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/__init__.py +0 -0
  308. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/calibrator.py +0 -0
  309. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/dixon_coles.py +0 -0
  310. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/elo.py +0 -0
  311. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/form.py +0 -0
  312. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/h2h.py +0 -0
  313. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/ml_model.py +0 -0
  314. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/predictor.py +0 -0
  315. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/tracker.py +0 -0
  316. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/__init__.py +0 -0
  317. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/gbm_enhanced.py +0 -0
  318. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/ito_calculus.py +0 -0
  319. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/kelly_criterion.py +0 -0
  320. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/monte_carlo_advanced.py +0 -0
  321. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/options_pricing.py +0 -0
  322. {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/stochastic_processes.py +0 -0
  323. {aria_code-4.1.3 → aria_code-4.1.7}/plan_utils.py +0 -0
  324. {aria_code-4.1.3 → aria_code-4.1.7}/plugin_loader.py +0 -0
  325. {aria_code-4.1.3 → aria_code-4.1.7}/privacy/__init__.py +0 -0
  326. {aria_code-4.1.3 → aria_code-4.1.7}/privacy/feedback.py +0 -0
  327. {aria_code-4.1.3 → aria_code-4.1.7}/project_tools.py +0 -0
  328. {aria_code-4.1.3 → aria_code-4.1.7}/providers/__init__.py +0 -0
  329. {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/__init__.py +0 -0
  330. {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/anthropic.py +0 -0
  331. {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/base.py +0 -0
  332. {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/ollama.py +0 -0
  333. {aria_code-4.1.3 → aria_code-4.1.7}/realty_data_tools.py +0 -0
  334. {aria_code-4.1.3 → aria_code-4.1.7}/report_generator.py +0 -0
  335. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/__init__.py +0 -0
  336. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/approval.py +0 -0
  337. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/events.py +0 -0
  338. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/lsp.py +0 -0
  339. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/subagent.py +0 -0
  340. {aria_code-4.1.3 → aria_code-4.1.7}/runtime/tool_policy.py +0 -0
  341. {aria_code-4.1.3 → aria_code-4.1.7}/safety/permissions.py +0 -0
  342. {aria_code-4.1.3 → aria_code-4.1.7}/setup.cfg +0 -0
  343. {aria_code-4.1.3 → aria_code-4.1.7}/setup_wizard.py +0 -0
  344. {aria_code-4.1.3 → aria_code-4.1.7}/strategy_vault.py +0 -0
  345. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_artifacts_and_reports.py +0 -0
  346. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_backtest_report.py +0 -0
  347. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_broker_planning.py +0 -0
  348. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_business_workflow_cmds.py +0 -0
  349. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_chart_handlers.py +0 -0
  350. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_bootstrap.py +0 -0
  351. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_config_store.py +0 -0
  352. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_lifecycle_hooks.py +0 -0
  353. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_codegen_output.py +0 -0
  354. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_command_safety.py +0 -0
  355. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_completions_builder.py +0 -0
  356. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_config_paths.py +0 -0
  357. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_context_service.py +0 -0
  358. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_dashboard_generator.py +0 -0
  359. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_data_service.py +0 -0
  360. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_deep_analysis.py +0 -0
  361. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_football_prediction_output.py +0 -0
  362. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_image_inputs.py +0 -0
  363. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_intent_router.py +0 -0
  364. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_lsp.py +0 -0
  365. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_market_data_client.py +0 -0
  366. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_market_universe.py +0 -0
  367. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_new_modules.py +0 -0
  368. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_output_rendering.py +0 -0
  369. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_plan_mode.py +0 -0
  370. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_plotly_html_output.py +0 -0
  371. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_preflight.py +0 -0
  372. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_privacy_feedback.py +0 -0
  373. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_project_aria.py +0 -0
  374. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_provider_integration.py +0 -0
  375. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_provider_registry.py +0 -0
  376. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_approval.py +0 -0
  377. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_gateway.py +0 -0
  378. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_safety_permissions.py +0 -0
  379. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_session_search.py +0 -0
  380. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_streaming_pipeline.py +0 -0
  381. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_subagent.py +0 -0
  382. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_system_prompts.py +0 -0
  383. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_system_tools_output.py +0 -0
  384. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_team_synthesis.py +0 -0
  385. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_tool_policy.py +0 -0
  386. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_trading_service.py +0 -0
  387. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_ui_console_theme.py +0 -0
  388. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_workspace_files.py +0 -0
  389. {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_workspace_verify.py +0 -0
  390. {aria_code-4.1.3 → aria_code-4.1.7}/ui/image_render.py +0 -0
  391. {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/__init__.py +0 -0
  392. {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/market.py +0 -0
  393. {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/team.py +0 -0
  394. {aria_code-4.1.3 → aria_code-4.1.7}/ui/robot.py +0 -0
  395. {aria_code-4.1.3 → aria_code-4.1.7}/workspace/__init__.py +0 -0
  396. {aria_code-4.1.3 → aria_code-4.1.7}/workspace/files.py +0 -0
  397. {aria_code-4.1.3 → aria_code-4.1.7}/workspace/verify.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aria-code
3
- Version: 4.1.3
3
+ Version: 4.1.7
4
4
  Summary: AI-powered financial terminal — local LLM + multi-source market data
5
5
  License: BUSL-1.1
6
6
  Project-URL: Homepage, https://github.com/artherahq/aria-code
@@ -31,10 +31,11 @@ Requires-Dist: PyJWT>=2.8.0
31
31
  Requires-Dist: aiofiles>=23.2.0
32
32
  Requires-Dist: websockets>=12.0
33
33
  Requires-Dist: apscheduler>=3.10.0
34
+ Requires-Dist: ddgs>=9.0
34
35
  Requires-Dist: numpy>=1.26.0
35
36
  Requires-Dist: pandas>=2.2.0
36
37
  Requires-Dist: scipy>=1.13.0
37
- Requires-Dist: pandas_ta>=0.3.14b
38
+ Requires-Dist: pandas_ta>=0.4.67b0; python_version >= "3.12"
38
39
  Requires-Dist: yfinance>=0.2.55
39
40
  Provides-Extra: cn
40
41
  Requires-Dist: akshare>=1.14.68; extra == "cn"
@@ -51,6 +52,8 @@ Requires-Dist: python-docx>=1.1.2; extra == "files"
51
52
  Requires-Dist: openpyxl>=3.1.5; extra == "files"
52
53
  Requires-Dist: beautifulsoup4>=4.12.3; extra == "files"
53
54
  Requires-Dist: Pillow>=10.4.0; extra == "files"
55
+ Provides-Extra: video
56
+ Requires-Dist: opencv-python>=4.8.0; extra == "video"
54
57
  Provides-Extra: ibkr
55
58
  Requires-Dist: ib_insync>=0.9.86; extra == "ibkr"
56
59
  Provides-Extra: futu
@@ -114,6 +117,7 @@ Requires-Dist: ddgs>=9.0; extra == "all"
114
117
  Requires-Dist: playwright>=1.44.0; extra == "all"
115
118
  Requires-Dist: mss>=9.0.1; extra == "all"
116
119
  Requires-Dist: pyautogui>=0.9.54; extra == "all"
120
+ Requires-Dist: opencv-python>=4.8.0; extra == "all"
117
121
  Requires-Dist: understat>=0.1.0; extra == "all"
118
122
  Requires-Dist: ib_insync>=0.9.86; extra == "all"
119
123
  Requires-Dist: futu-api>=9.1.5108; extra == "all"
@@ -139,6 +143,8 @@ Dynamic: license-file
139
143
 
140
144
  <p align="center">
141
145
  <a href="https://www.npmjs.com/package/@artheras/aria-code"><img src="https://img.shields.io/npm/v/@artheras/aria-code?style=for-the-badge&logo=npm&color=cb3837&label=npm" alt="npm"/></a>
146
+ <a href="https://pypi.org/project/aria-code/"><img src="https://img.shields.io/pypi/v/aria-code?style=for-the-badge&logo=pypi&logoColor=white&label=PyPI&color=3775A9" alt="PyPI"/></a>
147
+ <a href="https://github.com/artherahq/aria-code/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/artherahq/aria-code/ci.yml?branch=main&style=for-the-badge&logo=githubactions&logoColor=white&label=CI" alt="CI"/></a>
142
148
  <img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="python"/>
143
149
  <img src="https://img.shields.io/badge/Ollama-Local_LLM-black?style=for-the-badge&logo=llama&logoColor=white" alt="ollama"/>
144
150
  <img src="https://img.shields.io/badge/Providers-19+_Cloud-f59e0b?style=for-the-badge" alt="providers"/>
@@ -176,7 +182,7 @@ Aria Code is a **terminal-first AI financial agent** — think of it as Claude C
176
182
  ```
177
183
  $ aria-code
178
184
 
179
- ▣ Aria Code v4.0 local-first agent
185
+ ▣ Aria Code v4.1 local-first agent
180
186
  model qwen2.5-coder:7b local
181
187
  workspace ~/my-portfolio
182
188
  mode workspace-write · network on · local-only
@@ -214,6 +220,8 @@ $ aria-code
214
220
  | **MCP tools** | 5 new quantitative MCP tools in the tool registry |
215
221
  | **83 commands** | Consolidated from ~150 — removed all LLM-replaceable commands; natural language handles the rest |
216
222
  | **LLM routing fix** | Model now knows it can call real-time data tools instead of saying "I don't have live data" |
223
+ | **Unified agent loop** | CLI, SDK and self-host backend now run the *same* tested runtime (`runtime.run_turn`) — consistent provider routing, cloud→local fallback and tool execution on every surface |
224
+ | **One-command install** | `pip install aria-code` (PyPI) or `npm install -g @artheras/aria-code` — verified clean on Python 3.10 / 3.11 / 3.12 |
217
225
 
218
226
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
219
227
 
@@ -223,7 +231,7 @@ See [CHANGELOG.md](CHANGELOG.md) for the full history.
223
231
  |---------|-------------|
224
232
  | ⌨️ **Keyboard shortcuts** | `Shift+Tab` cycle modes · `Alt+T` thinking · `Alt+P` model picker · `Ctrl+O` transcript · `Ctrl+T` tasks |
225
233
  | `!` **Shell mode** | Type `! git status` to run shell commands, output auto-added to AI context |
226
- | `@` **File autocomplete** | Type `@src/` to get instant file path completion anywhere in input |
234
+ | `@` **Typed context references** | Attach files, folders, assets, portfolios, strategies, datasets, runs, or reports without executing an action |
227
235
  | `/btw` **Side questions** | Ask quick questions without polluting conversation history |
228
236
  | 🌍 **Auto language** | UI and responses auto-detect Chinese/English from OS locale on first run |
229
237
  | 🤖 **19+ cloud providers** | Google Gemini · xAI Grok · Mistral · Cohere · Perplexity · Baidu ERNIE · ByteDance · MiniMax · StepFun · 01.AI + all originals |
@@ -295,7 +303,7 @@ mindmap
295
303
  | 🔍 **Quant research** | `/backtest` `/signal` `/kelly` `/factor` `/portfolio` `/screen` `/corr` `/ptbt` |
296
304
  | 🤖 **19+ cloud providers** | All major international + Chinese LLM APIs supported |
297
305
  | 🔌 **MCP protocol** | Connect any [Model Context Protocol](https://modelcontextprotocol.io) server |
298
- | ⌨️ **Rich keyboard UX** | Vim mode · `!` shell · `@` files · `Shift+Tab` modes · transcript viewer |
306
+ | ⌨️ **Rich keyboard UX** | Vim mode · `!` shell · typed `@` context · `Shift+Tab` modes · transcript viewer |
299
307
  | 💬 **Feishu / Telegram** | Ask Aria from any chat app, anytime |
300
308
  | 📱 **iOS push alerts** | Real-time price alerts via APNs |
301
309
  | 🌍 **Auto bilingual** | OS language auto-detected on first run; output follows user's input language |
@@ -474,9 +482,26 @@ Aria Code has a full keyboard shortcut system powered by `prompt_toolkit`:
474
482
  |--------|------|---------|
475
483
  | `/` | Slash command with fuzzy autocomplete | `/backtest momentum SPY` |
476
484
  | `!` | Shell mode — runs command, adds output to context | `! git diff HEAD~1` |
477
- | `@` | File path autocomplete | `@src/components/` |
485
+ | `@` | Read-only typed context reference | `@file:src/app.py` · `@asset:AAPL` |
478
486
  | `"""` | Multi-line input mode (end with `"""`) | For pasting code blocks |
479
487
 
488
+ `/` and `@` are intentionally different: `/` selects an action; `@` selects
489
+ context for that action or for a natural-language request. They can be combined:
490
+
491
+ ```text
492
+ /risk @portfolio:core
493
+ /backtest @strategy:momentum-v2 @asset:AAPL --period 3y
494
+ Review @folder:apps/cli against @report:last-audit
495
+ ```
496
+
497
+ Available reference types: `@file:`, `@folder:`, `@asset:`, `@portfolio:`,
498
+ `@strategy:`, `@dataset:`, `@run:`, and `@report:`. A plain `@path` remains a
499
+ file reference for compatibility; unknown references fail locally instead of
500
+ being guessed by the model. References contain pointers only: Aria reads them
501
+ on demand through audited tools such as `read_file`, `list_files`,
502
+ `analyze_file`, and `get_market_data`; source content is never silently
503
+ expanded into the prompt.
504
+
480
505
  ### Bottom Toolbar (always visible)
481
506
 
482
507
  ```
@@ -761,6 +786,54 @@ Analyze NVDA momentum → Full AI analysis
761
786
 
762
787
  ---
763
788
 
789
+ ## 📡 TradingView Alerts
790
+
791
+ Pipe TradingView alerts into Aria: the daemon receives the webhook, verifies
792
+ it, and runs a tool-less AI analysis through the shared runtime gateway, then
793
+ pushes the result to your notify channels (Telegram / Feishu).
794
+
795
+ ### Setup
796
+
797
+ ```env
798
+ ARIA_WEBHOOK_SECRET=your-strong-passphrase # REQUIRED for non-local use
799
+ ARIA_WEBHOOK_HOST=127.0.0.1 # bind address (default local-only)
800
+ ARIA_WEBHOOK_PORT=8765
801
+ ARIA_DAEMON_MODEL=qwen2.5:7b # model for alert analysis
802
+ ```
803
+
804
+ ```bash
805
+ python3 aria_daemon.py start
806
+ # endpoint: POST http://127.0.0.1:8765/api/v1/webhook/tradingview
807
+ ```
808
+
809
+ ### TradingView alert message (Webhook URL → your public endpoint)
810
+
811
+ ```json
812
+ {
813
+ "symbol": "{{ticker}}",
814
+ "action": "{{strategy.order.action}}",
815
+ "price": "{{close}}",
816
+ "message": "MA cross on {{interval}}",
817
+ "passphrase": "your-strong-passphrase"
818
+ }
819
+ ```
820
+
821
+ ### Security model
822
+
823
+ - **Passphrase (fail-closed):** with `ARIA_WEBHOOK_SECRET` set, alerts without
824
+ a matching `passphrase` are rejected (constant-time compare). TradingView
825
+ cannot send custom headers, so the body passphrase is the documented way.
826
+ - **Open-mode guard:** with *no* secret and *no* `WEBHOOK_TOKEN` configured,
827
+ only loopback clients may submit — a non-local request gets `403` with a
828
+ fix-it message instead of silently accepting injected buy/sell alerts.
829
+ - **HMAC option:** a fronting relay that can sign requests may send
830
+ `sha256=<hex>` of the raw body; HMAC verification never runs in open mode.
831
+ - **Analysis, not trading:** the alert turn runs with an empty tool set and a
832
+ prompt that forbids order placement. Order *previews* (when a broker is
833
+ configured) still require explicit confirmation via the preview flow.
834
+
835
+ ---
836
+
764
837
  ## 🏗️ Architecture
765
838
 
766
839
  ```
@@ -791,7 +864,7 @@ Analyze NVDA momentum → Full AI analysis
791
864
 
792
865
  ```
793
866
  aria-code/
794
- ├── aria_cli.py # Main CLI + REPL (keyboard shortcuts, ! shell, @files)
867
+ ├── aria_cli.py # Main CLI + REPL (keyboard shortcuts, ! shell, @ context)
795
868
  ├── aria_daemon.py # Background daemon + scheduler
796
869
  ├── market_data_client.py # Unified market data (Finnhub primary for US)
797
870
  ├── setup_wizard.py # Bilingual setup wizard (19 providers)
@@ -807,7 +880,7 @@ aria-code/
807
880
  │
808
881
  ├── ui/
809
882
  │ ├── banner.py # Bilingual banner (i18n aware)
810
- │ └── completer.py # Fuzzy autocomplete: / commands · @ files · ! history
883
+ │ └── completer.py # Fuzzy autocomplete: / commands · @ context · ! history
811
884
  │
812
885
  ├── providers/llm/ # LLM adapters (19+ cloud endpoints)
813
886
  ├── agents/financial/ # Fundamental / Technical / Macro / Risk / Synthesis
@@ -12,6 +12,8 @@
12
12
 
13
13
  <p align="center">
14
14
  <a href="https://www.npmjs.com/package/@artheras/aria-code"><img src="https://img.shields.io/npm/v/@artheras/aria-code?style=for-the-badge&logo=npm&color=cb3837&label=npm" alt="npm"/></a>
15
+ <a href="https://pypi.org/project/aria-code/"><img src="https://img.shields.io/pypi/v/aria-code?style=for-the-badge&logo=pypi&logoColor=white&label=PyPI&color=3775A9" alt="PyPI"/></a>
16
+ <a href="https://github.com/artherahq/aria-code/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/artherahq/aria-code/ci.yml?branch=main&style=for-the-badge&logo=githubactions&logoColor=white&label=CI" alt="CI"/></a>
15
17
  <img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="python"/>
16
18
  <img src="https://img.shields.io/badge/Ollama-Local_LLM-black?style=for-the-badge&logo=llama&logoColor=white" alt="ollama"/>
17
19
  <img src="https://img.shields.io/badge/Providers-19+_Cloud-f59e0b?style=for-the-badge" alt="providers"/>
@@ -49,7 +51,7 @@ Aria Code is a **terminal-first AI financial agent** — think of it as Claude C
49
51
  ```
50
52
  $ aria-code
51
53
 
52
- ▣ Aria Code v4.0 local-first agent
54
+ ▣ Aria Code v4.1 local-first agent
53
55
  model qwen2.5-coder:7b local
54
56
  workspace ~/my-portfolio
55
57
  mode workspace-write · network on · local-only
@@ -87,6 +89,8 @@ $ aria-code
87
89
  | **MCP tools** | 5 new quantitative MCP tools in the tool registry |
88
90
  | **83 commands** | Consolidated from ~150 — removed all LLM-replaceable commands; natural language handles the rest |
89
91
  | **LLM routing fix** | Model now knows it can call real-time data tools instead of saying "I don't have live data" |
92
+ | **Unified agent loop** | CLI, SDK and self-host backend now run the *same* tested runtime (`runtime.run_turn`) — consistent provider routing, cloud→local fallback and tool execution on every surface |
93
+ | **One-command install** | `pip install aria-code` (PyPI) or `npm install -g @artheras/aria-code` — verified clean on Python 3.10 / 3.11 / 3.12 |
90
94
 
91
95
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
92
96
 
@@ -96,7 +100,7 @@ See [CHANGELOG.md](CHANGELOG.md) for the full history.
96
100
  |---------|-------------|
97
101
  | ⌨️ **Keyboard shortcuts** | `Shift+Tab` cycle modes · `Alt+T` thinking · `Alt+P` model picker · `Ctrl+O` transcript · `Ctrl+T` tasks |
98
102
  | `!` **Shell mode** | Type `! git status` to run shell commands, output auto-added to AI context |
99
- | `@` **File autocomplete** | Type `@src/` to get instant file path completion anywhere in input |
103
+ | `@` **Typed context references** | Attach files, folders, assets, portfolios, strategies, datasets, runs, or reports without executing an action |
100
104
  | `/btw` **Side questions** | Ask quick questions without polluting conversation history |
101
105
  | 🌍 **Auto language** | UI and responses auto-detect Chinese/English from OS locale on first run |
102
106
  | 🤖 **19+ cloud providers** | Google Gemini · xAI Grok · Mistral · Cohere · Perplexity · Baidu ERNIE · ByteDance · MiniMax · StepFun · 01.AI + all originals |
@@ -168,7 +172,7 @@ mindmap
168
172
  | 🔍 **Quant research** | `/backtest` `/signal` `/kelly` `/factor` `/portfolio` `/screen` `/corr` `/ptbt` |
169
173
  | 🤖 **19+ cloud providers** | All major international + Chinese LLM APIs supported |
170
174
  | 🔌 **MCP protocol** | Connect any [Model Context Protocol](https://modelcontextprotocol.io) server |
171
- | ⌨️ **Rich keyboard UX** | Vim mode · `!` shell · `@` files · `Shift+Tab` modes · transcript viewer |
175
+ | ⌨️ **Rich keyboard UX** | Vim mode · `!` shell · typed `@` context · `Shift+Tab` modes · transcript viewer |
172
176
  | 💬 **Feishu / Telegram** | Ask Aria from any chat app, anytime |
173
177
  | 📱 **iOS push alerts** | Real-time price alerts via APNs |
174
178
  | 🌍 **Auto bilingual** | OS language auto-detected on first run; output follows user's input language |
@@ -347,9 +351,26 @@ Aria Code has a full keyboard shortcut system powered by `prompt_toolkit`:
347
351
  |--------|------|---------|
348
352
  | `/` | Slash command with fuzzy autocomplete | `/backtest momentum SPY` |
349
353
  | `!` | Shell mode — runs command, adds output to context | `! git diff HEAD~1` |
350
- | `@` | File path autocomplete | `@src/components/` |
354
+ | `@` | Read-only typed context reference | `@file:src/app.py` · `@asset:AAPL` |
351
355
  | `"""` | Multi-line input mode (end with `"""`) | For pasting code blocks |
352
356
 
357
+ `/` and `@` are intentionally different: `/` selects an action; `@` selects
358
+ context for that action or for a natural-language request. They can be combined:
359
+
360
+ ```text
361
+ /risk @portfolio:core
362
+ /backtest @strategy:momentum-v2 @asset:AAPL --period 3y
363
+ Review @folder:apps/cli against @report:last-audit
364
+ ```
365
+
366
+ Available reference types: `@file:`, `@folder:`, `@asset:`, `@portfolio:`,
367
+ `@strategy:`, `@dataset:`, `@run:`, and `@report:`. A plain `@path` remains a
368
+ file reference for compatibility; unknown references fail locally instead of
369
+ being guessed by the model. References contain pointers only: Aria reads them
370
+ on demand through audited tools such as `read_file`, `list_files`,
371
+ `analyze_file`, and `get_market_data`; source content is never silently
372
+ expanded into the prompt.
373
+
353
374
  ### Bottom Toolbar (always visible)
354
375
 
355
376
  ```
@@ -634,6 +655,54 @@ Analyze NVDA momentum → Full AI analysis
634
655
 
635
656
  ---
636
657
 
658
+ ## 📡 TradingView Alerts
659
+
660
+ Pipe TradingView alerts into Aria: the daemon receives the webhook, verifies
661
+ it, and runs a tool-less AI analysis through the shared runtime gateway, then
662
+ pushes the result to your notify channels (Telegram / Feishu).
663
+
664
+ ### Setup
665
+
666
+ ```env
667
+ ARIA_WEBHOOK_SECRET=your-strong-passphrase # REQUIRED for non-local use
668
+ ARIA_WEBHOOK_HOST=127.0.0.1 # bind address (default local-only)
669
+ ARIA_WEBHOOK_PORT=8765
670
+ ARIA_DAEMON_MODEL=qwen2.5:7b # model for alert analysis
671
+ ```
672
+
673
+ ```bash
674
+ python3 aria_daemon.py start
675
+ # endpoint: POST http://127.0.0.1:8765/api/v1/webhook/tradingview
676
+ ```
677
+
678
+ ### TradingView alert message (Webhook URL → your public endpoint)
679
+
680
+ ```json
681
+ {
682
+ "symbol": "{{ticker}}",
683
+ "action": "{{strategy.order.action}}",
684
+ "price": "{{close}}",
685
+ "message": "MA cross on {{interval}}",
686
+ "passphrase": "your-strong-passphrase"
687
+ }
688
+ ```
689
+
690
+ ### Security model
691
+
692
+ - **Passphrase (fail-closed):** with `ARIA_WEBHOOK_SECRET` set, alerts without
693
+ a matching `passphrase` are rejected (constant-time compare). TradingView
694
+ cannot send custom headers, so the body passphrase is the documented way.
695
+ - **Open-mode guard:** with *no* secret and *no* `WEBHOOK_TOKEN` configured,
696
+ only loopback clients may submit — a non-local request gets `403` with a
697
+ fix-it message instead of silently accepting injected buy/sell alerts.
698
+ - **HMAC option:** a fronting relay that can sign requests may send
699
+ `sha256=<hex>` of the raw body; HMAC verification never runs in open mode.
700
+ - **Analysis, not trading:** the alert turn runs with an empty tool set and a
701
+ prompt that forbids order placement. Order *previews* (when a broker is
702
+ configured) still require explicit confirmation via the preview flow.
703
+
704
+ ---
705
+
637
706
  ## 🏗️ Architecture
638
707
 
639
708
  ```
@@ -664,7 +733,7 @@ Analyze NVDA momentum → Full AI analysis
664
733
 
665
734
  ```
666
735
  aria-code/
667
- ├── aria_cli.py # Main CLI + REPL (keyboard shortcuts, ! shell, @files)
736
+ ├── aria_cli.py # Main CLI + REPL (keyboard shortcuts, ! shell, @ context)
668
737
  ├── aria_daemon.py # Background daemon + scheduler
669
738
  ├── market_data_client.py # Unified market data (Finnhub primary for US)
670
739
  ├── setup_wizard.py # Bilingual setup wizard (19 providers)
@@ -680,7 +749,7 @@ aria-code/
680
749
  │
681
750
  ├── ui/
682
751
  │ ├── banner.py # Bilingual banner (i18n aware)
683
- │ └── completer.py # Fuzzy autocomplete: / commands · @ files · ! history
752
+ │ └── completer.py # Fuzzy autocomplete: / commands · @ context · ! history
684
753
  │
685
754
  ├── providers/llm/ # LLM adapters (19+ cloud endpoints)
686
755
  ├── agents/financial/ # Fundamental / Technical / Macro / Risk / Synthesis
@@ -0,0 +1,17 @@
1
+ """Aria channels — external entrypoints as structured-task producers."""
2
+
3
+ from .registry import (
4
+ CHANNEL_TASK_SCHEMA,
5
+ ChannelSpec,
6
+ channel_map,
7
+ default_channels,
8
+ enabled_channels,
9
+ )
10
+
11
+ __all__ = [
12
+ "CHANNEL_TASK_SCHEMA",
13
+ "ChannelSpec",
14
+ "channel_map",
15
+ "default_channels",
16
+ "enabled_channels",
17
+ ]
@@ -0,0 +1,92 @@
1
+ """Channel intake policy + gateway submission (the daemon-facing half).
2
+
3
+ Completes the channels contract loop: the daemon's webhook endpoint hands
4
+ verified channel tasks to ``runtime.run_turn`` instead of poking CLI
5
+ internals, and refuses unauthenticated ("open mode") intake from anywhere
6
+ but localhost.
7
+
8
+ Two pieces, both dependency-light so the daemon can import them without
9
+ dragging in aria_cli:
10
+
11
+ • should_refuse_open_intake() — pure policy: when neither an intake token
12
+ nor ARIA_WEBHOOK_SECRET is configured, only loopback clients may submit.
13
+ • analyze_alert_via_gateway() — submits a task prompt through the shared
14
+ runtime gateway with an EMPTY tool set: channel-triggered turns get
15
+ model analysis but can never execute tools from the daemon context.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from typing import Any, Callable, Dict, Optional
21
+
22
+ _LOOPBACK_HOSTS = {"127.0.0.1", "::1", "localhost"}
23
+
24
+
25
+ def should_refuse_open_intake(
26
+ client_host: Optional[str],
27
+ *,
28
+ token_configured: bool,
29
+ secret_configured: bool,
30
+ ) -> bool:
31
+ """True when an unauthenticated intake must be rejected.
32
+
33
+ With any credential configured (endpoint token or webhook passphrase),
34
+ authentication handles trust and remote clients are fine. With neither
35
+ configured the endpoint is running "open", which is only acceptable from
36
+ the loopback interface — an open endpoint reachable off-host would let
37
+ anyone on the network inject buy/sell alerts.
38
+ """
39
+ if token_configured or secret_configured:
40
+ return False
41
+ host = str(client_host or "").strip().lower()
42
+ if host.startswith("[") and host.endswith("]"): # bracketed IPv6
43
+ host = host[1:-1]
44
+ return host not in _LOOPBACK_HOSTS
45
+
46
+
47
+ async def analyze_alert_via_gateway(
48
+ prompt: str,
49
+ config: Dict[str, Any],
50
+ *,
51
+ run_turn_fn: Optional[Callable] = None,
52
+ max_rounds: int = 4,
53
+ ) -> str:
54
+ """Run one tool-less analysis turn for a channel task; returns the text.
55
+
56
+ ``run_turn_fn`` is injectable for tests; the default builds the same
57
+ provider selection the CLI uses (chat_routing via runtime_bridge) and
58
+ drives ``runtime.gateway.run_turn``. Raises on failure — the caller
59
+ decides its own fallback (the daemon keeps its legacy quick summary).
60
+ """
61
+ if run_turn_fn is None:
62
+ # stream_ollama borrows 47 bare names from aria_cli's module globals
63
+ # (verified by AST audit) and only works after aria_cli's import-time
64
+ # rebinding. Until that module is untangled, any out-of-CLI consumer
65
+ # of the default Ollama path must import aria_cli first — a one-time
66
+ # ~1s cost the long-lived daemon amortizes.
67
+ import aria_cli # noqa: F401 (side effect: binds stream_ollama globals)
68
+ from apps.cli.providers.runtime_bridge import build_tool_executor, make_provider_fn
69
+ from runtime.gateway import run_turn as run_turn_fn_impl
70
+
71
+ provider_fn = make_provider_fn(
72
+ model=str(config.get("model", "qwen2.5:7b")),
73
+ config=config,
74
+ api_url=config.get("api_url"),
75
+ ollama_url=str(config.get("ollama_url", "http://localhost:11434")),
76
+ tool_schemas=[],
77
+ )
78
+ executor = build_tool_executor({}, config)
79
+
80
+ async def run_turn_fn(prompt_, history_, **kw):
81
+ return await run_turn_fn_impl(
82
+ prompt_, history_,
83
+ provider_fn=provider_fn, tool_executor=executor,
84
+ tool_schemas=[], max_rounds=max_rounds,
85
+ )
86
+
87
+ result = await run_turn_fn(prompt, [])
88
+ text = (getattr(result, "text", "") or "").strip()
89
+ error = getattr(result, "error", None)
90
+ if error or not text:
91
+ raise RuntimeError(f"gateway turn failed: {error or 'empty response'}")
92
+ return text
@@ -0,0 +1,95 @@
1
+ """Channel registry — the declared inventory of external entrypoints.
2
+
3
+ First slice of the channels layer (contract: "Channels submit structured
4
+ tasks to gateway/runtime and never call CLI internals directly"). The
5
+ registry is pure data + config resolution: it names each channel, its
6
+ direction, the config/env that enables it, and which capability it maps to,
7
+ so the daemon and doctor can reason about channels uniformly instead of each
8
+ integration hard-coding its own discovery.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass, field
14
+ from typing import Any, Dict, List, Mapping, Tuple
15
+
16
+ CHANNEL_TASK_SCHEMA = "aria.channel_task.v1"
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class ChannelSpec:
21
+ name: str
22
+ direction: str # "inbound" | "outbound" | "both"
23
+ description: str
24
+ capabilities: Tuple[str, ...] = ()
25
+ # Any of these config keys (or env vars) being truthy enables the channel.
26
+ config_keys: Tuple[str, ...] = ()
27
+ env_keys: Tuple[str, ...] = ()
28
+
29
+ def enabled(self, config: Mapping[str, Any], env: Mapping[str, str]) -> bool:
30
+ for key in self.config_keys:
31
+ if config.get(key):
32
+ return True
33
+ for key in self.env_keys:
34
+ if str(env.get(key, "") or "").strip():
35
+ return True
36
+ return False
37
+
38
+
39
+ def default_channels() -> List[ChannelSpec]:
40
+ return [
41
+ ChannelSpec(
42
+ name="tradingview",
43
+ direction="inbound",
44
+ description="TradingView alert webhooks → structured alert tasks",
45
+ capabilities=("alerts.ingest", "orders.preview"),
46
+ config_keys=("tradingview_webhook",),
47
+ env_keys=("ARIA_WEBHOOK_SECRET",),
48
+ ),
49
+ ChannelSpec(
50
+ name="webhook_jobs",
51
+ direction="inbound",
52
+ description="Generic daemon webhook job queue (/webhook/trigger)",
53
+ capabilities=("tasks.enqueue",),
54
+ env_keys=("WEBHOOK_TOKEN",),
55
+ ),
56
+ ChannelSpec(
57
+ name="telegram",
58
+ direction="both",
59
+ description="Telegram bot push + command intake via the daemon",
60
+ capabilities=("notify.push", "chat.intake"),
61
+ config_keys=("telegram_bot_token",),
62
+ env_keys=("TELEGRAM_BOT_TOKEN",),
63
+ ),
64
+ ChannelSpec(
65
+ name="feishu",
66
+ direction="outbound",
67
+ description="Feishu webhook card push",
68
+ capabilities=("notify.push",),
69
+ config_keys=("feishu_webhook",),
70
+ env_keys=("FEISHU_WEBHOOK_URL",),
71
+ ),
72
+ ChannelSpec(
73
+ name="macos_notify",
74
+ direction="outbound",
75
+ description="Local macOS notification center",
76
+ capabilities=("notify.push",),
77
+ config_keys=("macos_notifications",),
78
+ ),
79
+ ChannelSpec(
80
+ name="email",
81
+ direction="outbound",
82
+ description="SMTP email push",
83
+ capabilities=("notify.push",),
84
+ config_keys=("email_smtp_host",),
85
+ env_keys=("ARIA_SMTP_HOST",),
86
+ ),
87
+ ]
88
+
89
+
90
+ def channel_map() -> Dict[str, ChannelSpec]:
91
+ return {spec.name: spec for spec in default_channels()}
92
+
93
+
94
+ def enabled_channels(config: Mapping[str, Any], env: Mapping[str, str]) -> List[ChannelSpec]:
95
+ return [spec for spec in default_channels() if spec.enabled(config, env)]
@@ -0,0 +1,94 @@
1
+ """TradingView alert → structured channel task (aria.channel_task.v1).
2
+
3
+ The channels contract requires external entrypoints to submit *structured
4
+ tasks* to the gateway instead of poking CLI internals. This adapter turns a
5
+ raw TradingView webhook payload into that task shape, reusing the hardened
6
+ primitives that already live in apps/cli/tradingview_bridge.py (field-tolerant
7
+ parsing, passphrase + HMAC verification, dedup keys).
8
+
9
+ Verification posture mirrors the bridge's documented semantics: with
10
+ ARIA_WEBHOOK_SECRET unset verification is open (localhost-only assumption),
11
+ but the task carries explicit ``verified`` / ``open_mode`` flags so a
12
+ downstream gate (daemon, SafetyService) can refuse open-mode tasks in
13
+ non-local deployments.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import time
19
+ from typing import Any, Callable, Dict, Optional
20
+
21
+ from apps.cli.tradingview_bridge import (
22
+ _alert_dedup_key as alert_dedup_key,
23
+ _expected_webhook_secret,
24
+ parse_tradingview_alert,
25
+ verify_webhook_hmac,
26
+ verify_webhook_secret,
27
+ )
28
+ from apps.channels.registry import CHANNEL_TASK_SCHEMA
29
+
30
+
31
+ def alert_to_task(
32
+ payload: Dict[str, Any] | str,
33
+ *,
34
+ raw_body: Optional[bytes | str] = None,
35
+ signature: Optional[str] = None,
36
+ clock: Callable[[], float] = time.time,
37
+ ) -> Dict[str, Any]:
38
+ """Normalize + authenticate one webhook delivery.
39
+
40
+ Returns ``{"success": True, "task": {...}}`` or
41
+ ``{"success": False, "error": ...}`` (tool-result convention).
42
+ """
43
+ alert = parse_tradingview_alert(payload)
44
+ raw = alert.get("raw") or {}
45
+
46
+ secret_configured = bool(_expected_webhook_secret())
47
+ if signature is not None:
48
+ # A fronting signer supplied an HMAC — it must verify (never open).
49
+ if not verify_webhook_hmac(raw_body if raw_body is not None else "", signature):
50
+ return {"success": False, "error": "tradingview alert rejected: HMAC signature mismatch"}
51
+ verified = True
52
+ else:
53
+ if not verify_webhook_secret(raw):
54
+ return {"success": False, "error": "tradingview alert rejected: passphrase missing or wrong"}
55
+ verified = secret_configured # open mode when no secret is configured
56
+
57
+ if not alert.get("symbol"):
58
+ return {"success": False, "error": "tradingview alert rejected: no symbol in payload"}
59
+
60
+ task = {
61
+ "schema": CHANNEL_TASK_SCHEMA,
62
+ "channel": "tradingview",
63
+ "kind": "alert",
64
+ "received_at": clock(),
65
+ "verified": verified,
66
+ "open_mode": not secret_configured and signature is None,
67
+ "dedup_key": alert_dedup_key(alert),
68
+ "symbol": alert["symbol"],
69
+ "action": alert["action"],
70
+ "price": alert.get("price"),
71
+ "time": alert.get("time"),
72
+ "message": alert.get("message") or "",
73
+ "prompt": task_prompt(alert),
74
+ }
75
+ return {"success": True, "task": task}
76
+
77
+
78
+ def task_prompt(alert: Dict[str, Any]) -> str:
79
+ """Render the gateway-facing natural-language task for this alert.
80
+
81
+ The daemon submits this prompt to runtime's ``run_turn`` — the agent then
82
+ analyses the alert with its normal tools; nothing here places orders.
83
+ """
84
+ symbol = alert.get("symbol", "")
85
+ action = alert.get("action", "ALERT")
86
+ price = alert.get("price")
87
+ at = f" at {price}" if price not in (None, "") else ""
88
+ msg = str(alert.get("message") or "").strip()
89
+ tail = f' Alert message: "{msg}".' if msg else ""
90
+ return (
91
+ f"TradingView alert received: {action} signal for {symbol}{at}.{tail} "
92
+ f"Assess the signal against current market data and the portfolio, and "
93
+ f"summarize whether it warrants action. Do not place any orders."
94
+ )
@@ -70,6 +70,8 @@ def default_config() -> dict:
70
70
  ),
71
71
  "local_url": "http://localhost:8000",
72
72
  "ollama_url": os.getenv("OLLAMA_URL", "http://localhost:11434"),
73
+ "local_provider": os.getenv("ARIA_LLM_PROVIDER", "ollama"),
74
+ "provider_fallback": "configured",
73
75
  "model": "qwen2.5-coder:1.5b",
74
76
  "thinking_mode": "auto",
75
77
  "watchlist": ["AAPL", "MSFT", "GOOGL", "TSLA", "NVDA"],