aria-code 0.167.0__py3-none-macosx_13_0_arm64.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 +0 -0
- aria_code/_bin/aria-runtime +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,75 @@
|
|
|
1
|
+
"""Domain-neutral task roles for the existing Aria runtime.
|
|
2
|
+
|
|
3
|
+
Profiles narrow a task's instructions and available tools. They do not provide
|
|
4
|
+
credentials, install integrations, choose another model, or grant permissions.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class AgentProfile:
|
|
13
|
+
name: str
|
|
14
|
+
description: str
|
|
15
|
+
instructions: str
|
|
16
|
+
tools: frozenset[str] | None = None
|
|
17
|
+
writable: bool = False
|
|
18
|
+
max_rounds: int = 20
|
|
19
|
+
timeout_seconds: int = 300
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
READ = frozenset({"read_file", "list_files", "search_code", "glob", "analyze_file", "notebook_read", "lsp_diagnostics"})
|
|
23
|
+
RESEARCH = READ | {"web_search", "web_fetch"}
|
|
24
|
+
WRITE = READ | {"write_file", "edit_file", "multi_edit", "apply_patch", "notebook_edit", "run_command"}
|
|
25
|
+
|
|
26
|
+
PROFILES = {
|
|
27
|
+
p.name: p for p in (
|
|
28
|
+
AgentProfile("general", "General-purpose fallback for tasks that do not fit a narrower role.",
|
|
29
|
+
"Complete the delegated goal using available tools. State missing capabilities and evidence explicitly.",
|
|
30
|
+
writable=True, max_rounds=30),
|
|
31
|
+
AgentProfile("explorer", "Find and explain files, architecture and execution paths without edits.",
|
|
32
|
+
"Read targeted sources, trace the actual execution path, and cite files and symbols. Do not implement changes.", READ),
|
|
33
|
+
AgentProfile("planner", "Turn a goal into an evidence-based plan, dependencies and acceptance criteria.",
|
|
34
|
+
"Inspect the relevant context. Return a concrete plan, dependencies, assumptions and observable acceptance criteria. Do not implement it.", RESEARCH),
|
|
35
|
+
AgentProfile("researcher", "Research technical, product or business questions with source evidence.",
|
|
36
|
+
"Search and read primary sources when available. Separate sourced facts, inferences and unknowns; include source locations and dates for time-sensitive claims. If search access is absent, say so.", RESEARCH),
|
|
37
|
+
AgentProfile("implementer", "Implement and test a bounded software change in an isolated workspace.",
|
|
38
|
+
"Read relevant code before editing. Implement the requested scope and run appropriate checks. Report changed files, actual commands and failures. Never push, publish or deploy.", WRITE, writable=True, max_rounds=30),
|
|
39
|
+
AgentProfile("reviewer", "Independently inspect correctness, security and missing validation without edits.",
|
|
40
|
+
"Review the actual sources and available evidence. Report actionable findings with file locations, severity and reasoning. Distinguish static review from executed tests; no findings does not prove correctness.", READ),
|
|
41
|
+
AgentProfile("data_analyst", "Analyze datasets, validate quality and produce reproducible calculations across domains.",
|
|
42
|
+
"Inspect supplied data and its grain, schema and quality. Use verified tool outputs for calculations; never invent computed totals. Use command execution only under inherited host policy. Write outputs only when workspace-write was requested. If no computation tool is available, return a reproducible method and the limitation instead of pretending to execute it.", WRITE, writable=True),
|
|
43
|
+
AgentProfile("writer", "Draft and revise documents, specifications and content grounded in supplied sources.",
|
|
44
|
+
"Use authorized context and source files. Preserve audience, voice and factual provenance. Write requested files only in the permitted workspace and read them back. Return drafts for review; never send messages or publish content.", WRITE, writable=True),
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_profile(name: str = "general") -> AgentProfile:
|
|
50
|
+
try:
|
|
51
|
+
return PROFILES[name]
|
|
52
|
+
except KeyError:
|
|
53
|
+
raise ValueError(f"Unknown agent profile: {name}. Use list_agents to discover supported roles.") from None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def tool_list_agents(params: dict) -> dict:
|
|
57
|
+
return {"success": True, "agents": [
|
|
58
|
+
{"name": p.name, "description": p.description,
|
|
59
|
+
"modes": ["read-only", "workspace-write"] if p.writable else ["read-only"],
|
|
60
|
+
"tool_policy": "inherit parent minus delegation" if p.tools is None else sorted(p.tools),
|
|
61
|
+
"max_rounds": p.max_rounds, "timeout_seconds": p.timeout_seconds}
|
|
62
|
+
for p in PROFILES.values()
|
|
63
|
+
], "note": "Profiles use the existing Aria model/runtime. Tools are intersected with the host's actual tool registry; listed roles do not imply connected services. Command execution remains subject to the host permission policy."}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
DELEGATION_GUIDANCE = """General task delegation:
|
|
67
|
+
- Aria handles software, research, data inspection, documents and other authorized tasks across domains.
|
|
68
|
+
- Built-in roles: explorer (source exploration), planner (plans), researcher (sourced research), implementer (software changes), reviewer (independent review), data_analyst (datasets), writer (documents); general is the fallback.
|
|
69
|
+
- Use list_agents to discover reusable roles; select one by its description and the task context, not a keyword router. Use spawn_task(agent=..., prompt=..., success_criteria=...) for a bounded independent task when delegation is useful. Keep simple/dependent work in the main conversation unless the user explicitly requests a delegate. Honor explicit delegation requests: do not replace a requested independent writer/researcher task with a draft produced in the parent conversation.
|
|
70
|
+
- Discover relevant project skill/memory descriptions with list_task_context(agent=target_role), then pass only needed IDs in spawn_task.context_refs. Only explicit project auto entries load by default; no global memory scan occurs. Context provenance records source hashes, not proof of current facts. Never copy unrelated personal context into a delegate.
|
|
71
|
+
- Give the delegate its goal, relevant source context and observable acceptance criteria. Inherit the current model and permissions; never delegate to bypass a denial or gain access.
|
|
72
|
+
- Declare observable checks in the spawn_task checks argument when the goal permits artifact, tool or command predicates. Describing these checks in prompt/context does not declare them. For a file-based research task, use checks=[{"kind":"tool","tool":"read_file","path":"brief.md"},{"kind":"artifact","path":"brief.md","format":"text","min_bytes":1}] with the actual requested file. File checks read actual bounded workspace bytes; command checks require a zero exit code from the exact observed command and never execute additional commands. Checks cover only declared predicates, not semantic correctness.
|
|
73
|
+
- Retrieve task_result before relying on a delegate. verified=true means the declared predicates passed; verified=null means no checks were requested: explicitly report that machine acceptance was not performed and never say those checks passed. Never call either a done status or a VERIFICATION heading independent acceptance. A spawned or done task is not proof that the user's goal was verified. Check the reported evidence, artifacts and blockers; disclose missing tools or failed checks.
|
|
74
|
+
- Specialized financial and warehouse capabilities remain optional domain extensions. Do not impose stock symbols, trading signals or financial-evidence requirements on unrelated tasks.
|
|
75
|
+
"""
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Approval decisions for tools that require user consent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class ApprovalDecision:
|
|
10
|
+
"""Structured result from a tool approval prompt."""
|
|
11
|
+
|
|
12
|
+
approved: bool
|
|
13
|
+
policy: str | None = None
|
|
14
|
+
user_approved: bool = False
|
|
15
|
+
upgrade_policy: bool = False
|
|
16
|
+
auto_approve_session: bool = False
|
|
17
|
+
tool_scope: str = ""
|
|
18
|
+
command_prefix: tuple[str, ...] = ()
|
|
19
|
+
reason: str = ""
|
|
20
|
+
# What the user said instead of approving. A denial with feedback does
|
|
21
|
+
# not end the turn: the call is skipped and the model reads this.
|
|
22
|
+
feedback: str = ""
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def allow(
|
|
26
|
+
cls,
|
|
27
|
+
*,
|
|
28
|
+
policy: str | None = None,
|
|
29
|
+
user_approved: bool = False,
|
|
30
|
+
upgrade_policy: bool = False,
|
|
31
|
+
auto_approve_session: bool = False,
|
|
32
|
+
tool_scope: str = "",
|
|
33
|
+
command_prefix: tuple[str, ...] = (),
|
|
34
|
+
reason: str = "",
|
|
35
|
+
) -> "ApprovalDecision":
|
|
36
|
+
return cls(
|
|
37
|
+
approved=True,
|
|
38
|
+
policy=policy,
|
|
39
|
+
user_approved=user_approved,
|
|
40
|
+
upgrade_policy=upgrade_policy,
|
|
41
|
+
auto_approve_session=auto_approve_session,
|
|
42
|
+
tool_scope=tool_scope,
|
|
43
|
+
command_prefix=command_prefix,
|
|
44
|
+
reason=reason,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def deny(cls, reason: str = "", *, feedback: str = "") -> "ApprovalDecision":
|
|
49
|
+
return cls(approved=False, reason=reason, feedback=feedback.strip())
|
|
50
|
+
|
|
51
|
+
def as_declined_result(self) -> dict:
|
|
52
|
+
"""What the model reads in place of a call the user declined with feedback."""
|
|
53
|
+
return {
|
|
54
|
+
"success": False,
|
|
55
|
+
"error": (
|
|
56
|
+
"The user declined this call and said: "
|
|
57
|
+
f"\"{self.feedback}\". Do what they asked instead; do not retry the same call."
|
|
58
|
+
),
|
|
59
|
+
"declined_by_user": True,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def apply_approval_decision(params: dict, decision: ApprovalDecision) -> dict:
|
|
64
|
+
"""Apply execution-facing approval fields to tool params."""
|
|
65
|
+
if decision.policy is not None:
|
|
66
|
+
params["policy"] = decision.policy
|
|
67
|
+
if decision.user_approved:
|
|
68
|
+
params["user_approved"] = True
|
|
69
|
+
if decision.upgrade_policy:
|
|
70
|
+
params["_upgrade_policy"] = True
|
|
71
|
+
return params
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Test baseline: was this check already failing before the change?
|
|
2
|
+
|
|
3
|
+
A red check sends the model back to repair. When the test was failing before
|
|
4
|
+
the task touched anything, that sends it to "fix" code unrelated to the
|
|
5
|
+
request — or to give up on a task that was actually done. The baseline runs
|
|
6
|
+
the failed command once more on the code as it was before the change and
|
|
7
|
+
compares:
|
|
8
|
+
|
|
9
|
+
* pytest: by test id (``FAILED tests/x.py::test_y``). Failures that also
|
|
10
|
+
fail on the baseline are pre-existing; the rest are the change's. The
|
|
11
|
+
baseline run continues past collection errors (see ``_keep_collecting``).
|
|
12
|
+
* anything else: by exit status. A command that fails on the baseline too
|
|
13
|
+
is pre-existing as a whole.
|
|
14
|
+
|
|
15
|
+
"Before the change" is the task's starting snapshot when the turn runs in a
|
|
16
|
+
task worktree. Otherwise it is the working tree now with this turn's edits
|
|
17
|
+
undone from their checkpoints — edits a shell command made are not
|
|
18
|
+
recorded, so they are in the baseline too. Outside a git repository the
|
|
19
|
+
working tree is copied instead of checked out, when it is small enough
|
|
20
|
+
(``_COPY_MAX_FILES``/``_COPY_MAX_BYTES``); without a baseline every failure
|
|
21
|
+
counts as the change's, and the model is sent to "fix" unrelated code.
|
|
22
|
+
|
|
23
|
+
It runs only after a failure, in a scratch worktree removed straight after,
|
|
24
|
+
and each command at most once per turn.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import inspect
|
|
30
|
+
import logging
|
|
31
|
+
import os
|
|
32
|
+
import re
|
|
33
|
+
import shutil
|
|
34
|
+
import uuid
|
|
35
|
+
from dataclasses import dataclass
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
from typing import Any, Awaitable, Callable, Optional, Union
|
|
38
|
+
|
|
39
|
+
from .task_worktree import TaskWorktreeError, checkout, remove_checkout, repository_root, snapshot
|
|
40
|
+
|
|
41
|
+
logger = logging.getLogger(__name__)
|
|
42
|
+
|
|
43
|
+
_PYTEST_FAILURE = re.compile(r"^(?:FAILED|ERROR)\s+(\S+?)(?:\s+-\s|$)", re.MULTILINE)
|
|
44
|
+
|
|
45
|
+
# A workspace outside git is copied for its baseline only up to this size; a
|
|
46
|
+
# turn started in a home directory must not copy the home directory.
|
|
47
|
+
_COPY_MAX_FILES = 5_000
|
|
48
|
+
_COPY_MAX_BYTES = 100 * 1024 * 1024
|
|
49
|
+
_COPY_SKIPPED = frozenset({
|
|
50
|
+
".git", ".hg", ".svn", "node_modules", ".venv", "venv", "__pycache__",
|
|
51
|
+
".mypy_cache", ".pytest_cache", ".ruff_cache", ".tox", ".nox",
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
# ``(command, cwd) -> run result dict``, as the acceptance gate's runner returns.
|
|
55
|
+
BaselineRunner = Callable[[str, str], Union[dict, Awaitable[dict]]]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def failing_tests(output: str) -> frozenset[str]:
|
|
59
|
+
"""pytest's failing test ids, from its short summary lines."""
|
|
60
|
+
return frozenset(match.group(1) for match in _PYTEST_FAILURE.finditer(output or ""))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class Comparison:
|
|
65
|
+
preexisting: bool # every failure was already there
|
|
66
|
+
new_failures: tuple[str, ...] = () # test ids failing only after the change
|
|
67
|
+
old_failures: tuple[str, ...] = () # test ids failing before it too
|
|
68
|
+
note: str = ""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def compare(after_output: str, after_failed: bool, before: Optional[tuple[int, str]]) -> Comparison:
|
|
72
|
+
"""Classify a failed check against its baseline run ``(exit_code, output)``."""
|
|
73
|
+
if before is None or not after_failed:
|
|
74
|
+
return Comparison(preexisting=False)
|
|
75
|
+
before_code, before_output = before
|
|
76
|
+
if before_code == 0:
|
|
77
|
+
return Comparison(preexisting=False, note="passed before this change")
|
|
78
|
+
after_ids, before_ids = failing_tests(after_output), failing_tests(before_output)
|
|
79
|
+
if after_ids:
|
|
80
|
+
new = tuple(sorted(after_ids - before_ids))
|
|
81
|
+
old = tuple(sorted(after_ids & before_ids))
|
|
82
|
+
return Comparison(preexisting=not new, new_failures=new, old_failures=old,
|
|
83
|
+
note="failing before this change" if not new else "")
|
|
84
|
+
return Comparison(preexisting=True, note="failing before this change")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
_PYTEST_COMMAND = re.compile(r"(?:^|[\s/])(?:py\.test|pytest)(?:\s|$)")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _keep_collecting(command: str) -> str:
|
|
91
|
+
"""Let a pytest baseline run past collection errors.
|
|
92
|
+
|
|
93
|
+
Before the change a test file often cannot even be imported — it tests the
|
|
94
|
+
function the task is about to add — and pytest then stops at collection,
|
|
95
|
+
running nothing else. A test that was already red elsewhere is missing from
|
|
96
|
+
that baseline, so after the change it would look new and be "repaired".
|
|
97
|
+
"""
|
|
98
|
+
if (not _PYTEST_COMMAND.search(command) or "--continue-on-collection-errors" in command
|
|
99
|
+
or re.search(r"[|;&<>`$]", command)):
|
|
100
|
+
return command
|
|
101
|
+
return f"{command} --continue-on-collection-errors"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class Baseline:
|
|
105
|
+
def __init__(
|
|
106
|
+
self,
|
|
107
|
+
workspace: Path | str,
|
|
108
|
+
*,
|
|
109
|
+
run: BaselineRunner,
|
|
110
|
+
base_commit: str = "",
|
|
111
|
+
undo_since: Optional[int] = None,
|
|
112
|
+
session_id: str = "",
|
|
113
|
+
scratch_root: Path | str,
|
|
114
|
+
) -> None:
|
|
115
|
+
self.workspace = Path(workspace).expanduser().resolve()
|
|
116
|
+
self.run = run
|
|
117
|
+
self.base_commit = base_commit
|
|
118
|
+
self.undo_since = undo_since
|
|
119
|
+
self.session_id = session_id
|
|
120
|
+
self.scratch_root = Path(scratch_root).expanduser()
|
|
121
|
+
self._results: dict[str, Optional[tuple[int, str]]] = {}
|
|
122
|
+
|
|
123
|
+
async def result(self, command: str) -> Optional[tuple[int, str]]:
|
|
124
|
+
"""``(exit_code, output)`` of ``command`` before the change; None if unknown."""
|
|
125
|
+
if command not in self._results:
|
|
126
|
+
try:
|
|
127
|
+
self._results[command] = await self._run(_keep_collecting(command))
|
|
128
|
+
except Exception as exc:
|
|
129
|
+
logger.debug("baseline run failed: %s", exc)
|
|
130
|
+
self._results[command] = None
|
|
131
|
+
return self._results[command]
|
|
132
|
+
|
|
133
|
+
async def _run(self, command: str) -> Optional[tuple[int, str]]:
|
|
134
|
+
repo = repository_root(self.workspace)
|
|
135
|
+
destination = (self.scratch_root / f"baseline-{uuid.uuid4().hex[:8]}").resolve()
|
|
136
|
+
if repo is None:
|
|
137
|
+
if self.base_commit or not self._copy(destination):
|
|
138
|
+
return None
|
|
139
|
+
try:
|
|
140
|
+
self._undo_turn(self.workspace, destination)
|
|
141
|
+
raw = self.run(command, str(destination))
|
|
142
|
+
if inspect.isawaitable(raw):
|
|
143
|
+
raw = await raw
|
|
144
|
+
finally:
|
|
145
|
+
shutil.rmtree(destination, ignore_errors=True)
|
|
146
|
+
return self._result(raw)
|
|
147
|
+
commit = self.base_commit or snapshot(repo)[0]
|
|
148
|
+
linked = checkout(repo, commit, destination)
|
|
149
|
+
try:
|
|
150
|
+
if not self.base_commit:
|
|
151
|
+
self._undo_turn(repo, destination)
|
|
152
|
+
inside = self.workspace.relative_to(repo) if self.workspace.is_relative_to(repo) else Path()
|
|
153
|
+
cwd = destination / inside
|
|
154
|
+
cwd.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
raw = self.run(command, str(cwd))
|
|
156
|
+
if inspect.isawaitable(raw):
|
|
157
|
+
raw = await raw
|
|
158
|
+
finally:
|
|
159
|
+
remove_checkout(repo, destination, linked)
|
|
160
|
+
return self._result(raw)
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def _result(raw: Any) -> tuple[int, str]:
|
|
164
|
+
from .acceptance import _read_run_result
|
|
165
|
+
|
|
166
|
+
code, output, error = _read_run_result(raw)
|
|
167
|
+
return (code if not error else 1, output)
|
|
168
|
+
|
|
169
|
+
def _copy(self, destination: Path) -> bool:
|
|
170
|
+
"""Copy the workspace to ``destination``; False (and nothing left) when too big."""
|
|
171
|
+
files: list[tuple[Path, Path]] = []
|
|
172
|
+
total = 0
|
|
173
|
+
for directory, dirnames, filenames in os.walk(self.workspace):
|
|
174
|
+
dirnames[:] = [name for name in dirnames if name not in _COPY_SKIPPED]
|
|
175
|
+
for name in filenames:
|
|
176
|
+
source = Path(directory) / name
|
|
177
|
+
if source.is_symlink():
|
|
178
|
+
pass # copied as a link: it may point outside the workspace
|
|
179
|
+
elif source.is_file():
|
|
180
|
+
total += source.stat().st_size
|
|
181
|
+
else:
|
|
182
|
+
continue
|
|
183
|
+
files.append((source, destination / source.relative_to(self.workspace)))
|
|
184
|
+
if len(files) > _COPY_MAX_FILES or total > _COPY_MAX_BYTES:
|
|
185
|
+
return False
|
|
186
|
+
try:
|
|
187
|
+
for source, target in files:
|
|
188
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
189
|
+
shutil.copy2(source, target, follow_symlinks=False)
|
|
190
|
+
except OSError:
|
|
191
|
+
shutil.rmtree(destination, ignore_errors=True)
|
|
192
|
+
raise
|
|
193
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
return True
|
|
195
|
+
|
|
196
|
+
def _undo_turn(self, repo: Path, destination: Path) -> None:
|
|
197
|
+
"""Put back what this turn's checkpointed edits replaced."""
|
|
198
|
+
if self.undo_since is None:
|
|
199
|
+
return
|
|
200
|
+
from .checkpoints import CheckpointStore
|
|
201
|
+
|
|
202
|
+
earliest: dict[str, Any] = {}
|
|
203
|
+
for record in reversed(CheckpointStore().since(self.undo_since, session_id=self.session_id or None)):
|
|
204
|
+
for file in record.files:
|
|
205
|
+
earliest.setdefault(file.path, file) # oldest change holds the true "before"
|
|
206
|
+
for path, file in earliest.items():
|
|
207
|
+
try:
|
|
208
|
+
relative = Path(path).resolve().relative_to(repo)
|
|
209
|
+
except ValueError:
|
|
210
|
+
continue
|
|
211
|
+
target = destination / relative
|
|
212
|
+
if file.existed_before:
|
|
213
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
214
|
+
target.write_text(file.before_content, encoding="utf-8")
|
|
215
|
+
elif target.exists():
|
|
216
|
+
target.unlink()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
__all__ = ["Baseline", "Comparison", "compare", "failing_tests", "TaskWorktreeError"]
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Token / 成本预算:给能自主跑多轮的 agent 一个花费上限。
|
|
2
|
+
|
|
3
|
+
为什么需要:run_agent() 默认可以跑 30 轮,每轮都可能调云端模型;
|
|
4
|
+
agents/team.py 还会并行拉起多个 agent。这些循环在无人看管时(定时任务、
|
|
5
|
+
飞书 bot、后台 subagent)一旦进入一个"工具失败→重试→再失败"的死循环,
|
|
6
|
+
会持续消耗真金白银,而现有的唯一护栏是轮数上限——轮数管不住单轮消耗,
|
|
7
|
+
一轮塞进 200k token 的上下文和一轮塞进 2k,成本差两个数量级。
|
|
8
|
+
|
|
9
|
+
设计要点:
|
|
10
|
+
|
|
11
|
+
1. **本地模型不计费**。ollama / lmstudio / local 的边际成本是零,把它们计入
|
|
12
|
+
预算只会让本地用户莫名其妙被打断。这跟 /cost 命令已有的判断保持一致。
|
|
13
|
+
|
|
14
|
+
2. **超限是暂停,不是抛异常**。异常会让调用方拿不到已经产出的中间结果;
|
|
15
|
+
返回一个明确的"已暂停"状态,调用方可以决定是展示给用户确认后继续,
|
|
16
|
+
还是就此收尾。这也是 pause/resume 语义能成立的前提。
|
|
17
|
+
|
|
18
|
+
3. **预检查而非事后补记**。在发起下一轮之前判断"这一轮预计会花多少",
|
|
19
|
+
而不是花完了才发现超了——后者每次都会超支一轮。
|
|
20
|
+
|
|
21
|
+
4. **默认值保守但不碍事**。默认 2.0 美元/会话,够正常交互用很久,又能在
|
|
22
|
+
死循环烧掉几十美元之前叫停。设成 0 表示不限制(显式选择,不是默认)。
|
|
23
|
+
|
|
24
|
+
价格表按 2026-08 的公开价格,只用于**估算**:真实账单以各家为准。宁可估高
|
|
25
|
+
不估低——估低会让预算形同虚设。
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import os
|
|
31
|
+
from dataclasses import dataclass, field
|
|
32
|
+
from typing import Dict, Optional, Tuple
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"BudgetConfig", "BudgetState", "BudgetTracker",
|
|
36
|
+
"BudgetExceeded", "estimate_cost_usd", "is_local_provider",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
# 零边际成本的 provider —— 与 /cost 命令的判断保持一致
|
|
40
|
+
_LOCAL_PROVIDERS = frozenset({"ollama", "ollama_cache", "local", "lmstudio"})
|
|
41
|
+
|
|
42
|
+
# (输入, 输出) 美元 / 每百万 token。取各家公开价格的较高档,宁可估高。
|
|
43
|
+
_PRICE_TABLE: Dict[str, Tuple[float, float]] = {
|
|
44
|
+
"openai": (2.50, 10.00),
|
|
45
|
+
"anthropic": (3.00, 15.00),
|
|
46
|
+
"deepseek": (0.27, 1.10),
|
|
47
|
+
"groq": (0.59, 0.79),
|
|
48
|
+
"siliconflow": (0.27, 1.10),
|
|
49
|
+
"dashscope": (0.40, 1.20),
|
|
50
|
+
"moonshot": (1.70, 1.70),
|
|
51
|
+
"zhipu": (0.10, 0.10),
|
|
52
|
+
"together": (0.88, 0.88),
|
|
53
|
+
}
|
|
54
|
+
_DEFAULT_PRICE = (2.00, 8.00) # 未知 provider(含用户自定义的)按较贵档估
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def is_local_provider(provider: Optional[str]) -> bool:
|
|
58
|
+
return (provider or "").strip().lower() in _LOCAL_PROVIDERS
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def estimate_cost_usd(provider: Optional[str], input_tokens: int, output_tokens: int) -> float:
|
|
62
|
+
"""估算一次调用的美元成本。本地 provider 恒为 0。"""
|
|
63
|
+
if is_local_provider(provider):
|
|
64
|
+
return 0.0
|
|
65
|
+
price_in, price_out = _PRICE_TABLE.get((provider or "").strip().lower(), _DEFAULT_PRICE)
|
|
66
|
+
return (max(0, input_tokens) * price_in + max(0, output_tokens) * price_out) / 1_000_000
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(frozen=True)
|
|
70
|
+
class BudgetConfig:
|
|
71
|
+
"""预算上限。任一项设为 0 表示该项不限制。"""
|
|
72
|
+
max_usd: float = 2.0
|
|
73
|
+
max_tokens: int = 0
|
|
74
|
+
max_rounds: int = 0
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_env(cls) -> "BudgetConfig":
|
|
78
|
+
"""环境变量覆盖默认值,便于定时任务/容器里单独收紧或放开。"""
|
|
79
|
+
def _num(name: str, default: float) -> float:
|
|
80
|
+
raw = os.environ.get(name, "").strip()
|
|
81
|
+
if not raw:
|
|
82
|
+
return default
|
|
83
|
+
try:
|
|
84
|
+
return max(0.0, float(raw))
|
|
85
|
+
except ValueError:
|
|
86
|
+
return default
|
|
87
|
+
|
|
88
|
+
return cls(
|
|
89
|
+
max_usd=_num("ARIA_BUDGET_MAX_USD", 2.0),
|
|
90
|
+
max_tokens=int(_num("ARIA_BUDGET_MAX_TOKENS", 0)),
|
|
91
|
+
max_rounds=int(_num("ARIA_BUDGET_MAX_ROUNDS", 0)),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def unlimited(self) -> bool:
|
|
96
|
+
return not (self.max_usd or self.max_tokens or self.max_rounds)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class BudgetState:
|
|
101
|
+
spent_usd: float = 0.0
|
|
102
|
+
input_tokens: int = 0
|
|
103
|
+
output_tokens: int = 0
|
|
104
|
+
rounds: int = 0
|
|
105
|
+
billable_calls: int = 0 # 计费调用次数(本地调用不计)
|
|
106
|
+
per_provider: Dict[str, float] = field(default_factory=dict)
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def total_tokens(self) -> int:
|
|
110
|
+
return self.input_tokens + self.output_tokens
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class BudgetExceeded(RuntimeError):
|
|
114
|
+
"""仅供确实需要硬中断的调用方使用。默认路径不抛这个——见模块文档第 2 点。"""
|
|
115
|
+
|
|
116
|
+
def __init__(self, reason: str, state: BudgetState):
|
|
117
|
+
super().__init__(reason)
|
|
118
|
+
self.reason = reason
|
|
119
|
+
self.state = state
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class BudgetTracker:
|
|
123
|
+
"""累计消耗并回答"还能不能再跑一轮"。
|
|
124
|
+
|
|
125
|
+
刻意不持有任何 provider 或循环对象:它只接收数字、返回判断,因此可以在
|
|
126
|
+
CLI 会话、后台 subagent、agents.team 并行编排里用同一套逻辑,也容易测试。
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(self, config: Optional[BudgetConfig] = None):
|
|
130
|
+
self.config = config or BudgetConfig.from_env()
|
|
131
|
+
self.state = BudgetState()
|
|
132
|
+
self._paused_reason: Optional[str] = None
|
|
133
|
+
|
|
134
|
+
# ── 记账 ──────────────────────────────────────────────────────────
|
|
135
|
+
def record(self, provider: Optional[str], input_tokens: int, output_tokens: int) -> float:
|
|
136
|
+
"""记录一次模型调用,返回本次估算成本。"""
|
|
137
|
+
cost = estimate_cost_usd(provider, input_tokens, output_tokens)
|
|
138
|
+
self.state.input_tokens += max(0, input_tokens)
|
|
139
|
+
self.state.output_tokens += max(0, output_tokens)
|
|
140
|
+
self.state.spent_usd += cost
|
|
141
|
+
if cost > 0:
|
|
142
|
+
self.state.billable_calls += 1
|
|
143
|
+
key = (provider or "unknown").strip().lower()
|
|
144
|
+
self.state.per_provider[key] = self.state.per_provider.get(key, 0.0) + cost
|
|
145
|
+
return cost
|
|
146
|
+
|
|
147
|
+
def record_round(self) -> None:
|
|
148
|
+
self.state.rounds += 1
|
|
149
|
+
|
|
150
|
+
def projected_next_round_usd(self) -> float:
|
|
151
|
+
"""按已观测到的平均单轮成本,预测下一轮会花多少。
|
|
152
|
+
|
|
153
|
+
没有这个预测,闸门只能事后止损:$1 的预算实测会花到 $1.275——超支的
|
|
154
|
+
正是最后那一轮,而它恰恰可能是上下文最满、最贵的一轮。用历史均值做
|
|
155
|
+
预测,能在**发起调用之前**就拦住。
|
|
156
|
+
|
|
157
|
+
还没有任何计费轮次时返回 0(没有依据就不猜,第一轮总是放行)。
|
|
158
|
+
|
|
159
|
+
因此**第一轮永远无法被预算拦住**——预算比单轮成本还低时会超支一次。
|
|
160
|
+
这是有意的:宁可放行第一轮,也不要因为一个凭空的猜测把正常会话
|
|
161
|
+
堵死在起点。真要限制到单轮以下,应该用更小的模型或更短的上下文,
|
|
162
|
+
而不是指望预算闸门。
|
|
163
|
+
"""
|
|
164
|
+
if self.state.rounds <= 0 or self.state.spent_usd <= 0:
|
|
165
|
+
return 0.0
|
|
166
|
+
return self.state.spent_usd / self.state.rounds
|
|
167
|
+
|
|
168
|
+
# ── 判断 ──────────────────────────────────────────────────────────
|
|
169
|
+
def check(self, *, projected_usd: float = 0.0, projected_tokens: int = 0) -> Optional[str]:
|
|
170
|
+
"""返回超限原因;未超限返回 None。
|
|
171
|
+
|
|
172
|
+
projected_* 是"下一轮预计消耗"。传入它就变成**预检查**——在花掉之前
|
|
173
|
+
拦住,而不是花完才发现超了(后者每次都会超支一轮)。
|
|
174
|
+
"""
|
|
175
|
+
cfg = self.config
|
|
176
|
+
if cfg.unlimited:
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
if cfg.max_usd:
|
|
180
|
+
projected = self.state.spent_usd + max(0.0, projected_usd)
|
|
181
|
+
if projected >= cfg.max_usd:
|
|
182
|
+
return (f"预算上限 ${cfg.max_usd:.2f} 已达到"
|
|
183
|
+
f"(已用 ${self.state.spent_usd:.4f}"
|
|
184
|
+
f"{f',本轮预计 ${projected_usd:.4f}' if projected_usd else ''})")
|
|
185
|
+
|
|
186
|
+
if cfg.max_tokens:
|
|
187
|
+
projected_tok = self.state.total_tokens + max(0, projected_tokens)
|
|
188
|
+
if projected_tok >= cfg.max_tokens:
|
|
189
|
+
return (f"token 上限 {cfg.max_tokens:,} 已达到"
|
|
190
|
+
f"(已用 {self.state.total_tokens:,})")
|
|
191
|
+
|
|
192
|
+
if cfg.max_rounds and self.state.rounds >= cfg.max_rounds:
|
|
193
|
+
return f"轮数上限 {cfg.max_rounds} 已达到"
|
|
194
|
+
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
def should_continue(self, *, projected_usd: float = 0.0, projected_tokens: int = 0) -> bool:
|
|
198
|
+
reason = self.check(projected_usd=projected_usd, projected_tokens=projected_tokens)
|
|
199
|
+
if reason:
|
|
200
|
+
self._paused_reason = reason
|
|
201
|
+
return reason is None
|
|
202
|
+
|
|
203
|
+
# ── 状态 ──────────────────────────────────────────────────────────
|
|
204
|
+
@property
|
|
205
|
+
def paused(self) -> bool:
|
|
206
|
+
return self._paused_reason is not None
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def paused_reason(self) -> Optional[str]:
|
|
210
|
+
return self._paused_reason
|
|
211
|
+
|
|
212
|
+
def resume(self, *, additional_usd: float = 0.0) -> None:
|
|
213
|
+
"""用户确认后继续。可选地追加额度——不追加就会在下一次检查时再次暂停,
|
|
214
|
+
这是刻意的:确认一次只放行一次,避免"确认后无限继续"。
|
|
215
|
+
"""
|
|
216
|
+
self._paused_reason = None
|
|
217
|
+
if additional_usd > 0:
|
|
218
|
+
self.config = BudgetConfig(
|
|
219
|
+
max_usd=self.config.max_usd + additional_usd,
|
|
220
|
+
max_tokens=self.config.max_tokens,
|
|
221
|
+
max_rounds=self.config.max_rounds,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def summary(self) -> str:
|
|
225
|
+
s = self.state
|
|
226
|
+
parts = [f"${s.spent_usd:.4f}", f"{s.total_tokens:,} tokens", f"{s.rounds} 轮"]
|
|
227
|
+
if self.config.max_usd:
|
|
228
|
+
pct = (s.spent_usd / self.config.max_usd * 100) if self.config.max_usd else 0
|
|
229
|
+
parts.append(f"用量 {pct:.0f}% / ${self.config.max_usd:.2f}")
|
|
230
|
+
if not s.billable_calls and s.total_tokens:
|
|
231
|
+
parts.append("(全部走本地模型,零成本)")
|
|
232
|
+
return " · ".join(parts)
|