aria-code 0.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_code/__init__.py +42 -0
- aria_code/_version.py +20 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +34 -0
- aria_code/agents/base.py +318 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +303 -0
- aria_code/agents/financial/fundamental.py +191 -0
- aria_code/agents/financial/macro.py +99 -0
- aria_code/agents/financial/news.py +207 -0
- aria_code/agents/financial/risk.py +165 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +258 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +363 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +158 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +492 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +15 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +95 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/bootstrap.py +145 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +16 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +369 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +239 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2543 -0
- aria_code/apps/cli/commands/broker_cmds.py +1234 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +319 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +87 -0
- aria_code/apps/cli/commands/core_cmds.py +2520 -0
- aria_code/apps/cli/commands/data_cmds.py +457 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +230 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +434 -0
- aria_code/apps/cli/commands/market_cmds.py +1381 -0
- aria_code/apps/cli/commands/market_context.py +425 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2153 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +179 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1278 -0
- aria_code/apps/cli/commands/report.py +437 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +669 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +79 -0
- aria_code/apps/cli/commands/workflow_cmds.py +480 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1494 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +78 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/deterministic.py +191 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +196 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1309 -0
- aria_code/apps/cli/handlers/market_handlers.py +2513 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/helpers.py +302 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +297 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +276 -0
- aria_code/apps/cli/intent_signals.py +344 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +536 -0
- aria_code/apps/cli/main.py +29 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/model_catalog.py +620 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +59 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +53 -0
- aria_code/apps/cli/prompts/select.py +142 -0
- aria_code/apps/cli/prompts/system_prompts.py +552 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +521 -0
- aria_code/apps/cli/providers/chat_routing.py +128 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1594 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +257 -0
- aria_code/apps/cli/providers/runtime_bridge.py +353 -0
- aria_code/apps/cli/providers/vertexai_stream.py +316 -0
- aria_code/apps/cli/runtime_consumer.py +657 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_store.py +112 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +823 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +106 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +180 -0
- aria_code/apps/cli/tools/market_tools.py +620 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +726 -0
- aria_code/apps/cli/tools/write_tools.py +845 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +153 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1597 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +6743 -0
- aria_code/aria_daemon.py +1398 -0
- aria_code/aria_feishu_bot.py +1423 -0
- aria_code/aria_mcp_server.py +7 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_relay_server.py +490 -0
- aria_code/aria_telegram_bot.py +202 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +182 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1976 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +181 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/demo_player.py +207 -0
- aria_code/doctor.py +813 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/backtest_engine.py +354 -0
- aria_code/domain/backtest_report.py +472 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/harness.py +598 -0
- aria_code/evals/runner.py +238 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +386 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +639 -0
- aria_code/memory_manager.py +246 -0
- aria_code/model_capability.py +486 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +23 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +52 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +201 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +111 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1550 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +396 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +79 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +268 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +57 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +157 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +8 -0
- aria_code/packages/aria_tools/financial/_paths.py +130 -0
- aria_code/packages/aria_tools/financial/compliance.py +31 -0
- aria_code/packages/aria_tools/financial/factors.py +33 -0
- aria_code/packages/aria_tools/financial/risk_tools.py +33 -0
- aria_code/packages/aria_tools/financial/strategy.py +31 -0
- aria_code/packages/aria_tools/registry.py +128 -0
- aria_code/packages/quant_engine/__init__.py +34 -0
- aria_code/packages/quant_engine/_namespace.py +62 -0
- aria_code/packages/quant_engine/backtest/__init__.py +14 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +96 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +13 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +80 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/ml_model.py +377 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +35 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/logistics/__init__.py +169 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +129 -0
- aria_code/providers/llm/openai_compat.py +313 -0
- aria_code/providers/llm/registry.py +444 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +589 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/runtime/__init__.py +169 -0
- aria_code/runtime/acceptance.py +481 -0
- aria_code/runtime/agent_loop.py +1520 -0
- aria_code/runtime/approval.py +57 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +432 -0
- aria_code/runtime/crash_report.py +174 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +150 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/repo_map.py +700 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +450 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/subagent.py +547 -0
- aria_code/runtime/task_ledger.py +86 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/tool_executor.py +217 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +23 -0
- aria_code/safety/permissions.py +306 -0
- aria_code/safety/service.py +102 -0
- aria_code/setup_wizard.py +673 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +504 -0
- aria_code/tools/data_analysis_tools.py +809 -0
- aria_code/tools/enterprise_finance_tools.py +156 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +885 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3417 -0
- aria_code/tools/logistics_tools.py +135 -0
- aria_code/tools/macro_tools.py +369 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +659 -0
- aria_code/tools/spreadsheet_tools.py +388 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +508 -0
- aria_code/ui/completer.py +501 -0
- aria_code/ui/console.py +281 -0
- aria_code/ui/image_render.py +243 -0
- aria_code/ui/input_box.py +488 -0
- aria_code/ui/picker.py +201 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/finance.py +1705 -0
- aria_code/ui/render/market.py +225 -0
- aria_code/ui/render/output.py +775 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +354 -0
- aria_code/ui/robot.py +235 -0
- aria_code/ui/startup_dashboard.py +109 -0
- aria_code/utils/vscode_uri.py +37 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +271 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +193 -0
- aria_code/workspace/verify.py +113 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_context.py +233 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.52.0.dist-info/METADATA +237 -0
- aria_code-0.52.0.dist-info/RECORD +478 -0
- aria_code-0.52.0.dist-info/WHEEL +5 -0
- aria_code-0.52.0.dist-info/entry_points.txt +3 -0
- aria_code-0.52.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.52.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.52.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Short-TTL response cache shared by the CLI and the extracted Ollama stream.
|
|
2
|
+
|
|
3
|
+
These four names used to live in aria_cli.py and reach stream_ollama only
|
|
4
|
+
through the module-global rebind in that file (see
|
|
5
|
+
``_rebind_module_function_globals`` and the stream_ollama rebind site). Any
|
|
6
|
+
caller that had not imported aria_cli first — the SDK and the daemon — got the
|
|
7
|
+
un-rebound function instead and died on the first cache-eligible turn with
|
|
8
|
+
``NameError: name '_cache_key' is not defined``.
|
|
9
|
+
|
|
10
|
+
Keeping them here means both callers share one cache dict rather than each
|
|
11
|
+
growing its own, and removes four of the borrowed globals that
|
|
12
|
+
packages/aria_core/architecture.py tracks as debt.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import hashlib
|
|
18
|
+
import time
|
|
19
|
+
|
|
20
|
+
__all__ = ["RESPONSE_CACHE", "RESPONSE_CACHE_TTL", "RESPONSE_CACHE_MAX_ENTRIES",
|
|
21
|
+
"cache_get", "cache_set", "cache_clear", "cache_key"]
|
|
22
|
+
|
|
23
|
+
RESPONSE_CACHE: dict = {} # key → (response_text, expire_ts)
|
|
24
|
+
RESPONSE_CACHE_TTL = 60.0 # seconds
|
|
25
|
+
RESPONSE_CACHE_MAX_ENTRIES = 200
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def cache_get(key: str) -> str | None:
|
|
29
|
+
"""Return cached response text if still valid, else None."""
|
|
30
|
+
entry = RESPONSE_CACHE.get(key)
|
|
31
|
+
if entry and time.time() < entry[1]:
|
|
32
|
+
return entry[0]
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def cache_set(key: str, value: str) -> None:
|
|
37
|
+
"""Store response in cache with TTL expiry."""
|
|
38
|
+
RESPONSE_CACHE[key] = (value, time.time() + RESPONSE_CACHE_TTL)
|
|
39
|
+
# Keep cache small — evict expired entries when it grows large
|
|
40
|
+
if len(RESPONSE_CACHE) > RESPONSE_CACHE_MAX_ENTRIES:
|
|
41
|
+
now = time.time()
|
|
42
|
+
for k in list(RESPONSE_CACHE.keys()):
|
|
43
|
+
if RESPONSE_CACHE[k][1] < now:
|
|
44
|
+
del RESPONSE_CACHE[k]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def cache_clear() -> None:
|
|
48
|
+
"""Drop every cached response — for /clear and for test isolation.
|
|
49
|
+
|
|
50
|
+
v4.4.2 grew a second copy of this module at apps/cli/response_cache.py.
|
|
51
|
+
That copy is not taken: this one is already where the two callers share it,
|
|
52
|
+
and duplicating it would put two cache dicts behind one name. Only the
|
|
53
|
+
parts this one lacked came across.
|
|
54
|
+
"""
|
|
55
|
+
RESPONSE_CACHE.clear()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def cache_key(model: str, message: str) -> str:
|
|
59
|
+
raw = f"{model}::{message.strip().lower()}"
|
|
60
|
+
return hashlib.md5(raw.encode()).hexdigest()
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""stream_chat — Aria cloud SSE provider extracted from aria_cli.py.
|
|
2
|
+
|
|
3
|
+
Streams AI responses from the Aria backend via Server-Sent Events (SSE).
|
|
4
|
+
Supports cancellation, thinking tokens, tool calls, retries, and usage stats.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import json
|
|
10
|
+
from typing import Callable, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def build_chat_payload(
|
|
14
|
+
message: str,
|
|
15
|
+
history: list,
|
|
16
|
+
*,
|
|
17
|
+
model: str,
|
|
18
|
+
thinking_mode: str,
|
|
19
|
+
user_context: Optional[dict],
|
|
20
|
+
project_context: str,
|
|
21
|
+
use_react_gateway: bool,
|
|
22
|
+
) -> tuple[str, dict]:
|
|
23
|
+
"""Build either the legacy chat payload or the shared ReAct envelope.
|
|
24
|
+
|
|
25
|
+
This is deliberately pure: it gives CLI, desktop, and iOS an auditable
|
|
26
|
+
parity point without forcing the local-first CLI to use cloud services.
|
|
27
|
+
"""
|
|
28
|
+
if use_react_gateway:
|
|
29
|
+
context = dict(user_context or {})
|
|
30
|
+
if project_context:
|
|
31
|
+
context["project_context"] = project_context
|
|
32
|
+
mode = str(context.pop("workspace_mode", "code"))
|
|
33
|
+
return "/api/v2/chat/react", {
|
|
34
|
+
"message": {
|
|
35
|
+
"role": "user",
|
|
36
|
+
"content": [{"type": "text", "text": message}],
|
|
37
|
+
},
|
|
38
|
+
"mode": mode,
|
|
39
|
+
"surface": "aria_code",
|
|
40
|
+
"history": history[-20:],
|
|
41
|
+
"model": {"id": model or "auto", "effort": thinking_mode or "auto"},
|
|
42
|
+
"context": context,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
payload: dict = {
|
|
46
|
+
"message": message,
|
|
47
|
+
"conversation_history": history[-20:],
|
|
48
|
+
"model": model,
|
|
49
|
+
"thinking_mode": thinking_mode,
|
|
50
|
+
"stream": True,
|
|
51
|
+
}
|
|
52
|
+
if user_context:
|
|
53
|
+
if project_context:
|
|
54
|
+
user_context = {**user_context, "project_context": project_context}
|
|
55
|
+
payload["user_context"] = user_context
|
|
56
|
+
return "/api/v2/ai/chat/stream", payload
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def stream_chat(
|
|
60
|
+
base_url: str,
|
|
61
|
+
message: str,
|
|
62
|
+
history: list,
|
|
63
|
+
model: str = "qwen2.5:7b",
|
|
64
|
+
thinking_mode: str = "auto",
|
|
65
|
+
user_context: Optional[dict] = None,
|
|
66
|
+
auth_token: Optional[str] = None,
|
|
67
|
+
on_token: Optional[Callable[[str], None]] = None,
|
|
68
|
+
on_thinking: Optional[Callable[[str], None]] = None,
|
|
69
|
+
on_tool_call: Optional[Callable[[str, dict], None]] = None,
|
|
70
|
+
on_tool_result: Optional[Callable[[str, str], None]] = None,
|
|
71
|
+
on_status: Optional[Callable[[str, str], None]] = None,
|
|
72
|
+
cancel_event: Optional[asyncio.Event] = None,
|
|
73
|
+
project_context: str = "",
|
|
74
|
+
use_react_gateway: bool = False,
|
|
75
|
+
) -> dict:
|
|
76
|
+
"""Stream AI chat via SSE with cancel support and user context.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
project_context:
|
|
81
|
+
ARIA.md / CLAUDE.md content to inject into user_context.
|
|
82
|
+
Callers pass ``_PROJECT_CONTEXT`` from aria_cli, keeping this
|
|
83
|
+
module free of global state.
|
|
84
|
+
"""
|
|
85
|
+
import aiohttp
|
|
86
|
+
|
|
87
|
+
endpoint, payload = build_chat_payload(
|
|
88
|
+
message, history, model=model, thinking_mode=thinking_mode,
|
|
89
|
+
user_context=user_context, project_context=project_context,
|
|
90
|
+
use_react_gateway=use_react_gateway,
|
|
91
|
+
)
|
|
92
|
+
url = f"{base_url.rstrip('/')}{endpoint}"
|
|
93
|
+
|
|
94
|
+
headers: dict = {}
|
|
95
|
+
if auth_token:
|
|
96
|
+
headers["Authorization"] = f"Bearer {auth_token}"
|
|
97
|
+
|
|
98
|
+
full_response = ""
|
|
99
|
+
thinking_content = ""
|
|
100
|
+
tools_used: list = []
|
|
101
|
+
sources: list = []
|
|
102
|
+
tool_calls_pending: list = []
|
|
103
|
+
usage: dict = {"prompt_tokens": 0, "completion_tokens": 0, "thinking_tokens": 0}
|
|
104
|
+
|
|
105
|
+
_max_connect_retries = 2
|
|
106
|
+
_last_connect_error: Optional[str] = None
|
|
107
|
+
|
|
108
|
+
for _attempt in range(_max_connect_retries + 1):
|
|
109
|
+
if cancel_event and cancel_event.is_set():
|
|
110
|
+
return {
|
|
111
|
+
"success": True, "response": "", "cancelled": True,
|
|
112
|
+
"tools_used": [], "sources": [], "usage": usage,
|
|
113
|
+
}
|
|
114
|
+
# Reset per-attempt accumulators
|
|
115
|
+
full_response = ""
|
|
116
|
+
thinking_content = ""
|
|
117
|
+
tools_used = []
|
|
118
|
+
sources = []
|
|
119
|
+
tool_calls_pending = []
|
|
120
|
+
usage = {"prompt_tokens": 0, "completion_tokens": 0, "thinking_tokens": 0}
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
async with aiohttp.ClientSession() as session:
|
|
124
|
+
async with session.post(
|
|
125
|
+
url, json=payload, headers=headers,
|
|
126
|
+
timeout=aiohttp.ClientTimeout(total=120),
|
|
127
|
+
) as resp:
|
|
128
|
+
if resp.status != 200:
|
|
129
|
+
error_text = await resp.text()
|
|
130
|
+
return {"success": False, "error": f"HTTP {resp.status}: {error_text[:200]}"}
|
|
131
|
+
|
|
132
|
+
buffer = ""
|
|
133
|
+
event_type = "delta"
|
|
134
|
+
|
|
135
|
+
async for chunk in resp.content:
|
|
136
|
+
if cancel_event and cancel_event.is_set():
|
|
137
|
+
try:
|
|
138
|
+
if not use_react_gateway:
|
|
139
|
+
await session.post(
|
|
140
|
+
f"{base_url.rstrip('/')}/api/v2/ai/chat/cancel",
|
|
141
|
+
headers=headers,
|
|
142
|
+
timeout=aiohttp.ClientTimeout(total=3),
|
|
143
|
+
)
|
|
144
|
+
except Exception:
|
|
145
|
+
pass
|
|
146
|
+
return {
|
|
147
|
+
"success": True, "response": full_response,
|
|
148
|
+
"cancelled": True, "tools_used": tools_used,
|
|
149
|
+
"sources": sources, "usage": usage,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
text = chunk.decode("utf-8", errors="ignore")
|
|
153
|
+
buffer += text
|
|
154
|
+
|
|
155
|
+
while "\n" in buffer:
|
|
156
|
+
line, buffer = buffer.split("\n", 1)
|
|
157
|
+
line = line.strip()
|
|
158
|
+
|
|
159
|
+
if not line or line.startswith(":"):
|
|
160
|
+
continue
|
|
161
|
+
if line.startswith("event:"):
|
|
162
|
+
event_type = line[6:].strip()
|
|
163
|
+
continue
|
|
164
|
+
if not line.startswith("data:"):
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
data_str = line[5:].strip()
|
|
168
|
+
if data_str == "[DONE]":
|
|
169
|
+
break
|
|
170
|
+
try:
|
|
171
|
+
data = json.loads(data_str)
|
|
172
|
+
except json.JSONDecodeError:
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
# Backend error: {"success": false, "error": "..."}
|
|
176
|
+
if data.get("success") is False:
|
|
177
|
+
err_msg = data.get("error", "Backend error")
|
|
178
|
+
return {"success": False, "error": f"Backend: {err_msg}"}
|
|
179
|
+
|
|
180
|
+
evt = data.get("type", event_type)
|
|
181
|
+
|
|
182
|
+
if evt == "delta":
|
|
183
|
+
token = data.get("text", data.get("content", ""))
|
|
184
|
+
if token:
|
|
185
|
+
full_response += token
|
|
186
|
+
usage["completion_tokens"] += 1
|
|
187
|
+
if on_token:
|
|
188
|
+
on_token(token)
|
|
189
|
+
|
|
190
|
+
elif evt == "thinking_content":
|
|
191
|
+
tc = data.get("content", "")
|
|
192
|
+
if tc:
|
|
193
|
+
thinking_content += tc
|
|
194
|
+
usage["thinking_tokens"] += 1
|
|
195
|
+
if on_thinking:
|
|
196
|
+
on_thinking(tc)
|
|
197
|
+
|
|
198
|
+
elif evt == "tool_call":
|
|
199
|
+
tool = data.get("tool", data.get("name", ""))
|
|
200
|
+
params = data.get("params", {})
|
|
201
|
+
tools_used.append(tool)
|
|
202
|
+
tool_calls_pending.append({"tool": tool, "params": params})
|
|
203
|
+
if on_tool_call:
|
|
204
|
+
on_tool_call(tool, params)
|
|
205
|
+
|
|
206
|
+
elif evt == "tool_result":
|
|
207
|
+
if on_tool_result:
|
|
208
|
+
on_tool_result(data.get("tool", ""), data.get("summary", ""))
|
|
209
|
+
|
|
210
|
+
elif evt == "status":
|
|
211
|
+
if on_status:
|
|
212
|
+
on_status(data.get("state", ""), data.get("label", data.get("message", "")))
|
|
213
|
+
|
|
214
|
+
elif evt == "final":
|
|
215
|
+
full_response = data.get("answer", full_response)
|
|
216
|
+
sources = data.get("sources", [])
|
|
217
|
+
if data.get("usage"):
|
|
218
|
+
u = data["usage"]
|
|
219
|
+
usage["prompt_tokens"] = u.get("prompt_tokens", usage["prompt_tokens"])
|
|
220
|
+
usage["completion_tokens"] = u.get("completion_tokens", usage["completion_tokens"])
|
|
221
|
+
|
|
222
|
+
elif evt == "error":
|
|
223
|
+
return {"success": False, "error": data.get("message", data.get("error", "Unknown error"))}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
"success": True,
|
|
227
|
+
"response": full_response,
|
|
228
|
+
"thinking": thinking_content,
|
|
229
|
+
"tools_used": tools_used,
|
|
230
|
+
"sources": sources,
|
|
231
|
+
"tool_calls_pending": tool_calls_pending,
|
|
232
|
+
"usage": usage,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
except asyncio.TimeoutError:
|
|
236
|
+
return {"success": False, "error": "Request timed out (120s)"}
|
|
237
|
+
except asyncio.CancelledError:
|
|
238
|
+
return {
|
|
239
|
+
"success": True, "response": full_response, "cancelled": True,
|
|
240
|
+
"tools_used": tools_used, "sources": sources, "usage": usage,
|
|
241
|
+
}
|
|
242
|
+
except aiohttp.ClientConnectorError as exc:
|
|
243
|
+
_last_connect_error = str(exc)
|
|
244
|
+
if _attempt < _max_connect_retries:
|
|
245
|
+
wait = 1.5 * (_attempt + 1)
|
|
246
|
+
await asyncio.sleep(wait)
|
|
247
|
+
if on_status:
|
|
248
|
+
on_status("retry", f"Connection failed, retrying ({_attempt + 2}/{_max_connect_retries + 1})...")
|
|
249
|
+
continue
|
|
250
|
+
break
|
|
251
|
+
except Exception as exc:
|
|
252
|
+
return {"success": False, "error": str(exc)}
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
"success": False,
|
|
256
|
+
"error": f"Connection failed after {_max_connect_retries + 1} attempts: {_last_connect_error}",
|
|
257
|
+
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"""Phase-3 bridge: run one chat turn through the shared ``runtime.run_agent``.
|
|
2
|
+
|
|
3
|
+
The documented runtime next step is to route the CLI tool loop through
|
|
4
|
+
``run_agent`` and keep aria_cli as orchestration glue. This module is that engine
|
|
5
|
+
— the two adapters run_agent needs plus a thin driver:
|
|
6
|
+
|
|
7
|
+
• build_tool_executor() — wraps the CLI's ``LOCAL_TOOLS`` ({name: (handler, schema)})
|
|
8
|
+
• make_provider_fn() — selects the provider (chat_routing) + streams it
|
|
9
|
+
• run_chat_via_runtime() — drives run_agent, renders via callbacks, returns text
|
|
10
|
+
|
|
11
|
+
This is THE chat path: ``send_message`` runs every turn through it (the old
|
|
12
|
+
inline per-round loop was retired in 2026-07 after the runtime path was
|
|
13
|
+
validated with real turns). Tool approval and execution context are threaded
|
|
14
|
+
through to run_agent's tool loop; on failure send_message attempts one direct
|
|
15
|
+
cloud rescue (``providers/llm/registry.stream_cloud_fallback``) before
|
|
16
|
+
presenting the error.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Any, Callable, List, Optional
|
|
22
|
+
|
|
23
|
+
from .chat_routing import first_round_route, is_placeholder_response, should_fallback
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def build_tool_executor(
|
|
27
|
+
local_tools,
|
|
28
|
+
config: Optional[dict] = None,
|
|
29
|
+
execution_context: Optional[Callable[[], dict]] = None,
|
|
30
|
+
):
|
|
31
|
+
"""Wrap the CLI's LOCAL_TOOLS registry for run_agent."""
|
|
32
|
+
from aria_code.runtime.tool_executor import ToolExecutor
|
|
33
|
+
return ToolExecutor(
|
|
34
|
+
local_tools,
|
|
35
|
+
config=config or {},
|
|
36
|
+
execution_context=execution_context,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Modes in which nothing can be written, so nothing can need verifying.
|
|
41
|
+
_READ_ONLY_MODES = frozenset({"read-only", "readonly", "read_only", "plan"})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _declared_acceptance_commands(cfg: dict, message: str) -> tuple:
|
|
45
|
+
"""What this workspace says "correct" means for this particular message.
|
|
46
|
+
|
|
47
|
+
Precedence, most specific first:
|
|
48
|
+
|
|
49
|
+
1. ``acceptance_commands`` in the session config — the user said it out
|
|
50
|
+
loud for this session, so nothing overrides it.
|
|
51
|
+
2. The active domain packs' commands. A pack contributes only when it
|
|
52
|
+
resolved a concrete entity from *this* message, so a declared
|
|
53
|
+
logistics check cannot fire on a payments question.
|
|
54
|
+
3. The workspace's ``acceptance.default`` from ``.ariarc``.
|
|
55
|
+
|
|
56
|
+
Nothing declared falls through to inference from the changed files, which
|
|
57
|
+
is the behaviour that existed before packs could speak here at all.
|
|
58
|
+
"""
|
|
59
|
+
explicit = tuple(cfg.get("acceptance_commands") or ())
|
|
60
|
+
if explicit:
|
|
61
|
+
return explicit
|
|
62
|
+
|
|
63
|
+
commands: list = []
|
|
64
|
+
try:
|
|
65
|
+
from aria_code.packs import (
|
|
66
|
+
activate_packs,
|
|
67
|
+
active_acceptance_commands,
|
|
68
|
+
load_builtin_packs,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
load_builtin_packs()
|
|
72
|
+
commands.extend(active_acceptance_commands(activate_packs(message or "")))
|
|
73
|
+
except Exception:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
from aria_code.packs.rules import default_acceptance_commands
|
|
78
|
+
|
|
79
|
+
for command in default_acceptance_commands():
|
|
80
|
+
if command not in commands:
|
|
81
|
+
commands.append(command)
|
|
82
|
+
except Exception:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
return tuple(commands)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def build_acceptance_gate(executor, config: Optional[dict] = None, message: str = ""):
|
|
89
|
+
"""The CLI's acceptance gate, or ``None`` when this session shouldn't have one.
|
|
90
|
+
|
|
91
|
+
The gate runs its checks through the session's own ``run_command`` tool
|
|
92
|
+
rather than spawning subprocesses itself, so the workspace sandbox, the
|
|
93
|
+
command policy and the trace all apply to a verification run exactly as
|
|
94
|
+
they apply to a command the model asked for.
|
|
95
|
+
|
|
96
|
+
``user_approved`` is set because the commands are the *planner's*, not the
|
|
97
|
+
model's or the user's prose — the same inferred plan ``/verify`` already
|
|
98
|
+
runs on request. Anything else would put an approval prompt between the
|
|
99
|
+
model finishing and the check that tells us whether it finished correctly,
|
|
100
|
+
which is the one place a prompt cannot help.
|
|
101
|
+
"""
|
|
102
|
+
cfg = config or {}
|
|
103
|
+
if not cfg.get("acceptance_gate", True):
|
|
104
|
+
return None
|
|
105
|
+
mode = str(cfg.get("permission_mode", "workspace-write") or "")
|
|
106
|
+
if mode in _READ_ONLY_MODES:
|
|
107
|
+
return None
|
|
108
|
+
if "run_command" not in getattr(executor, "local_tools", {}):
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
import os
|
|
112
|
+
from aria_code.runtime.acceptance import AcceptanceGate
|
|
113
|
+
|
|
114
|
+
timeout = int(cfg.get("acceptance_timeout", 300) or 300)
|
|
115
|
+
|
|
116
|
+
def _runner(command: str) -> dict:
|
|
117
|
+
return executor.execute_local("run_command", {
|
|
118
|
+
"command": command,
|
|
119
|
+
"policy": "balanced",
|
|
120
|
+
"permission_mode": mode,
|
|
121
|
+
"network_enabled": bool(cfg.get("network_enabled", True)),
|
|
122
|
+
"user_approved": True,
|
|
123
|
+
"timeout": timeout,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
return AcceptanceGate(
|
|
127
|
+
runner=_runner,
|
|
128
|
+
root=os.getcwd(),
|
|
129
|
+
max_attempts=int(cfg.get("acceptance_max_attempts", 2) or 2),
|
|
130
|
+
commands=_declared_acceptance_commands(cfg, message),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
async def run_with_fallback(
|
|
135
|
+
route: str,
|
|
136
|
+
*,
|
|
137
|
+
run_cloud: Callable,
|
|
138
|
+
run_ollama: Callable,
|
|
139
|
+
on_token: Optional[Callable[[str], None]] = None,
|
|
140
|
+
) -> dict:
|
|
141
|
+
"""Primary generation per ``route``, with cloud→Ollama fallback parity.
|
|
142
|
+
|
|
143
|
+
Mirrors ``send_message``'s inline fallback, but keyed on *route* (via
|
|
144
|
+
``should_fallback``) so a genuinely-good forced-backend answer is kept
|
|
145
|
+
instead of being discarded and re-run:
|
|
146
|
+
|
|
147
|
+
• ``skip`` / ``ollama`` → run local Ollama directly (no cloud round)
|
|
148
|
+
• ``cloud`` → run cloud; if it fails or returns a placeholder
|
|
149
|
+
(empty / canned / backend stub), fall back to
|
|
150
|
+
local Ollama
|
|
151
|
+
|
|
152
|
+
``run_cloud`` / ``run_ollama`` are async ``(on_token) -> result dict``
|
|
153
|
+
closures; injecting them keeps this orchestration unit-testable without
|
|
154
|
+
real providers or network.
|
|
155
|
+
"""
|
|
156
|
+
if route in ("skip", "ollama", "configured"):
|
|
157
|
+
return await run_ollama(on_token)
|
|
158
|
+
|
|
159
|
+
# route == "cloud": count streamed tokens so a long-but-unstreamed canned
|
|
160
|
+
# backend reply is recognised as a placeholder, not a real generation.
|
|
161
|
+
_tokens = [0]
|
|
162
|
+
|
|
163
|
+
def _counting_on_token(tok: str) -> None:
|
|
164
|
+
_tokens[0] += 1
|
|
165
|
+
if on_token is not None:
|
|
166
|
+
on_token(tok)
|
|
167
|
+
|
|
168
|
+
result = await run_cloud(_counting_on_token)
|
|
169
|
+
if result.get("cancelled"):
|
|
170
|
+
return result # user-cancelled — never silently re-run on a different provider
|
|
171
|
+
|
|
172
|
+
placeholder = is_placeholder_response(result.get("response", ""), _tokens[0])
|
|
173
|
+
if should_fallback("cloud", result, is_placeholder=placeholder):
|
|
174
|
+
return await run_ollama(on_token)
|
|
175
|
+
return result
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def make_provider_fn(
|
|
179
|
+
*,
|
|
180
|
+
model: str,
|
|
181
|
+
config: dict,
|
|
182
|
+
api_url: Optional[str],
|
|
183
|
+
ollama_url: str,
|
|
184
|
+
tool_schemas: List[dict],
|
|
185
|
+
thinking_mode: str = "auto",
|
|
186
|
+
user_context: Optional[dict] = None,
|
|
187
|
+
auth_token: Optional[str] = None,
|
|
188
|
+
project_context: Any = None,
|
|
189
|
+
system_override: Optional[str] = None,
|
|
190
|
+
) -> Callable:
|
|
191
|
+
"""Build an async ``provider_fn`` for run_agent.
|
|
192
|
+
|
|
193
|
+
Selects the provider per chat_routing (cloud → AriaSSE backend; ollama/skip →
|
|
194
|
+
local Ollama) and streams it through the shared ``stream_provider_result``.
|
|
195
|
+
A pending system-role override is threaded the same way ``send_message`` does
|
|
196
|
+
it: cloud via ``user_context['system_role_override']``, Ollama via the
|
|
197
|
+
provider's ``system_override`` argument.
|
|
198
|
+
"""
|
|
199
|
+
# Bare root on purpose: this is the module the tests patch, and the two
|
|
200
|
+
# roots are distinct module objects — importing the packaged one made
|
|
201
|
+
# monkeypatched providers silently unused.
|
|
202
|
+
from apps.cli.providers.base import AriaSSEProvider, ConfiguredProvider, OllamaProvider
|
|
203
|
+
# Bare root: the tests patch packages.aria_sdk.streaming, and the packaged
|
|
204
|
+
# root is a different module object, so the patch would not apply.
|
|
205
|
+
from packages.aria_sdk.streaming import stream_provider_result
|
|
206
|
+
|
|
207
|
+
_cloud_uctx = dict(user_context or {})
|
|
208
|
+
if system_override:
|
|
209
|
+
_cloud_uctx["system_role_override"] = system_override
|
|
210
|
+
|
|
211
|
+
def _scoped_tools(prompt: str) -> List[dict]:
|
|
212
|
+
"""Tools this message may use: core always, domain only when claimed."""
|
|
213
|
+
try:
|
|
214
|
+
from aria_code.apps.cli.tool_scope import select_tool_schemas
|
|
215
|
+
|
|
216
|
+
return select_tool_schemas(tool_schemas, prompt)
|
|
217
|
+
except Exception:
|
|
218
|
+
return list(tool_schemas)
|
|
219
|
+
|
|
220
|
+
def _system_for(prompt: str) -> str:
|
|
221
|
+
"""The rules this turn runs under, for the non-Ollama providers.
|
|
222
|
+
|
|
223
|
+
ollama_stream assembles its own (with prefetched data and sized
|
|
224
|
+
project context); everything else used to get nothing at all, so a
|
|
225
|
+
cloud model was never told the tool discipline. Built per message
|
|
226
|
+
because the right prompt depends on what was asked.
|
|
227
|
+
"""
|
|
228
|
+
try:
|
|
229
|
+
from aria_code.apps.cli.prompts.select import build_turn_system_prompt
|
|
230
|
+
|
|
231
|
+
return build_turn_system_prompt(
|
|
232
|
+
prompt,
|
|
233
|
+
override=system_override,
|
|
234
|
+
project_context=str(project_context or ""),
|
|
235
|
+
)
|
|
236
|
+
except Exception:
|
|
237
|
+
return system_override or ""
|
|
238
|
+
|
|
239
|
+
async def _provider_fn(prompt, history, *, on_token=None, on_thinking=None,
|
|
240
|
+
on_tool_call=None, on_tool_result=None, on_status=None,
|
|
241
|
+
cancel_event=None):
|
|
242
|
+
route = first_round_route(model, config, api_url)
|
|
243
|
+
|
|
244
|
+
# ollama_stream does its own intent-based selection; the other
|
|
245
|
+
# providers had none, so a coding turn reached Gemini carrying all 74
|
|
246
|
+
# tool schemas including 34 domain tools. Scoped per message because
|
|
247
|
+
# what a turn may call depends on what it asked.
|
|
248
|
+
_scoped = _scoped_tools(prompt)
|
|
249
|
+
|
|
250
|
+
async def _stream(provider, _on_token):
|
|
251
|
+
return await stream_provider_result(
|
|
252
|
+
provider, prompt, history, tools=_scoped,
|
|
253
|
+
cancel_event=cancel_event, on_token=_on_token, on_thinking=on_thinking,
|
|
254
|
+
on_tool_call=on_tool_call, on_tool_result=on_tool_result, on_status=on_status,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
async def run_cloud(_on_token):
|
|
258
|
+
return await _stream(
|
|
259
|
+
AriaSSEProvider(
|
|
260
|
+
api_url, model, thinking_mode=thinking_mode,
|
|
261
|
+
user_context=_cloud_uctx, auth_token=auth_token,
|
|
262
|
+
project_context=project_context,
|
|
263
|
+
use_react_gateway=bool(config.get("arthera_react_gateway")),
|
|
264
|
+
),
|
|
265
|
+
_on_token,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
async def run_ollama(_on_token):
|
|
269
|
+
selected = (
|
|
270
|
+
OllamaProvider(ollama_url, model, system_override=system_override)
|
|
271
|
+
if route == "ollama" else
|
|
272
|
+
ConfiguredProvider(config, model, system_override=_system_for(prompt))
|
|
273
|
+
)
|
|
274
|
+
return await _stream(
|
|
275
|
+
selected,
|
|
276
|
+
_on_token,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
return await run_with_fallback(
|
|
280
|
+
route, run_cloud=run_cloud, run_ollama=run_ollama, on_token=on_token,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
return _provider_fn
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
async def run_chat_via_runtime(
|
|
287
|
+
*,
|
|
288
|
+
prompt: str,
|
|
289
|
+
history: list,
|
|
290
|
+
local_tools,
|
|
291
|
+
tool_schemas: List[dict],
|
|
292
|
+
model: str,
|
|
293
|
+
config: dict,
|
|
294
|
+
api_url: Optional[str],
|
|
295
|
+
ollama_url: str,
|
|
296
|
+
cancel_event=None,
|
|
297
|
+
on_token: Optional[Callable[[str], None]] = None,
|
|
298
|
+
on_thinking: Optional[Callable[[str], None]] = None,
|
|
299
|
+
on_tool_call: Optional[Callable[[str, dict], None]] = None,
|
|
300
|
+
on_tool_result: Optional[Callable[[str, dict], None]] = None,
|
|
301
|
+
on_status: Optional[Callable[[str, str], None]] = None,
|
|
302
|
+
thinking_mode: str = "auto",
|
|
303
|
+
user_context: Optional[dict] = None,
|
|
304
|
+
auth_token: Optional[str] = None,
|
|
305
|
+
project_context: Any = None,
|
|
306
|
+
system_override: Optional[str] = None,
|
|
307
|
+
max_rounds: int = 30,
|
|
308
|
+
return_result: bool = False,
|
|
309
|
+
execution_context: Optional[Callable[[], dict]] = None,
|
|
310
|
+
confirm_tools=(),
|
|
311
|
+
approval_callback: Optional[Callable] = None,
|
|
312
|
+
approval_applier: Optional[Callable] = None,
|
|
313
|
+
requires_evidence: bool = False,
|
|
314
|
+
grounding_tools=(),
|
|
315
|
+
evidence_already_grounded: bool = False,
|
|
316
|
+
):
|
|
317
|
+
"""Run one chat turn through the shared runtime Gateway.
|
|
318
|
+
|
|
319
|
+
This is the CLI *adapter* for ``runtime.gateway.run_turn``: it builds the
|
|
320
|
+
CLI's ``provider_fn`` (AriaSSE/Ollama selection + cloud→Ollama fallback) and
|
|
321
|
+
tool executor (the LOCAL_TOOLS registry), then hands them to the neutral
|
|
322
|
+
gateway, which drives ``run_agent`` and streams via the callbacks. By
|
|
323
|
+
default this returns assistant text for compatibility. ``return_result``
|
|
324
|
+
exposes the gateway result so terminal adapters can preserve provider and
|
|
325
|
+
usage metadata during final rendering.
|
|
326
|
+
"""
|
|
327
|
+
from aria_code.runtime.gateway import run_turn
|
|
328
|
+
|
|
329
|
+
provider_fn = make_provider_fn(
|
|
330
|
+
model=model, config=config, api_url=api_url, ollama_url=ollama_url,
|
|
331
|
+
tool_schemas=tool_schemas, thinking_mode=thinking_mode,
|
|
332
|
+
user_context=user_context, auth_token=auth_token, project_context=project_context,
|
|
333
|
+
system_override=system_override,
|
|
334
|
+
)
|
|
335
|
+
executor = build_tool_executor(local_tools, config, execution_context)
|
|
336
|
+
gate = build_acceptance_gate(executor, config, prompt)
|
|
337
|
+
|
|
338
|
+
result = await run_turn(
|
|
339
|
+
prompt, history,
|
|
340
|
+
provider_fn=provider_fn, tool_executor=executor,
|
|
341
|
+
tool_schemas=list(tool_schemas),
|
|
342
|
+
on_token=on_token, on_thinking=on_thinking,
|
|
343
|
+
on_tool_call=on_tool_call, on_tool_result=on_tool_result, on_status=on_status,
|
|
344
|
+
cancel_event=cancel_event, max_rounds=max_rounds,
|
|
345
|
+
confirm_tools=confirm_tools,
|
|
346
|
+
approval_callback=approval_callback,
|
|
347
|
+
approval_applier=approval_applier,
|
|
348
|
+
requires_evidence=requires_evidence,
|
|
349
|
+
grounding_tools=grounding_tools,
|
|
350
|
+
evidence_already_grounded=evidence_already_grounded,
|
|
351
|
+
acceptance=gate,
|
|
352
|
+
)
|
|
353
|
+
return result if return_result else result.text
|