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,86 @@
|
|
|
1
|
+
"""Typed public objects for the lightweight Aria Agent SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass, field
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class AriaAgentOptions:
|
|
11
|
+
"""Options for an Aria SDK agent session.
|
|
12
|
+
|
|
13
|
+
The fields mirror the concerns exposed by modern agent SDKs: model/provider
|
|
14
|
+
selection, deterministic tool routing, permission intent, cwd, and metadata.
|
|
15
|
+
CLI rendering and terminal state stay outside this contract.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
model: str = "qwen2.5-coder:1.5b"
|
|
19
|
+
provider: str = "auto"
|
|
20
|
+
ollama_url: str = "http://localhost:11434"
|
|
21
|
+
api_url: str = "http://localhost:8000"
|
|
22
|
+
auth_token: str = ""
|
|
23
|
+
thinking_mode: str = "auto"
|
|
24
|
+
user_context: dict[str, Any] = field(default_factory=dict)
|
|
25
|
+
local_mode: bool = True
|
|
26
|
+
deterministic: bool = True
|
|
27
|
+
model_has_tools: bool = False
|
|
28
|
+
system_prompt: str = ""
|
|
29
|
+
permission_mode: str = "workspace-write"
|
|
30
|
+
allowed_tools: tuple[str, ...] = ()
|
|
31
|
+
disallowed_tools: tuple[str, ...] = ()
|
|
32
|
+
tool_schemas: tuple[dict[str, Any], ...] = ()
|
|
33
|
+
max_turns: int = 1
|
|
34
|
+
cwd: str = ""
|
|
35
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
36
|
+
has_brokers: bool = False
|
|
37
|
+
get_broker_registry: Callable[[], Any] | None = field(
|
|
38
|
+
default=None,
|
|
39
|
+
repr=False,
|
|
40
|
+
compare=False,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def to_dict(self) -> dict[str, Any]:
|
|
44
|
+
data = asdict(self)
|
|
45
|
+
data["get_broker_registry"] = None
|
|
46
|
+
return data
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class AriaMessage:
|
|
51
|
+
"""Event/message yielded by the SDK query stream."""
|
|
52
|
+
|
|
53
|
+
kind: str
|
|
54
|
+
content: str = ""
|
|
55
|
+
role: str = ""
|
|
56
|
+
data: dict[str, Any] = field(default_factory=dict)
|
|
57
|
+
|
|
58
|
+
def to_dict(self) -> dict[str, Any]:
|
|
59
|
+
return {
|
|
60
|
+
"kind": self.kind,
|
|
61
|
+
"role": self.role,
|
|
62
|
+
"content": self.content,
|
|
63
|
+
"data": dict(self.data),
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True)
|
|
68
|
+
class AriaResult:
|
|
69
|
+
"""Final collected SDK result."""
|
|
70
|
+
|
|
71
|
+
success: bool
|
|
72
|
+
content: str = ""
|
|
73
|
+
provider: str = ""
|
|
74
|
+
session_id: str = ""
|
|
75
|
+
error: str = ""
|
|
76
|
+
data: dict[str, Any] = field(default_factory=dict)
|
|
77
|
+
|
|
78
|
+
def to_dict(self) -> dict[str, Any]:
|
|
79
|
+
return asdict(self)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
__all__ = [
|
|
83
|
+
"AriaAgentOptions",
|
|
84
|
+
"AriaMessage",
|
|
85
|
+
"AriaResult",
|
|
86
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Service boundary manifests for Aria Code."""
|
|
2
|
+
|
|
3
|
+
from .context import (
|
|
4
|
+
ContextDecision,
|
|
5
|
+
ContextPolicy,
|
|
6
|
+
ContextService,
|
|
7
|
+
ContextSummaryEnvelope,
|
|
8
|
+
build_context_service,
|
|
9
|
+
)
|
|
10
|
+
from .provider_health import (
|
|
11
|
+
GLOBAL_PROVIDER_HEALTH,
|
|
12
|
+
PublicServiceStatus,
|
|
13
|
+
ProviderHealthRegistry,
|
|
14
|
+
ProviderIssue,
|
|
15
|
+
ProviderState,
|
|
16
|
+
classify_provider_error,
|
|
17
|
+
public_service_status,
|
|
18
|
+
summarize_provider_health,
|
|
19
|
+
)
|
|
20
|
+
from .references import (
|
|
21
|
+
REFERENCE_KINDS,
|
|
22
|
+
ContextReference,
|
|
23
|
+
PreparedReferences,
|
|
24
|
+
ReferenceKind,
|
|
25
|
+
ReferencePolicy,
|
|
26
|
+
ReferenceService,
|
|
27
|
+
build_reference_service,
|
|
28
|
+
iter_reference_tokens,
|
|
29
|
+
reference_search_roots,
|
|
30
|
+
)
|
|
31
|
+
from .research_quality import (
|
|
32
|
+
ReportQualityAssessment,
|
|
33
|
+
ReportQualityDecision,
|
|
34
|
+
ReportQualityPolicy,
|
|
35
|
+
assess_team_report,
|
|
36
|
+
)
|
|
37
|
+
from .research_protocol import grounding_tool_names, requires_financial_evidence
|
|
38
|
+
from .registry import ServiceSpec, list_service_specs, required_service_names, service_map
|
|
39
|
+
from .usage import ServiceUsageSpec, list_service_usage_specs, service_usage_map
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"ContextDecision",
|
|
43
|
+
"ContextPolicy",
|
|
44
|
+
"ContextService",
|
|
45
|
+
"ContextSummaryEnvelope",
|
|
46
|
+
"ContextReference",
|
|
47
|
+
"DataBundle",
|
|
48
|
+
"DataService",
|
|
49
|
+
"DataServiceResult",
|
|
50
|
+
"GLOBAL_PROVIDER_HEALTH",
|
|
51
|
+
"PublicServiceStatus",
|
|
52
|
+
"ProviderHealthRegistry",
|
|
53
|
+
"ProviderIssue",
|
|
54
|
+
"ProviderState",
|
|
55
|
+
"PreparedReferences",
|
|
56
|
+
"REFERENCE_KINDS",
|
|
57
|
+
"ReferenceKind",
|
|
58
|
+
"ReferencePolicy",
|
|
59
|
+
"ReferenceService",
|
|
60
|
+
"ReportQualityAssessment",
|
|
61
|
+
"ReportQualityDecision",
|
|
62
|
+
"ReportQualityPolicy",
|
|
63
|
+
"ServiceSpec",
|
|
64
|
+
"ServiceUsageSpec",
|
|
65
|
+
"build_context_service",
|
|
66
|
+
"build_reference_service",
|
|
67
|
+
"assess_team_report",
|
|
68
|
+
"classify_provider_error",
|
|
69
|
+
"public_service_status",
|
|
70
|
+
"list_service_specs",
|
|
71
|
+
"list_service_usage_specs",
|
|
72
|
+
"grounding_tool_names",
|
|
73
|
+
"iter_reference_tokens",
|
|
74
|
+
"reference_search_roots",
|
|
75
|
+
"required_service_names",
|
|
76
|
+
"requires_financial_evidence",
|
|
77
|
+
"service_map",
|
|
78
|
+
"service_usage_map",
|
|
79
|
+
"summarize_provider_health",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def __getattr__(name: str):
|
|
84
|
+
if name in {"DataBundle", "DataService", "DataServiceResult"}:
|
|
85
|
+
from .data import DataBundle, DataService, DataServiceResult
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
"DataBundle": DataBundle,
|
|
89
|
+
"DataService": DataService,
|
|
90
|
+
"DataServiceResult": DataServiceResult,
|
|
91
|
+
}[name]
|
|
92
|
+
raise AttributeError(name)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
class DistributedCacheManager:
|
|
9
|
+
"""
|
|
10
|
+
Distributed Cache Manager for multi-agent processes.
|
|
11
|
+
Supports Redis, falls back to local memory if Redis is unavailable.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, redis_url: str = None):
|
|
15
|
+
self.redis = None
|
|
16
|
+
self._local_cache = {}
|
|
17
|
+
|
|
18
|
+
if redis_url:
|
|
19
|
+
try:
|
|
20
|
+
import redis
|
|
21
|
+
self.redis = redis.from_url(redis_url, decode_responses=True)
|
|
22
|
+
# Test connection
|
|
23
|
+
self.redis.ping()
|
|
24
|
+
logger.info("Connected to Redis cache.")
|
|
25
|
+
except ImportError:
|
|
26
|
+
logger.warning("redis-py not installed. Falling back to local cache.")
|
|
27
|
+
self.redis = None
|
|
28
|
+
except Exception:
|
|
29
|
+
logger.warning("Redis connection failed; falling back to local cache.")
|
|
30
|
+
self.redis = None
|
|
31
|
+
|
|
32
|
+
def get(self, key: str) -> Optional[Any]:
|
|
33
|
+
if self.redis:
|
|
34
|
+
try:
|
|
35
|
+
val = self.redis.get(key)
|
|
36
|
+
if val:
|
|
37
|
+
return json.loads(val)
|
|
38
|
+
except Exception:
|
|
39
|
+
logger.debug("Redis get failed; falling back to local cache.")
|
|
40
|
+
|
|
41
|
+
# Fallback to local cache
|
|
42
|
+
if key in self._local_cache:
|
|
43
|
+
value, expiry = self._local_cache[key]
|
|
44
|
+
if time.time() < expiry:
|
|
45
|
+
return value
|
|
46
|
+
else:
|
|
47
|
+
del self._local_cache[key]
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
def set(self, key: str, value: Any, ttl_seconds: int = 3600):
|
|
51
|
+
if self.redis:
|
|
52
|
+
try:
|
|
53
|
+
self.redis.setex(key, ttl_seconds, json.dumps(value))
|
|
54
|
+
return
|
|
55
|
+
except Exception:
|
|
56
|
+
logger.debug("Redis set failed; falling back to local cache.")
|
|
57
|
+
|
|
58
|
+
# Fallback to local cache
|
|
59
|
+
expiry = time.time() + ttl_seconds
|
|
60
|
+
self._local_cache[key] = (value, expiry)
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"""Context management service for Aria Code.
|
|
2
|
+
|
|
3
|
+
This module owns deterministic context pressure and local compaction behavior.
|
|
4
|
+
LLM-based summarisation remains an adapter concern, but the prompt/envelope
|
|
5
|
+
shape is defined here so CLI, daemon, and future channels can share it.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import asdict, dataclass
|
|
11
|
+
from typing import Any, Dict, Iterable, List
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _int_or(value: Any, default: int) -> int:
|
|
15
|
+
try:
|
|
16
|
+
return int(value)
|
|
17
|
+
except Exception:
|
|
18
|
+
return default
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _float_or(value: Any, default: float) -> float:
|
|
22
|
+
try:
|
|
23
|
+
return float(value)
|
|
24
|
+
except Exception:
|
|
25
|
+
return default
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class ContextPolicy:
|
|
30
|
+
max_tokens: int = 16384
|
|
31
|
+
threshold: float = 0.78
|
|
32
|
+
min_messages: int = 8
|
|
33
|
+
target_ratio: float = 0.55
|
|
34
|
+
compact_ratio: float = 0.70
|
|
35
|
+
tail_messages: int = 8
|
|
36
|
+
summary_tail_messages: int = 6
|
|
37
|
+
|
|
38
|
+
def normalized(self) -> "ContextPolicy":
|
|
39
|
+
max_tokens = max(1024, _int_or(self.max_tokens, 16384))
|
|
40
|
+
threshold = max(0.50, min(0.95, _float_or(self.threshold, 0.78)))
|
|
41
|
+
min_messages = max(1, _int_or(self.min_messages, 8))
|
|
42
|
+
target_ratio = max(0.20, min(0.85, _float_or(self.target_ratio, 0.55)))
|
|
43
|
+
compact_ratio = max(target_ratio, min(0.90, _float_or(self.compact_ratio, 0.70)))
|
|
44
|
+
tail_messages = max(2, _int_or(self.tail_messages, 8))
|
|
45
|
+
summary_tail_messages = max(2, _int_or(self.summary_tail_messages, 6))
|
|
46
|
+
return ContextPolicy(
|
|
47
|
+
max_tokens=max_tokens,
|
|
48
|
+
threshold=threshold,
|
|
49
|
+
min_messages=min_messages,
|
|
50
|
+
target_ratio=target_ratio,
|
|
51
|
+
compact_ratio=compact_ratio,
|
|
52
|
+
tail_messages=tail_messages,
|
|
53
|
+
summary_tail_messages=summary_tail_messages,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class ContextDecision:
|
|
59
|
+
should_compact: bool
|
|
60
|
+
estimated_tokens: int
|
|
61
|
+
max_tokens: int
|
|
62
|
+
fill_ratio: float
|
|
63
|
+
fill_pct: int
|
|
64
|
+
threshold: float
|
|
65
|
+
message_count: int
|
|
66
|
+
reason: str = ""
|
|
67
|
+
target_tokens: int = 0
|
|
68
|
+
|
|
69
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
70
|
+
return asdict(self)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True)
|
|
74
|
+
class ContextSummaryEnvelope:
|
|
75
|
+
messages: List[Dict[str, str]]
|
|
76
|
+
old_message_count: int
|
|
77
|
+
new_message_count: int
|
|
78
|
+
tail_message_count: int
|
|
79
|
+
|
|
80
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
81
|
+
return asdict(self)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ContextService:
|
|
85
|
+
"""Pure context service with no terminal, Rich, or LLM dependency."""
|
|
86
|
+
|
|
87
|
+
def __init__(self, policy: ContextPolicy | None = None):
|
|
88
|
+
self.policy = (policy or ContextPolicy()).normalized()
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def estimate_message_tokens(messages: Iterable[dict], extra_content: str = "") -> int:
|
|
92
|
+
total_chars = sum(len(str(message.get("content", ""))) for message in messages)
|
|
93
|
+
total_chars += len(str(extra_content or ""))
|
|
94
|
+
return total_chars // 3
|
|
95
|
+
|
|
96
|
+
def compaction_decision(self, messages: List[dict], extra_content: str = "") -> ContextDecision:
|
|
97
|
+
estimated = self.estimate_message_tokens(messages, extra_content=extra_content)
|
|
98
|
+
max_tokens = max(self.policy.max_tokens, 1)
|
|
99
|
+
fill_ratio = estimated / max_tokens
|
|
100
|
+
message_count = len(messages)
|
|
101
|
+
reason = ""
|
|
102
|
+
should_compact = False
|
|
103
|
+
if message_count < self.policy.min_messages:
|
|
104
|
+
reason = "message_count_below_minimum"
|
|
105
|
+
elif fill_ratio >= self.policy.threshold:
|
|
106
|
+
reason = "threshold_exceeded"
|
|
107
|
+
should_compact = True
|
|
108
|
+
else:
|
|
109
|
+
reason = "below_threshold"
|
|
110
|
+
return ContextDecision(
|
|
111
|
+
should_compact=should_compact,
|
|
112
|
+
estimated_tokens=estimated,
|
|
113
|
+
max_tokens=max_tokens,
|
|
114
|
+
fill_ratio=fill_ratio,
|
|
115
|
+
fill_pct=min(100, int(fill_ratio * 100)),
|
|
116
|
+
threshold=self.policy.threshold,
|
|
117
|
+
message_count=message_count,
|
|
118
|
+
reason=reason,
|
|
119
|
+
target_tokens=int(max_tokens * self.policy.target_ratio),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def compact_messages(self, messages: List[dict], max_chars: int = 0) -> List[dict]:
|
|
123
|
+
"""Compact history locally while preserving recent turns and errors."""
|
|
124
|
+
|
|
125
|
+
if max_chars <= 0:
|
|
126
|
+
max_chars = int(self.policy.max_tokens * 3 * self.policy.compact_ratio)
|
|
127
|
+
|
|
128
|
+
total = sum(len(str(message.get("content", ""))) for message in messages)
|
|
129
|
+
if total <= max_chars:
|
|
130
|
+
return messages
|
|
131
|
+
|
|
132
|
+
if not messages:
|
|
133
|
+
return []
|
|
134
|
+
|
|
135
|
+
if len(messages) == 1:
|
|
136
|
+
return [self._compact_recent_message(messages[0], max_chars)]
|
|
137
|
+
|
|
138
|
+
system = messages[0]
|
|
139
|
+
keep_tail = min(self.policy.tail_messages, max(1, len(messages) - 1))
|
|
140
|
+
middle = messages[1:-keep_tail]
|
|
141
|
+
tail = messages[-keep_tail:]
|
|
142
|
+
|
|
143
|
+
compacted_middle = [self._compact_middle_message(message) for message in middle]
|
|
144
|
+
per_tail_budget = max(500, max_chars // max(4, keep_tail + 2))
|
|
145
|
+
compacted_tail = [
|
|
146
|
+
self._compact_recent_message(message, per_tail_budget)
|
|
147
|
+
for message in tail
|
|
148
|
+
if not self._is_summary_wrapper(message)
|
|
149
|
+
]
|
|
150
|
+
compacted: List[dict] = [system, *compacted_middle, *compacted_tail]
|
|
151
|
+
if self.estimate_message_tokens(compacted) * 3 <= max_chars:
|
|
152
|
+
return compacted
|
|
153
|
+
|
|
154
|
+
# Many old messages can still exceed the target even after each one is
|
|
155
|
+
# shortened. Collapse the middle into one deterministic envelope while
|
|
156
|
+
# retaining errors, user decisions and the bounded recent tail.
|
|
157
|
+
reserved = len(str(system.get("content", ""))) + sum(
|
|
158
|
+
len(str(message.get("content", ""))) for message in compacted_tail
|
|
159
|
+
)
|
|
160
|
+
middle_budget = max(800, max_chars - reserved - 400)
|
|
161
|
+
middle_text = self.build_summary_transcript(compacted_middle)[:middle_budget]
|
|
162
|
+
middle_envelope = {
|
|
163
|
+
"role": "user",
|
|
164
|
+
"content": f"[Earlier context compacted locally]\n{middle_text}",
|
|
165
|
+
}
|
|
166
|
+
return [system, middle_envelope, *compacted_tail]
|
|
167
|
+
|
|
168
|
+
def _compact_middle_message(self, message: dict) -> dict:
|
|
169
|
+
content = self._clean_context_text(str(message.get("content", "")))
|
|
170
|
+
role = str(message.get("role", ""))
|
|
171
|
+
|
|
172
|
+
if role == "tool" and len(content) > 200:
|
|
173
|
+
lines = content.splitlines()
|
|
174
|
+
kept: List[str] = []
|
|
175
|
+
has_error = False
|
|
176
|
+
for line in lines[:30]:
|
|
177
|
+
stripped = line.strip()
|
|
178
|
+
if not stripped:
|
|
179
|
+
continue
|
|
180
|
+
low = stripped.lower()
|
|
181
|
+
if any(keyword in low for keyword in ("error", "traceback", "exception", "failed", "failure")):
|
|
182
|
+
kept.append(stripped)
|
|
183
|
+
has_error = True
|
|
184
|
+
elif len(kept) < 4 and len(stripped) > 8:
|
|
185
|
+
kept.append(stripped)
|
|
186
|
+
summary = " | ".join(kept[:4]) if kept else content[:150]
|
|
187
|
+
flag = " [error preserved]" if has_error else " [compacted]"
|
|
188
|
+
return {"role": role, "content": f"{summary}{flag}"}
|
|
189
|
+
|
|
190
|
+
if role == "assistant" and len(content) > 500:
|
|
191
|
+
paras = [part.strip() for part in content.split("\n\n") if part.strip()]
|
|
192
|
+
if len(paras) >= 2:
|
|
193
|
+
head = paras[0][:280]
|
|
194
|
+
tail = paras[-1][-180:]
|
|
195
|
+
return {"role": role, "content": f"{head}\n...\n{tail} [compacted]"}
|
|
196
|
+
return {"role": role, "content": content[:350] + "... [compacted]"}
|
|
197
|
+
|
|
198
|
+
return {**message, "content": content}
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def _clean_context_text(content: str) -> str:
|
|
202
|
+
"""Remove runtime-only markers and exact duplicate paragraphs."""
|
|
203
|
+
text = str(content or "")
|
|
204
|
+
runtime_markers = (
|
|
205
|
+
"*[model stopped — repetition detected]*",
|
|
206
|
+
"[model stopped — repetition detected]",
|
|
207
|
+
)
|
|
208
|
+
for marker in runtime_markers:
|
|
209
|
+
text = text.replace(marker, "")
|
|
210
|
+
paragraphs = [part.strip() for part in text.split("\n\n") if part.strip()]
|
|
211
|
+
deduped: List[str] = []
|
|
212
|
+
for paragraph in paragraphs:
|
|
213
|
+
if deduped and paragraph == deduped[-1]:
|
|
214
|
+
continue
|
|
215
|
+
deduped.append(paragraph)
|
|
216
|
+
return "\n\n".join(deduped).strip()
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def _is_summary_wrapper(message: dict) -> bool:
|
|
220
|
+
content = str(message.get("content", "")).lstrip()
|
|
221
|
+
return content.startswith((
|
|
222
|
+
"[Session summary - earlier conversation compressed]",
|
|
223
|
+
"[会话摘要 — 早期对话已压缩]",
|
|
224
|
+
)) or content in {
|
|
225
|
+
"Summary loaded. Continuing with the current task.",
|
|
226
|
+
"已获取摘要,继续之前的工作。",
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
def _compact_recent_message(self, message: dict, max_chars: int) -> dict:
|
|
230
|
+
"""Bound a recent message so compaction actually lowers context use."""
|
|
231
|
+
content_obj = message.get("content", "")
|
|
232
|
+
if not isinstance(content_obj, str):
|
|
233
|
+
# Preserve multimodal content structures; they are rare and losing
|
|
234
|
+
# image/file blocks would be worse than keeping their metadata.
|
|
235
|
+
return message
|
|
236
|
+
content = self._clean_context_text(content_obj)
|
|
237
|
+
if len(content) <= max_chars:
|
|
238
|
+
return {**message, "content": content}
|
|
239
|
+
|
|
240
|
+
role = str(message.get("role", ""))
|
|
241
|
+
if role == "tool":
|
|
242
|
+
return self._compact_middle_message({**message, "content": content})
|
|
243
|
+
|
|
244
|
+
tail_chars = max(120, max_chars // 3)
|
|
245
|
+
head_chars = max(200, max_chars - tail_chars - 40)
|
|
246
|
+
compacted = (
|
|
247
|
+
content[:head_chars].rstrip()
|
|
248
|
+
+ "\n… [recent message compacted] …\n"
|
|
249
|
+
+ content[-tail_chars:].lstrip()
|
|
250
|
+
)
|
|
251
|
+
return {**message, "content": compacted}
|
|
252
|
+
|
|
253
|
+
def build_summary_transcript(self, messages: List[dict]) -> str:
|
|
254
|
+
parts: List[str] = []
|
|
255
|
+
for message in messages:
|
|
256
|
+
role = str(message.get("role", ""))
|
|
257
|
+
content = self._clean_context_text(str(message.get("content", "")))
|
|
258
|
+
if role == "tool":
|
|
259
|
+
lines = [line.strip() for line in content.splitlines() if line.strip()]
|
|
260
|
+
has_error = any(
|
|
261
|
+
"error" in line.lower() or "traceback" in line.lower()
|
|
262
|
+
for line in lines[:10]
|
|
263
|
+
)
|
|
264
|
+
excerpt = " | ".join(lines[:3]) if lines else content[:200]
|
|
265
|
+
label = "Tool[error]" if has_error else "Tool"
|
|
266
|
+
parts.append(f"{label}: {excerpt[:300]}")
|
|
267
|
+
elif role == "user":
|
|
268
|
+
parts.append(f"User: {content[:800]}")
|
|
269
|
+
else:
|
|
270
|
+
parts.append(f"Aria: {content[:1200]}")
|
|
271
|
+
return "\n\n".join(parts)
|
|
272
|
+
|
|
273
|
+
def build_summary_prompt(self, messages: List[dict]) -> str:
|
|
274
|
+
transcript = self.build_summary_transcript(messages)
|
|
275
|
+
return (
|
|
276
|
+
"You are a context compressor for a general product-review and software-engineering assistant.\n"
|
|
277
|
+
"Given the conversation transcript, produce a DENSE SUMMARY (<=350 words).\n"
|
|
278
|
+
"You MUST preserve:\n"
|
|
279
|
+
" - Product goals, target users, requirements, and acceptance criteria\n"
|
|
280
|
+
" - Important domain entities and numerical results, including financial data when relevant\n"
|
|
281
|
+
" - Code files written or modified (file paths + purpose)\n"
|
|
282
|
+
" - Unresolved blockers and the final resolution of past errors\n"
|
|
283
|
+
" - User preferences or decisions made\n"
|
|
284
|
+
" - The last task status (complete / in-progress / blocked)\n"
|
|
285
|
+
"Do NOT copy raw tool logs, permission prompts, install transcripts, or obsolete "
|
|
286
|
+
"statements such as 'cannot read the file' after the file was successfully read.\n"
|
|
287
|
+
"For resolved failures, keep only one short 'failed → resolved by ...' fact.\n"
|
|
288
|
+
"Write in concise third-person present tense. "
|
|
289
|
+
"Start with: 'Session summary: ...'\n\n"
|
|
290
|
+
f"TRANSCRIPT:\n{transcript}\n\nSUMMARY:"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def build_summary_envelope(self, messages: List[dict], summary: str) -> ContextSummaryEnvelope:
|
|
294
|
+
eligible = [message for message in messages if not self._is_summary_wrapper(message)]
|
|
295
|
+
tail_count = min(self.policy.summary_tail_messages, len(eligible))
|
|
296
|
+
raw_tail = eligible[-tail_count:] if tail_count else []
|
|
297
|
+
target_chars = int(self.policy.max_tokens * 3 * self.policy.target_ratio)
|
|
298
|
+
wrapper_chars = len(summary) + 500
|
|
299
|
+
tail_budget = max(1600, target_chars - wrapper_chars)
|
|
300
|
+
per_message = max(500, tail_budget // max(1, tail_count))
|
|
301
|
+
tail = [self._compact_recent_message(message, per_message) for message in raw_tail]
|
|
302
|
+
envelope_messages = [
|
|
303
|
+
{
|
|
304
|
+
"role": "user",
|
|
305
|
+
"content": (
|
|
306
|
+
"[Session summary - earlier conversation compressed]\n\n"
|
|
307
|
+
f"{summary.strip()}\n\n"
|
|
308
|
+
"[Recent conversation follows]"
|
|
309
|
+
),
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"role": "assistant",
|
|
313
|
+
"content": "Summary loaded. Continuing with the current task.",
|
|
314
|
+
},
|
|
315
|
+
*tail,
|
|
316
|
+
]
|
|
317
|
+
return ContextSummaryEnvelope(
|
|
318
|
+
messages=envelope_messages,
|
|
319
|
+
old_message_count=len(messages),
|
|
320
|
+
new_message_count=len(envelope_messages),
|
|
321
|
+
tail_message_count=tail_count,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def context_health_snapshot(
|
|
326
|
+
messages: Iterable[dict],
|
|
327
|
+
*,
|
|
328
|
+
max_tokens: int,
|
|
329
|
+
threshold: float = 0.78,
|
|
330
|
+
) -> Dict[str, Any]:
|
|
331
|
+
"""One-call context-health dict for /doctor and the support bundle."""
|
|
332
|
+
service = ContextService(ContextPolicy(max_tokens=max_tokens, threshold=threshold))
|
|
333
|
+
return service.compaction_decision(list(messages)).to_dict()
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def build_context_service(
|
|
337
|
+
*,
|
|
338
|
+
max_tokens: int = 16384,
|
|
339
|
+
threshold: float = 0.78,
|
|
340
|
+
min_messages: int = 8,
|
|
341
|
+
target_ratio: float = 0.55,
|
|
342
|
+
compact_ratio: float = 0.70,
|
|
343
|
+
tail_messages: int = 8,
|
|
344
|
+
summary_tail_messages: int = 6,
|
|
345
|
+
) -> ContextService:
|
|
346
|
+
return ContextService(
|
|
347
|
+
ContextPolicy(
|
|
348
|
+
max_tokens=max_tokens,
|
|
349
|
+
threshold=threshold,
|
|
350
|
+
min_messages=min_messages,
|
|
351
|
+
target_ratio=target_ratio,
|
|
352
|
+
compact_ratio=compact_ratio,
|
|
353
|
+
tail_messages=tail_messages,
|
|
354
|
+
summary_tail_messages=summary_tail_messages,
|
|
355
|
+
)
|
|
356
|
+
)
|