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,632 @@
|
|
|
1
|
+
"""The acceptance gate — making "done" a claim that was executed.
|
|
2
|
+
|
|
3
|
+
Why this exists
|
|
4
|
+
---------------
|
|
5
|
+
Aria could already *suggest* verification. ``VerificationPlanner`` infers the
|
|
6
|
+
right checks from what changed, ``write_file`` attaches the inferred command to
|
|
7
|
+
its result as ``suggested_verification``, and ``/verify`` runs the plan when a
|
|
8
|
+
human asks for it. Every one of those paths ends with a suggestion. Nothing
|
|
9
|
+
in the loop ever ran the check, read the failure, or refused to let the turn
|
|
10
|
+
finish; the model announced "已完成" and the turn ended, verified or not.
|
|
11
|
+
|
|
12
|
+
That is the whole distance between an agent that writes code and an agent you
|
|
13
|
+
can hand a repository to. The strong coding agents are not better at emitting
|
|
14
|
+
a patch — they are structurally unable to stop while the check is red. The
|
|
15
|
+
loop, not the model, is what holds that line, which is exactly why this belongs
|
|
16
|
+
in the runtime and works the same whether the turn is driven by a 7B local
|
|
17
|
+
model or a frontier one.
|
|
18
|
+
|
|
19
|
+
What it does
|
|
20
|
+
------------
|
|
21
|
+
The gate arms itself when a turn actually mutates a file on disk, and fires at
|
|
22
|
+
the moment the model stops requesting tools — the point where the loop would
|
|
23
|
+
otherwise ``break`` and report success. It runs the inferred checks; if they
|
|
24
|
+
pass, the turn ends as it always did, now carrying evidence. If they fail, the
|
|
25
|
+
loop gets a repair directive built from the *failing* output — trimmed, with
|
|
26
|
+
``file:line`` anchors pulled out — and continues, so the model repairs against
|
|
27
|
+
a real signal instead of its own recollection of what it wrote.
|
|
28
|
+
|
|
29
|
+
Three constraints keep it from becoming a tax:
|
|
30
|
+
|
|
31
|
+
- **Read-only turns never pay it.** Arming requires an applied write. A
|
|
32
|
+
market question, a code review, a staged-but-unapplied edit: no checks run.
|
|
33
|
+
- **It is bounded.** After ``max_attempts`` failed rounds the gate stops
|
|
34
|
+
re-arming and the turn ends *honestly* — ``verified: false`` with the
|
|
35
|
+
failing command in the result — rather than looping until the budget dies.
|
|
36
|
+
An unverified answer that says so is useful; an infinite loop is not.
|
|
37
|
+
- **It never invents a sandbox.** Commands go through the caller's own
|
|
38
|
+
runner (the CLI passes ``run_command``, with its policy, permission mode
|
|
39
|
+
and approval path intact), so the gate cannot execute anything the user's
|
|
40
|
+
current mode would not already allow.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
import inspect
|
|
46
|
+
import hashlib
|
|
47
|
+
import re
|
|
48
|
+
import time
|
|
49
|
+
from dataclasses import dataclass, field, replace
|
|
50
|
+
from pathlib import Path
|
|
51
|
+
from typing import Any, Awaitable, Callable, Dict, Iterable, List, Optional, Sequence, Union
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"AcceptanceGate",
|
|
55
|
+
"AcceptanceReport",
|
|
56
|
+
"CheckResult",
|
|
57
|
+
"DEFAULT_MUTATING_TOOLS",
|
|
58
|
+
"extract_mutated_paths",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Tools whose success means bytes changed on disk. ``run_command`` is
|
|
63
|
+
# deliberately absent: it can mutate, but gating on it would re-arm the gate
|
|
64
|
+
# with every check the gate itself runs — the checks would never terminate.
|
|
65
|
+
DEFAULT_MUTATING_TOOLS = frozenset({
|
|
66
|
+
"write_file",
|
|
67
|
+
"edit_file",
|
|
68
|
+
"multi_edit",
|
|
69
|
+
"apply_patch",
|
|
70
|
+
"notebook_edit",
|
|
71
|
+
"str_replace",
|
|
72
|
+
"create_file",
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
# A failing test log is the single most context-hungry payload in a coding
|
|
76
|
+
# turn — a full pytest run can exceed the window on its own. Head carries the
|
|
77
|
+
# collection error, tail carries the assertion and the summary line; the middle
|
|
78
|
+
# is almost always repeated passing output.
|
|
79
|
+
_HEAD_LINES = 20
|
|
80
|
+
_TAIL_LINES = 45
|
|
81
|
+
_MAX_CHARS = 6000
|
|
82
|
+
|
|
83
|
+
# ``File "x.py", line 12`` (Python), ``x.ts:12:5`` (tsc/eslint/jest).
|
|
84
|
+
_PY_ANCHOR = re.compile(r'File "([^"]+)", line (\d+)')
|
|
85
|
+
_COLON_ANCHOR = re.compile(r"(?m)^\s*([\w./\\-]+\.[A-Za-z]{1,4}):(\d+)(?::\d+)?")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _as_dict(value: Any) -> Dict[str, Any]:
|
|
89
|
+
return value if isinstance(value, dict) else {}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def extract_mutated_paths(
|
|
93
|
+
tool: str,
|
|
94
|
+
result: Any,
|
|
95
|
+
*,
|
|
96
|
+
mutating_tools: Iterable[str] = DEFAULT_MUTATING_TOOLS,
|
|
97
|
+
) -> tuple[str, ...]:
|
|
98
|
+
"""Paths this tool result actually wrote to disk.
|
|
99
|
+
|
|
100
|
+
Returns nothing for a failed call or an unapplied staged change. The
|
|
101
|
+
distinction matters: ``write_file`` in review mode returns success with
|
|
102
|
+
``applied: False`` and the file on disk is untouched, so running the test
|
|
103
|
+
suite would verify the previous state and report a green that means
|
|
104
|
+
nothing.
|
|
105
|
+
"""
|
|
106
|
+
canonical = str(tool or "").rsplit("__", 1)[-1]
|
|
107
|
+
if canonical not in set(mutating_tools):
|
|
108
|
+
return ()
|
|
109
|
+
|
|
110
|
+
payload = _as_dict(result)
|
|
111
|
+
if payload.get("success") is False or payload.get("error"):
|
|
112
|
+
return ()
|
|
113
|
+
|
|
114
|
+
data = _as_dict(payload.get("data")) or payload
|
|
115
|
+
if data.get("applied") is False or (
|
|
116
|
+
data.get("staged") is True and data.get("applied") is not True
|
|
117
|
+
):
|
|
118
|
+
return ()
|
|
119
|
+
|
|
120
|
+
found: List[str] = []
|
|
121
|
+
|
|
122
|
+
def _add(value: Any) -> None:
|
|
123
|
+
text = str(value or "").strip()
|
|
124
|
+
if text and text not in found:
|
|
125
|
+
found.append(text)
|
|
126
|
+
|
|
127
|
+
_add(data.get("path"))
|
|
128
|
+
_add(data.get("file_path"))
|
|
129
|
+
for entry in data.get("paths", ()) or ():
|
|
130
|
+
_add(entry)
|
|
131
|
+
# multi_edit reports per-edit records rather than a single path.
|
|
132
|
+
for entry in data.get("edits", ()) or ():
|
|
133
|
+
_add(_as_dict(entry).get("path"))
|
|
134
|
+
|
|
135
|
+
return tuple(found)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _trim(text: str) -> str:
|
|
139
|
+
"""Head + tail of command output, with the uninformative middle dropped."""
|
|
140
|
+
body = (text or "").strip()
|
|
141
|
+
if not body:
|
|
142
|
+
return ""
|
|
143
|
+
lines = body.splitlines()
|
|
144
|
+
if len(lines) > _HEAD_LINES + _TAIL_LINES:
|
|
145
|
+
omitted = len(lines) - _HEAD_LINES - _TAIL_LINES
|
|
146
|
+
lines = (
|
|
147
|
+
lines[:_HEAD_LINES]
|
|
148
|
+
+ [f"… [{omitted} lines omitted] …"]
|
|
149
|
+
+ lines[-_TAIL_LINES:]
|
|
150
|
+
)
|
|
151
|
+
joined = "\n".join(lines)
|
|
152
|
+
if len(joined) > _MAX_CHARS:
|
|
153
|
+
keep = _MAX_CHARS // 2
|
|
154
|
+
joined = f"{joined[:keep]}\n… [truncated] …\n{joined[-keep:]}"
|
|
155
|
+
return joined
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _anchors(text: str, limit: int = 5) -> tuple[str, ...]:
|
|
159
|
+
"""``file:line`` locations named in a failure, most recent frame last.
|
|
160
|
+
|
|
161
|
+
Handing the model the anchors separately is what turns a wall of log into
|
|
162
|
+
an edit: without them a weaker model tends to rewrite the whole file
|
|
163
|
+
instead of patching the line the traceback already identified.
|
|
164
|
+
"""
|
|
165
|
+
out: List[str] = []
|
|
166
|
+
for match in _PY_ANCHOR.finditer(text or ""):
|
|
167
|
+
entry = f"{match.group(1)}:{match.group(2)}"
|
|
168
|
+
if entry not in out:
|
|
169
|
+
out.append(entry)
|
|
170
|
+
for match in _COLON_ANCHOR.finditer(text or ""):
|
|
171
|
+
entry = f"{match.group(1)}:{match.group(2)}"
|
|
172
|
+
if entry not in out:
|
|
173
|
+
out.append(entry)
|
|
174
|
+
# The last frames are the ones inside the code that just changed; the first
|
|
175
|
+
# are usually the runner's own stack.
|
|
176
|
+
return tuple(out[-limit:])
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# What a runner prints when the tool itself is missing, as opposed to a test failing:
|
|
180
|
+
# `python3 -m pytest` -> "/opt/homebrew/bin/python3.14: No module named pytest", and
|
|
181
|
+
# a missing program -> "command not found" (shell exit 127). A project's own
|
|
182
|
+
# ModuleNotFoundError inside its tests looks different and stays a failure.
|
|
183
|
+
_RUNNER_MISSING = re.compile(r"(?m)^\S*python[\d.]*: No module named ['\"]?([\w.]+)['\"]?\s*$")
|
|
184
|
+
_PROGRAM_MISSING = re.compile(r"(?m)^(?:\S+: )*(?:([\w.+-]+): (?:command )?not found|command not found: ([\w.+-]+))\s*$")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def unavailable_reason(exit_code: int, output: str, error: str = "") -> str:
|
|
188
|
+
"""Why a check could not run at all ("" when it ran, whatever its verdict)."""
|
|
189
|
+
text = f"{output or ''}\n{error or ''}"
|
|
190
|
+
match = _RUNNER_MISSING.search(text)
|
|
191
|
+
if match:
|
|
192
|
+
return f"{match.group(1)} is not installed for this python"
|
|
193
|
+
match = _PROGRAM_MISSING.search(text)
|
|
194
|
+
if match or exit_code == 127:
|
|
195
|
+
name = (match.group(1) or match.group(2)) if match else ""
|
|
196
|
+
return f"{name or 'the command'} is not installed"
|
|
197
|
+
return ""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@dataclass(frozen=True)
|
|
201
|
+
class CheckResult:
|
|
202
|
+
"""One verification command, run."""
|
|
203
|
+
|
|
204
|
+
command: str
|
|
205
|
+
exit_code: int
|
|
206
|
+
passed: bool
|
|
207
|
+
output: str = ""
|
|
208
|
+
duration: float = 0.0
|
|
209
|
+
error: str = ""
|
|
210
|
+
# Set from the test baseline when the check failed: whether every failure
|
|
211
|
+
# was already there before the change, and which test ids are which.
|
|
212
|
+
preexisting: bool = False
|
|
213
|
+
new_failures: tuple[str, ...] = ()
|
|
214
|
+
old_failures: tuple[str, ...] = ()
|
|
215
|
+
baseline_note: str = ""
|
|
216
|
+
# Non-empty when the tool needed to run this check is missing. Not a red check:
|
|
217
|
+
# nothing was verified, and asking the model to "fix" it only makes it install things.
|
|
218
|
+
unavailable: str = ""
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def anchors(self) -> tuple[str, ...]:
|
|
222
|
+
return () if self.passed else _anchors(self.output)
|
|
223
|
+
|
|
224
|
+
def summary(self) -> dict:
|
|
225
|
+
data = {
|
|
226
|
+
"command": self.command,
|
|
227
|
+
"exit_code": self.exit_code,
|
|
228
|
+
"passed": self.passed,
|
|
229
|
+
"duration": round(self.duration, 3),
|
|
230
|
+
"error": self.error,
|
|
231
|
+
}
|
|
232
|
+
if self.unavailable:
|
|
233
|
+
data["not_run"] = self.unavailable
|
|
234
|
+
if not self.passed and (self.baseline_note or self.new_failures or self.old_failures):
|
|
235
|
+
data.update({"preexisting": self.preexisting, "new_failures": list(self.new_failures),
|
|
236
|
+
"old_failures": list(self.old_failures), "baseline": self.baseline_note})
|
|
237
|
+
return data
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@dataclass(frozen=True)
|
|
241
|
+
class AcceptanceReport:
|
|
242
|
+
"""The outcome of one pass of the gate."""
|
|
243
|
+
|
|
244
|
+
attempt: int
|
|
245
|
+
checks: tuple[CheckResult, ...] = ()
|
|
246
|
+
reason: str = ""
|
|
247
|
+
paths: tuple[str, ...] = ()
|
|
248
|
+
attempts_remaining: int = 0
|
|
249
|
+
revision_status: str = "not_recorded"
|
|
250
|
+
revision_paths: tuple[tuple[str, str, str], ...] = ()
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
def ran(self) -> bool:
|
|
254
|
+
return any(not check.unavailable for check in self.checks)
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def not_run(self) -> tuple[CheckResult, ...]:
|
|
258
|
+
"""Checks whose tool is missing: nothing was verified by them."""
|
|
259
|
+
return tuple(check for check in self.checks if check.unavailable)
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def passed(self) -> bool:
|
|
263
|
+
"""True only when at least one check ran and every check that could run passed.
|
|
264
|
+
|
|
265
|
+
A gate that reports "verified" without running anything is worse than
|
|
266
|
+
no gate: it launders an unchecked claim into a checked-looking one.
|
|
267
|
+
"""
|
|
268
|
+
return (self.revision_status not in {"changed_during_checks", "unavailable"}
|
|
269
|
+
and self.ran and all(check.passed for check in self.checks if not check.unavailable))
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def failures(self) -> tuple[CheckResult, ...]:
|
|
273
|
+
return tuple(check for check in self.checks if not check.passed and not check.unavailable)
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def regressed(self) -> bool:
|
|
277
|
+
"""A check failed that was not already failing before the change."""
|
|
278
|
+
return any(not check.preexisting for check in self.failures)
|
|
279
|
+
|
|
280
|
+
def headline(self) -> str:
|
|
281
|
+
if self.revision_status in {"changed_during_checks", "unavailable"} and not self.failures:
|
|
282
|
+
return "验收未确认:检查期间文件版本变化或无法取得安全的文件指纹"
|
|
283
|
+
if not self.ran:
|
|
284
|
+
if self.not_run:
|
|
285
|
+
first = self.not_run[0]
|
|
286
|
+
return f"验收未执行:`{first.command}` 无法运行({first.unavailable})"
|
|
287
|
+
return "验收未执行:未推断出检查命令"
|
|
288
|
+
if self.passed:
|
|
289
|
+
names = ", ".join(check.command for check in self.checks if not check.unavailable)
|
|
290
|
+
if self.not_run:
|
|
291
|
+
skipped = "; ".join(f"`{c.command}` ({c.unavailable})" for c in self.not_run)
|
|
292
|
+
return f"验收部分通过 ({names});未能运行:{skipped}"
|
|
293
|
+
return f"验收通过 ({names})"
|
|
294
|
+
first = self.failures[0]
|
|
295
|
+
if not self.regressed:
|
|
296
|
+
return f"验收未通过,但失败在改动前就已存在:`{first.command}` exit {first.exit_code}"
|
|
297
|
+
return f"验收失败:`{first.command}` exit {first.exit_code}"
|
|
298
|
+
|
|
299
|
+
def repair_directive(self) -> str:
|
|
300
|
+
"""What the model is told when the check came back red.
|
|
301
|
+
|
|
302
|
+
Written as evidence plus one instruction. The failing output is the
|
|
303
|
+
evidence; the instruction exists because the observed failure mode is
|
|
304
|
+
not that the model cannot fix the bug — it is that it re-announces
|
|
305
|
+
completion without having looked at why the command failed.
|
|
306
|
+
"""
|
|
307
|
+
if self.revision_status in {"changed_during_checks", "unavailable"}:
|
|
308
|
+
return ("文件内容在检查期间变化,或无法取得安全指纹;当前结果未验证。"
|
|
309
|
+
"先重新读取工作区并确认变更,不要覆盖用户修改。"
|
|
310
|
+
"保留原有权限与审批,通过正常验收流程重新检查。")
|
|
311
|
+
blocks: List[str] = [
|
|
312
|
+
"## 验收未通过 (Acceptance check failed)",
|
|
313
|
+
"",
|
|
314
|
+
"你声明任务已完成,但改动过的文件没有通过自动验收检查。"
|
|
315
|
+
"以下是**实际执行**的命令和真实输出:",
|
|
316
|
+
"",
|
|
317
|
+
]
|
|
318
|
+
for check in self.failures:
|
|
319
|
+
if check.preexisting:
|
|
320
|
+
continue
|
|
321
|
+
blocks.append(f"### `{check.command}` → exit {check.exit_code}")
|
|
322
|
+
if check.new_failures:
|
|
323
|
+
blocks.append("本次改动新引入的失败:" + ", ".join(f"`{t}`" for t in check.new_failures))
|
|
324
|
+
if check.old_failures:
|
|
325
|
+
blocks.append("以下失败在改动前就存在,与本任务无关,不要修改:"
|
|
326
|
+
+ ", ".join(f"`{t}`" for t in check.old_failures))
|
|
327
|
+
if check.error:
|
|
328
|
+
blocks.append(f"(执行错误:{check.error})")
|
|
329
|
+
body = _trim(check.output)
|
|
330
|
+
if body:
|
|
331
|
+
blocks.append(f"```\n{body}\n```")
|
|
332
|
+
if check.anchors:
|
|
333
|
+
blocks.append("定位:" + ", ".join(f"`{a}`" for a in check.anchors))
|
|
334
|
+
blocks.append("")
|
|
335
|
+
|
|
336
|
+
blocks.append(
|
|
337
|
+
"请依次:(1) 读出错位置的代码确认原因,(2) 用 `edit_file` 定点修补"
|
|
338
|
+
"——不要整文件重写,(3) 修好后直接说明修了什么。"
|
|
339
|
+
"修改后验收会自动重跑,你**不需要**自己调用验收命令。"
|
|
340
|
+
)
|
|
341
|
+
if self.attempts_remaining <= 0:
|
|
342
|
+
blocks.append(
|
|
343
|
+
"注意:这是最后一次修复机会。若仍未通过,请如实说明失败原因,"
|
|
344
|
+
"不要声称任务已完成。"
|
|
345
|
+
)
|
|
346
|
+
else:
|
|
347
|
+
blocks.append(f"剩余自动重试次数:{self.attempts_remaining}。")
|
|
348
|
+
return "\n".join(blocks)
|
|
349
|
+
|
|
350
|
+
def summary(self) -> dict:
|
|
351
|
+
return {
|
|
352
|
+
"attempt": self.attempt,
|
|
353
|
+
"passed": self.passed,
|
|
354
|
+
"regressed": self.regressed,
|
|
355
|
+
"ran": self.ran,
|
|
356
|
+
"reason": self.reason,
|
|
357
|
+
"paths": list(self.paths),
|
|
358
|
+
"checks": [check.summary() for check in self.checks],
|
|
359
|
+
"revision_status": self.revision_status,
|
|
360
|
+
"revision_paths": [dict(path=p, state=s, sha256=h or None) for p, s, h in self.revision_paths],
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# ``(command) -> result dict`` — sync or async. The result is read loosely
|
|
365
|
+
# because every surface in this codebase wraps command output slightly
|
|
366
|
+
# differently; see ``_read_run_result``.
|
|
367
|
+
CommandRunner = Callable[[str], Union[dict, Awaitable[dict]]]
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _read_run_result(raw: Any) -> tuple[int, str, str]:
|
|
371
|
+
"""Normalise a runner result into ``(exit_code, output, error)``.
|
|
372
|
+
|
|
373
|
+
Deliberately permissive. ``tool_run_command`` returns
|
|
374
|
+
``{"success": True, "data": {"exit_code": .., "stdout": .., "stderr": ..}}``
|
|
375
|
+
on a completed command and ``{"success": False, "error": "…timed out"}``
|
|
376
|
+
when it never completed — and a timeout is a *failed* check, not a passing
|
|
377
|
+
one, so an unreadable result must never be read as exit 0.
|
|
378
|
+
"""
|
|
379
|
+
payload = _as_dict(raw)
|
|
380
|
+
if not payload:
|
|
381
|
+
return 1, "", "runner returned no result"
|
|
382
|
+
|
|
383
|
+
if payload.get("success") is False:
|
|
384
|
+
return 1, str(payload.get("output") or ""), str(payload.get("error") or "command failed")
|
|
385
|
+
|
|
386
|
+
data = _as_dict(payload.get("data")) or payload
|
|
387
|
+
for key in ("exit_code", "returncode", "code", "status"):
|
|
388
|
+
if key in data:
|
|
389
|
+
try:
|
|
390
|
+
exit_code = int(data[key])
|
|
391
|
+
break
|
|
392
|
+
except (TypeError, ValueError):
|
|
393
|
+
continue
|
|
394
|
+
else:
|
|
395
|
+
return 1, "", "runner returned no exit status"
|
|
396
|
+
|
|
397
|
+
stdout = str(data.get("stdout") or data.get("output") or "")
|
|
398
|
+
stderr = str(data.get("stderr") or "")
|
|
399
|
+
output = "\n".join(part for part in (stdout, stderr) if part.strip())
|
|
400
|
+
return exit_code, output, ""
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
class AcceptanceGate:
|
|
404
|
+
"""Arms on real writes, fires when the model says it is done."""
|
|
405
|
+
|
|
406
|
+
def __init__(
|
|
407
|
+
self,
|
|
408
|
+
*,
|
|
409
|
+
runner: CommandRunner,
|
|
410
|
+
root: Union[str, Path] = ".",
|
|
411
|
+
planner: Any = None,
|
|
412
|
+
max_attempts: int = 2,
|
|
413
|
+
mutating_tools: Iterable[str] = DEFAULT_MUTATING_TOOLS,
|
|
414
|
+
enabled: bool = True,
|
|
415
|
+
commands: Optional[Sequence[str]] = None,
|
|
416
|
+
baseline: Any = None,
|
|
417
|
+
revision_inputs: Sequence[str] = (),
|
|
418
|
+
) -> None:
|
|
419
|
+
self.root = Path(root).expanduser()
|
|
420
|
+
# ``runtime.baseline.Baseline``: reruns a failed check on the code as
|
|
421
|
+
# it was before the change, so pre-existing failures are not repaired.
|
|
422
|
+
self.baseline = baseline
|
|
423
|
+
self.runner = runner
|
|
424
|
+
self.max_attempts = max(0, int(max_attempts))
|
|
425
|
+
self.mutating_tools = frozenset(mutating_tools)
|
|
426
|
+
self.enabled = bool(enabled)
|
|
427
|
+
# An explicit command list overrides inference — this is the hook a
|
|
428
|
+
# domain pack or a repo's own config uses to say what "green" means
|
|
429
|
+
# for it (``make check``, ``bazel test //...``), which inference can
|
|
430
|
+
# never guess.
|
|
431
|
+
self.commands = tuple(commands or ())
|
|
432
|
+
self._planner = planner
|
|
433
|
+
self.attempts = 0
|
|
434
|
+
self.reports: List[AcceptanceReport] = []
|
|
435
|
+
self._pending: List[str] = []
|
|
436
|
+
self._all_paths: List[str] = []
|
|
437
|
+
if (not isinstance(revision_inputs, (tuple, list)) or len(revision_inputs) > 64
|
|
438
|
+
or any(not isinstance(p, str) or not p or len(p) > 512 for p in revision_inputs)):
|
|
439
|
+
raise ValueError("revision_inputs must contain at most 64 bounded paths")
|
|
440
|
+
self.revision_inputs = tuple(revision_inputs)
|
|
441
|
+
|
|
442
|
+
def _revision(self, paths: Sequence[str]) -> tuple[tuple[str, str, str], ...] | None:
|
|
443
|
+
"""Bounded content snapshots, not an atomic Git/dependency revision."""
|
|
444
|
+
from .task_verification import _read_file, relative_path
|
|
445
|
+
if not paths or len(paths) > 64:
|
|
446
|
+
return None
|
|
447
|
+
snapshots = []
|
|
448
|
+
try:
|
|
449
|
+
root = self.root.resolve(strict=True)
|
|
450
|
+
for value in paths:
|
|
451
|
+
path = Path(value)
|
|
452
|
+
name = relative_path(str(path.relative_to(root)) if path.is_absolute() else value)
|
|
453
|
+
try:
|
|
454
|
+
digest = hashlib.sha256(_read_file(str(root), name)).hexdigest()
|
|
455
|
+
snapshots.append((name, "file", digest))
|
|
456
|
+
except FileNotFoundError:
|
|
457
|
+
snapshots.append((name, "absent", ""))
|
|
458
|
+
except (OSError, ValueError, TypeError):
|
|
459
|
+
return None
|
|
460
|
+
return tuple(snapshots)
|
|
461
|
+
|
|
462
|
+
# ── arming ────────────────────────────────────────────────────────────
|
|
463
|
+
|
|
464
|
+
def record_tool(self, tool: str, result: Any) -> tuple[str, ...]:
|
|
465
|
+
"""Note one tool result; arms the gate if it wrote to disk."""
|
|
466
|
+
if not self.enabled:
|
|
467
|
+
return ()
|
|
468
|
+
paths = extract_mutated_paths(tool, result, mutating_tools=self.mutating_tools)
|
|
469
|
+
for path in paths:
|
|
470
|
+
if path not in self._pending:
|
|
471
|
+
self._pending.append(path)
|
|
472
|
+
if path not in self._all_paths:
|
|
473
|
+
self._all_paths.append(path)
|
|
474
|
+
return paths
|
|
475
|
+
|
|
476
|
+
@property
|
|
477
|
+
def armed(self) -> bool:
|
|
478
|
+
return bool(self._pending)
|
|
479
|
+
|
|
480
|
+
@property
|
|
481
|
+
def exhausted(self) -> bool:
|
|
482
|
+
return self.attempts >= self.max_attempts
|
|
483
|
+
|
|
484
|
+
def should_run(self) -> bool:
|
|
485
|
+
return self.enabled and self.armed and not self.exhausted
|
|
486
|
+
|
|
487
|
+
# ── firing ────────────────────────────────────────────────────────────
|
|
488
|
+
|
|
489
|
+
def _plan(self, paths: Sequence[str]) -> tuple[tuple[str, ...], str]:
|
|
490
|
+
if self.commands:
|
|
491
|
+
return self.commands, "configured acceptance commands"
|
|
492
|
+
planner = self._planner
|
|
493
|
+
if planner is None:
|
|
494
|
+
try:
|
|
495
|
+
from aria_code.workspace.verify import VerificationPlanner
|
|
496
|
+
except Exception:
|
|
497
|
+
return (), "verification planner unavailable"
|
|
498
|
+
planner = VerificationPlanner(root=self.root)
|
|
499
|
+
self._planner = planner
|
|
500
|
+
try:
|
|
501
|
+
plan = planner.infer(list(paths))
|
|
502
|
+
except Exception as exc: # a planner fault must not fail the turn
|
|
503
|
+
return (), f"verification planning failed: {exc}"
|
|
504
|
+
return tuple(plan.commands or ()), str(plan.reason or "")
|
|
505
|
+
|
|
506
|
+
async def _run_one(self, command: str) -> CheckResult:
|
|
507
|
+
started = time.time()
|
|
508
|
+
try:
|
|
509
|
+
raw = self.runner(command)
|
|
510
|
+
if inspect.isawaitable(raw):
|
|
511
|
+
raw = await raw
|
|
512
|
+
except Exception as exc:
|
|
513
|
+
return CheckResult(
|
|
514
|
+
command=command,
|
|
515
|
+
exit_code=1,
|
|
516
|
+
passed=False,
|
|
517
|
+
error=str(exc),
|
|
518
|
+
duration=time.time() - started,
|
|
519
|
+
)
|
|
520
|
+
exit_code, output, error = _read_run_result(raw)
|
|
521
|
+
passed = exit_code == 0 and not error
|
|
522
|
+
return CheckResult(
|
|
523
|
+
command=command,
|
|
524
|
+
exit_code=exit_code,
|
|
525
|
+
passed=passed,
|
|
526
|
+
output=output,
|
|
527
|
+
error=error,
|
|
528
|
+
duration=time.time() - started,
|
|
529
|
+
unavailable="" if passed else unavailable_reason(exit_code, output, error),
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
async def _against_baseline(self, check: CheckResult) -> CheckResult:
|
|
533
|
+
if check.passed or check.unavailable:
|
|
534
|
+
return check
|
|
535
|
+
from .baseline import compare
|
|
536
|
+
|
|
537
|
+
try:
|
|
538
|
+
before = await self.baseline.result(check.command)
|
|
539
|
+
except Exception:
|
|
540
|
+
return check
|
|
541
|
+
result = compare(check.output, True, before)
|
|
542
|
+
return replace(check, preexisting=result.preexisting, new_failures=result.new_failures,
|
|
543
|
+
old_failures=result.old_failures, baseline_note=result.note)
|
|
544
|
+
|
|
545
|
+
async def run(self) -> Optional[AcceptanceReport]:
|
|
546
|
+
"""Run the inferred checks once. ``None`` when the gate is not armed.
|
|
547
|
+
|
|
548
|
+
Disarms before running: the paths this pass covers are consumed, so a
|
|
549
|
+
turn that fixes nothing cannot re-fire the same checks forever, while
|
|
550
|
+
a repair that writes a file re-arms the gate for the next pass.
|
|
551
|
+
"""
|
|
552
|
+
if not self.should_run():
|
|
553
|
+
return None
|
|
554
|
+
|
|
555
|
+
paths = tuple(self._pending)
|
|
556
|
+
self._pending.clear()
|
|
557
|
+
self.attempts += 1
|
|
558
|
+
|
|
559
|
+
commands, reason = self._plan(paths)
|
|
560
|
+
bound_paths = tuple(dict.fromkeys((*paths, *self.revision_inputs)))
|
|
561
|
+
before = self._revision(bound_paths)
|
|
562
|
+
checks: List[CheckResult] = []
|
|
563
|
+
for command in commands:
|
|
564
|
+
check = await self._run_one(command)
|
|
565
|
+
checks.append(check)
|
|
566
|
+
# Stop at the first red. Later checks usually fail for the same
|
|
567
|
+
# cause, and each extra failing log costs context the repair needs.
|
|
568
|
+
# A check that could not run says nothing about the code, so the rest still run.
|
|
569
|
+
if not check.passed and not check.unavailable:
|
|
570
|
+
break
|
|
571
|
+
|
|
572
|
+
if self.baseline is not None:
|
|
573
|
+
checks = [await self._against_baseline(check) for check in checks]
|
|
574
|
+
|
|
575
|
+
after = self._revision(bound_paths)
|
|
576
|
+
revision_status = ("unavailable" if before is None or after is None else
|
|
577
|
+
"current" if before == after else "changed_during_checks")
|
|
578
|
+
report = AcceptanceReport(
|
|
579
|
+
attempt=self.attempts,
|
|
580
|
+
checks=tuple(checks),
|
|
581
|
+
reason=reason,
|
|
582
|
+
paths=paths,
|
|
583
|
+
attempts_remaining=max(0, self.max_attempts - self.attempts),
|
|
584
|
+
revision_status=revision_status,
|
|
585
|
+
revision_paths=after or (),
|
|
586
|
+
)
|
|
587
|
+
self.reports.append(report)
|
|
588
|
+
return report
|
|
589
|
+
|
|
590
|
+
# ── reporting ─────────────────────────────────────────────────────────
|
|
591
|
+
|
|
592
|
+
def summary(self) -> dict:
|
|
593
|
+
"""What the turn result carries so a caller can prove the claim.
|
|
594
|
+
|
|
595
|
+
``verified`` is tri-state on purpose. ``True`` means checks ran green,
|
|
596
|
+
``False`` means they ran red, and ``None`` means nothing was verified —
|
|
597
|
+
a read-only turn, or a workspace with no inferable check. Collapsing
|
|
598
|
+
the last two into ``False`` would make every analysis turn look failed;
|
|
599
|
+
collapsing it into ``True`` would be the exact lie this module exists
|
|
600
|
+
to prevent.
|
|
601
|
+
"""
|
|
602
|
+
last = self.reports[-1] if self.reports else None
|
|
603
|
+
freshness = "not_checked"
|
|
604
|
+
if last is not None:
|
|
605
|
+
if last.revision_status != "current":
|
|
606
|
+
freshness = last.revision_status
|
|
607
|
+
else:
|
|
608
|
+
current = self._revision(tuple(p for p, _, _ in last.revision_paths))
|
|
609
|
+
freshness = ("unavailable" if current is None else
|
|
610
|
+
"current" if current == last.revision_paths else "stale")
|
|
611
|
+
verified: Optional[bool] = None
|
|
612
|
+
if last is not None and last.ran:
|
|
613
|
+
verified = last.passed and not self.armed
|
|
614
|
+
if verified and last.not_run:
|
|
615
|
+
verified = None # what could run passed, but part of the plan did not run
|
|
616
|
+
if freshness != "current" and not last.failures:
|
|
617
|
+
verified = None
|
|
618
|
+
return {
|
|
619
|
+
"verified": verified,
|
|
620
|
+
# False when the checks are red only where they were red before
|
|
621
|
+
# the change; None when nothing ran or nothing failed.
|
|
622
|
+
"regressions": (last.regressed if last is not None and last.ran and not last.passed else None),
|
|
623
|
+
"attempts": self.attempts,
|
|
624
|
+
"paths": list(self._all_paths),
|
|
625
|
+
"reports": [report.summary() for report in self.reports],
|
|
626
|
+
"pending_paths": list(self._pending),
|
|
627
|
+
"revision_freshness": freshness,
|
|
628
|
+
"revision_scope": "latest_check_paths_and_host_inputs_content_only",
|
|
629
|
+
"headline": ("改动后尚未重新验收" if self.armed else
|
|
630
|
+
"文件内容变化或指纹不可用,需重新验收" if freshness not in {"current", "not_checked"} and not last.failures else
|
|
631
|
+
last.headline() if last is not None else ""),
|
|
632
|
+
}
|