aria-code 0.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_code/__init__.py +42 -0
- aria_code/_version.py +20 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +34 -0
- aria_code/agents/base.py +318 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +303 -0
- aria_code/agents/financial/fundamental.py +191 -0
- aria_code/agents/financial/macro.py +99 -0
- aria_code/agents/financial/news.py +207 -0
- aria_code/agents/financial/risk.py +165 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +258 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +363 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +158 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +492 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +15 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +95 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/bootstrap.py +145 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +16 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +369 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +239 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
- aria_code/apps/cli/commands/broker_cmds.py +1234 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +87 -0
- aria_code/apps/cli/commands/core_cmds.py +2520 -0
- aria_code/apps/cli/commands/data_cmds.py +457 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +434 -0
- aria_code/apps/cli/commands/market_cmds.py +1381 -0
- aria_code/apps/cli/commands/market_context.py +425 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2153 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
- aria_code/apps/cli/commands/report.py +437 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +669 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
- aria_code/apps/cli/commands/workflow_cmds.py +480 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +78 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/deterministic.py +191 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +196 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
- aria_code/apps/cli/handlers/market_handlers.py +2513 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/helpers.py +302 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +297 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +276 -0
- aria_code/apps/cli/intent_signals.py +344 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +536 -0
- aria_code/apps/cli/main.py +29 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/model_catalog.py +620 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +59 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +53 -0
- aria_code/apps/cli/prompts/select.py +142 -0
- aria_code/apps/cli/prompts/system_prompts.py +552 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +521 -0
- aria_code/apps/cli/providers/chat_routing.py +128 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
- aria_code/apps/cli/providers/runtime_bridge.py +353 -0
- aria_code/apps/cli/providers/vertexai_stream.py +316 -0
- aria_code/apps/cli/runtime_consumer.py +657 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_store.py +112 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +823 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +106 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +180 -0
- aria_code/apps/cli/tools/market_tools.py +620 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +726 -0
- aria_code/apps/cli/tools/write_tools.py +845 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +153 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1597 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +6743 -0
- aria_code/aria_daemon.py +1398 -0
- aria_code/aria_feishu_bot.py +1423 -0
- aria_code/aria_mcp_server.py +7 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_relay_server.py +490 -0
- aria_code/aria_telegram_bot.py +202 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +182 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1976 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +181 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/demo_player.py +207 -0
- aria_code/doctor.py +813 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/backtest_engine.py +354 -0
- aria_code/domain/backtest_report.py +472 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/harness.py +598 -0
- aria_code/evals/runner.py +238 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +386 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +639 -0
- aria_code/memory_manager.py +246 -0
- aria_code/model_capability.py +486 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +23 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +52 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +201 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +111 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1550 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +396 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +79 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +268 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +57 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +157 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +8 -0
- aria_code/packages/aria_tools/financial/_paths.py +130 -0
- aria_code/packages/aria_tools/financial/compliance.py +31 -0
- aria_code/packages/aria_tools/financial/factors.py +33 -0
- aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
- aria_code/packages/aria_tools/financial/strategy.py +31 -0
- aria_code/packages/aria_tools/registry.py +128 -0
- aria_code/packages/quant_engine/__init__.py +34 -0
- aria_code/packages/quant_engine/_namespace.py +62 -0
- aria_code/packages/quant_engine/backtest/__init__.py +14 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +96 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +80 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/ml_model.py +377 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/logistics/__init__.py +169 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +129 -0
- aria_code/providers/llm/openai_compat.py +313 -0
- aria_code/providers/llm/registry.py +444 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +589 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/runtime/__init__.py +169 -0
- aria_code/runtime/acceptance.py +481 -0
- aria_code/runtime/agent_loop.py +1520 -0
- aria_code/runtime/approval.py +57 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +432 -0
- aria_code/runtime/crash_report.py +174 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +150 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/repo_map.py +700 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +450 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/subagent.py +547 -0
- aria_code/runtime/task_ledger.py +86 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/tool_executor.py +217 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +23 -0
- aria_code/safety/permissions.py +306 -0
- aria_code/safety/service.py +102 -0
- aria_code/setup_wizard.py +673 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +504 -0
- aria_code/tools/data_analysis_tools.py +809 -0
- aria_code/tools/enterprise_finance_tools.py +156 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +885 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3417 -0
- aria_code/tools/logistics_tools.py +135 -0
- aria_code/tools/macro_tools.py +369 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +659 -0
- aria_code/tools/spreadsheet_tools.py +388 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +508 -0
- aria_code/ui/completer.py +501 -0
- aria_code/ui/console.py +281 -0
- aria_code/ui/image_render.py +243 -0
- aria_code/ui/input_box.py +488 -0
- aria_code/ui/picker.py +201 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/finance.py +1705 -0
- aria_code/ui/render/market.py +225 -0
- aria_code/ui/render/output.py +775 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +354 -0
- aria_code/ui/robot.py +235 -0
- aria_code/ui/startup_dashboard.py +109 -0
- aria_code/utils/vscode_uri.py +37 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +271 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +193 -0
- aria_code/workspace/verify.py +113 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_context.py +233 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.52.0.dist-info/METADATA +237 -0
- aria_code-0.52.0.dist-info/RECORD +478 -0
- aria_code-0.52.0.dist-info/WHEEL +5 -0
- aria_code-0.52.0.dist-info/entry_points.txt +3 -0
- aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.52.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Runtime primitives for Aria Code agent execution."""
|
|
2
|
+
|
|
3
|
+
from .agent_loop import (
|
|
4
|
+
AgentErrorPresentation,
|
|
5
|
+
AgentEvent,
|
|
6
|
+
AgentEventCancelled,
|
|
7
|
+
AgentEventComplete,
|
|
8
|
+
AgentEventError,
|
|
9
|
+
AgentEventStatus,
|
|
10
|
+
AgentEventThinking,
|
|
11
|
+
AgentEventToken,
|
|
12
|
+
AgentEventToolCall,
|
|
13
|
+
AgentEventToolResult,
|
|
14
|
+
AgentOptions,
|
|
15
|
+
AgentTurnMetadata,
|
|
16
|
+
AgentTurnEnvelope,
|
|
17
|
+
AgentTurnResult,
|
|
18
|
+
AgentTurnState,
|
|
19
|
+
ToolBatchState,
|
|
20
|
+
ToolExecutionActivity,
|
|
21
|
+
ToolExecutionTurnResult,
|
|
22
|
+
ToolCallTask,
|
|
23
|
+
ToolTurnPlan,
|
|
24
|
+
build_next_turn_messages,
|
|
25
|
+
build_tool_followup,
|
|
26
|
+
collect_parallel_done,
|
|
27
|
+
detect_task_complete,
|
|
28
|
+
execute_tool_turn,
|
|
29
|
+
LoopGuard,
|
|
30
|
+
record_tool_result,
|
|
31
|
+
run_agent,
|
|
32
|
+
run_parallel_tools,
|
|
33
|
+
run_serial_tool,
|
|
34
|
+
split_tool_calls,
|
|
35
|
+
)
|
|
36
|
+
from .acceptance import (
|
|
37
|
+
AcceptanceGate,
|
|
38
|
+
AcceptanceReport,
|
|
39
|
+
CheckResult,
|
|
40
|
+
DEFAULT_MUTATING_TOOLS,
|
|
41
|
+
extract_mutated_paths,
|
|
42
|
+
)
|
|
43
|
+
from .repo_map import (
|
|
44
|
+
REPO_MAP_SCHEMAS,
|
|
45
|
+
REPO_MAP_TOOLS,
|
|
46
|
+
RepoMap,
|
|
47
|
+
Symbol,
|
|
48
|
+
extract_symbols,
|
|
49
|
+
)
|
|
50
|
+
from .gateway import TurnResult, run_turn
|
|
51
|
+
from .approval import ApprovalDecision, apply_approval_decision
|
|
52
|
+
from .events import RuntimeEvent, RuntimeTrace, ToolCallRecord, TurnResultRecord
|
|
53
|
+
from .run_state import (
|
|
54
|
+
ACTIVE_RUN_STATUSES,
|
|
55
|
+
TERMINAL_RUN_STATUSES,
|
|
56
|
+
InvalidRunTransition,
|
|
57
|
+
RunStatus,
|
|
58
|
+
can_transition,
|
|
59
|
+
is_terminal,
|
|
60
|
+
require_transition,
|
|
61
|
+
)
|
|
62
|
+
from .run_store import RunEventRecord, RunNotFoundError, RunRecord, RunStore
|
|
63
|
+
from .checkpoints import (
|
|
64
|
+
CheckpointConflictError,
|
|
65
|
+
CheckpointFile,
|
|
66
|
+
CheckpointNotFoundError,
|
|
67
|
+
CheckpointRecord,
|
|
68
|
+
CheckpointStore,
|
|
69
|
+
RestoreResult,
|
|
70
|
+
)
|
|
71
|
+
from .worktrees import WorktreeApplyResult, WorktreeError, WorktreeManager, WorktreeSpec
|
|
72
|
+
from .tool_executor import ToolExecutor
|
|
73
|
+
from .tool_policy import check_tool_policy, add_to_policy, remove_from_policy, load_tool_policy
|
|
74
|
+
from .subagent import (
|
|
75
|
+
SUBAGENT_TOOLS,
|
|
76
|
+
SUBAGENT_SCHEMAS,
|
|
77
|
+
tool_spawn_task,
|
|
78
|
+
tool_task_status,
|
|
79
|
+
tool_task_result,
|
|
80
|
+
tool_task_list,
|
|
81
|
+
tool_task_cancel,
|
|
82
|
+
register_runner,
|
|
83
|
+
restore_tasks,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
__all__ = [
|
|
87
|
+
"REPO_MAP_SCHEMAS",
|
|
88
|
+
"REPO_MAP_TOOLS",
|
|
89
|
+
"RepoMap",
|
|
90
|
+
"Symbol",
|
|
91
|
+
"extract_symbols",
|
|
92
|
+
"AcceptanceGate",
|
|
93
|
+
"AcceptanceReport",
|
|
94
|
+
"CheckResult",
|
|
95
|
+
"DEFAULT_MUTATING_TOOLS",
|
|
96
|
+
"extract_mutated_paths",
|
|
97
|
+
"AgentErrorPresentation",
|
|
98
|
+
"AgentEvent",
|
|
99
|
+
"AgentEventCancelled",
|
|
100
|
+
"AgentEventComplete",
|
|
101
|
+
"AgentEventError",
|
|
102
|
+
"AgentEventStatus",
|
|
103
|
+
"AgentEventThinking",
|
|
104
|
+
"AgentEventToken",
|
|
105
|
+
"AgentEventToolCall",
|
|
106
|
+
"AgentEventToolResult",
|
|
107
|
+
"AgentOptions",
|
|
108
|
+
"AgentTurnMetadata",
|
|
109
|
+
"AgentTurnEnvelope",
|
|
110
|
+
"AgentTurnResult",
|
|
111
|
+
"AgentTurnState",
|
|
112
|
+
"ApprovalDecision",
|
|
113
|
+
"RuntimeEvent",
|
|
114
|
+
"RuntimeTrace",
|
|
115
|
+
"RunEventRecord",
|
|
116
|
+
"RunNotFoundError",
|
|
117
|
+
"RunRecord",
|
|
118
|
+
"RunStatus",
|
|
119
|
+
"RunStore",
|
|
120
|
+
"InvalidRunTransition",
|
|
121
|
+
"CheckpointConflictError",
|
|
122
|
+
"CheckpointFile",
|
|
123
|
+
"CheckpointNotFoundError",
|
|
124
|
+
"CheckpointRecord",
|
|
125
|
+
"CheckpointStore",
|
|
126
|
+
"RestoreResult",
|
|
127
|
+
"WorktreeError",
|
|
128
|
+
"WorktreeApplyResult",
|
|
129
|
+
"WorktreeManager",
|
|
130
|
+
"WorktreeSpec",
|
|
131
|
+
"ACTIVE_RUN_STATUSES",
|
|
132
|
+
"TERMINAL_RUN_STATUSES",
|
|
133
|
+
"ToolCallRecord",
|
|
134
|
+
"TurnResultRecord",
|
|
135
|
+
"ToolBatchState",
|
|
136
|
+
"ToolExecutionActivity",
|
|
137
|
+
"ToolExecutionTurnResult",
|
|
138
|
+
"ToolCallTask",
|
|
139
|
+
"ToolExecutor",
|
|
140
|
+
"ToolTurnPlan",
|
|
141
|
+
"apply_approval_decision",
|
|
142
|
+
"build_next_turn_messages",
|
|
143
|
+
"build_tool_followup",
|
|
144
|
+
"collect_parallel_done",
|
|
145
|
+
"detect_task_complete",
|
|
146
|
+
"execute_tool_turn",
|
|
147
|
+
"LoopGuard",
|
|
148
|
+
"record_tool_result",
|
|
149
|
+
"run_agent",
|
|
150
|
+
"run_parallel_tools",
|
|
151
|
+
"run_serial_tool",
|
|
152
|
+
"split_tool_calls",
|
|
153
|
+
"can_transition",
|
|
154
|
+
"is_terminal",
|
|
155
|
+
"require_transition",
|
|
156
|
+
"check_tool_policy",
|
|
157
|
+
"add_to_policy",
|
|
158
|
+
"remove_from_policy",
|
|
159
|
+
"load_tool_policy",
|
|
160
|
+
"SUBAGENT_TOOLS",
|
|
161
|
+
"SUBAGENT_SCHEMAS",
|
|
162
|
+
"tool_spawn_task",
|
|
163
|
+
"tool_task_status",
|
|
164
|
+
"tool_task_result",
|
|
165
|
+
"tool_task_list",
|
|
166
|
+
"tool_task_cancel",
|
|
167
|
+
"register_runner",
|
|
168
|
+
"restore_tasks",
|
|
169
|
+
]
|
|
@@ -0,0 +1,481 @@
|
|
|
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 re
|
|
47
|
+
import time
|
|
48
|
+
from dataclasses import dataclass, field
|
|
49
|
+
from pathlib import Path
|
|
50
|
+
from typing import Any, Awaitable, Callable, Dict, Iterable, List, Optional, Sequence, Union
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"AcceptanceGate",
|
|
54
|
+
"AcceptanceReport",
|
|
55
|
+
"CheckResult",
|
|
56
|
+
"DEFAULT_MUTATING_TOOLS",
|
|
57
|
+
"extract_mutated_paths",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Tools whose success means bytes changed on disk. ``run_command`` is
|
|
62
|
+
# deliberately absent: it can mutate, but gating on it would re-arm the gate
|
|
63
|
+
# with every check the gate itself runs — the checks would never terminate.
|
|
64
|
+
DEFAULT_MUTATING_TOOLS = frozenset({
|
|
65
|
+
"write_file",
|
|
66
|
+
"edit_file",
|
|
67
|
+
"multi_edit",
|
|
68
|
+
"apply_patch",
|
|
69
|
+
"notebook_edit",
|
|
70
|
+
"str_replace",
|
|
71
|
+
"create_file",
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
# A failing test log is the single most context-hungry payload in a coding
|
|
75
|
+
# turn — a full pytest run can exceed the window on its own. Head carries the
|
|
76
|
+
# collection error, tail carries the assertion and the summary line; the middle
|
|
77
|
+
# is almost always repeated passing output.
|
|
78
|
+
_HEAD_LINES = 20
|
|
79
|
+
_TAIL_LINES = 45
|
|
80
|
+
_MAX_CHARS = 6000
|
|
81
|
+
|
|
82
|
+
# ``File "x.py", line 12`` (Python), ``x.ts:12:5`` (tsc/eslint/jest).
|
|
83
|
+
_PY_ANCHOR = re.compile(r'File "([^"]+)", line (\d+)')
|
|
84
|
+
_COLON_ANCHOR = re.compile(r"(?m)^\s*([\w./\\-]+\.[A-Za-z]{1,4}):(\d+)(?::\d+)?")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _as_dict(value: Any) -> Dict[str, Any]:
|
|
88
|
+
return value if isinstance(value, dict) else {}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def extract_mutated_paths(
|
|
92
|
+
tool: str,
|
|
93
|
+
result: Any,
|
|
94
|
+
*,
|
|
95
|
+
mutating_tools: Iterable[str] = DEFAULT_MUTATING_TOOLS,
|
|
96
|
+
) -> tuple[str, ...]:
|
|
97
|
+
"""Paths this tool result actually wrote to disk.
|
|
98
|
+
|
|
99
|
+
Returns nothing for a failed call and nothing for a *staged* change. The
|
|
100
|
+
distinction matters: ``write_file`` in review mode returns success with
|
|
101
|
+
``applied: False`` and the file on disk is untouched, so running the test
|
|
102
|
+
suite would verify the previous state and report a green that means
|
|
103
|
+
nothing.
|
|
104
|
+
"""
|
|
105
|
+
canonical = str(tool or "").rsplit("__", 1)[-1]
|
|
106
|
+
if canonical not in set(mutating_tools):
|
|
107
|
+
return ()
|
|
108
|
+
|
|
109
|
+
payload = _as_dict(result)
|
|
110
|
+
if payload.get("success") is False or payload.get("error"):
|
|
111
|
+
return ()
|
|
112
|
+
|
|
113
|
+
data = _as_dict(payload.get("data")) or payload
|
|
114
|
+
if data.get("applied") is False or data.get("staged") is True:
|
|
115
|
+
return ()
|
|
116
|
+
|
|
117
|
+
found: List[str] = []
|
|
118
|
+
|
|
119
|
+
def _add(value: Any) -> None:
|
|
120
|
+
text = str(value or "").strip()
|
|
121
|
+
if text and text not in found:
|
|
122
|
+
found.append(text)
|
|
123
|
+
|
|
124
|
+
_add(data.get("path"))
|
|
125
|
+
_add(data.get("file_path"))
|
|
126
|
+
for entry in data.get("paths", ()) or ():
|
|
127
|
+
_add(entry)
|
|
128
|
+
# multi_edit reports per-edit records rather than a single path.
|
|
129
|
+
for entry in data.get("edits", ()) or ():
|
|
130
|
+
_add(_as_dict(entry).get("path"))
|
|
131
|
+
|
|
132
|
+
return tuple(found)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _trim(text: str) -> str:
|
|
136
|
+
"""Head + tail of command output, with the uninformative middle dropped."""
|
|
137
|
+
body = (text or "").strip()
|
|
138
|
+
if not body:
|
|
139
|
+
return ""
|
|
140
|
+
lines = body.splitlines()
|
|
141
|
+
if len(lines) > _HEAD_LINES + _TAIL_LINES:
|
|
142
|
+
omitted = len(lines) - _HEAD_LINES - _TAIL_LINES
|
|
143
|
+
lines = (
|
|
144
|
+
lines[:_HEAD_LINES]
|
|
145
|
+
+ [f"… [{omitted} lines omitted] …"]
|
|
146
|
+
+ lines[-_TAIL_LINES:]
|
|
147
|
+
)
|
|
148
|
+
joined = "\n".join(lines)
|
|
149
|
+
if len(joined) > _MAX_CHARS:
|
|
150
|
+
keep = _MAX_CHARS // 2
|
|
151
|
+
joined = f"{joined[:keep]}\n… [truncated] …\n{joined[-keep:]}"
|
|
152
|
+
return joined
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _anchors(text: str, limit: int = 5) -> tuple[str, ...]:
|
|
156
|
+
"""``file:line`` locations named in a failure, most recent frame last.
|
|
157
|
+
|
|
158
|
+
Handing the model the anchors separately is what turns a wall of log into
|
|
159
|
+
an edit: without them a weaker model tends to rewrite the whole file
|
|
160
|
+
instead of patching the line the traceback already identified.
|
|
161
|
+
"""
|
|
162
|
+
out: List[str] = []
|
|
163
|
+
for match in _PY_ANCHOR.finditer(text or ""):
|
|
164
|
+
entry = f"{match.group(1)}:{match.group(2)}"
|
|
165
|
+
if entry not in out:
|
|
166
|
+
out.append(entry)
|
|
167
|
+
for match in _COLON_ANCHOR.finditer(text or ""):
|
|
168
|
+
entry = f"{match.group(1)}:{match.group(2)}"
|
|
169
|
+
if entry not in out:
|
|
170
|
+
out.append(entry)
|
|
171
|
+
# The last frames are the ones inside the code that just changed; the first
|
|
172
|
+
# are usually the runner's own stack.
|
|
173
|
+
return tuple(out[-limit:])
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@dataclass(frozen=True)
|
|
177
|
+
class CheckResult:
|
|
178
|
+
"""One verification command, run."""
|
|
179
|
+
|
|
180
|
+
command: str
|
|
181
|
+
exit_code: int
|
|
182
|
+
passed: bool
|
|
183
|
+
output: str = ""
|
|
184
|
+
duration: float = 0.0
|
|
185
|
+
error: str = ""
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def anchors(self) -> tuple[str, ...]:
|
|
189
|
+
return () if self.passed else _anchors(self.output)
|
|
190
|
+
|
|
191
|
+
def summary(self) -> dict:
|
|
192
|
+
return {
|
|
193
|
+
"command": self.command,
|
|
194
|
+
"exit_code": self.exit_code,
|
|
195
|
+
"passed": self.passed,
|
|
196
|
+
"duration": round(self.duration, 3),
|
|
197
|
+
"error": self.error,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@dataclass(frozen=True)
|
|
202
|
+
class AcceptanceReport:
|
|
203
|
+
"""The outcome of one pass of the gate."""
|
|
204
|
+
|
|
205
|
+
attempt: int
|
|
206
|
+
checks: tuple[CheckResult, ...] = ()
|
|
207
|
+
reason: str = ""
|
|
208
|
+
paths: tuple[str, ...] = ()
|
|
209
|
+
attempts_remaining: int = 0
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def ran(self) -> bool:
|
|
213
|
+
return bool(self.checks)
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def passed(self) -> bool:
|
|
217
|
+
"""True only when at least one check ran and every check passed.
|
|
218
|
+
|
|
219
|
+
A gate that reports "verified" without running anything is worse than
|
|
220
|
+
no gate: it launders an unchecked claim into a checked-looking one.
|
|
221
|
+
"""
|
|
222
|
+
return self.ran and all(check.passed for check in self.checks)
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def failures(self) -> tuple[CheckResult, ...]:
|
|
226
|
+
return tuple(check for check in self.checks if not check.passed)
|
|
227
|
+
|
|
228
|
+
def headline(self) -> str:
|
|
229
|
+
if not self.ran:
|
|
230
|
+
return "验收未执行:未推断出检查命令"
|
|
231
|
+
if self.passed:
|
|
232
|
+
names = ", ".join(check.command for check in self.checks)
|
|
233
|
+
return f"验收通过 ({names})"
|
|
234
|
+
first = self.failures[0]
|
|
235
|
+
return f"验收失败:`{first.command}` exit {first.exit_code}"
|
|
236
|
+
|
|
237
|
+
def repair_directive(self) -> str:
|
|
238
|
+
"""What the model is told when the check came back red.
|
|
239
|
+
|
|
240
|
+
Written as evidence plus one instruction. The failing output is the
|
|
241
|
+
evidence; the instruction exists because the observed failure mode is
|
|
242
|
+
not that the model cannot fix the bug — it is that it re-announces
|
|
243
|
+
completion without having looked at why the command failed.
|
|
244
|
+
"""
|
|
245
|
+
blocks: List[str] = [
|
|
246
|
+
"## 验收未通过 (Acceptance check failed)",
|
|
247
|
+
"",
|
|
248
|
+
"你声明任务已完成,但改动过的文件没有通过自动验收检查。"
|
|
249
|
+
"以下是**实际执行**的命令和真实输出:",
|
|
250
|
+
"",
|
|
251
|
+
]
|
|
252
|
+
for check in self.failures:
|
|
253
|
+
blocks.append(f"### `{check.command}` → exit {check.exit_code}")
|
|
254
|
+
if check.error:
|
|
255
|
+
blocks.append(f"(执行错误:{check.error})")
|
|
256
|
+
body = _trim(check.output)
|
|
257
|
+
if body:
|
|
258
|
+
blocks.append(f"```\n{body}\n```")
|
|
259
|
+
if check.anchors:
|
|
260
|
+
blocks.append("定位:" + ", ".join(f"`{a}`" for a in check.anchors))
|
|
261
|
+
blocks.append("")
|
|
262
|
+
|
|
263
|
+
blocks.append(
|
|
264
|
+
"请依次:(1) 读出错位置的代码确认原因,(2) 用 `edit_file` 定点修补"
|
|
265
|
+
"——不要整文件重写,(3) 修好后直接说明修了什么。"
|
|
266
|
+
"修改后验收会自动重跑,你**不需要**自己调用验收命令。"
|
|
267
|
+
)
|
|
268
|
+
if self.attempts_remaining <= 0:
|
|
269
|
+
blocks.append(
|
|
270
|
+
"注意:这是最后一次修复机会。若仍未通过,请如实说明失败原因,"
|
|
271
|
+
"不要声称任务已完成。"
|
|
272
|
+
)
|
|
273
|
+
else:
|
|
274
|
+
blocks.append(f"剩余自动重试次数:{self.attempts_remaining}。")
|
|
275
|
+
return "\n".join(blocks)
|
|
276
|
+
|
|
277
|
+
def summary(self) -> dict:
|
|
278
|
+
return {
|
|
279
|
+
"attempt": self.attempt,
|
|
280
|
+
"passed": self.passed,
|
|
281
|
+
"ran": self.ran,
|
|
282
|
+
"reason": self.reason,
|
|
283
|
+
"paths": list(self.paths),
|
|
284
|
+
"checks": [check.summary() for check in self.checks],
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# ``(command) -> result dict`` — sync or async. The result is read loosely
|
|
289
|
+
# because every surface in this codebase wraps command output slightly
|
|
290
|
+
# differently; see ``_read_run_result``.
|
|
291
|
+
CommandRunner = Callable[[str], Union[dict, Awaitable[dict]]]
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _read_run_result(raw: Any) -> tuple[int, str, str]:
|
|
295
|
+
"""Normalise a runner result into ``(exit_code, output, error)``.
|
|
296
|
+
|
|
297
|
+
Deliberately permissive. ``tool_run_command`` returns
|
|
298
|
+
``{"success": True, "data": {"exit_code": .., "stdout": .., "stderr": ..}}``
|
|
299
|
+
on a completed command and ``{"success": False, "error": "…timed out"}``
|
|
300
|
+
when it never completed — and a timeout is a *failed* check, not a passing
|
|
301
|
+
one, so an unreadable result must never be read as exit 0.
|
|
302
|
+
"""
|
|
303
|
+
payload = _as_dict(raw)
|
|
304
|
+
if not payload:
|
|
305
|
+
return 1, "", "runner returned no result"
|
|
306
|
+
|
|
307
|
+
if payload.get("success") is False:
|
|
308
|
+
return 1, str(payload.get("output") or ""), str(payload.get("error") or "command failed")
|
|
309
|
+
|
|
310
|
+
data = _as_dict(payload.get("data")) or payload
|
|
311
|
+
for key in ("exit_code", "returncode", "code", "status"):
|
|
312
|
+
if key in data:
|
|
313
|
+
try:
|
|
314
|
+
exit_code = int(data[key])
|
|
315
|
+
break
|
|
316
|
+
except (TypeError, ValueError):
|
|
317
|
+
continue
|
|
318
|
+
else:
|
|
319
|
+
exit_code = 0
|
|
320
|
+
|
|
321
|
+
stdout = str(data.get("stdout") or data.get("output") or "")
|
|
322
|
+
stderr = str(data.get("stderr") or "")
|
|
323
|
+
output = "\n".join(part for part in (stdout, stderr) if part.strip())
|
|
324
|
+
return exit_code, output, ""
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class AcceptanceGate:
|
|
328
|
+
"""Arms on real writes, fires when the model says it is done."""
|
|
329
|
+
|
|
330
|
+
def __init__(
|
|
331
|
+
self,
|
|
332
|
+
*,
|
|
333
|
+
runner: CommandRunner,
|
|
334
|
+
root: Union[str, Path] = ".",
|
|
335
|
+
planner: Any = None,
|
|
336
|
+
max_attempts: int = 2,
|
|
337
|
+
mutating_tools: Iterable[str] = DEFAULT_MUTATING_TOOLS,
|
|
338
|
+
enabled: bool = True,
|
|
339
|
+
commands: Optional[Sequence[str]] = None,
|
|
340
|
+
) -> None:
|
|
341
|
+
self.root = Path(root).expanduser()
|
|
342
|
+
self.runner = runner
|
|
343
|
+
self.max_attempts = max(0, int(max_attempts))
|
|
344
|
+
self.mutating_tools = frozenset(mutating_tools)
|
|
345
|
+
self.enabled = bool(enabled)
|
|
346
|
+
# An explicit command list overrides inference — this is the hook a
|
|
347
|
+
# domain pack or a repo's own config uses to say what "green" means
|
|
348
|
+
# for it (``make check``, ``bazel test //...``), which inference can
|
|
349
|
+
# never guess.
|
|
350
|
+
self.commands = tuple(commands or ())
|
|
351
|
+
self._planner = planner
|
|
352
|
+
self.attempts = 0
|
|
353
|
+
self.reports: List[AcceptanceReport] = []
|
|
354
|
+
self._pending: List[str] = []
|
|
355
|
+
self._all_paths: List[str] = []
|
|
356
|
+
|
|
357
|
+
# ── arming ────────────────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
def record_tool(self, tool: str, result: Any) -> tuple[str, ...]:
|
|
360
|
+
"""Note one tool result; arms the gate if it wrote to disk."""
|
|
361
|
+
if not self.enabled:
|
|
362
|
+
return ()
|
|
363
|
+
paths = extract_mutated_paths(tool, result, mutating_tools=self.mutating_tools)
|
|
364
|
+
for path in paths:
|
|
365
|
+
if path not in self._pending:
|
|
366
|
+
self._pending.append(path)
|
|
367
|
+
if path not in self._all_paths:
|
|
368
|
+
self._all_paths.append(path)
|
|
369
|
+
return paths
|
|
370
|
+
|
|
371
|
+
@property
|
|
372
|
+
def armed(self) -> bool:
|
|
373
|
+
return bool(self._pending)
|
|
374
|
+
|
|
375
|
+
@property
|
|
376
|
+
def exhausted(self) -> bool:
|
|
377
|
+
return self.attempts >= self.max_attempts
|
|
378
|
+
|
|
379
|
+
def should_run(self) -> bool:
|
|
380
|
+
return self.enabled and self.armed and not self.exhausted
|
|
381
|
+
|
|
382
|
+
# ── firing ────────────────────────────────────────────────────────────
|
|
383
|
+
|
|
384
|
+
def _plan(self, paths: Sequence[str]) -> tuple[tuple[str, ...], str]:
|
|
385
|
+
if self.commands:
|
|
386
|
+
return self.commands, "configured acceptance commands"
|
|
387
|
+
planner = self._planner
|
|
388
|
+
if planner is None:
|
|
389
|
+
try:
|
|
390
|
+
from aria_code.workspace.verify import VerificationPlanner
|
|
391
|
+
except Exception:
|
|
392
|
+
return (), "verification planner unavailable"
|
|
393
|
+
planner = VerificationPlanner(root=self.root)
|
|
394
|
+
self._planner = planner
|
|
395
|
+
try:
|
|
396
|
+
plan = planner.infer(list(paths))
|
|
397
|
+
except Exception as exc: # a planner fault must not fail the turn
|
|
398
|
+
return (), f"verification planning failed: {exc}"
|
|
399
|
+
return tuple(plan.commands or ()), str(plan.reason or "")
|
|
400
|
+
|
|
401
|
+
async def _run_one(self, command: str) -> CheckResult:
|
|
402
|
+
started = time.time()
|
|
403
|
+
try:
|
|
404
|
+
raw = self.runner(command)
|
|
405
|
+
if inspect.isawaitable(raw):
|
|
406
|
+
raw = await raw
|
|
407
|
+
except Exception as exc:
|
|
408
|
+
return CheckResult(
|
|
409
|
+
command=command,
|
|
410
|
+
exit_code=1,
|
|
411
|
+
passed=False,
|
|
412
|
+
error=str(exc),
|
|
413
|
+
duration=time.time() - started,
|
|
414
|
+
)
|
|
415
|
+
exit_code, output, error = _read_run_result(raw)
|
|
416
|
+
return CheckResult(
|
|
417
|
+
command=command,
|
|
418
|
+
exit_code=exit_code,
|
|
419
|
+
passed=exit_code == 0 and not error,
|
|
420
|
+
output=output,
|
|
421
|
+
error=error,
|
|
422
|
+
duration=time.time() - started,
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
async def run(self) -> Optional[AcceptanceReport]:
|
|
426
|
+
"""Run the inferred checks once. ``None`` when the gate is not armed.
|
|
427
|
+
|
|
428
|
+
Disarms before running: the paths this pass covers are consumed, so a
|
|
429
|
+
turn that fixes nothing cannot re-fire the same checks forever, while
|
|
430
|
+
a repair that writes a file re-arms the gate for the next pass.
|
|
431
|
+
"""
|
|
432
|
+
if not self.should_run():
|
|
433
|
+
return None
|
|
434
|
+
|
|
435
|
+
paths = tuple(self._pending)
|
|
436
|
+
self._pending.clear()
|
|
437
|
+
self.attempts += 1
|
|
438
|
+
|
|
439
|
+
commands, reason = self._plan(paths)
|
|
440
|
+
checks: List[CheckResult] = []
|
|
441
|
+
for command in commands:
|
|
442
|
+
check = await self._run_one(command)
|
|
443
|
+
checks.append(check)
|
|
444
|
+
# Stop at the first red. Later checks usually fail for the same
|
|
445
|
+
# cause, and each extra failing log costs context the repair needs.
|
|
446
|
+
if not check.passed:
|
|
447
|
+
break
|
|
448
|
+
|
|
449
|
+
report = AcceptanceReport(
|
|
450
|
+
attempt=self.attempts,
|
|
451
|
+
checks=tuple(checks),
|
|
452
|
+
reason=reason,
|
|
453
|
+
paths=paths,
|
|
454
|
+
attempts_remaining=max(0, self.max_attempts - self.attempts),
|
|
455
|
+
)
|
|
456
|
+
self.reports.append(report)
|
|
457
|
+
return report
|
|
458
|
+
|
|
459
|
+
# ── reporting ─────────────────────────────────────────────────────────
|
|
460
|
+
|
|
461
|
+
def summary(self) -> dict:
|
|
462
|
+
"""What the turn result carries so a caller can prove the claim.
|
|
463
|
+
|
|
464
|
+
``verified`` is tri-state on purpose. ``True`` means checks ran green,
|
|
465
|
+
``False`` means they ran red, and ``None`` means nothing was verified —
|
|
466
|
+
a read-only turn, or a workspace with no inferable check. Collapsing
|
|
467
|
+
the last two into ``False`` would make every analysis turn look failed;
|
|
468
|
+
collapsing it into ``True`` would be the exact lie this module exists
|
|
469
|
+
to prevent.
|
|
470
|
+
"""
|
|
471
|
+
last = self.reports[-1] if self.reports else None
|
|
472
|
+
verified: Optional[bool] = None
|
|
473
|
+
if last is not None and last.ran:
|
|
474
|
+
verified = last.passed
|
|
475
|
+
return {
|
|
476
|
+
"verified": verified,
|
|
477
|
+
"attempts": self.attempts,
|
|
478
|
+
"paths": list(self._all_paths),
|
|
479
|
+
"reports": [report.summary() for report in self.reports],
|
|
480
|
+
"headline": last.headline() if last is not None else "",
|
|
481
|
+
}
|