aria-code 0.167.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_bots/__init__.py +7 -0
- aria_bots/channels/README.md +97 -0
- aria_bots/channels/__init__.py +1 -0
- aria_bots/channels/approvals.py +263 -0
- aria_bots/channels/conversation.py +280 -0
- aria_bots/channels/digest.py +186 -0
- aria_bots/channels/registry.py +95 -0
- aria_bots/engine.py +144 -0
- aria_bots/feishu_bot.py +1385 -0
- aria_bots/logistics/__init__.py +1 -0
- aria_bots/logistics/carriers.py +253 -0
- aria_bots/logistics/freight.py +154 -0
- aria_bots/logistics/inventory.py +242 -0
- aria_bots/logistics/mcp_server.py +156 -0
- aria_bots/logistics/records.py +119 -0
- aria_bots/logistics/tenancy.py +152 -0
- aria_bots/market.py +91 -0
- aria_bots/relay_client.py +326 -0
- aria_bots/telegram_bot.py +299 -0
- aria_code/__init__.py +111 -0
- aria_code/_bin/aria-native.exe +0 -0
- aria_code/_bin/aria-runtime.exe +0 -0
- aria_code/_version.py +20 -0
- aria_code/account_memory.py +296 -0
- aria_code/account_session.py +166 -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 +49 -0
- aria_code/agents/base.py +329 -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 +315 -0
- aria_code/agents/financial/fundamental.py +178 -0
- aria_code/agents/financial/macro.py +111 -0
- aria_code/agents/financial/news.py +231 -0
- aria_code/agents/financial/risk.py +146 -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 +277 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +392 -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 +168 -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 +500 -0
- aria_code/agents/video/__init__.py +16 -0
- aria_code/agents/video/director.py +376 -0
- aria_code/agents/video/qa_agent.py +143 -0
- aria_code/agents/video/script_doctor.py +112 -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/navigation.schema.json +110 -0
- aria_code/agents/warehouse/task_agent.py +172 -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 +9 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/approvals.py +11 -0
- aria_code/apps/channels/conversation.py +11 -0
- aria_code/apps/channels/digest.py +11 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +11 -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/app_server.py +656 -0
- aria_code/apps/cli/auto_update.py +125 -0
- aria_code/apps/cli/bootstrap.py +206 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/chat_turn.py +1327 -0
- aria_code/apps/cli/cloud_models.py +231 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +34 -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 +378 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +215 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
- aria_code/apps/cli/commands/broker_cmds.py +1236 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +189 -0
- aria_code/apps/cli/commands/core_cmds.py +2748 -0
- aria_code/apps/cli/commands/data_cmds.py +521 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/engineering_cmds.py +399 -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 +544 -0
- aria_code/apps/cli/commands/market_cmds.py +1419 -0
- aria_code/apps/cli/commands/market_context.py +432 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2374 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
- aria_code/apps/cli/commands/report.py +476 -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 +723 -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 +297 -0
- aria_code/apps/cli/commands/workflow_cmds.py +629 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +158 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/conversation_policy.py +53 -0
- aria_code/apps/cli/deterministic.py +200 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/earnings_view.py +172 -0
- aria_code/apps/cli/endpoint_migration.py +64 -0
- aria_code/apps/cli/exec_events.py +255 -0
- aria_code/apps/cli/file_references.py +155 -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 +239 -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 +1314 -0
- aria_code/apps/cli/handlers/market_handlers.py +2570 -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/headless.py +352 -0
- aria_code/apps/cli/helpers.py +326 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +310 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +305 -0
- aria_code/apps/cli/intent_shadow.py +72 -0
- aria_code/apps/cli/intent_signals.py +347 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +550 -0
- aria_code/apps/cli/main.py +39 -0
- aria_code/apps/cli/market_hours.py +100 -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/mixin_binding.py +32 -0
- aria_code/apps/cli/model_catalog.py +652 -0
- aria_code/apps/cli/model_probe.py +169 -0
- aria_code/apps/cli/model_retirement.py +65 -0
- aria_code/apps/cli/native_branding.py +12 -0
- aria_code/apps/cli/native_bridge.py +118 -0
- aria_code/apps/cli/native_entry.py +58 -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 +78 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +71 -0
- aria_code/apps/cli/prompts/select.py +193 -0
- aria_code/apps/cli/prompts/system_prompts.py +562 -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 +775 -0
- aria_code/apps/cli/providers/chat_routing.py +139 -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 +1574 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
- aria_code/apps/cli/providers/runtime_bridge.py +586 -0
- aria_code/apps/cli/providers/vertexai_stream.py +592 -0
- aria_code/apps/cli/release_download.py +159 -0
- aria_code/apps/cli/review_runner.py +111 -0
- aria_code/apps/cli/runtime_consumer.py +769 -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_refresh.py +123 -0
- aria_code/apps/cli/session_store.py +125 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/task_isolation.py +211 -0
- aria_code/apps/cli/terminal_chrome.py +412 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +932 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +113 -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 +181 -0
- aria_code/apps/cli/tools/market_tools.py +626 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +656 -0
- aria_code/apps/cli/tools/write_tools.py +961 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/transactions.py +269 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +257 -0
- aria_code/apps/cli/updater.py +373 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1663 -0
- aria_code/apps/cli/web_login.py +136 -0
- aria_code/apps/cli/workflow_runner.py +127 -0
- aria_code/apps/cli/workspace_route.py +121 -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 +5244 -0
- aria_code/aria_daemon.py +1372 -0
- aria_code/aria_feishu_bot.py +16 -0
- aria_code/aria_mcp_server.py +61 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_telegram_bot.py +11 -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 +16 -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 +1985 -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 +190 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_server.py +276 -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/sec_statements.py +217 -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/doctor.py +860 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/_finance_core/__init__.py +5 -0
- aria_code/domain/_finance_core/backtest_engine.py +325 -0
- aria_code/domain/_finance_core/performance_stats.py +101 -0
- aria_code/domain/backtest_engine.py +75 -0
- aria_code/domain/backtest_report.py +488 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/performance_stats.py +6 -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/behavior.py +113 -0
- aria_code/evals/gap.py +93 -0
- aria_code/evals/harness.py +949 -0
- aria_code/evals/review_probe.py +132 -0
- aria_code/evals/runner.py +425 -0
- aria_code/evals/scorecard.py +322 -0
- aria_code/evals/summary.py +125 -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 +459 -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 +744 -0
- aria_code/memory_manager.py +273 -0
- aria_code/model_capability.py +512 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +26 -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 +58 -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 +232 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +162 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1705 -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 +393 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +75 -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 +304 -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 +137 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +160 -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 +5 -0
- aria_code/packages/aria_tools/financial/_paths.py +92 -0
- aria_code/packages/aria_tools/registry.py +129 -0
- aria_code/packages/quant_engine/__init__.py +33 -0
- aria_code/packages/quant_engine/_namespace.py +24 -0
- aria_code/packages/quant_engine/backtest/__init__.py +10 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +102 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +76 -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/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +31 -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/healthcare/__init__.py +40 -0
- aria_code/packs/logistics/__init__.py +171 -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/google_video_provider.py +256 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/arthera_gateway.py +90 -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 +137 -0
- aria_code/providers/llm/openai_compat.py +350 -0
- aria_code/providers/llm/registry.py +457 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +549 -0
- aria_code/providers/ollama_models.py +79 -0
- aria_code/providers/openai_params.py +32 -0
- aria_code/providers/tool_messages.py +100 -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/review_service.py +497 -0
- aria_code/runtime/__init__.py +176 -0
- aria_code/runtime/acceptance.py +632 -0
- aria_code/runtime/agent_loop.py +1851 -0
- aria_code/runtime/agent_profiles.py +75 -0
- aria_code/runtime/approval.py +71 -0
- aria_code/runtime/baseline.py +219 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +481 -0
- aria_code/runtime/consult.py +65 -0
- aria_code/runtime/contract.py +282 -0
- aria_code/runtime/delivery.py +432 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +167 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/native_index.py +153 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/processes.py +343 -0
- aria_code/runtime/project_graph.py +614 -0
- aria_code/runtime/repo_map.py +712 -0
- aria_code/runtime/research_bundle.py +105 -0
- aria_code/runtime/review.py +269 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +522 -0
- aria_code/runtime/scoped_runs.py +113 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/semantic_diff.py +171 -0
- aria_code/runtime/subagent.py +721 -0
- aria_code/runtime/symbol_edit.py +117 -0
- aria_code/runtime/task_brief.py +46 -0
- aria_code/runtime/task_context.py +145 -0
- aria_code/runtime/task_ledger.py +108 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/task_outcome.py +33 -0
- aria_code/runtime/task_verification.py +266 -0
- aria_code/runtime/task_worktree.py +448 -0
- aria_code/runtime/tool_executor.py +329 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/transactions.py +216 -0
- aria_code/runtime/windows_job.py +115 -0
- aria_code/runtime/workflows.py +222 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +27 -0
- aria_code/safety/client_isolation.py +178 -0
- aria_code/safety/permissions.py +339 -0
- aria_code/safety/risk.py +699 -0
- aria_code/safety/sandbox.py +148 -0
- aria_code/safety/service.py +102 -0
- aria_code/service_endpoints.py +14 -0
- aria_code/setup_wizard.py +684 -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 +509 -0
- aria_code/tools/data_analysis_tools.py +831 -0
- aria_code/tools/enterprise_finance_tools.py +202 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +880 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3488 -0
- aria_code/tools/logistics_carriers.py +11 -0
- aria_code/tools/logistics_inventory.py +11 -0
- aria_code/tools/logistics_io.py +11 -0
- aria_code/tools/logistics_tenancy.py +11 -0
- aria_code/tools/logistics_tools.py +11 -0
- aria_code/tools/macro_tools.py +412 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +662 -0
- aria_code/tools/spreadsheet_tools.py +399 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/tools/video_tools.py +500 -0
- aria_code/training/__init__.py +1 -0
- aria_code/training/compare.py +117 -0
- aria_code/training/prelude_commands.py +111 -0
- aria_code/training/prelude_eval.py +390 -0
- aria_code/training/prelude_real.py +183 -0
- aria_code/training/prelude_train.py +248 -0
- aria_code/training/sft_dataset.py +230 -0
- aria_code/training/trajectory_dataset.py +263 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +404 -0
- aria_code/ui/completer.py +571 -0
- aria_code/ui/console.py +285 -0
- aria_code/ui/input_box.py +505 -0
- aria_code/ui/mentions.py +206 -0
- aria_code/ui/picker.py +248 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/actions.py +297 -0
- aria_code/ui/render/finance.py +1732 -0
- aria_code/ui/render/market.py +253 -0
- aria_code/ui/render/output.py +954 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +367 -0
- aria_code/ui/robot.py +239 -0
- aria_code/ui/startup_dashboard.py +110 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +518 -0
- aria_code/video_workflow/__init__.py +8 -0
- aria_code/video_workflow/__main__.py +61 -0
- aria_code/video_workflow/engines/__init__.py +18 -0
- aria_code/video_workflow/engines/base.py +69 -0
- aria_code/video_workflow/engines/custom_model.py +204 -0
- aria_code/video_workflow/engines/google_veo.py +94 -0
- aria_code/video_workflow/engines/local_engine.py +71 -0
- aria_code/video_workflow/engines/registry.py +98 -0
- aria_code/video_workflow/google_models.py +278 -0
- aria_code/video_workflow/music/__init__.py +5 -0
- aria_code/video_workflow/music/foley_service.py +132 -0
- aria_code/video_workflow/music/service.py +212 -0
- aria_code/video_workflow/pipeline.py +620 -0
- aria_code/video_workflow/plan.py +202 -0
- aria_code/video_workflow/session.py +297 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +219 -0
- aria_code/workspace/verify.py +167 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.167.0.dist-info/METADATA +330 -0
- aria_code-0.167.0.dist-info/RECORD +601 -0
- aria_code-0.167.0.dist-info/WHEEL +5 -0
- aria_code-0.167.0.dist-info/entry_points.txt +5 -0
- aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.167.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""CLI bridge for QuantEngine's auditable next-session A-share predictions.
|
|
2
|
+
|
|
3
|
+
The bridge intentionally keeps prediction execution explicit. A market snapshot
|
|
4
|
+
is cheap and safe to show automatically; a cross-sectional prediction run may
|
|
5
|
+
fetch thousands of histories and writes an auditable report, so it only runs
|
|
6
|
+
after the user enters ``/ashare predict``.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from datetime import date
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class ASharePredictArgs:
|
|
18
|
+
universe: str = "core50"
|
|
19
|
+
limit: int | None = None
|
|
20
|
+
period: str = "1y"
|
|
21
|
+
strategy: str = "momentum"
|
|
22
|
+
include_ai_analysis: bool = True
|
|
23
|
+
include_ml_confirmation: bool = True
|
|
24
|
+
universe_file: str = ""
|
|
25
|
+
live_universe: bool = False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def parse_ashare_predict_args(text: str) -> ASharePredictArgs:
|
|
29
|
+
"""Parse ``/ashare predict`` flags without importing the QuantEngine."""
|
|
30
|
+
tokens = str(text or "").split()
|
|
31
|
+
universe = "core50"
|
|
32
|
+
limit: int | None = None
|
|
33
|
+
period, strategy, universe_file = "1y", "momentum", ""
|
|
34
|
+
include_ai_analysis = include_ml_confirmation = True
|
|
35
|
+
live_universe = False
|
|
36
|
+
index = 0
|
|
37
|
+
if tokens and not tokens[0].startswith("--"):
|
|
38
|
+
universe = tokens[0].lower()
|
|
39
|
+
index = 1
|
|
40
|
+
while index < len(tokens):
|
|
41
|
+
token = tokens[index]
|
|
42
|
+
if token in {"--limit", "--period", "--strategy", "--universe-file"}:
|
|
43
|
+
if index + 1 >= len(tokens):
|
|
44
|
+
raise ValueError(f"{token} requires a value")
|
|
45
|
+
value = tokens[index + 1]
|
|
46
|
+
if token == "--limit":
|
|
47
|
+
limit = int(value)
|
|
48
|
+
if limit < 1:
|
|
49
|
+
raise ValueError("--limit must be positive")
|
|
50
|
+
elif token == "--period":
|
|
51
|
+
period = value
|
|
52
|
+
elif token == "--strategy":
|
|
53
|
+
strategy = value
|
|
54
|
+
else:
|
|
55
|
+
universe_file = value
|
|
56
|
+
index += 2
|
|
57
|
+
continue
|
|
58
|
+
if token == "--no-ai":
|
|
59
|
+
include_ai_analysis = False
|
|
60
|
+
elif token == "--no-ml":
|
|
61
|
+
include_ml_confirmation = False
|
|
62
|
+
elif token == "--live-universe":
|
|
63
|
+
live_universe = True
|
|
64
|
+
else:
|
|
65
|
+
raise ValueError(f"unknown option: {token}")
|
|
66
|
+
index += 1
|
|
67
|
+
if universe not in {"core50", "default", "broad", "broad200", "all"}:
|
|
68
|
+
raise ValueError("universe must be core50, broad, broad200, or all")
|
|
69
|
+
return ASharePredictArgs(
|
|
70
|
+
universe=universe, limit=limit, period=period, strategy=strategy,
|
|
71
|
+
include_ai_analysis=include_ai_analysis,
|
|
72
|
+
include_ml_confirmation=include_ml_confirmation,
|
|
73
|
+
universe_file=universe_file,
|
|
74
|
+
live_universe=live_universe,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def load_universe_file(path: str) -> list[str]:
|
|
79
|
+
"""Load a simple comma/newline-separated stock universe with no coercion."""
|
|
80
|
+
source = Path(path).expanduser()
|
|
81
|
+
if not source.is_file():
|
|
82
|
+
raise ValueError(f"universe file not found: {source}")
|
|
83
|
+
return list(dict.fromkeys(
|
|
84
|
+
item.strip().upper()
|
|
85
|
+
for item in source.read_text(encoding="utf-8").replace("\n", ",").split(",")
|
|
86
|
+
if item.strip()
|
|
87
|
+
))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def fetch_live_ashare_universe(*, include_st: bool = False) -> tuple[list[str], dict]:
|
|
91
|
+
"""Get the current listed A-share code universe from AkShare's spot feed.
|
|
92
|
+
|
|
93
|
+
This is only universe discovery; it does not claim price history is clean or
|
|
94
|
+
tradeable. The prediction service subsequently applies its own data-quality
|
|
95
|
+
and execution gates before issuing any candidate label.
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
import akshare as ak
|
|
99
|
+
except ImportError as exc:
|
|
100
|
+
raise RuntimeError("AkShare is required: install aria-code[cn]") from exc
|
|
101
|
+
frame = ak.stock_zh_a_spot_em()
|
|
102
|
+
if frame is None or getattr(frame, "empty", True):
|
|
103
|
+
raise RuntimeError("AkShare returned an empty A-share spot universe")
|
|
104
|
+
records = frame.to_dict("records")
|
|
105
|
+
codes, excluded_st = [], 0
|
|
106
|
+
allowed_prefixes = ("000", "001", "002", "003", "300", "301", "600", "601", "603", "605", "688", "689", "4", "8")
|
|
107
|
+
for row in records:
|
|
108
|
+
code = str(row.get("代码") or row.get("code") or "").strip()
|
|
109
|
+
name = str(row.get("名称") or row.get("name") or "").upper()
|
|
110
|
+
if len(code) != 6 or not code.isdigit() or not code.startswith(allowed_prefixes):
|
|
111
|
+
continue
|
|
112
|
+
if not include_st and ("ST" in name or "退" in name):
|
|
113
|
+
excluded_st += 1
|
|
114
|
+
continue
|
|
115
|
+
codes.append(code)
|
|
116
|
+
codes = list(dict.fromkeys(codes))
|
|
117
|
+
if not codes:
|
|
118
|
+
raise RuntimeError("No eligible A-share codes found in AkShare spot feed")
|
|
119
|
+
return codes, {"source": "akshare.stock_zh_a_spot_em", "count": len(codes), "excluded_st": excluded_st}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def prediction_freshness(result: dict, today: date | None = None) -> dict:
|
|
123
|
+
"""Classify an existing run without claiming a stale result is live."""
|
|
124
|
+
today = today or date.today()
|
|
125
|
+
quality = result.get("dataQuality") or {}
|
|
126
|
+
latest = str(quality.get("latestDataDate") or "")
|
|
127
|
+
try:
|
|
128
|
+
last_date = date.fromisoformat(f"{latest[:4]}-{latest[4:6]}-{latest[6:8]}")
|
|
129
|
+
age_days = (today - last_date).days
|
|
130
|
+
except (TypeError, ValueError):
|
|
131
|
+
last_date, age_days = None, None
|
|
132
|
+
return {
|
|
133
|
+
"latest_data_date": latest or None,
|
|
134
|
+
"age_days": age_days,
|
|
135
|
+
"is_quality_pass": quality.get("qualityStatus") == "pass",
|
|
136
|
+
"is_current": bool(last_date and age_days is not None and age_days <= 1),
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def build_prediction_service(config: dict):
|
|
141
|
+
"""Create the platform service with a stable, user-visible report location."""
|
|
142
|
+
from packages.quant_engine.services.daily_ashare_prediction_service import DailyASharePredictionService
|
|
143
|
+
|
|
144
|
+
service = DailyASharePredictionService()
|
|
145
|
+
configured = str(config.get("ashare_prediction_dir") or os.getenv("ARTHERA_DAILY_PREDICTION_DIR") or "").strip()
|
|
146
|
+
if configured:
|
|
147
|
+
service.storage_dir = Path(configured).expanduser()
|
|
148
|
+
else:
|
|
149
|
+
# Existing platform installs wrote their reports here. Prefer that
|
|
150
|
+
# location when present so the CLI can diagnose historical freshness.
|
|
151
|
+
platform_dir = Path(__file__).resolve().parents[4] / "Arthera" / "packages" / "risk_reports" / "ashare_daily"
|
|
152
|
+
if platform_dir.is_dir():
|
|
153
|
+
service.storage_dir = platform_dir
|
|
154
|
+
service.storage_dir.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
return service
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
import json
|
|
159
|
+
import asyncio
|
|
160
|
+
import datetime
|
|
161
|
+
import time
|
|
162
|
+
import shlex
|
|
163
|
+
from typing import Dict, Any, Optional
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
import json
|
|
167
|
+
import asyncio
|
|
168
|
+
import datetime
|
|
169
|
+
import time
|
|
170
|
+
import shlex
|
|
171
|
+
import sys
|
|
172
|
+
import os
|
|
173
|
+
from typing import Dict, Any, Optional
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
import json
|
|
177
|
+
import asyncio
|
|
178
|
+
import datetime
|
|
179
|
+
import time
|
|
180
|
+
import shlex
|
|
181
|
+
import sys
|
|
182
|
+
import os
|
|
183
|
+
from typing import Dict, Any, Optional
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class ASharePredictionCommandsMixin:
|
|
187
|
+
"""Expose QuantEngine prediction runs to the interactive and direct CLI."""
|
|
188
|
+
|
|
189
|
+
async def cmd_ashare(self, args: str):
|
|
190
|
+
parts = args.strip().split(maxsplit=1)
|
|
191
|
+
action = parts[0].lower() if parts else "status"
|
|
192
|
+
rest = parts[1] if len(parts) > 1 else ""
|
|
193
|
+
if action in {"status", "latest"}:
|
|
194
|
+
self._print_ashare_status(show_candidates=action == "latest")
|
|
195
|
+
return
|
|
196
|
+
if action == "predict":
|
|
197
|
+
try:
|
|
198
|
+
parsed = parse_ashare_predict_args(rest)
|
|
199
|
+
symbols = load_universe_file(parsed.universe_file) if parsed.universe_file else None
|
|
200
|
+
except ValueError as exc:
|
|
201
|
+
msg = f"⚠ {exc}"
|
|
202
|
+
self.context.console.print(f"[yellow]{msg}[/yellow]") if self.context.has_rich else print(msg)
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
# The service's built-in 'all' alias is a curated broad list, not
|
|
206
|
+
# every listed A-share. Do not let the CLI falsely label it 'all'.
|
|
207
|
+
if parsed.universe == "all" and parsed.live_universe:
|
|
208
|
+
try:
|
|
209
|
+
symbols, universe_meta = await asyncio.to_thread(fetch_live_ashare_universe)
|
|
210
|
+
except Exception as exc:
|
|
211
|
+
msg = f"无法构建实时全 A 股股票池:{exc}"
|
|
212
|
+
self.context.console.print(f"[red]{msg}[/red]") if self.context.has_rich else print(msg)
|
|
213
|
+
return
|
|
214
|
+
self.context.console.print(
|
|
215
|
+
f"[dim]已从 {universe_meta['source']} 获取 {universe_meta['count']} 只股票;"
|
|
216
|
+
f"已排除 {universe_meta['excluded_st']} 只 ST/退市风险标的。[/dim]"
|
|
217
|
+
if self.context.has_rich else f"Live universe: {universe_meta['count']} stocks"
|
|
218
|
+
)
|
|
219
|
+
if parsed.universe == "all" and not symbols:
|
|
220
|
+
msg = (
|
|
221
|
+
"全 A 股运行需要 --universe-file <文件>(一行/逗号分隔的完整当日股票池)。\n"
|
|
222
|
+
"内置 all 只是精选 broad 股票池,不能冒充全市场。"
|
|
223
|
+
)
|
|
224
|
+
self.context.console.print(f"[yellow]{msg}[/yellow]") if self.context.has_rich else print(msg)
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
# No hidden 500-stock truncation for an explicit externally supplied
|
|
228
|
+
# full universe. The service still receives a bounded list.
|
|
229
|
+
limit = parsed.limit or (len(symbols) if symbols else 500)
|
|
230
|
+
if symbols:
|
|
231
|
+
symbols = symbols[:limit]
|
|
232
|
+
scope = f"自定义股票池 {len(symbols)} 只" if symbols else f"{parsed.universe}(最多 {limit} 只)"
|
|
233
|
+
notice = (
|
|
234
|
+
f"开始 A 股次交易日预测:{scope} · {parsed.period} · {parsed.strategy}\n"
|
|
235
|
+
"将拉取历史行情并生成可审计报告;结果仅供研究/仿真,不执行交易。"
|
|
236
|
+
)
|
|
237
|
+
self.context.console.print(f"[dim]{notice}[/dim]") if self.context.has_rich else print(notice)
|
|
238
|
+
try:
|
|
239
|
+
service = build_prediction_service(self.terminal.config)
|
|
240
|
+
result = await asyncio.to_thread(
|
|
241
|
+
service.run_once, symbols=symbols, universe=parsed.universe, limit=limit,
|
|
242
|
+
period=parsed.period, strategy=parsed.strategy,
|
|
243
|
+
include_ai_analysis=parsed.include_ai_analysis,
|
|
244
|
+
include_ml_confirmation=parsed.include_ml_confirmation,
|
|
245
|
+
)
|
|
246
|
+
except Exception as exc:
|
|
247
|
+
msg = f"A 股预测引擎未能完成:{exc}"
|
|
248
|
+
self.context.console.print(f"[red]{msg}[/red]") if self.context.has_rich else print(msg)
|
|
249
|
+
return
|
|
250
|
+
self._print_ashare_result(result)
|
|
251
|
+
return
|
|
252
|
+
if action == "evaluate":
|
|
253
|
+
try:
|
|
254
|
+
result = await asyncio.to_thread(build_prediction_service(self.terminal.config).evaluate_latest, rest.strip() or None)
|
|
255
|
+
except Exception as exc:
|
|
256
|
+
msg = f"A 股预测评估未能完成:{exc}"
|
|
257
|
+
self.context.console.print(f"[red]{msg}[/red]") if self.context.has_rich else print(msg)
|
|
258
|
+
return
|
|
259
|
+
self.context.console.print(result) if self.context.has_rich else print(result)
|
|
260
|
+
return
|
|
261
|
+
if action == "universe":
|
|
262
|
+
include_st = "--include-st" in rest.split()
|
|
263
|
+
try:
|
|
264
|
+
symbols, meta = await asyncio.to_thread(fetch_live_ashare_universe, include_st=include_st)
|
|
265
|
+
except Exception as exc:
|
|
266
|
+
msg = f"无法构建实时 A 股股票池:{exc}"
|
|
267
|
+
self.context.console.print(f"[red]{msg}[/red]") if self.context.has_rich else print(msg)
|
|
268
|
+
return
|
|
269
|
+
msg = f"实时 A 股股票池:{meta['count']} 只 · 来源 {meta['source']} · 排除 ST/退市风险 {meta['excluded_st']} 只"
|
|
270
|
+
self.context.console.print(f"[green]{msg}[/green]") if self.context.has_rich else print(msg)
|
|
271
|
+
self.context.console.print("[dim]运行完整扫描:/ashare predict all --live-universe[/dim]" if self.context.has_rich else "Run: /ashare predict all --live-universe")
|
|
272
|
+
return
|
|
273
|
+
msg = "Usage: /ashare [status|latest|universe|predict|evaluate]"
|
|
274
|
+
self.context.console.print(f"[yellow]{msg}[/yellow]") if self.context.has_rich else print(msg)
|
|
275
|
+
|
|
276
|
+
def _print_ashare_status(self, *, show_candidates: bool):
|
|
277
|
+
try:
|
|
278
|
+
result = build_prediction_service(self.terminal.config).latest()
|
|
279
|
+
except Exception as exc:
|
|
280
|
+
result = None
|
|
281
|
+
error = str(exc)
|
|
282
|
+
else:
|
|
283
|
+
error = ""
|
|
284
|
+
if not result:
|
|
285
|
+
msg = f"没有本地预测结果。{'引擎不可用:' + error if error else '运行 /ashare predict core50 开始。'}"
|
|
286
|
+
self.context.console.print(f"[yellow]{msg}[/yellow]") if self.context.has_rich else print(msg)
|
|
287
|
+
return
|
|
288
|
+
freshness = prediction_freshness(result)
|
|
289
|
+
summary = result.get("summary") or {}
|
|
290
|
+
label = "当前/近一日" if freshness["is_current"] else "过期,不能作为当日预测"
|
|
291
|
+
lines = [
|
|
292
|
+
"A 股次交易日预测状态",
|
|
293
|
+
f"运行:{result.get('runId', '-')}",
|
|
294
|
+
f"数据日期:{freshness['latest_data_date'] or '-'} · {label}",
|
|
295
|
+
f"覆盖:{summary.get('succeeded', 0)}/{summary.get('requested', 0)} · 质量:{summary.get('qualityStatus', '-')}",
|
|
296
|
+
f"强候选/候选/弱候选:{summary.get('strongCandidates', 0)}/{summary.get('longCandidates', 0)}/{summary.get('weakCandidates', 0)}",
|
|
297
|
+
]
|
|
298
|
+
self.context.console.print("\n".join(lines))
|
|
299
|
+
if show_candidates:
|
|
300
|
+
self._print_ashare_result(result, include_header=False)
|
|
301
|
+
|
|
302
|
+
def _print_ashare_result(self, result: dict, *, include_header: bool = True):
|
|
303
|
+
summary = result.get("summary") or {}
|
|
304
|
+
freshness = prediction_freshness(result)
|
|
305
|
+
predictions = result.get("predictions") or []
|
|
306
|
+
candidates = [item for item in predictions if item.get("signal") in {"strong_candidate", "long_candidate", "weak_candidate"}]
|
|
307
|
+
if include_header:
|
|
308
|
+
title = "A 股次交易日预测(质量通过)" if freshness["is_quality_pass"] else "A 股次交易日预测(质量未通过)"
|
|
309
|
+
self.context.console.print(f"[bold]{title}[/bold]" if self.context.has_rich else title)
|
|
310
|
+
self.context.console.print(
|
|
311
|
+
f"覆盖 {summary.get('succeeded', 0)}/{summary.get('requested', 0)} · "
|
|
312
|
+
f"数据 {freshness['latest_data_date'] or '-'} · "
|
|
313
|
+
f"候选 {len(candidates)} · 阻断 {summary.get('blocked', 0)}"
|
|
314
|
+
)
|
|
315
|
+
if not freshness["is_current"]:
|
|
316
|
+
self.context.console.print("[yellow]⚠ 数据不是当前交易日前一日,结果只可作为历史记录。[/yellow]" if self.context.has_rich else "⚠ Result is stale; historical only.")
|
|
317
|
+
for item in candidates[:10]:
|
|
318
|
+
pred = item.get("prediction") or {}
|
|
319
|
+
line = (
|
|
320
|
+
f" {item.get('rank', '-'):>2}. {item.get('symbol', '-')} {item.get('signal', '-')} "
|
|
321
|
+
f"上涨概率 {float(pred.get('upProbability') or 0):.1%} "
|
|
322
|
+
f"预测收益 {float(pred.get('predictedReturn') or 0):+.1%} "
|
|
323
|
+
f"风险 {float(pred.get('riskScore') or 0):.2f}"
|
|
324
|
+
)
|
|
325
|
+
self.context.console.print(line)
|
|
326
|
+
if not candidates:
|
|
327
|
+
self.context.console.print(" 无通过候选;不应以模型名义强行给出买入名单。")
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""Account commands use the same Firebase UID as Web and desktop."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import asyncio
|
|
5
|
+
import sys
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from ._ui import print_error
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _esc_watcher():
|
|
11
|
+
from aria_code.aria_cli import _esc_watcher as watcher
|
|
12
|
+
|
|
13
|
+
return watcher
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AuthCommandsMixin:
|
|
17
|
+
"""Mixin: authentication commands (/login, /logout, /whoami)."""
|
|
18
|
+
|
|
19
|
+
async def cmd_login(self, args: str):
|
|
20
|
+
"""Sign in to Arthera.
|
|
21
|
+
|
|
22
|
+
Usage: /login — sign in or sign up in the browser
|
|
23
|
+
/login <email> — email + password, prompted securely
|
|
24
|
+
|
|
25
|
+
Bare ``/login`` opens the browser, the way Claude Code and Codex do it.
|
|
26
|
+
Signing in there covers signing up too: the gateway serves the model, so
|
|
27
|
+
a new account has a working setup without configuring any API key. The
|
|
28
|
+
email/password path stays for accounts that predate it and for machines
|
|
29
|
+
with no browser.
|
|
30
|
+
"""
|
|
31
|
+
import getpass as _getpass
|
|
32
|
+
|
|
33
|
+
parts = args.split()
|
|
34
|
+
|
|
35
|
+
if not parts or parts[0].lower() in {"google", "--google", "-g", "web", "--web"}:
|
|
36
|
+
await self._login_with_google()
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
if parts[0].lower() in {"email", "--email", "password", "--password"}:
|
|
40
|
+
parts = parts[1:]
|
|
41
|
+
|
|
42
|
+
if parts:
|
|
43
|
+
email = parts[0]
|
|
44
|
+
else:
|
|
45
|
+
try:
|
|
46
|
+
prompt_fn = self.context.console.input if self.context.has_rich else input
|
|
47
|
+
email = prompt_fn(" Email: ").strip()
|
|
48
|
+
except (EOFError, KeyboardInterrupt):
|
|
49
|
+
self.context.console.print("[dim]Cancelled[/dim]" if self.context.has_rich else "Cancelled")
|
|
50
|
+
return
|
|
51
|
+
if not email:
|
|
52
|
+
self.context.console.print(
|
|
53
|
+
"[dim]Usage: /login <email>[/dim]" if self.context.has_rich else "Usage: /login <email>"
|
|
54
|
+
)
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
# Always prompt for password — never accept it as a CLI argument (security)
|
|
58
|
+
try:
|
|
59
|
+
_esc_watcher().pause()
|
|
60
|
+
password = _getpass.getpass(" Password: ")
|
|
61
|
+
except (EOFError, KeyboardInterrupt):
|
|
62
|
+
self.context.console.print("[dim]Cancelled[/dim]" if self.context.has_rich else "Cancelled")
|
|
63
|
+
return
|
|
64
|
+
finally:
|
|
65
|
+
_esc_watcher().resume()
|
|
66
|
+
|
|
67
|
+
if not password:
|
|
68
|
+
self.context.console.print(
|
|
69
|
+
"[red]Password cannot be empty[/red]" if self.context.has_rich else "Password cannot be empty"
|
|
70
|
+
)
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
if self.context.has_rich:
|
|
74
|
+
self.context.console.print("[dim]Authenticating...[/dim]")
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
from aria_code.account_session import password_session
|
|
78
|
+
|
|
79
|
+
session = await asyncio.to_thread(password_session, email.strip(), password)
|
|
80
|
+
self._accept_session(session)
|
|
81
|
+
who = self.terminal.config.get("email") or session["user_id"]
|
|
82
|
+
self.context.console.print(f"Signed in as {who}")
|
|
83
|
+
except Exception:
|
|
84
|
+
print_error(
|
|
85
|
+
self.context, "Sign-in failed. Check your email/password or run /login in the browser.", "login"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
async def _login_with_google(self):
|
|
89
|
+
"""Browser-based account sign-in (see apps/cli/web_login.py).
|
|
90
|
+
|
|
91
|
+
Run off the event loop: the flow blocks on a loopback socket for as long
|
|
92
|
+
as the user takes in the browser, which would otherwise stall every other
|
|
93
|
+
coroutine in the REPL.
|
|
94
|
+
"""
|
|
95
|
+
import asyncio as _asyncio
|
|
96
|
+
|
|
97
|
+
from ..google_login import login_api_url
|
|
98
|
+
|
|
99
|
+
from ..web_login import run_web_login
|
|
100
|
+
|
|
101
|
+
rich = self.context.has_rich
|
|
102
|
+
api_url = login_api_url(self.terminal.api_url)
|
|
103
|
+
self.context.console.print(
|
|
104
|
+
"[dim]Opening your browser to sign in or create an account…[/dim]"
|
|
105
|
+
if rich
|
|
106
|
+
else "Opening your browser to sign in or create an account…"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
session = await _asyncio.to_thread(run_web_login, api_url)
|
|
111
|
+
except RuntimeError as exc:
|
|
112
|
+
print_error(self.context, str(exc), "login")
|
|
113
|
+
return
|
|
114
|
+
except Exception as exc:
|
|
115
|
+
print_error(self.context, f"Account sign-in failed: {exc}", "login")
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
self._accept_session(session)
|
|
120
|
+
except ValueError:
|
|
121
|
+
print_error(self.context, "The session identity could not be verified. Run /login again.", "login")
|
|
122
|
+
return
|
|
123
|
+
who = self.terminal.config.get("email") or session["user_id"]
|
|
124
|
+
self.context.console.print(f"[green]✓ Signed in as {who}[/green]" if rich else f"Signed in as {who}")
|
|
125
|
+
|
|
126
|
+
def _reset_account_context(self):
|
|
127
|
+
from aria_code.memory_manager import MemoryManager
|
|
128
|
+
|
|
129
|
+
self.terminal.conversation = []
|
|
130
|
+
self.terminal._last_response = ""
|
|
131
|
+
self.terminal.memory_mgr = MemoryManager(config=self.terminal.config)
|
|
132
|
+
# Personal profile context is resolved per turn, never retained from A.
|
|
133
|
+
from aria_code.apps.cli.helpers import _load_project_context
|
|
134
|
+
|
|
135
|
+
for module_name in ("aria_cli", "aria_code.aria_cli"):
|
|
136
|
+
module = sys.modules.get(module_name)
|
|
137
|
+
if module is not None:
|
|
138
|
+
module._PROJECT_CONTEXT = _load_project_context()
|
|
139
|
+
|
|
140
|
+
def _accept_session(self, session):
|
|
141
|
+
from aria_code.account_session import claims_for
|
|
142
|
+
|
|
143
|
+
token, uid = session.get("auth_token"), session.get("user_id")
|
|
144
|
+
claims = claims_for(token or "")
|
|
145
|
+
if not token or not uid or claims.get("sub") != uid:
|
|
146
|
+
raise ValueError("Missing account identity")
|
|
147
|
+
cfg = self.terminal.config
|
|
148
|
+
cfg.update(
|
|
149
|
+
auth_token=token,
|
|
150
|
+
user_id=uid,
|
|
151
|
+
email=str(claims.get("email") or session.get("email") or "").strip().lower(),
|
|
152
|
+
display_name=session.get("display_name") or claims.get("name") or "",
|
|
153
|
+
auth_provider=session.get("provider") or "firebase",
|
|
154
|
+
)
|
|
155
|
+
cfg.pop("refresh_token", None)
|
|
156
|
+
cfg.pop("token_expires_at", None)
|
|
157
|
+
if session.get("refresh_token"):
|
|
158
|
+
cfg["refresh_token"] = session["refresh_token"]
|
|
159
|
+
if claims.get("exp"):
|
|
160
|
+
cfg["token_expires_at"] = datetime.fromtimestamp(float(claims["exp"]), timezone.utc).isoformat()
|
|
161
|
+
self.context.save_config(cfg)
|
|
162
|
+
self._reset_account_context()
|
|
163
|
+
|
|
164
|
+
def cmd_logout(self, args: str):
|
|
165
|
+
self.terminal.config["auth_token"] = None
|
|
166
|
+
self.terminal.config["user_id"] = None
|
|
167
|
+
self.terminal.config.pop("token_expires_at", None)
|
|
168
|
+
# Added by the Google flow; leaving them behind would let /whoami report
|
|
169
|
+
# a provider for a session that no longer exists.
|
|
170
|
+
self.terminal.config.pop("refresh_token", None)
|
|
171
|
+
self.terminal.config.pop("auth_provider", None)
|
|
172
|
+
self.terminal.config.pop("email", None)
|
|
173
|
+
self.terminal.config.pop("display_name", None)
|
|
174
|
+
self.context.save_config(self.terminal.config)
|
|
175
|
+
self._reset_account_context()
|
|
176
|
+
self.context.console.print("[dim]Logged out[/dim]" if self.context.has_rich else "Logged out")
|
|
177
|
+
|
|
178
|
+
def cmd_whoami(self, args: str):
|
|
179
|
+
"""Show current authentication status."""
|
|
180
|
+
cfg = self.terminal.config
|
|
181
|
+
user_id = cfg.get("user_id")
|
|
182
|
+
token = cfg.get("auth_token")
|
|
183
|
+
email = cfg.get("email") or ""
|
|
184
|
+
expires = cfg.get("token_expires_at")
|
|
185
|
+
|
|
186
|
+
if not token:
|
|
187
|
+
self.context.console.print(
|
|
188
|
+
"[dim]Not logged in — use /login <email>[/dim]" if self.context.has_rich else "Not logged in"
|
|
189
|
+
)
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
if self.context.has_rich:
|
|
193
|
+
self.context.console.print()
|
|
194
|
+
self.context.console.print(f" [dim]User:[/dim] {user_id or 'unknown'}")
|
|
195
|
+
self.context.console.print(f" [dim]Email:[/dim] {email or 'unknown'}")
|
|
196
|
+
if expires:
|
|
197
|
+
# Check expiry
|
|
198
|
+
try:
|
|
199
|
+
exp_dt = datetime.fromisoformat(expires.replace("Z", "+00:00"))
|
|
200
|
+
now = datetime.now(exp_dt.tzinfo)
|
|
201
|
+
if now > exp_dt:
|
|
202
|
+
self.context.console.print(f" [dim]Expires:[/dim] [red]EXPIRED ({expires[:10]})[/red]")
|
|
203
|
+
self.context.console.print(" [dim]Run /login to refresh your session[/dim]")
|
|
204
|
+
else:
|
|
205
|
+
delta = exp_dt - now
|
|
206
|
+
hours = int(delta.total_seconds() // 3600)
|
|
207
|
+
self.context.console.print(f" [dim]Expires:[/dim] {expires[:10]} [dim](in {hours}h)[/dim]")
|
|
208
|
+
except Exception:
|
|
209
|
+
self.context.console.print(f" [dim]Expires:[/dim] {expires}")
|
|
210
|
+
self.context.console.print()
|
|
211
|
+
else:
|
|
212
|
+
print(f"User: {user_id or 'unknown'}")
|
|
213
|
+
print(f"Email: {email or 'unknown'}")
|
|
214
|
+
if expires:
|
|
215
|
+
print(f"Expires: {expires}")
|