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,422 @@
|
|
|
1
|
+
"""
|
|
2
|
+
runtime/self_healing.py — Lightweight Static Pre-flight & Traceback Patch Self-Healing Engine
|
|
3
|
+
===========================================================================================
|
|
4
|
+
1. Fast Static Syntax Compilation (<10ms via compile / py_compile)
|
|
5
|
+
2. Sandbox Dry-run Execution
|
|
6
|
+
3. Traceback Parsing (Error Type, Offending Line, Context)
|
|
7
|
+
4. Surgical Differential Patch Repair (Never rewrites entire file)
|
|
8
|
+
5. Metric Extraction & Deliverable Packaging (No terminal log flooding)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import ast
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import pathlib
|
|
18
|
+
import re
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class TracebackInfo:
|
|
29
|
+
file_path: str
|
|
30
|
+
line_number: int
|
|
31
|
+
error_type: str
|
|
32
|
+
error_message: str
|
|
33
|
+
code_snippet: str
|
|
34
|
+
full_traceback: str
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class SelfHealingResult:
|
|
39
|
+
success: bool
|
|
40
|
+
retries_used: int
|
|
41
|
+
final_output: str
|
|
42
|
+
error: Optional[str] = None
|
|
43
|
+
metrics: Dict[str, Any] = field(default_factory=dict)
|
|
44
|
+
artifact_paths: List[str] = field(default_factory=list)
|
|
45
|
+
patches_applied: List[Dict[str, Any]] = field(default_factory=list)
|
|
46
|
+
|
|
47
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
48
|
+
return {
|
|
49
|
+
"success": self.success,
|
|
50
|
+
"retries_used": self.retries_used,
|
|
51
|
+
"error": self.error,
|
|
52
|
+
"metrics": self.metrics,
|
|
53
|
+
"artifact_paths": self.artifact_paths,
|
|
54
|
+
"patches_applied": self.patches_applied,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class SelfHealingEngine:
|
|
59
|
+
"""
|
|
60
|
+
Automated execution, diagnostics, and patch self-healing engine.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
python_executable: str = sys.executable,
|
|
66
|
+
max_retries: int = 3,
|
|
67
|
+
llm_fixer: Optional[Callable[[TracebackInfo, str], Any]] = None,
|
|
68
|
+
) -> None:
|
|
69
|
+
self.python_executable = python_executable
|
|
70
|
+
self.max_retries = max_retries
|
|
71
|
+
self.llm_fixer = llm_fixer
|
|
72
|
+
|
|
73
|
+
def verify_syntax(self, file_path: pathlib.Path) -> Tuple[bool, Optional[str], Optional[int]]:
|
|
74
|
+
"""
|
|
75
|
+
Fast static syntax check using AST compilation (<10ms).
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
content = file_path.read_text(encoding="utf-8")
|
|
79
|
+
compile(content, str(file_path), "exec")
|
|
80
|
+
return True, None, None
|
|
81
|
+
except SyntaxError as exc:
|
|
82
|
+
line = exc.lineno or 1
|
|
83
|
+
msg = f"SyntaxError: {exc.msg} at line {line}"
|
|
84
|
+
return False, msg, line
|
|
85
|
+
except Exception as exc:
|
|
86
|
+
return False, str(exc), None
|
|
87
|
+
|
|
88
|
+
def run_sandbox_execution(
|
|
89
|
+
self,
|
|
90
|
+
file_path: pathlib.Path,
|
|
91
|
+
timeout: float = 30.0,
|
|
92
|
+
cwd: Optional[pathlib.Path] = None,
|
|
93
|
+
) -> Tuple[int, str, str]:
|
|
94
|
+
"""
|
|
95
|
+
Run the Python script in a dry-run subprocess sandbox.
|
|
96
|
+
"""
|
|
97
|
+
work_dir = cwd or file_path.parent
|
|
98
|
+
env = dict(os.environ)
|
|
99
|
+
env["PYTHONPATH"] = f"{work_dir}:{env.get('PYTHONPATH', '')}"
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
proc = subprocess.run(
|
|
103
|
+
[self.python_executable, str(file_path)],
|
|
104
|
+
cwd=str(work_dir),
|
|
105
|
+
capture_output=True,
|
|
106
|
+
text=True,
|
|
107
|
+
timeout=timeout,
|
|
108
|
+
env=env,
|
|
109
|
+
)
|
|
110
|
+
return proc.returncode, proc.stdout, proc.stderr
|
|
111
|
+
except subprocess.TimeoutExpired:
|
|
112
|
+
return -1, "", f"Execution timed out after {timeout}s"
|
|
113
|
+
except Exception as exc:
|
|
114
|
+
return -1, "", f"Failed to execute script: {exc}"
|
|
115
|
+
|
|
116
|
+
def parse_traceback(self, stderr: str, target_file: pathlib.Path) -> Optional[TracebackInfo]:
|
|
117
|
+
"""
|
|
118
|
+
Extract exact error line, error type, and snippet from python stderr.
|
|
119
|
+
"""
|
|
120
|
+
if not stderr:
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
# Look for standard Python traceback lines: File "path", line X, in Y
|
|
124
|
+
lines = stderr.strip().splitlines()
|
|
125
|
+
target_name = target_file.name
|
|
126
|
+
|
|
127
|
+
target_line = None
|
|
128
|
+
snippet = ""
|
|
129
|
+
error_type = "UnknownError"
|
|
130
|
+
error_msg = ""
|
|
131
|
+
|
|
132
|
+
for i, line in enumerate(lines):
|
|
133
|
+
if "File " in line and target_name in line:
|
|
134
|
+
m = re.search(r'line (\d+)', line)
|
|
135
|
+
if m:
|
|
136
|
+
target_line = int(m.group(1))
|
|
137
|
+
if i + 1 < len(lines) and not lines[i + 1].strip().startswith("File "):
|
|
138
|
+
snippet = lines[i + 1].strip()
|
|
139
|
+
|
|
140
|
+
# The last non-empty line usually contains ErrorType: message
|
|
141
|
+
for line in reversed(lines):
|
|
142
|
+
line_str = line.strip()
|
|
143
|
+
if ":" in line_str and not line_str.startswith("File "):
|
|
144
|
+
parts = line_str.split(":", 1)
|
|
145
|
+
error_type = parts[0].strip()
|
|
146
|
+
error_msg = parts[1].strip()
|
|
147
|
+
break
|
|
148
|
+
|
|
149
|
+
if target_line is None:
|
|
150
|
+
# Check if any line number is mentioned
|
|
151
|
+
m = re.search(r'line (\d+)', stderr)
|
|
152
|
+
if m:
|
|
153
|
+
target_line = int(m.group(1))
|
|
154
|
+
|
|
155
|
+
if target_line is None:
|
|
156
|
+
target_line = 1
|
|
157
|
+
|
|
158
|
+
return TracebackInfo(
|
|
159
|
+
file_path=str(target_file),
|
|
160
|
+
line_number=target_line,
|
|
161
|
+
error_type=error_type,
|
|
162
|
+
error_message=error_msg,
|
|
163
|
+
code_snippet=snippet,
|
|
164
|
+
full_traceback=stderr,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def apply_patch(
|
|
168
|
+
self,
|
|
169
|
+
file_path: pathlib.Path,
|
|
170
|
+
target_line: int,
|
|
171
|
+
replacement_code: str,
|
|
172
|
+
context_radius: int = 0,
|
|
173
|
+
) -> bool:
|
|
174
|
+
"""
|
|
175
|
+
Surgically edit the target file at target_line (1-indexed).
|
|
176
|
+
Never rewrites the entire file.
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
content = file_path.read_text(encoding="utf-8")
|
|
180
|
+
lines = content.splitlines(keepends=True)
|
|
181
|
+
|
|
182
|
+
if not (1 <= target_line <= len(lines) + 1):
|
|
183
|
+
logger.error(f"Target line {target_line} out of range for {file_path}")
|
|
184
|
+
return False
|
|
185
|
+
|
|
186
|
+
start_idx = max(0, target_line - 1 - context_radius)
|
|
187
|
+
end_idx = min(len(lines), target_line + context_radius)
|
|
188
|
+
|
|
189
|
+
# Format replacement lines
|
|
190
|
+
if not replacement_code.endswith("\n"):
|
|
191
|
+
replacement_code += "\n"
|
|
192
|
+
|
|
193
|
+
# Replace slice
|
|
194
|
+
lines[start_idx:end_idx] = [replacement_code]
|
|
195
|
+
file_path.write_text("".join(lines), encoding="utf-8")
|
|
196
|
+
return True
|
|
197
|
+
except Exception as exc:
|
|
198
|
+
logger.error(f"Failed to apply patch on {file_path}: {exc}")
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
def generate_heuristic_fix(
|
|
202
|
+
self,
|
|
203
|
+
tb: TracebackInfo,
|
|
204
|
+
file_content: str,
|
|
205
|
+
) -> Optional[Tuple[int, str, int]]:
|
|
206
|
+
"""
|
|
207
|
+
Rule-based heuristic patch generator for common quant/python runtime issues.
|
|
208
|
+
Returns: (target_line, replacement_content, context_radius)
|
|
209
|
+
"""
|
|
210
|
+
lines = file_content.splitlines()
|
|
211
|
+
if not (1 <= tb.line_number <= len(lines)):
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
offending_line = lines[tb.line_number - 1]
|
|
215
|
+
indent = len(offending_line) - len(offending_line.lstrip())
|
|
216
|
+
indent_str = " " * indent
|
|
217
|
+
|
|
218
|
+
# Case 1: ZeroDivisionError (e.g. sharpe ratio or return calculation)
|
|
219
|
+
if "ZeroDivisionError" in tb.error_type or "division by zero" in tb.error_message:
|
|
220
|
+
if "/" in offending_line:
|
|
221
|
+
# Add safe division
|
|
222
|
+
fixed = offending_line.replace("/", " / max(1e-9, ")
|
|
223
|
+
fixed += ")"
|
|
224
|
+
return tb.line_number, fixed, 0
|
|
225
|
+
|
|
226
|
+
# Case 2: Column KeyError (e.g. 'Adj Close' vs 'Close' vs 'close')
|
|
227
|
+
if "KeyError" in tb.error_type:
|
|
228
|
+
col_match = re.search(r"['\"]([^'\"]+)['\"]", tb.error_message)
|
|
229
|
+
if col_match:
|
|
230
|
+
missing_col = col_match.group(1)
|
|
231
|
+
# Replace df['missing'] with df.get(missing, df.get('close', df.get('Close', 0)))
|
|
232
|
+
pattern = rf"\[['\"]{re.escape(missing_col)}['\"]\]"
|
|
233
|
+
replacement = f".get('{missing_col.lower()}', df.get('{missing_col}', df.get('close', df.get('Close'))))"
|
|
234
|
+
if re.search(pattern, offending_line):
|
|
235
|
+
fixed = re.sub(pattern, replacement, offending_line)
|
|
236
|
+
return tb.line_number, fixed, 0
|
|
237
|
+
|
|
238
|
+
# Case 3: Missing Import (NameError)
|
|
239
|
+
if "NameError" in tb.error_type:
|
|
240
|
+
m = re.search(r"name ['\"]([^'\"]+)['\"] is not defined", tb.error_message)
|
|
241
|
+
if m:
|
|
242
|
+
missing_name = m.group(1)
|
|
243
|
+
if missing_name in {"np", "numpy"}:
|
|
244
|
+
return 1, "import numpy as np\n" + lines[0], 0
|
|
245
|
+
elif missing_name in {"pd", "pandas"}:
|
|
246
|
+
return 1, "import pandas as pd\n" + lines[0], 0
|
|
247
|
+
elif missing_name in {"math", "json", "os", "sys"}:
|
|
248
|
+
return 1, f"import {missing_name}\n" + lines[0], 0
|
|
249
|
+
|
|
250
|
+
# Case 4: IndexError on empty dataframe/array
|
|
251
|
+
if "IndexError" in tb.error_type:
|
|
252
|
+
fixed = f"{indent_str}if len(df) > 0 and len(data) > 0:\n{indent_str} {offending_line.strip()}"
|
|
253
|
+
return tb.line_number, fixed, 0
|
|
254
|
+
|
|
255
|
+
# Case 5: SyntaxError near line
|
|
256
|
+
if "SyntaxError" in tb.error_type:
|
|
257
|
+
# Clean common syntax typos (e.g. mismatched parentheses or quotes)
|
|
258
|
+
stripped = offending_line.strip()
|
|
259
|
+
if stripped.count("(") > stripped.count(")"):
|
|
260
|
+
fixed = offending_line + ")" * (stripped.count("(") - stripped.count(")"))
|
|
261
|
+
return tb.line_number, fixed, 0
|
|
262
|
+
|
|
263
|
+
return None
|
|
264
|
+
|
|
265
|
+
async def execute_and_heal(
|
|
266
|
+
self,
|
|
267
|
+
file_path: pathlib.Path,
|
|
268
|
+
timeout: float = 30.0,
|
|
269
|
+
) -> SelfHealingResult:
|
|
270
|
+
"""
|
|
271
|
+
Full pre-flight verification, execution, and multi-round patch self-healing loop.
|
|
272
|
+
"""
|
|
273
|
+
file_path = file_path.resolve()
|
|
274
|
+
patches: List[Dict[str, Any]] = []
|
|
275
|
+
|
|
276
|
+
for attempt in range(self.max_retries + 1):
|
|
277
|
+
# 1. Pre-flight Static Syntax Check
|
|
278
|
+
valid_syntax, syn_err, syn_line = self.verify_syntax(file_path)
|
|
279
|
+
if not valid_syntax:
|
|
280
|
+
if attempt >= self.max_retries:
|
|
281
|
+
return SelfHealingResult(
|
|
282
|
+
success=False,
|
|
283
|
+
retries_used=attempt,
|
|
284
|
+
final_output="",
|
|
285
|
+
error=f"Syntax pre-flight check failed: {syn_err}",
|
|
286
|
+
patches_applied=patches,
|
|
287
|
+
)
|
|
288
|
+
# Attempt syntax fix
|
|
289
|
+
content = file_path.read_text(encoding="utf-8")
|
|
290
|
+
tb_synth = TracebackInfo(
|
|
291
|
+
file_path=str(file_path),
|
|
292
|
+
line_number=syn_line or 1,
|
|
293
|
+
error_type="SyntaxError",
|
|
294
|
+
error_message=syn_err or "SyntaxError",
|
|
295
|
+
code_snippet="",
|
|
296
|
+
full_traceback=syn_err or "",
|
|
297
|
+
)
|
|
298
|
+
fix = self.generate_heuristic_fix(tb_synth, content)
|
|
299
|
+
if fix:
|
|
300
|
+
t_line, rep, rad = fix
|
|
301
|
+
self.apply_patch(file_path, t_line, rep, rad)
|
|
302
|
+
patches.append({"round": attempt + 1, "type": "syntax_fix", "line": t_line})
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
# 2. Dry-Run Execution
|
|
306
|
+
ret_code, stdout, stderr = self.run_sandbox_execution(file_path, timeout=timeout)
|
|
307
|
+
|
|
308
|
+
if ret_code == 0:
|
|
309
|
+
# Success! Extract metrics and artifacts
|
|
310
|
+
metrics, artifacts = self._extract_results(file_path, stdout)
|
|
311
|
+
return SelfHealingResult(
|
|
312
|
+
success=True,
|
|
313
|
+
retries_used=attempt,
|
|
314
|
+
final_output=stdout,
|
|
315
|
+
metrics=metrics,
|
|
316
|
+
artifact_paths=artifacts,
|
|
317
|
+
patches_applied=patches,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
# Failure occurred: inspect traceback
|
|
321
|
+
if attempt >= self.max_retries:
|
|
322
|
+
return SelfHealingResult(
|
|
323
|
+
success=False,
|
|
324
|
+
retries_used=attempt,
|
|
325
|
+
final_output=stdout,
|
|
326
|
+
error=f"Execution failed after {attempt} retries: {stderr[:300]}",
|
|
327
|
+
patches_applied=patches,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
tb = self.parse_traceback(stderr, file_path)
|
|
331
|
+
if not tb:
|
|
332
|
+
return SelfHealingResult(
|
|
333
|
+
success=False,
|
|
334
|
+
retries_used=attempt,
|
|
335
|
+
final_output=stdout,
|
|
336
|
+
error=f"Execution failed with no traceback: {stderr[:300]}",
|
|
337
|
+
patches_applied=patches,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
content = file_path.read_text(encoding="utf-8")
|
|
341
|
+
fix = None
|
|
342
|
+
|
|
343
|
+
# Try LLM fixer if available
|
|
344
|
+
if self.llm_fixer:
|
|
345
|
+
try:
|
|
346
|
+
fix = await self.llm_fixer(tb, content)
|
|
347
|
+
except Exception as exc:
|
|
348
|
+
logger.debug(f"LLM fixer failed: {exc}")
|
|
349
|
+
|
|
350
|
+
# Fallback to heuristic fixer
|
|
351
|
+
if not fix:
|
|
352
|
+
fix = self.generate_heuristic_fix(tb, content)
|
|
353
|
+
|
|
354
|
+
if fix:
|
|
355
|
+
t_line, rep, rad = fix
|
|
356
|
+
self.apply_patch(file_path, t_line, rep, rad)
|
|
357
|
+
patches.append({
|
|
358
|
+
"round": attempt + 1,
|
|
359
|
+
"error_type": tb.error_type,
|
|
360
|
+
"line": t_line,
|
|
361
|
+
"message": tb.error_message,
|
|
362
|
+
})
|
|
363
|
+
else:
|
|
364
|
+
# Could not determine patch
|
|
365
|
+
return SelfHealingResult(
|
|
366
|
+
success=False,
|
|
367
|
+
retries_used=attempt,
|
|
368
|
+
final_output=stdout,
|
|
369
|
+
error=f"Unresolvable {tb.error_type} at line {tb.line_number}: {tb.error_message}",
|
|
370
|
+
patches_applied=patches,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
return SelfHealingResult(
|
|
374
|
+
success=False,
|
|
375
|
+
retries_used=self.max_retries,
|
|
376
|
+
final_output="",
|
|
377
|
+
error="Exceeded max healing retries",
|
|
378
|
+
patches_applied=patches,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
def _extract_results(self, file_path: pathlib.Path, stdout: str) -> Tuple[Dict[str, Any], List[str]]:
|
|
382
|
+
"""
|
|
383
|
+
Extract backtest metrics and generated files from output.
|
|
384
|
+
"""
|
|
385
|
+
metrics: Dict[str, Any] = {}
|
|
386
|
+
artifacts: List[str] = [str(file_path)]
|
|
387
|
+
|
|
388
|
+
# 1. Look for companion metrics JSON file (e.g. strategy_nvda_metrics.json)
|
|
389
|
+
json_candidate = file_path.with_name(f"{file_path.stem}_metrics.json")
|
|
390
|
+
if json_candidate.exists():
|
|
391
|
+
try:
|
|
392
|
+
metrics = json.loads(json_candidate.read_text(encoding="utf-8"))
|
|
393
|
+
artifacts.append(str(json_candidate))
|
|
394
|
+
except Exception:
|
|
395
|
+
pass
|
|
396
|
+
|
|
397
|
+
# 2. Look for JSON in stdout lines or blocks
|
|
398
|
+
if not metrics and stdout:
|
|
399
|
+
for line in stdout.splitlines():
|
|
400
|
+
line_str = line.strip()
|
|
401
|
+
if line_str.startswith("{") and line_str.endswith("}"):
|
|
402
|
+
try:
|
|
403
|
+
parsed = json.loads(line_str)
|
|
404
|
+
if isinstance(parsed, dict):
|
|
405
|
+
metrics = parsed
|
|
406
|
+
break
|
|
407
|
+
except Exception:
|
|
408
|
+
pass
|
|
409
|
+
if not metrics and "{" in stdout and "}" in stdout:
|
|
410
|
+
try:
|
|
411
|
+
m = re.search(r"(\{.*\"[a-zA-Z0-9_-]+\"\s*:.*\})", stdout, re.DOTALL)
|
|
412
|
+
if m:
|
|
413
|
+
metrics = json.loads(m.group(1))
|
|
414
|
+
except Exception:
|
|
415
|
+
pass
|
|
416
|
+
|
|
417
|
+
# 3. Look for generated images or plots in the same folder
|
|
418
|
+
plot_candidate = file_path.with_name(f"{file_path.stem}_backtest.png")
|
|
419
|
+
if plot_candidate.exists():
|
|
420
|
+
artifacts.append(str(plot_candidate))
|
|
421
|
+
|
|
422
|
+
return metrics, artifacts
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Semantic diff — which definitions a change touched, not which lines.
|
|
2
|
+
|
|
3
|
+
"+43 -18 in session.py" says how much changed. What a reviewer reads first is
|
|
4
|
+
*what*: ``refresh_session()`` was modified, ``SessionManager`` added,
|
|
5
|
+
``legacy_refresh()`` removed. This module works that out per file, in any
|
|
6
|
+
language ``repo_map`` can parse (Python by AST, the rest by pattern):
|
|
7
|
+
|
|
8
|
+
1. Read the file as it is now.
|
|
9
|
+
2. Undo this turn's diffs, newest first, to get it as it was. A diff that does
|
|
10
|
+
not apply — the file was changed some other way in between — means no
|
|
11
|
+
answer for that file rather than a wrong one.
|
|
12
|
+
3. Extract definitions from both versions and compare each one's text.
|
|
13
|
+
|
|
14
|
+
A definition counts as modified when its own text changed; a class whose only
|
|
15
|
+
changes are inside its methods reports the methods, not itself.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import re
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Iterable, Optional, Sequence
|
|
24
|
+
|
|
25
|
+
_HUNK = re.compile(r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class SymbolChange:
|
|
30
|
+
kind: str # "added" | "modified" | "removed"
|
|
31
|
+
name: str # qualified: "SessionManager.refresh"
|
|
32
|
+
symbol_kind: str # "def", "class", "function", …
|
|
33
|
+
|
|
34
|
+
def label(self) -> str:
|
|
35
|
+
callable_kinds = {"def", "async def", "function", "method", "func", "fn"}
|
|
36
|
+
suffix = "()" if self.symbol_kind in callable_kinds else ""
|
|
37
|
+
return f"{self.name}{suffix} {self.kind}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def reverse_apply(after: str, diff: str) -> Optional[str]:
|
|
41
|
+
"""The text *diff* was made from, given the text it produced. None if it does not fit."""
|
|
42
|
+
from . import native_index
|
|
43
|
+
|
|
44
|
+
native = native_index.reverse_apply(after, diff)
|
|
45
|
+
if native is not native_index.UNAVAILABLE:
|
|
46
|
+
return native
|
|
47
|
+
lines = after.splitlines(keepends=True)
|
|
48
|
+
hunks = []
|
|
49
|
+
current = None
|
|
50
|
+
for raw in diff.splitlines(keepends=True):
|
|
51
|
+
match = _HUNK.match(raw)
|
|
52
|
+
if match:
|
|
53
|
+
current = {"new_start": int(match.group(3)), "old": [], "new": []}
|
|
54
|
+
hunks.append(current)
|
|
55
|
+
continue
|
|
56
|
+
if current is None or raw.startswith(("---", "+++", "\\")):
|
|
57
|
+
continue
|
|
58
|
+
tag, body = raw[:1], raw[1:]
|
|
59
|
+
if tag == " ":
|
|
60
|
+
current["old"].append(body)
|
|
61
|
+
current["new"].append(body)
|
|
62
|
+
elif tag == "-":
|
|
63
|
+
current["old"].append(body)
|
|
64
|
+
elif tag == "+":
|
|
65
|
+
current["new"].append(body)
|
|
66
|
+
elif raw.strip() == "": # a context line whose leading space was trimmed
|
|
67
|
+
current["old"].append(raw)
|
|
68
|
+
current["new"].append(raw)
|
|
69
|
+
if not hunks:
|
|
70
|
+
return None
|
|
71
|
+
for hunk in reversed(hunks):
|
|
72
|
+
start = max(0, hunk["new_start"] - 1) if hunk["new"] else hunk["new_start"]
|
|
73
|
+
end = start + len(hunk["new"])
|
|
74
|
+
if [l.rstrip("\r\n") for l in lines[start:end]] != [l.rstrip("\r\n") for l in hunk["new"]]:
|
|
75
|
+
return None
|
|
76
|
+
lines[start:end] = hunk["old"]
|
|
77
|
+
return "".join(lines)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _bodies(source: str, language: str) -> dict:
|
|
81
|
+
"""qualified name → (kind, text) for each definition."""
|
|
82
|
+
from .repo_map import extract_symbols
|
|
83
|
+
|
|
84
|
+
symbols = sorted(extract_symbols(source, language), key=lambda s: s.line)
|
|
85
|
+
lines = source.splitlines()
|
|
86
|
+
out = {}
|
|
87
|
+
for index, symbol in enumerate(symbols):
|
|
88
|
+
# A definition runs to the next one at the same or an outer level.
|
|
89
|
+
end = len(lines)
|
|
90
|
+
for later in symbols[index + 1:]:
|
|
91
|
+
if later.parent != symbol.qualified and not later.parent.startswith(symbol.qualified + "."):
|
|
92
|
+
end = later.line - 1
|
|
93
|
+
break
|
|
94
|
+
children = {s.line for s in symbols[index + 1:] if s.parent == symbol.qualified}
|
|
95
|
+
own = [line for number, line in enumerate(lines[symbol.line - 1:end], start=symbol.line)
|
|
96
|
+
if not _inside_child(number, children, symbols)]
|
|
97
|
+
# Blank and comment-only lines at the end belong to whatever follows;
|
|
98
|
+
# counting them made a comment above the next definition "modify"
|
|
99
|
+
# the one before it.
|
|
100
|
+
while own and (not own[-1].strip() or own[-1].lstrip().startswith(("#", "//"))):
|
|
101
|
+
own.pop()
|
|
102
|
+
out[symbol.qualified] = (symbol.kind, "\n".join(own))
|
|
103
|
+
return out
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _inside_child(number: int, child_lines: set, symbols: Sequence) -> bool:
|
|
107
|
+
if not child_lines:
|
|
108
|
+
return False
|
|
109
|
+
starts = sorted(child_lines)
|
|
110
|
+
for start in starts:
|
|
111
|
+
nxt = next((s.line for s in symbols if s.line > start), None)
|
|
112
|
+
if start <= number < (nxt or 10 ** 9):
|
|
113
|
+
return True
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _parent(name: str) -> str:
|
|
118
|
+
return name.rsplit(".", 1)[0] if "." in name else ""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def symbol_changes(before: str, after: str, language: str) -> list[SymbolChange]:
|
|
122
|
+
from . import native_index
|
|
123
|
+
|
|
124
|
+
native = native_index.symbol_changes(before, after, language)
|
|
125
|
+
if native is not None:
|
|
126
|
+
return [SymbolChange(kind, name, symbol_kind) for kind, name, symbol_kind in native]
|
|
127
|
+
old, new = _bodies(before, language), _bodies(after, language)
|
|
128
|
+
changes = []
|
|
129
|
+
for name, (kind, text) in new.items():
|
|
130
|
+
if name not in old:
|
|
131
|
+
parent = _parent(name)
|
|
132
|
+
if parent and parent in new and parent not in old:
|
|
133
|
+
continue # inside an added class: the class says it
|
|
134
|
+
changes.append(SymbolChange("added", name, kind))
|
|
135
|
+
elif old[name][1] != text:
|
|
136
|
+
changes.append(SymbolChange("modified", name, kind))
|
|
137
|
+
for name, (kind, _) in old.items():
|
|
138
|
+
if name not in new:
|
|
139
|
+
parent = _parent(name)
|
|
140
|
+
if parent and parent in old and parent not in new:
|
|
141
|
+
continue # inside a removed class
|
|
142
|
+
changes.append(SymbolChange("removed", name, kind))
|
|
143
|
+
order = {"added": 0, "modified": 1, "removed": 2}
|
|
144
|
+
return sorted(changes, key=lambda c: (order[c.kind], c.name))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def file_symbol_changes(path: str | Path, diffs: Iterable[str]) -> Optional[list[SymbolChange]]:
|
|
148
|
+
"""What this turn's *diffs* (oldest first) did to the definitions in *path*. None if unknown."""
|
|
149
|
+
from .repo_map import LANGUAGES
|
|
150
|
+
|
|
151
|
+
path = Path(path)
|
|
152
|
+
language = LANGUAGES.get(path.suffix.lower(), "")
|
|
153
|
+
if not language:
|
|
154
|
+
return None
|
|
155
|
+
try:
|
|
156
|
+
after = path.read_text(encoding="utf-8")
|
|
157
|
+
except (OSError, UnicodeDecodeError):
|
|
158
|
+
return None
|
|
159
|
+
before = after
|
|
160
|
+
for diff in reversed(list(diffs)):
|
|
161
|
+
if "--- /dev/null" in diff:
|
|
162
|
+
before = ""
|
|
163
|
+
break
|
|
164
|
+
previous = reverse_apply(before, diff)
|
|
165
|
+
if previous is None:
|
|
166
|
+
return None
|
|
167
|
+
before = previous
|
|
168
|
+
return symbol_changes(before, after, language)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
__all__ = ["SymbolChange", "file_symbol_changes", "reverse_apply", "symbol_changes"]
|