aria-code 0.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_code/__init__.py +42 -0
- aria_code/_version.py +20 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +34 -0
- aria_code/agents/base.py +318 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +303 -0
- aria_code/agents/financial/fundamental.py +191 -0
- aria_code/agents/financial/macro.py +99 -0
- aria_code/agents/financial/news.py +207 -0
- aria_code/agents/financial/risk.py +165 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +258 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +363 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +158 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +492 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +15 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +95 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/bootstrap.py +145 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +16 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +369 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +239 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
- aria_code/apps/cli/commands/broker_cmds.py +1234 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +87 -0
- aria_code/apps/cli/commands/core_cmds.py +2520 -0
- aria_code/apps/cli/commands/data_cmds.py +457 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +434 -0
- aria_code/apps/cli/commands/market_cmds.py +1381 -0
- aria_code/apps/cli/commands/market_context.py +425 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2153 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
- aria_code/apps/cli/commands/report.py +437 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +669 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
- aria_code/apps/cli/commands/workflow_cmds.py +480 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +78 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/deterministic.py +191 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +196 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
- aria_code/apps/cli/handlers/market_handlers.py +2513 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/helpers.py +302 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +297 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +276 -0
- aria_code/apps/cli/intent_signals.py +344 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +536 -0
- aria_code/apps/cli/main.py +29 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/model_catalog.py +620 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +59 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +53 -0
- aria_code/apps/cli/prompts/select.py +142 -0
- aria_code/apps/cli/prompts/system_prompts.py +552 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +521 -0
- aria_code/apps/cli/providers/chat_routing.py +128 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
- aria_code/apps/cli/providers/runtime_bridge.py +353 -0
- aria_code/apps/cli/providers/vertexai_stream.py +316 -0
- aria_code/apps/cli/runtime_consumer.py +657 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_store.py +112 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +823 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +106 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +180 -0
- aria_code/apps/cli/tools/market_tools.py +620 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +726 -0
- aria_code/apps/cli/tools/write_tools.py +845 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +153 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1597 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +6743 -0
- aria_code/aria_daemon.py +1398 -0
- aria_code/aria_feishu_bot.py +1423 -0
- aria_code/aria_mcp_server.py +7 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_relay_server.py +490 -0
- aria_code/aria_telegram_bot.py +202 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +182 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1976 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +181 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/demo_player.py +207 -0
- aria_code/doctor.py +813 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/backtest_engine.py +354 -0
- aria_code/domain/backtest_report.py +472 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/harness.py +598 -0
- aria_code/evals/runner.py +238 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +386 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +639 -0
- aria_code/memory_manager.py +246 -0
- aria_code/model_capability.py +486 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +23 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +52 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +201 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +111 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1550 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +396 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +79 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +268 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +57 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +157 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +8 -0
- aria_code/packages/aria_tools/financial/_paths.py +130 -0
- aria_code/packages/aria_tools/financial/compliance.py +31 -0
- aria_code/packages/aria_tools/financial/factors.py +33 -0
- aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
- aria_code/packages/aria_tools/financial/strategy.py +31 -0
- aria_code/packages/aria_tools/registry.py +128 -0
- aria_code/packages/quant_engine/__init__.py +34 -0
- aria_code/packages/quant_engine/_namespace.py +62 -0
- aria_code/packages/quant_engine/backtest/__init__.py +14 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +96 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +80 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/ml_model.py +377 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/logistics/__init__.py +169 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +129 -0
- aria_code/providers/llm/openai_compat.py +313 -0
- aria_code/providers/llm/registry.py +444 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +589 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/runtime/__init__.py +169 -0
- aria_code/runtime/acceptance.py +481 -0
- aria_code/runtime/agent_loop.py +1520 -0
- aria_code/runtime/approval.py +57 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +432 -0
- aria_code/runtime/crash_report.py +174 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +150 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/repo_map.py +700 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +450 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/subagent.py +547 -0
- aria_code/runtime/task_ledger.py +86 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/tool_executor.py +217 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +23 -0
- aria_code/safety/permissions.py +306 -0
- aria_code/safety/service.py +102 -0
- aria_code/setup_wizard.py +673 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +504 -0
- aria_code/tools/data_analysis_tools.py +809 -0
- aria_code/tools/enterprise_finance_tools.py +156 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +885 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3417 -0
- aria_code/tools/logistics_tools.py +135 -0
- aria_code/tools/macro_tools.py +369 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +659 -0
- aria_code/tools/spreadsheet_tools.py +388 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +508 -0
- aria_code/ui/completer.py +501 -0
- aria_code/ui/console.py +281 -0
- aria_code/ui/image_render.py +243 -0
- aria_code/ui/input_box.py +488 -0
- aria_code/ui/picker.py +201 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/finance.py +1705 -0
- aria_code/ui/render/market.py +225 -0
- aria_code/ui/render/output.py +775 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +354 -0
- aria_code/ui/robot.py +235 -0
- aria_code/ui/startup_dashboard.py +109 -0
- aria_code/utils/vscode_uri.py +37 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +271 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +193 -0
- aria_code/workspace/verify.py +113 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_context.py +233 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.52.0.dist-info/METADATA +237 -0
- aria_code-0.52.0.dist-info/RECORD +478 -0
- aria_code-0.52.0.dist-info/WHEEL +5 -0
- aria_code-0.52.0.dist-info/entry_points.txt +3 -0
- aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.52.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"""Market command parsing and top-level routing helpers.
|
|
2
|
+
|
|
3
|
+
Keep this module independent from the terminal UI and market data providers so
|
|
4
|
+
CLI, Feishu, and future gateway adapters can share the same command semantics.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Mapping
|
|
11
|
+
|
|
12
|
+
from aria_code.apps.cli.utils.market_detect import (
|
|
13
|
+
_extract_market_symbol,
|
|
14
|
+
_extract_market_symbols,
|
|
15
|
+
_is_blocked_market_symbol_candidate,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
TOP_LEVEL_ROUTES: Mapping[str, str] = {
|
|
20
|
+
# quant workflow keywords -> slash command name
|
|
21
|
+
"analyze": "/analyze",
|
|
22
|
+
"analysis": "/analyze",
|
|
23
|
+
"分析": "/analyze",
|
|
24
|
+
"backtest": "/backtest",
|
|
25
|
+
"回测": "/backtest",
|
|
26
|
+
"risk": "/risk",
|
|
27
|
+
"风险": "/risk",
|
|
28
|
+
"report": "/report",
|
|
29
|
+
"报告": "/report",
|
|
30
|
+
"market": "/market",
|
|
31
|
+
"行情": "/market",
|
|
32
|
+
"screen": "/screen",
|
|
33
|
+
"筛选": "/screen",
|
|
34
|
+
"strategy": "/strategy",
|
|
35
|
+
"策略": "/strategy",
|
|
36
|
+
"signal": "/signal",
|
|
37
|
+
"信号": "/signal",
|
|
38
|
+
"chart": "/chart",
|
|
39
|
+
"图表": "/chart",
|
|
40
|
+
"news": "/news",
|
|
41
|
+
"新闻": "/news",
|
|
42
|
+
"predict": "/predict",
|
|
43
|
+
"预测": "/predict",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_VISUAL_ROUTE_PATTERNS: tuple[tuple[tuple[str, ...], str], ...] = (
|
|
47
|
+
(("晨报", "日报", "周报", "月报", "看板", "dashboard", "heatmap"), "/dashboard"),
|
|
48
|
+
(("报告", "report", "研报"), "/report"),
|
|
49
|
+
(("图表", "走势图", "k线图", "k线", "k-line", "kline", "candlestick", "chart", "plot"), "/chart"),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
_DASHBOARD_MODE_HINTS: tuple[tuple[tuple[str, ...], str], ...] = (
|
|
53
|
+
(("持仓", "portfolio", "仓位", "组合", "资产"), "portfolio"),
|
|
54
|
+
(("市场", "行情", "quote", "prices", "watchlist", "热力图", "heatmap"), "market"),
|
|
55
|
+
(("晨报", "日报", "brief"), "brief"),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
_CHART_PERIOD_HINTS: tuple[tuple[tuple[str, ...], str], ...] = (
|
|
59
|
+
(("近一年", "一年", "1y", "1年"), "1y"),
|
|
60
|
+
(("近三个月", "三个月", "3m", "3个月"), "3m"),
|
|
61
|
+
(("近六个月", "六个月", "6m", "6个月"), "6m"),
|
|
62
|
+
(("年初至今", "ytd"), "ytd"),
|
|
63
|
+
(("两年", "2y"), "2y"),
|
|
64
|
+
(("三年", "3y"), "3y"),
|
|
65
|
+
(("五年", "5y"), "5y"),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
_REPORT_TYPE_HINTS: tuple[tuple[tuple[str, ...], str], ...] = (
|
|
69
|
+
(("深度", "详细", "deep"), "deep"),
|
|
70
|
+
(("简评", "简报", "brief"), "brief"),
|
|
71
|
+
(("研究报告", "投研报告", "研究", "report"), "standard"),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
_TRADINGVIEW_HINTS = ("tradingview", "trading view", "pine")
|
|
75
|
+
_TRADINGVIEW_ZH_HINTS = ("用tradingview", "打开tradingview", "tradingview打开", "用 tv", "tv打开", "pine脚本")
|
|
76
|
+
_TRADINGVIEW_BULLISH_HINTS = ("看涨", "偏多", "多头", "上涨", "bullish", "bull", "upside")
|
|
77
|
+
_TRADINGVIEW_BEARISH_HINTS = ("看跌", "偏空", "空头", "下跌", "bearish", "bear", "downside")
|
|
78
|
+
_TRADINGVIEW_ANALYSIS_HINTS = (
|
|
79
|
+
"分析", "怎么看", "怎么判断", "哪些数据", "根据其的数据", "根据数据",
|
|
80
|
+
"指标", "信号", "analyze", "analysis", "data", "indicator", "signal",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
_ROUTE_SYMBOL_BLOCKLIST = {"K", "LINE", "CHART", "PLOT"}
|
|
84
|
+
_CHART_CONTEXT_TOKEN_BLOCKLIST = {
|
|
85
|
+
"ABOVE", "BELOW", "INC", "TTM", "RATIO", "SIGNAL", "SUPPORT", "RESIST",
|
|
86
|
+
"RESISTANCE", "LEVEL", "LEVELS", "HIGH", "LOW", "OPEN", "CLOSE", "AVG",
|
|
87
|
+
"AVERAGE", "RETURN", "RETURNS", "TREND", "MOMENTUM",
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_NEWS_DISCUSSION_HINTS = (
|
|
91
|
+
"新闻面", "技术面", "还有用吗", "是否有用", "你觉得", "怎么看",
|
|
92
|
+
"区别", "关系", "怎么结合", "如何结合", "为什么",
|
|
93
|
+
)
|
|
94
|
+
_NEWS_LOOKUP_HINTS = (
|
|
95
|
+
"最新新闻", "最近新闻", "相关新闻", "今日新闻", "新闻有哪些",
|
|
96
|
+
"查新闻", "搜新闻", "搜索新闻", "找新闻", "获取新闻",
|
|
97
|
+
"latest news", "recent news", "find news", "search news",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _is_news_discussion(text: str) -> bool:
|
|
102
|
+
"""True when 'news' is a discussion topic rather than a lookup request."""
|
|
103
|
+
low = (text or "").lower()
|
|
104
|
+
if any(hint in low for hint in _NEWS_LOOKUP_HINTS):
|
|
105
|
+
return False
|
|
106
|
+
return "新闻" in low and any(hint in low for hint in _NEWS_DISCUSSION_HINTS)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _news_topic(text: str, symbols: list[str]) -> str:
|
|
110
|
+
low = text.lower()
|
|
111
|
+
if "spacex" in low:
|
|
112
|
+
return "SpaceX"
|
|
113
|
+
if "lvmh" in low or "路易威登" in text:
|
|
114
|
+
return "LVMH"
|
|
115
|
+
return symbols[0] if symbols else text
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _route_symbols(text: str, *, limit: int = 6) -> list[str]:
|
|
119
|
+
"""Resolve ticker/company mentions for natural-language command routing."""
|
|
120
|
+
seen: set[str] = set()
|
|
121
|
+
out: list[str] = []
|
|
122
|
+
for source in (text, text.upper()):
|
|
123
|
+
for symbol in _extract_market_symbols(source, limit=limit):
|
|
124
|
+
normalized = str(symbol or "").upper()
|
|
125
|
+
if (
|
|
126
|
+
not normalized
|
|
127
|
+
or normalized in _ROUTE_SYMBOL_BLOCKLIST
|
|
128
|
+
or _is_blocked_market_symbol_candidate(normalized)
|
|
129
|
+
):
|
|
130
|
+
continue
|
|
131
|
+
if len(normalized) == 1 and "." not in normalized:
|
|
132
|
+
continue
|
|
133
|
+
if normalized not in seen:
|
|
134
|
+
seen.add(normalized)
|
|
135
|
+
out.append(normalized)
|
|
136
|
+
if len(out) >= limit:
|
|
137
|
+
return out
|
|
138
|
+
single = _extract_market_symbol(text) or _extract_market_symbol(text.upper())
|
|
139
|
+
normalized = str(single or "").upper()
|
|
140
|
+
if (
|
|
141
|
+
normalized
|
|
142
|
+
and normalized not in seen
|
|
143
|
+
and normalized not in _ROUTE_SYMBOL_BLOCKLIST
|
|
144
|
+
and not _is_blocked_market_symbol_candidate(normalized)
|
|
145
|
+
):
|
|
146
|
+
out.append(normalized)
|
|
147
|
+
return out
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass(frozen=True)
|
|
151
|
+
class RoutedCommand:
|
|
152
|
+
command: str
|
|
153
|
+
args: str = ""
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def text(self) -> str:
|
|
157
|
+
return f"{self.command} {self.args}".strip()
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@dataclass(frozen=True)
|
|
161
|
+
class TechnicalArgs:
|
|
162
|
+
symbol: str
|
|
163
|
+
days: int = 120
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass(frozen=True)
|
|
167
|
+
class AnalysisArgs:
|
|
168
|
+
symbol: str
|
|
169
|
+
focus: str = ""
|
|
170
|
+
lang: str = ""
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
_ANALYSIS_FOCUS_HINTS: tuple[tuple[tuple[str, ...], str], ...] = (
|
|
174
|
+
(("成交量", "交易量", "量价", "放量", "缩量", "volume", "volumes"), "volume"),
|
|
175
|
+
(("市值", "market cap", "marketcap", "capitalization"), "market_cap"),
|
|
176
|
+
(("基本面", "fundamental", "fundamentals", "valuation", "估值"), "fundamentals"),
|
|
177
|
+
(("技术面", "technical", "rsi", "macd", "支撑", "阻力"), "technical"),
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _analysis_focus_from_text(text: str) -> str:
|
|
182
|
+
low = text.lower()
|
|
183
|
+
for keywords, focus in _ANALYSIS_FOCUS_HINTS:
|
|
184
|
+
if any(k in low for k in keywords):
|
|
185
|
+
return focus
|
|
186
|
+
return ""
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def parse_analysis_args(args: str, *, default_symbol: str = "AAPL") -> AnalysisArgs:
|
|
190
|
+
"""Resolve natural-language /analyze args to one clean symbol plus focus."""
|
|
191
|
+
raw = (args or "").strip()
|
|
192
|
+
focus = ""
|
|
193
|
+
lang = ""
|
|
194
|
+
parts = raw.split()
|
|
195
|
+
cleaned_parts: list[str] = []
|
|
196
|
+
skip_next = False
|
|
197
|
+
for idx, part in enumerate(parts):
|
|
198
|
+
if skip_next:
|
|
199
|
+
skip_next = False
|
|
200
|
+
continue
|
|
201
|
+
token = part.strip()
|
|
202
|
+
low = token.lower()
|
|
203
|
+
if low.startswith("--focus="):
|
|
204
|
+
focus = low.split("=", 1)[1].strip()
|
|
205
|
+
continue
|
|
206
|
+
if low == "--focus" and idx + 1 < len(parts):
|
|
207
|
+
focus = parts[idx + 1].strip().lower()
|
|
208
|
+
skip_next = True
|
|
209
|
+
continue
|
|
210
|
+
if low.startswith("--lang="):
|
|
211
|
+
lang = low.split("=", 1)[1].strip().lower()
|
|
212
|
+
continue
|
|
213
|
+
if low == "--lang" and idx + 1 < len(parts):
|
|
214
|
+
lang = parts[idx + 1].strip().lower()
|
|
215
|
+
skip_next = True
|
|
216
|
+
continue
|
|
217
|
+
cleaned_parts.append(token)
|
|
218
|
+
|
|
219
|
+
cleaned = " ".join(cleaned_parts).strip()
|
|
220
|
+
if not focus:
|
|
221
|
+
focus = _analysis_focus_from_text(raw)
|
|
222
|
+
|
|
223
|
+
symbols = _route_symbols(cleaned or raw, limit=1)
|
|
224
|
+
symbol = symbols[0] if symbols else ""
|
|
225
|
+
if not symbol:
|
|
226
|
+
symbol = _extract_market_symbol(cleaned) or _extract_market_symbol((cleaned or raw).upper())
|
|
227
|
+
if not symbol:
|
|
228
|
+
for token in cleaned_parts:
|
|
229
|
+
candidate = token.strip(",,.。::;;()()[]【】").upper()
|
|
230
|
+
if candidate and not candidate.startswith("-") and not _is_blocked_market_symbol_candidate(candidate):
|
|
231
|
+
symbol = candidate
|
|
232
|
+
break
|
|
233
|
+
if lang not in ("zh", "en"):
|
|
234
|
+
zh_chars = sum(1 for c in raw if "\u4e00" <= c <= "\u9fff")
|
|
235
|
+
lang = "zh" if zh_chars else ""
|
|
236
|
+
return AnalysisArgs(symbol=(symbol or default_symbol).upper(), focus=focus, lang=lang)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def route_top_level_text(user_input: str, available_commands: set[str]) -> RoutedCommand | None:
|
|
240
|
+
"""Translate bare workflow text into a slash command when possible."""
|
|
241
|
+
|
|
242
|
+
stripped = user_input.strip()
|
|
243
|
+
if not stripped or stripped.startswith("/"):
|
|
244
|
+
return None
|
|
245
|
+
|
|
246
|
+
low = stripped.lower()
|
|
247
|
+
|
|
248
|
+
# ── Auto-Intercept SWE / Coding Intents ─────────────────
|
|
249
|
+
# If the user asks for coding tasks, instantly route to orchestrator (/route)
|
|
250
|
+
# allowing zero-friction natural language without typing /route.
|
|
251
|
+
swe_keywords = ["修 bug", "写代码", "写个", "写一个", "脚本", "bug", "代码", "报错", "前端", "后端", "测试", "项目", "github", "issue", "截图", "页面"]
|
|
252
|
+
if any(k in low for k in swe_keywords) and len(stripped) > 5:
|
|
253
|
+
if "/route" in available_commands:
|
|
254
|
+
return RoutedCommand(command="/route", args=stripped)
|
|
255
|
+
low = stripped.lower()
|
|
256
|
+
compact_low = low.replace(" ", "")
|
|
257
|
+
low_words = {part.strip(".,,。::;;") for part in low.split()}
|
|
258
|
+
if "/tv" in available_commands and (
|
|
259
|
+
any(k in low for k in _TRADINGVIEW_HINTS)
|
|
260
|
+
or "tv" in low_words
|
|
261
|
+
or any(k in compact_low for k in _TRADINGVIEW_ZH_HINTS)
|
|
262
|
+
or ("tradingview" in compact_low)
|
|
263
|
+
):
|
|
264
|
+
symbols = _route_symbols(stripped)
|
|
265
|
+
symbol = symbols[0] if symbols else ""
|
|
266
|
+
if symbol:
|
|
267
|
+
opts: list[str] = []
|
|
268
|
+
if any(k in low for k in ("pine", "strategy", "策略")):
|
|
269
|
+
opts.append("--pine")
|
|
270
|
+
if any(k in low for k in ("copy", "clipboard", "复制", "剪贴板")):
|
|
271
|
+
opts.append("--copy")
|
|
272
|
+
if any(k in low for k in ("reveal", "finder", "所在目录", "访达", "目录")):
|
|
273
|
+
opts.append("--reveal")
|
|
274
|
+
if any(k in low for k in ("txt", "text file", "文本副本", "文本")):
|
|
275
|
+
opts.append("--txt")
|
|
276
|
+
if any(k in low for k in ("打开", "open")) and "--pine" not in opts:
|
|
277
|
+
opts.append("--open")
|
|
278
|
+
if "--pine" not in opts:
|
|
279
|
+
if any(k in low for k in _TRADINGVIEW_BULLISH_HINTS):
|
|
280
|
+
opts.append("--bullish")
|
|
281
|
+
elif any(k in low for k in _TRADINGVIEW_BEARISH_HINTS):
|
|
282
|
+
opts.append("--bearish")
|
|
283
|
+
elif any(k in low for k in _TRADINGVIEW_ANALYSIS_HINTS):
|
|
284
|
+
opts.append("--analyze")
|
|
285
|
+
return RoutedCommand(command="/tv", args=" ".join([symbol, *opts]).strip())
|
|
286
|
+
for keywords, command in _VISUAL_ROUTE_PATTERNS:
|
|
287
|
+
if command not in available_commands:
|
|
288
|
+
continue
|
|
289
|
+
if any(k in low for k in keywords):
|
|
290
|
+
symbols = _route_symbols(stripped)
|
|
291
|
+
symbol = symbols[0] if symbols else ""
|
|
292
|
+
if command == "/dashboard":
|
|
293
|
+
mode = next(
|
|
294
|
+
(
|
|
295
|
+
dashboard_mode
|
|
296
|
+
for mode_kw, dashboard_mode in _DASHBOARD_MODE_HINTS
|
|
297
|
+
if any(k in low for k in mode_kw)
|
|
298
|
+
),
|
|
299
|
+
"brief",
|
|
300
|
+
)
|
|
301
|
+
return RoutedCommand(command=command, args=mode)
|
|
302
|
+
if command == "/chart":
|
|
303
|
+
if not symbols:
|
|
304
|
+
# A chart keyword with no resolvable symbol is a question
|
|
305
|
+
# ABOUT charting ("你会制作图表吗"), not a chart request.
|
|
306
|
+
# Routing the raw sentence produced `/chart <whole question>`
|
|
307
|
+
# and a guaranteed data-fetch failure; let the LLM answer.
|
|
308
|
+
continue
|
|
309
|
+
period = next(
|
|
310
|
+
(
|
|
311
|
+
period
|
|
312
|
+
for period_kw, period in _CHART_PERIOD_HINTS
|
|
313
|
+
if any(k in low for k in period_kw)
|
|
314
|
+
),
|
|
315
|
+
"1y",
|
|
316
|
+
)
|
|
317
|
+
rest = " ".join(symbols)
|
|
318
|
+
return RoutedCommand(command=command, args=f"{rest} {period}".strip())
|
|
319
|
+
if command == "/report":
|
|
320
|
+
report_type = next(
|
|
321
|
+
(
|
|
322
|
+
report_type
|
|
323
|
+
for type_kw, report_type in _REPORT_TYPE_HINTS
|
|
324
|
+
if any(k in low for k in type_kw)
|
|
325
|
+
),
|
|
326
|
+
"standard",
|
|
327
|
+
)
|
|
328
|
+
fmt = "html"
|
|
329
|
+
if any(k in low for k in ("markdown", "md")):
|
|
330
|
+
fmt = "md"
|
|
331
|
+
if not symbol:
|
|
332
|
+
continue # same rule as /chart: no symbol → not a report request
|
|
333
|
+
args = " ".join(part for part in [symbol, f"--type {report_type}" if report_type else "", f"--format {fmt}" if fmt else ""] if part)
|
|
334
|
+
return RoutedCommand(command=command, args=args)
|
|
335
|
+
if "/news" in available_commands and not _is_news_discussion(stripped) and any(k in low for k in (
|
|
336
|
+
"新闻", "消息", "最新进展", "最近进展", "news", "latest", "recent",
|
|
337
|
+
)):
|
|
338
|
+
symbols = _route_symbols(stripped)
|
|
339
|
+
return RoutedCommand(command="/news", args=_news_topic(stripped, symbols))
|
|
340
|
+
parts = stripped.split(maxsplit=1)
|
|
341
|
+
keyword = parts[0].lower()
|
|
342
|
+
rest = parts[1] if len(parts) > 1 else ""
|
|
343
|
+
command = TOP_LEVEL_ROUTES.get(keyword)
|
|
344
|
+
if not command or command not in available_commands:
|
|
345
|
+
return None
|
|
346
|
+
if command == "/analyze":
|
|
347
|
+
parsed = parse_analysis_args(rest)
|
|
348
|
+
focus_arg = f" --focus {parsed.focus}" if parsed.focus else ""
|
|
349
|
+
zh_chars = sum(1 for c in stripped if "\u4e00" <= c <= "\u9fff")
|
|
350
|
+
lang_arg = f" --lang {'zh' if zh_chars else 'en'}"
|
|
351
|
+
return RoutedCommand(command=command, args=f"{parsed.symbol}{focus_arg}{lang_arg}".strip())
|
|
352
|
+
return RoutedCommand(command=command, args=rest)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def parse_symbols(args: str, fallback: list[str] | tuple[str, ...]) -> list[str]:
|
|
356
|
+
symbols = [part.upper() for part in args.split() if part.strip()]
|
|
357
|
+
return symbols or [str(item).upper() for item in fallback]
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def sanitize_chart_symbol_args(raw_symbols: list[str] | tuple[str, ...]) -> list[str]:
|
|
361
|
+
"""Drop analysis words that sometimes leak into chart symbol arguments."""
|
|
362
|
+
cleaned = [str(item or "").strip().strip(",,") for item in raw_symbols]
|
|
363
|
+
cleaned = [item for item in cleaned if item]
|
|
364
|
+
if not cleaned:
|
|
365
|
+
return []
|
|
366
|
+
if len(cleaned) == 1:
|
|
367
|
+
upper = cleaned[0].upper()
|
|
368
|
+
return [] if _is_blocked_market_symbol_candidate(upper) else cleaned
|
|
369
|
+
|
|
370
|
+
upper_tokens = [item.upper() for item in cleaned]
|
|
371
|
+
has_context_noise = any(
|
|
372
|
+
token in _CHART_CONTEXT_TOKEN_BLOCKLIST or _is_blocked_market_symbol_candidate(token)
|
|
373
|
+
for token in upper_tokens
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
out: list[str] = []
|
|
377
|
+
for raw, upper in zip(cleaned, upper_tokens):
|
|
378
|
+
if upper in _CHART_CONTEXT_TOKEN_BLOCKLIST:
|
|
379
|
+
continue
|
|
380
|
+
if _is_blocked_market_symbol_candidate(upper):
|
|
381
|
+
continue
|
|
382
|
+
# MA is a valid ticker (Mastercard), but in noisy generated chart args it
|
|
383
|
+
# usually comes from moving-average text next to TTM/above/below terms.
|
|
384
|
+
if upper == "MA" and has_context_noise and len(cleaned) > 2:
|
|
385
|
+
continue
|
|
386
|
+
out.append(raw)
|
|
387
|
+
return out
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def parse_technical_args(args: str, *, default_symbol: str = "AAPL", default_days: int = 120) -> TechnicalArgs:
|
|
391
|
+
parts = args.strip().split()
|
|
392
|
+
symbol = default_symbol.upper()
|
|
393
|
+
days = default_days
|
|
394
|
+
|
|
395
|
+
if parts and not parts[0].startswith("-") and not parts[0].startswith("days="):
|
|
396
|
+
symbol = parts[0].upper()
|
|
397
|
+
option_parts = parts[1:]
|
|
398
|
+
else:
|
|
399
|
+
option_parts = parts
|
|
400
|
+
|
|
401
|
+
skip_next = False
|
|
402
|
+
for idx, part in enumerate(option_parts):
|
|
403
|
+
if skip_next:
|
|
404
|
+
skip_next = False
|
|
405
|
+
continue
|
|
406
|
+
raw = part.strip()
|
|
407
|
+
value = None
|
|
408
|
+
if raw.startswith("days="):
|
|
409
|
+
value = raw.split("=", 1)[1]
|
|
410
|
+
elif raw.startswith("--days="):
|
|
411
|
+
value = raw.split("=", 1)[1]
|
|
412
|
+
elif raw == "--days" and idx + 1 < len(option_parts):
|
|
413
|
+
value = option_parts[idx + 1]
|
|
414
|
+
skip_next = True
|
|
415
|
+
|
|
416
|
+
if value is not None:
|
|
417
|
+
try:
|
|
418
|
+
parsed = int(value)
|
|
419
|
+
if parsed > 0:
|
|
420
|
+
days = parsed
|
|
421
|
+
except ValueError:
|
|
422
|
+
pass
|
|
423
|
+
|
|
424
|
+
return TechnicalArgs(symbol=symbol, days=days)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
async def try_top_level_route(user_input: str, commands) -> bool:
|
|
428
|
+
"""Execute a top-level routed slash command through a SlashCommands object."""
|
|
429
|
+
|
|
430
|
+
routed = route_top_level_text(user_input, set(commands.commands))
|
|
431
|
+
if routed is None:
|
|
432
|
+
return False
|
|
433
|
+
await commands.execute(routed.text)
|
|
434
|
+
return True
|