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.
- {aria_code-4.1.3 → aria_code-4.1.7}/PKG-INFO +81 -8
- {aria_code-4.1.3 → aria_code-4.1.7}/README.md +75 -6
- aria_code-4.1.7/apps/channels/__init__.py +17 -0
- aria_code-4.1.7/apps/channels/intake.py +92 -0
- aria_code-4.1.7/apps/channels/registry.py +95 -0
- aria_code-4.1.7/apps/channels/tradingview.py +94 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/bootstrap.py +2 -0
- aria_code-4.1.7/apps/cli/commands/auth_cmds.py +135 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/backtest_cmds.py +565 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/broker_cmds.py +19 -2
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/diagnostic_ops_cmds.py +12 -0
- aria_code-4.1.7/apps/cli/commands/file_cmds.py +267 -0
- aria_code-4.1.7/apps/cli/commands/fx_commodity_cmds.py +87 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market.py +10 -3
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/model_cmds.py +154 -23
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/portfolio_cmds.py +92 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/session_cmds.py +28 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/session_ux_cmds.py +40 -0
- aria_code-4.1.7/apps/cli/config_store.py +66 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/deterministic.py +8 -2
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/i18n.py +4 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/market_universe.py +19 -2
- aria_code-4.1.7/apps/cli/prompt_assembly.py +59 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/system_prompts.py +4 -3
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/base.py +195 -4
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/chat_routing.py +26 -16
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/llm/ollama_stream.py +229 -51
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/runtime_bridge.py +40 -14
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/runtime_consumer.py +96 -14
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/session_export.py +6 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/market_tools.py +54 -12
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/system_tools.py +19 -4
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tradingview_bridge.py +100 -5
- aria_code-4.1.7/apps/cli/turn_planning.py +62 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/utils/market_detect.py +5 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_cli.py +888 -1138
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/PKG-INFO +81 -8
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/SOURCES.txt +42 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/requires.txt +8 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/top_level.txt +2 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_daemon.py +67 -2
- aria_code-4.1.7/backtest_engine.py +354 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/__init__.py +6 -0
- aria_code-4.1.7/brokers/automation.py +193 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/base.py +24 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/paper_broker.py +7 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/registry.py +32 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/trading.py +18 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/doctor.py +79 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/file_analysis_tools.py +124 -0
- aria_code-4.1.7/licensing.py +150 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/local_finance_tools.py +113 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/local_llm_provider.py +40 -3
- {aria_code-4.1.3 → aria_code-4.1.7}/mcp_client.py +106 -23
- {aria_code-4.1.3 → aria_code-4.1.7}/model_capability.py +4 -4
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/architecture.py +18 -16
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/export.py +23 -0
- aria_code-4.1.7/packages/aria_mcp/circuit.py +82 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/config.py +19 -5
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/tools.py +22 -4
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/streaming.py +9 -3
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/__init__.py +20 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/context.py +11 -0
- aria_code-4.1.7/packages/aria_services/context_checkpoints.py +156 -0
- aria_code-4.1.7/packages/aria_services/references.py +247 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/registry.py +14 -0
- aria_code-4.1.7/packages/aria_services/settings.py +146 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/usage.py +8 -0
- aria_code-4.1.7/packages/quant_engine/__init__.py +24 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/portfolio_ledger.py +44 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/openai_compat.py +12 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/registry.py +18 -14
- {aria_code-4.1.3 → aria_code-4.1.7}/pyproject.toml +7 -2
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/agent_loop.py +166 -13
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/gateway.py +10 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/tool_executor.py +69 -3
- {aria_code-4.1.3 → aria_code-4.1.7}/safety/__init__.py +2 -0
- aria_code-4.1.7/safety/service.py +86 -0
- aria_code-4.1.7/tests/test_analyze_file_tool.py +73 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_architecture_report.py +3 -2
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_aria_cli_core.py +66 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_aria_sdk.py +69 -0
- aria_code-4.1.7/tests/test_backtest_cmds.py +184 -0
- aria_code-4.1.7/tests/test_backtest_engine.py +146 -0
- aria_code-4.1.7/tests/test_broker_automation.py +133 -0
- aria_code-4.1.7/tests/test_broker_safety.py +96 -0
- aria_code-4.1.7/tests/test_channel_intake.py +73 -0
- aria_code-4.1.7/tests/test_channels.py +102 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_chat_routing.py +13 -4
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_app_split.py +4 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_runtime_consumer.py +59 -2
- aria_code-4.1.7/tests/test_configured_provider.py +102 -0
- aria_code-4.1.7/tests/test_context_checkpoints.py +130 -0
- aria_code-4.1.7/tests/test_context_references.py +177 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_doctor.py +79 -2
- aria_code-4.1.7/tests/test_finance_renderers.py +66 -0
- aria_code-4.1.7/tests/test_licensing.py +89 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_market_history_tool.py +51 -0
- aria_code-4.1.7/tests/test_market_symbol_extraction.py +72 -0
- aria_code-4.1.7/tests/test_mcp_circuit.py +170 -0
- aria_code-4.1.7/tests/test_mcp_client.py +64 -0
- aria_code-4.1.7/tests/test_model_selection_state.py +51 -0
- aria_code-4.1.7/tests/test_ollama_stream_tools.py +57 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_packages_facade.py +26 -0
- aria_code-4.1.7/tests/test_pick_best_installed_model.py +63 -0
- aria_code-4.1.7/tests/test_portfolio_ledger.py +89 -0
- aria_code-4.1.7/tests/test_prompt_assembly.py +70 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_agent_loop.py +67 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_bridge.py +56 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_bridge_fallback.py +2 -2
- aria_code-4.1.7/tests/test_runtime_tool_executor.py +137 -0
- aria_code-4.1.7/tests/test_safety_service.py +100 -0
- aria_code-4.1.7/tests/test_settings_service.py +108 -0
- aria_code-4.1.7/tests/test_startup_dashboard.py +122 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_tradingview_bridge.py +44 -0
- aria_code-4.1.7/tests/test_turn_planning.py +58 -0
- aria_code-4.1.7/tests/test_ui_completer_references.py +79 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_ui_input_box.py +93 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_ui_robot_banner.py +7 -6
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/__init__.py +7 -2
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/banner.py +220 -65
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/completer.py +132 -22
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/console.py +3 -1
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/input_box.py +134 -32
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/picker.py +9 -5
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/finance.py +91 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/output.py +2 -2
- aria_code-4.1.7/ui/startup_dashboard.py +109 -0
- aria_code-4.1.3/apps/cli/config_store.py +0 -61
- aria_code-4.1.3/packages/quant_engine/__init__.py +0 -6
- aria_code-4.1.3/tests/test_backtest_cmds.py +0 -96
- aria_code-4.1.3/tests/test_runtime_tool_executor.py +0 -63
- {aria_code-4.1.3 → aria_code-4.1.7}/LICENSE +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/base.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/calibration_loop.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/critic.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/deepen.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/models.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/pipeline.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/quant_fusion.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/themes.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/deep/tiers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/catalyst.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/debate.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/earnings.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/fundamental.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/macro.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/news.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/risk.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/sector.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/synthesis.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/financial/technical.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/portfolio_agent.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/asset_diagnosis.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/business_match.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/cashflow_verify.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/contract_rules.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/energy_anomaly.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/exit_settlement.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/fulfillment_risk.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/ops_optimize.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/realty/revenue_share.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/registry.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/sports/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/sports/football_agent.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/agents/team.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aliyun_data_client.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/README.md +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/channels/README.md +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/README.md +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/codegen_paths.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/analysis_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/business_workflow_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/catalog.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/data_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/diagnostic_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/finance_render.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market_context.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/market_render.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/ops_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/report.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/scaffold_templates.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/team.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/team_render.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/ui_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/workflow_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/commands/workspace_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/config_paths.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/direct.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/github_app_auth.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/broker_handlers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/chart_handlers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/market_handlers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/realty_handlers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/handlers/strategy_advice.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/hooks.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/intent.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/intent_router.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/lifecycle_hooks.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/main.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/market_metadata.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/message_processing.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/plan_mode.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/plotly_html.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prediction_feedback.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/preflight.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/project_aria.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/coding.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/prompts/ui.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/llm/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/providers/llm/sse_stream.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/session_jsonl.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/session_store.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/todo_tracker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/context.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/file_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/notebook_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/tools/write_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/update_check.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/cli/utils/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/daemon/README.md +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/vscode/README.md +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/apps/vscode/package.json +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/dependency_links.txt +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_code.egg-info/entry_points.txt +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_feishu_bot.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_relay_client.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_relay_server.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/aria_telegram_bot.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ariarc.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/artifacts.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/backtest_report.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/capabilities.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/easytrader_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/futu_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/longbridge_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/tiger_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/cn/xtquant_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/config.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/alpaca_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/ibkr_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/intl/webull_broker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/brokers/planning.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/change_store.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/command_safety.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/computer_use_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/dashboard_generator.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/data_analysis_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/data_cleaner.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/data_service.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/base.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/router.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/akshare_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/alpha_vantage_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/edgar_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/finnhub_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/fred_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/tushare_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/web_scraper_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/world_bank_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/datasources/sources/yfinance_source.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/demo_player.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/finance_formulas.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/football_data_client.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/intent_classifier.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/macro_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/market_data_client.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/memory_manager.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/notification_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_agents/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_agents/manifest.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_core/manifest.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/arthera.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/doctor.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_infra/product.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_mcp/bridge.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/client.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/providers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_sdk/types.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/data.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_services/provider_health.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_skills/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_skills/registry.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_tools/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/aria_tools/registry.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/calibrator.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/dixon_coles.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/elo.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/form.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/h2h.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/ml_model.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/predictor.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/sports/tracker.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/gbm_enhanced.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/ito_calculus.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/kelly_criterion.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/monte_carlo_advanced.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/options_pricing.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/packages/quant_engine/stochastic/stochastic_processes.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/plan_utils.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/plugin_loader.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/privacy/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/privacy/feedback.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/project_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/anthropic.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/base.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/providers/llm/ollama.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/realty_data_tools.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/report_generator.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/approval.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/events.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/lsp.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/subagent.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/runtime/tool_policy.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/safety/permissions.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/setup.cfg +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/setup_wizard.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/strategy_vault.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_artifacts_and_reports.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_backtest_report.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_broker_planning.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_business_workflow_cmds.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_chart_handlers.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_bootstrap.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_config_store.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_cli_lifecycle_hooks.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_codegen_output.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_command_safety.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_completions_builder.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_config_paths.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_context_service.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_dashboard_generator.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_data_service.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_deep_analysis.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_football_prediction_output.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_image_inputs.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_intent_router.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_lsp.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_market_data_client.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_market_universe.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_new_modules.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_output_rendering.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_plan_mode.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_plotly_html_output.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_preflight.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_privacy_feedback.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_project_aria.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_provider_integration.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_provider_registry.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_approval.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_runtime_gateway.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_safety_permissions.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_session_search.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_streaming_pipeline.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_subagent.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_system_prompts.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_system_tools_output.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_team_synthesis.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_tool_policy.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_trading_service.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_ui_console_theme.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_workspace_files.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/tests/test_workspace_verify.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/image_render.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/market.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/render/team.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/ui/robot.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/workspace/__init__.py +0 -0
- {aria_code-4.1.3 → aria_code-4.1.7}/workspace/files.py +0 -0
- {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
|
+
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.
|
|
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.
|
|
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
|
-
| `@` **
|
|
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 · `@`
|
|
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
|
-
| `@` |
|
|
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, @
|
|
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 · @
|
|
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.
|
|
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
|
-
| `@` **
|
|
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 · `@`
|
|
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
|
-
| `@` |
|
|
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, @
|
|
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 · @
|
|
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"],
|