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,236 @@
|
|
|
1
|
+
"""SessionCommandsMixin — session list/load/save/export commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ._ui import print_error
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from aria_code.apps.cli.session_export import build_session_export_payload
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import asyncio
|
|
14
|
+
import datetime
|
|
15
|
+
import time
|
|
16
|
+
import shlex
|
|
17
|
+
import sys
|
|
18
|
+
import os
|
|
19
|
+
from typing import Dict, Any, Optional
|
|
20
|
+
|
|
21
|
+
def _arrow_select(*args, **kwargs):
|
|
22
|
+
# Re-exported by aria_cli; imported from its own module here.
|
|
23
|
+
from aria_code.ui.picker import arrow_select as fn
|
|
24
|
+
return fn(*args, **kwargs)
|
|
25
|
+
def get_model_cfg(*args, **kwargs):
|
|
26
|
+
from ..model_catalog import get_model_cfg as fn
|
|
27
|
+
return fn(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import asyncio
|
|
31
|
+
import datetime
|
|
32
|
+
import time
|
|
33
|
+
import shlex
|
|
34
|
+
import sys
|
|
35
|
+
import os
|
|
36
|
+
from typing import Dict, Any, Optional
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SessionCommandsMixin:
|
|
40
|
+
"""Mixin: session list/load/save/export commands."""
|
|
41
|
+
|
|
42
|
+
def cmd_sessions(self, args: str):
|
|
43
|
+
keyword = args.strip().lower()
|
|
44
|
+
sessions = self.terminal.session_mgr.list_sessions()
|
|
45
|
+
if keyword:
|
|
46
|
+
sessions = [s for s in sessions if keyword in s["title"].lower()]
|
|
47
|
+
if not sessions:
|
|
48
|
+
msg = f"No sessions matching '{keyword}'" if keyword else "No saved sessions"
|
|
49
|
+
self.context.console.print(f"[dim]{msg}[/dim]" if self.context.has_rich else msg)
|
|
50
|
+
return
|
|
51
|
+
if self.context.has_rich:
|
|
52
|
+
self.context.console.print()
|
|
53
|
+
header = f" [bold]Sessions[/bold] [dim]({len(sessions)} found)[/dim]" if keyword else " [bold]Sessions[/bold]"
|
|
54
|
+
self.context.console.print(header)
|
|
55
|
+
for i, s in enumerate(sessions, 1):
|
|
56
|
+
updated = s["updated"][:16] if s["updated"] else "-"
|
|
57
|
+
self.context.console.print(f" [dim]{i}.[/dim] [bold]{s['title']}[/bold] "
|
|
58
|
+
f"[dim]{s['id'][:8]} {s['messages']} msgs {updated}[/dim]")
|
|
59
|
+
self.context.console.print()
|
|
60
|
+
self.context.console.print(" [dim]Use /load <number> to resume · /sessions <keyword> to search[/dim]")
|
|
61
|
+
else:
|
|
62
|
+
for i, s in enumerate(sessions, 1):
|
|
63
|
+
print(f" {i}. [{s['id'][:8]}] {s['title']} ({s['messages']} msgs)")
|
|
64
|
+
|
|
65
|
+
def cmd_save(self, args: str):
|
|
66
|
+
if not self.terminal.conversation:
|
|
67
|
+
self.context.console.print("[dim]Nothing to save[/dim]" if self.context.has_rich else "Nothing to save")
|
|
68
|
+
return
|
|
69
|
+
sid = self.terminal.session_id
|
|
70
|
+
title = args.strip().strip('"').strip("'") if args.strip() else None
|
|
71
|
+
meta = {}
|
|
72
|
+
if title:
|
|
73
|
+
meta["title"] = title
|
|
74
|
+
self.terminal.session_mgr.save_session(sid, self.terminal.conversation, metadata=meta)
|
|
75
|
+
self.terminal.config["last_session_id"] = sid
|
|
76
|
+
self.context.save_config(self.terminal.config)
|
|
77
|
+
display = f"{title} ({sid[:8]})" if title else f"{sid[:8]}..."
|
|
78
|
+
self.context.console.print(f"[green]Session saved: {display}[/green]" if self.context.has_rich
|
|
79
|
+
else f"Saved: {display}")
|
|
80
|
+
|
|
81
|
+
def cmd_rename(self, args: str):
|
|
82
|
+
"""Rename current session."""
|
|
83
|
+
title = args.strip().strip('"').strip("'")
|
|
84
|
+
if not title:
|
|
85
|
+
self.context.console.print("[dim]Usage: /rename <title>[/dim]" if self.context.has_rich else "Usage: /rename <title>")
|
|
86
|
+
return
|
|
87
|
+
sid = self.terminal.session_id
|
|
88
|
+
data = self.terminal.session_mgr.load_session(sid)
|
|
89
|
+
if data:
|
|
90
|
+
meta = data.get("metadata", {})
|
|
91
|
+
meta["title"] = title
|
|
92
|
+
self.terminal.session_mgr.save_session(sid, self.terminal.conversation, metadata=meta)
|
|
93
|
+
else:
|
|
94
|
+
self.terminal.session_mgr.save_session(sid, self.terminal.conversation, metadata={"title": title})
|
|
95
|
+
self.context.console.print(f"[green]Renamed: {title}[/green]" if self.context.has_rich else f"Renamed: {title}")
|
|
96
|
+
|
|
97
|
+
def cmd_load(self, args: str):
|
|
98
|
+
session_id = args.strip()
|
|
99
|
+
if not session_id:
|
|
100
|
+
sessions = self.terminal.session_mgr.list_sessions()
|
|
101
|
+
if not sessions:
|
|
102
|
+
self.context.console.print("[dim]No sessions. Usage: /load <session_id>[/dim]" if self.context.has_rich
|
|
103
|
+
else "No sessions")
|
|
104
|
+
return
|
|
105
|
+
options = []
|
|
106
|
+
for s in sessions[:20]:
|
|
107
|
+
title = s.get("metadata", {}).get("title", s["id"][:8])
|
|
108
|
+
ts = s.get("updated", "")[:10]
|
|
109
|
+
options.append((title, ts))
|
|
110
|
+
choice = _arrow_select(options, selected=0, title="Load Session")
|
|
111
|
+
if 0 <= choice < len(sessions):
|
|
112
|
+
session_id = sessions[choice]["id"]
|
|
113
|
+
else:
|
|
114
|
+
if self.context.has_rich:
|
|
115
|
+
self.context.console.print("[dim]Cancelled[/dim]")
|
|
116
|
+
else:
|
|
117
|
+
print("Cancelled")
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
data = self.terminal.session_mgr.load_session(session_id)
|
|
121
|
+
if data:
|
|
122
|
+
self.terminal.conversation = data.get("messages", [])
|
|
123
|
+
self.terminal.session_id = data["id"]
|
|
124
|
+
title = data.get("metadata", {}).get("title", "Untitled")
|
|
125
|
+
n = len(self.terminal.conversation)
|
|
126
|
+
self.context.console.print(f"[green]Loaded: {title} ({n} messages)[/green]" if self.context.has_rich
|
|
127
|
+
else f"Loaded: {title} ({n} msgs)")
|
|
128
|
+
else:
|
|
129
|
+
print_error(self.context, f"Session not found: {session_id}", "session")
|
|
130
|
+
|
|
131
|
+
def cmd_recall(self, args: str):
|
|
132
|
+
"""Full-text search across all saved sessions: /recall <query>"""
|
|
133
|
+
query = args.strip()
|
|
134
|
+
if not query:
|
|
135
|
+
self.context.console.print("[dim]Usage: /recall <query>[/dim]" if self.context.has_rich else "Usage: /recall <query>")
|
|
136
|
+
return
|
|
137
|
+
results = self.terminal.session_mgr.search_sessions(query)
|
|
138
|
+
if not results:
|
|
139
|
+
msg = f"No sessions found matching '{query}'"
|
|
140
|
+
self.context.console.print(f"[dim]{msg}[/dim]" if self.context.has_rich else msg)
|
|
141
|
+
return
|
|
142
|
+
if self.context.has_rich:
|
|
143
|
+
self.context.console.print()
|
|
144
|
+
self.context.console.print(f" [bold]Recall[/bold] [dim]{len(results)} session(s) match '{query}'[/dim]")
|
|
145
|
+
self.context.console.print()
|
|
146
|
+
for r in results[:10]:
|
|
147
|
+
updated = r["updated"][:16] if r["updated"] else ""
|
|
148
|
+
self.context.console.print(
|
|
149
|
+
f" [bold]{r['title']}[/bold] "
|
|
150
|
+
f"[dim]{r['id'][:8]} {r['match_count']} hit(s) {updated}[/dim]"
|
|
151
|
+
)
|
|
152
|
+
preview = r["preview"].replace("\n", " ")[:100]
|
|
153
|
+
self.context.console.print(f" [dim]…{preview}…[/dim]")
|
|
154
|
+
self.context.console.print()
|
|
155
|
+
self.context.console.print(" [dim]Use /load <id> to resume a session[/dim]")
|
|
156
|
+
else:
|
|
157
|
+
print(f"\n{len(results)} session(s) found:")
|
|
158
|
+
for r in results[:10]:
|
|
159
|
+
print(f" [{r['id'][:8]}] {r['title']} ({r['match_count']} hits)")
|
|
160
|
+
print(f" ...{r['preview'][:80]}...")
|
|
161
|
+
|
|
162
|
+
async def cmd_export(self, args: str):
|
|
163
|
+
parts = args.split()
|
|
164
|
+
fmt = parts[0].lower() if parts else "json"
|
|
165
|
+
filename = parts[1] if len(parts) > 1 else None
|
|
166
|
+
|
|
167
|
+
if not self.terminal.conversation:
|
|
168
|
+
self.context.console.print("[dim]Nothing to export[/dim]" if self.context.has_rich else "Nothing to export")
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
provider_health = []
|
|
173
|
+
doctor_report = None
|
|
174
|
+
mcp_status = None
|
|
175
|
+
context_health = None
|
|
176
|
+
if fmt == "bundle":
|
|
177
|
+
try:
|
|
178
|
+
from packages.aria_services.provider_health import GLOBAL_PROVIDER_HEALTH
|
|
179
|
+
provider_health = GLOBAL_PROVIDER_HEALTH.snapshot()
|
|
180
|
+
except Exception:
|
|
181
|
+
provider_health = []
|
|
182
|
+
# A support bundle should carry environment health and MCP/circuit
|
|
183
|
+
# state — the two things a maintainer asks for first. Best-effort.
|
|
184
|
+
try:
|
|
185
|
+
from doctor import run_doctor
|
|
186
|
+
doctor_report = run_doctor(self.terminal.config)
|
|
187
|
+
except Exception:
|
|
188
|
+
doctor_report = None
|
|
189
|
+
try:
|
|
190
|
+
_reg = getattr(self.terminal, "_mcp_registry", None)
|
|
191
|
+
mcp_status = _reg.status() if _reg else None
|
|
192
|
+
except Exception:
|
|
193
|
+
mcp_status = None
|
|
194
|
+
try:
|
|
195
|
+
from packages.aria_services.context import context_health_snapshot
|
|
196
|
+
_mc = get_model_cfg(self.terminal.config.get("model", "qwen2.5:7b"))
|
|
197
|
+
context_health = context_health_snapshot(
|
|
198
|
+
self.terminal.conversation,
|
|
199
|
+
max_tokens=int(_mc.get("num_ctx", 16384)),
|
|
200
|
+
threshold=float(self.terminal.config.get("auto_compact_threshold", 0.78)),
|
|
201
|
+
)
|
|
202
|
+
except Exception:
|
|
203
|
+
context_health = None
|
|
204
|
+
content, ext, prefix = build_session_export_payload(
|
|
205
|
+
fmt,
|
|
206
|
+
self.terminal.conversation,
|
|
207
|
+
session_id=self.terminal.session_id,
|
|
208
|
+
config=self.terminal.config,
|
|
209
|
+
trace=getattr(self.terminal, "runtime_trace", None),
|
|
210
|
+
provider_health=provider_health,
|
|
211
|
+
doctor_report=doctor_report,
|
|
212
|
+
mcp_status=mcp_status,
|
|
213
|
+
context_health=context_health,
|
|
214
|
+
)
|
|
215
|
+
except ValueError as exc:
|
|
216
|
+
if fmt == "sft" and "No user→assistant pairs" in str(exc):
|
|
217
|
+
self.context.console.print("[dim]No user→assistant pairs to export[/dim]" if self.context.has_rich else "No pairs to export")
|
|
218
|
+
return
|
|
219
|
+
self.context.console.print("[dim]Format: json, csv, md, sft, or bundle[/dim]" if self.context.has_rich
|
|
220
|
+
else "Format: json, csv, md, sft, bundle")
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
if fmt == "sft":
|
|
224
|
+
pairs = json.loads(content)
|
|
225
|
+
if self.context.has_rich:
|
|
226
|
+
self.context.console.print(f"[dim]{len(pairs)} training pairs extracted[/dim]")
|
|
227
|
+
else:
|
|
228
|
+
print(f"{len(pairs)} training pairs")
|
|
229
|
+
|
|
230
|
+
if not filename:
|
|
231
|
+
from datetime import datetime
|
|
232
|
+
filename = f"{prefix}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.{ext}"
|
|
233
|
+
with open(filename, "w", encoding="utf-8") as f:
|
|
234
|
+
f.write(content)
|
|
235
|
+
self.context.console.print(f"[green]Exported to {filename}[/green]" if self.context.has_rich
|
|
236
|
+
else f"Exported: {filename}")
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"""SessionUxCommandsMixin — clear, recap, history, compact, fork, copy commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import asyncio
|
|
10
|
+
import datetime
|
|
11
|
+
import time
|
|
12
|
+
import shlex
|
|
13
|
+
from typing import Dict, Any, Optional
|
|
14
|
+
|
|
15
|
+
def get_model_cfg(*args, **kwargs):
|
|
16
|
+
from ..model_catalog import get_model_cfg as fn
|
|
17
|
+
return fn(*args, **kwargs)
|
|
18
|
+
def OllamaProvider(*args, **kwargs):
|
|
19
|
+
# Re-exported by aria_cli; imported from its own module here.
|
|
20
|
+
from aria_code.apps.cli.providers.base import OllamaProvider as fn
|
|
21
|
+
return fn(*args, **kwargs)
|
|
22
|
+
def stream_provider_result(*args, **kwargs):
|
|
23
|
+
# Re-exported by aria_cli; imported from its own module here.
|
|
24
|
+
from aria_code.packages.aria_sdk.streaming import stream_provider_result as fn
|
|
25
|
+
return fn(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
import json
|
|
28
|
+
import asyncio
|
|
29
|
+
import datetime
|
|
30
|
+
import time
|
|
31
|
+
import shlex
|
|
32
|
+
import sys
|
|
33
|
+
import os
|
|
34
|
+
from typing import Dict, Any, Optional
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
import json
|
|
38
|
+
import asyncio
|
|
39
|
+
import datetime
|
|
40
|
+
import time
|
|
41
|
+
import shlex
|
|
42
|
+
import sys
|
|
43
|
+
import os
|
|
44
|
+
from typing import Dict, Any, Optional
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SessionUxCommandsMixin:
|
|
48
|
+
"""Mixin: session UX and conversation management commands."""
|
|
49
|
+
|
|
50
|
+
def cmd_clear(self, args: str):
|
|
51
|
+
self.terminal.conversation = []
|
|
52
|
+
os.system("clear" if os.name == "posix" else "cls")
|
|
53
|
+
self.context.console.print("[dim]Conversation cleared[/dim]" if self.context.has_rich else "Cleared")
|
|
54
|
+
|
|
55
|
+
def cmd_btw(self, args: str):
|
|
56
|
+
q = args.strip()
|
|
57
|
+
if not q:
|
|
58
|
+
self.context.console.print("[dim]/btw <question> — quick question without polluting history[/dim]" if self.context.has_rich else "/btw <question>")
|
|
59
|
+
return
|
|
60
|
+
conv = self.terminal.conversation
|
|
61
|
+
if not conv:
|
|
62
|
+
self.context.console.print("[dim](no conversation context yet)[/dim]" if self.context.has_rich else "(no context)")
|
|
63
|
+
return
|
|
64
|
+
_ctx_slice = conv[-6:] if len(conv) >= 6 else conv
|
|
65
|
+
_ctx = "\n".join(
|
|
66
|
+
f"{m['role'].upper()}: {str(m.get('content', ''))[:300]}"
|
|
67
|
+
for m in _ctx_slice
|
|
68
|
+
)
|
|
69
|
+
_btw_prompt = (
|
|
70
|
+
f"[Side question — answer briefly, do not reference this note]\n"
|
|
71
|
+
f"Context from conversation:\n{_ctx}\n\nQuestion: {q}"
|
|
72
|
+
)
|
|
73
|
+
if self.context.has_rich:
|
|
74
|
+
from rich.panel import Panel as _Panel
|
|
75
|
+
from rich import box as _rbox
|
|
76
|
+
self.context.console.print(_Panel(f"[dim]{q}[/dim]", title="[dim]/btw[/dim]", box=_rbox.ROUNDED, border_style="dim"))
|
|
77
|
+
import asyncio as _aio
|
|
78
|
+
|
|
79
|
+
async def _ask_btw():
|
|
80
|
+
try:
|
|
81
|
+
_result = await stream_provider_result(
|
|
82
|
+
OllamaProvider(
|
|
83
|
+
self.terminal.config.get("ollama_url", "http://localhost:11434"),
|
|
84
|
+
self.terminal.config.get("model", "qwen2.5:7b"),
|
|
85
|
+
show_market_prefetch_status=False,
|
|
86
|
+
),
|
|
87
|
+
_btw_prompt,
|
|
88
|
+
tools=[],
|
|
89
|
+
)
|
|
90
|
+
if _result.get("success"):
|
|
91
|
+
return _result.get("response", "")
|
|
92
|
+
return f"(error: {_result.get('error', '')})"
|
|
93
|
+
except Exception as _e:
|
|
94
|
+
return f"(error: {_e})"
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
loop = _aio.get_event_loop()
|
|
98
|
+
answer = loop.run_until_complete(_ask_btw()) if not loop.is_running() else "(run /btw from interactive prompt)"
|
|
99
|
+
except Exception:
|
|
100
|
+
answer = "(could not get answer)"
|
|
101
|
+
if self.context.has_rich:
|
|
102
|
+
from rich.panel import Panel as _Panel
|
|
103
|
+
from rich import box as _rbox
|
|
104
|
+
self.context.console.print(_Panel(answer.strip(), title="[dim]↩ btw[/dim]", box=_rbox.ROUNDED, border_style="dim #C08050"))
|
|
105
|
+
else:
|
|
106
|
+
print(f"\n [btw] {answer.strip()}\n")
|
|
107
|
+
|
|
108
|
+
def cmd_recap(self, args: str):
|
|
109
|
+
conv = self.terminal.conversation
|
|
110
|
+
if not conv:
|
|
111
|
+
self.context.console.print("[dim]No conversation yet[/dim]" if self.context.has_rich else "No conversation")
|
|
112
|
+
return
|
|
113
|
+
turns = len([m for m in conv if m.get("role") == "user"])
|
|
114
|
+
topics: list[str] = []
|
|
115
|
+
for m in conv:
|
|
116
|
+
if m.get("role") == "user":
|
|
117
|
+
snippet = str(m.get("content", ""))[:60].strip()
|
|
118
|
+
if snippet:
|
|
119
|
+
topics.append(snippet)
|
|
120
|
+
if self.context.has_rich:
|
|
121
|
+
from rich.panel import Panel as _Panel
|
|
122
|
+
from rich import box as _rbox
|
|
123
|
+
body = f"[dim]{turns} 轮对话[/dim]\n"
|
|
124
|
+
for i, t in enumerate(topics[-6:], 1):
|
|
125
|
+
body += f" [dim]{i}.[/dim] {t}…\n"
|
|
126
|
+
self.context.console.print(_Panel(body.rstrip(), title="[bold]会话摘要[/bold]", box=_rbox.ROUNDED, border_style="dim"))
|
|
127
|
+
else:
|
|
128
|
+
print(f"Session: {turns} turns")
|
|
129
|
+
for i, t in enumerate(topics[-6:], 1):
|
|
130
|
+
print(f" {i}. {t}…")
|
|
131
|
+
|
|
132
|
+
def cmd_history(self, args: str):
|
|
133
|
+
if not self.terminal.conversation:
|
|
134
|
+
self.context.console.print("[dim]No conversation history[/dim]" if self.context.has_rich else "No history")
|
|
135
|
+
return
|
|
136
|
+
for msg in self.terminal.conversation[-10:]:
|
|
137
|
+
role = msg["role"]
|
|
138
|
+
content = msg["content"][:120]
|
|
139
|
+
if self.context.has_rich:
|
|
140
|
+
prefix = "You" if role == "user" else "Aria"
|
|
141
|
+
style = "bold" if role == "user" else "bold"
|
|
142
|
+
self.context.console.print(f"[{style}]{prefix}:[/{style}] [dim]{content}[/dim]")
|
|
143
|
+
else:
|
|
144
|
+
print(f"{'You' if role == 'user' else 'Aria'}: {content}")
|
|
145
|
+
|
|
146
|
+
def _record_context_checkpoint(self, kind: str, envelope: dict | None = None) -> None:
|
|
147
|
+
"""Persist the pre-compaction conversation (aria.context_checkpoint.v1).
|
|
148
|
+
|
|
149
|
+
Best-effort by design: checkpointing must never turn a working
|
|
150
|
+
compaction into a failure, so every error is swallowed after a debug
|
|
151
|
+
log. Retention (keep-per-session / max-age) comes from config with
|
|
152
|
+
the defaults decided for the schema.
|
|
153
|
+
"""
|
|
154
|
+
try:
|
|
155
|
+
from packages.aria_services.context_checkpoints import (
|
|
156
|
+
ContextCheckpointStore,
|
|
157
|
+
default_checkpoint_root,
|
|
158
|
+
)
|
|
159
|
+
cfg = self.terminal.config
|
|
160
|
+
store = ContextCheckpointStore(
|
|
161
|
+
default_checkpoint_root(),
|
|
162
|
+
keep_per_session=int(cfg.get("context_checkpoint_keep", 5) or 5),
|
|
163
|
+
max_age_days=int(cfg.get("context_checkpoint_max_age_days", 30) or 30),
|
|
164
|
+
)
|
|
165
|
+
store.record(
|
|
166
|
+
getattr(self.terminal, "session_id", "session"),
|
|
167
|
+
self.terminal.conversation,
|
|
168
|
+
kind=kind,
|
|
169
|
+
envelope=envelope,
|
|
170
|
+
)
|
|
171
|
+
except Exception as exc:
|
|
172
|
+
import logging
|
|
173
|
+
logging.getLogger(__name__).debug("context checkpoint skipped: %s", exc)
|
|
174
|
+
|
|
175
|
+
def cmd_compact(self, args: str):
|
|
176
|
+
if "--hard" in args:
|
|
177
|
+
if len(self.terminal.conversation) > 10:
|
|
178
|
+
kept = self.terminal.conversation[-6:]
|
|
179
|
+
self._record_context_checkpoint("hard")
|
|
180
|
+
self.terminal.conversation = kept
|
|
181
|
+
self.context.console.print(f"[dim]Hard-compacted to last {len(kept)} messages[/dim]" if self.context.has_rich
|
|
182
|
+
else f"Hard-compacted to {len(kept)} messages")
|
|
183
|
+
else:
|
|
184
|
+
self.context.console.print("[dim]Context small enough, no compaction needed[/dim]" if self.context.has_rich
|
|
185
|
+
else "No compaction needed")
|
|
186
|
+
return
|
|
187
|
+
import asyncio as _asyncio
|
|
188
|
+
try:
|
|
189
|
+
loop = _asyncio.get_event_loop()
|
|
190
|
+
loop.run_until_complete(self._smart_compact_async(silent=False))
|
|
191
|
+
except RuntimeError:
|
|
192
|
+
if len(self.terminal.conversation) > 6:
|
|
193
|
+
from apps.cli.message_processing import compact_messages
|
|
194
|
+
compacted = compact_messages(
|
|
195
|
+
self.terminal.conversation,
|
|
196
|
+
model_key=self.terminal.config.get("model", "qwen2.5:7b"),
|
|
197
|
+
)
|
|
198
|
+
self._record_context_checkpoint("fallback")
|
|
199
|
+
self.terminal.conversation = (
|
|
200
|
+
compacted
|
|
201
|
+
if len(compacted) < len(self.terminal.conversation)
|
|
202
|
+
else self.terminal.conversation[-8:]
|
|
203
|
+
)
|
|
204
|
+
self.context.console.print("[dim]Compacted (fallback)[/dim]")
|
|
205
|
+
|
|
206
|
+
async def _smart_compact_async(self, silent: bool = False):
|
|
207
|
+
conv = self.terminal.conversation
|
|
208
|
+
if len(conv) <= 4:
|
|
209
|
+
if not silent:
|
|
210
|
+
self.context.console.print("[dim]Context small enough — no compaction needed[/dim]" if self.context.has_rich
|
|
211
|
+
else "Context small enough")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
if not silent and self.context.has_rich:
|
|
215
|
+
self.context.console.print("[dim]Summarising conversation...[/dim]")
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
max_ctx = int(get_model_cfg(self.terminal.config.get("model", "qwen2.5:7b")).get("num_ctx", 16384) or 16384)
|
|
219
|
+
except Exception:
|
|
220
|
+
max_ctx = 16384
|
|
221
|
+
from packages.aria_services.context import build_context_service
|
|
222
|
+
context_service = build_context_service(max_tokens=max_ctx)
|
|
223
|
+
summary_prompt = context_service.build_summary_prompt(conv)
|
|
224
|
+
|
|
225
|
+
summary = ""
|
|
226
|
+
try:
|
|
227
|
+
result = await stream_provider_result(
|
|
228
|
+
OllamaProvider(
|
|
229
|
+
self.terminal.config.get("ollama_url", "http://localhost:11434"),
|
|
230
|
+
self.terminal.config.get("model", "qwen2.5:7b"),
|
|
231
|
+
show_market_prefetch_status=False,
|
|
232
|
+
),
|
|
233
|
+
summary_prompt,
|
|
234
|
+
[],
|
|
235
|
+
tools=[],
|
|
236
|
+
)
|
|
237
|
+
if result.get("success") and result.get("response"):
|
|
238
|
+
summary = result["response"].strip()
|
|
239
|
+
except Exception:
|
|
240
|
+
pass
|
|
241
|
+
|
|
242
|
+
if not summary:
|
|
243
|
+
try:
|
|
244
|
+
compacted = context_service.compact_messages(conv)
|
|
245
|
+
except Exception:
|
|
246
|
+
compacted = []
|
|
247
|
+
self._record_context_checkpoint("fallback")
|
|
248
|
+
self.terminal.conversation = compacted if compacted and len(compacted) < len(conv) else conv[-8:]
|
|
249
|
+
if not silent:
|
|
250
|
+
self.context.console.print("[dim]Compacted (summary failed, used local fallback)[/dim]" if self.context.has_rich
|
|
251
|
+
else "Compacted (summary fallback)")
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
envelope = context_service.build_summary_envelope(conv, summary)
|
|
255
|
+
self._record_context_checkpoint(
|
|
256
|
+
"compact",
|
|
257
|
+
envelope={
|
|
258
|
+
"old_message_count": envelope.old_message_count,
|
|
259
|
+
"new_message_count": envelope.new_message_count,
|
|
260
|
+
"tail_message_count": envelope.tail_message_count,
|
|
261
|
+
},
|
|
262
|
+
)
|
|
263
|
+
self.terminal.conversation = envelope.messages
|
|
264
|
+
new_count = len(self.terminal.conversation)
|
|
265
|
+
old_count = len(conv)
|
|
266
|
+
if not silent:
|
|
267
|
+
if self.context.has_rich:
|
|
268
|
+
self.context.console.print(
|
|
269
|
+
f" [dim]✓ Compacted {old_count} → {new_count} messages "
|
|
270
|
+
f"(summary preserved context)[/dim]"
|
|
271
|
+
)
|
|
272
|
+
else:
|
|
273
|
+
print(f"Compacted {old_count} → {new_count} messages")
|
|
274
|
+
|
|
275
|
+
def cmd_fork(self, args: str):
|
|
276
|
+
import time as _t
|
|
277
|
+
name = args.strip() or f"fork-{_t.strftime('%H%M%S')}"
|
|
278
|
+
snapshot = {
|
|
279
|
+
"name": name,
|
|
280
|
+
"ts": _t.strftime("%Y-%m-%d %H:%M:%S"),
|
|
281
|
+
"conv": [dict(m) for m in self.terminal.conversation],
|
|
282
|
+
"config": dict(self.terminal.config),
|
|
283
|
+
}
|
|
284
|
+
self.terminal._forks.append(snapshot)
|
|
285
|
+
idx = len(self.terminal._forks) - 1
|
|
286
|
+
if self.context.has_rich:
|
|
287
|
+
self.context.console.print(
|
|
288
|
+
f" [dim]↳ Forked as [bold]{name}[/bold] "
|
|
289
|
+
f"(fork #{idx}, {len(snapshot['conv'])} messages). "
|
|
290
|
+
f"Restore with /load-fork {idx}[/dim]"
|
|
291
|
+
)
|
|
292
|
+
else:
|
|
293
|
+
print(f"Forked as '{name}' (#{idx}). Restore with /load-fork {idx}")
|
|
294
|
+
|
|
295
|
+
def cmd_load_fork(self, args: str):
|
|
296
|
+
forks = self.terminal._forks
|
|
297
|
+
if not forks:
|
|
298
|
+
self.context.console.print("[dim]No forks yet — use /fork to create one[/dim]" if self.context.has_rich else "No forks")
|
|
299
|
+
return
|
|
300
|
+
try:
|
|
301
|
+
idx = int(args.strip())
|
|
302
|
+
except (ValueError, IndexError):
|
|
303
|
+
if self.context.has_rich:
|
|
304
|
+
for i, f in enumerate(forks):
|
|
305
|
+
self.context.console.print(f" [dim]#{i}[/dim] {f['name']} [dim]{f['ts']} {len(f['conv'])} msgs[/dim]")
|
|
306
|
+
else:
|
|
307
|
+
for i, f in enumerate(forks):
|
|
308
|
+
print(f" #{i} {f['name']} {f['ts']}")
|
|
309
|
+
return
|
|
310
|
+
if idx < 0 or idx >= len(forks):
|
|
311
|
+
self.context.console.print(f"[dim]Fork #{idx} not found[/dim]" if self.context.has_rich else "Invalid index")
|
|
312
|
+
return
|
|
313
|
+
snap = forks[idx]
|
|
314
|
+
self.terminal.conversation = [dict(m) for m in snap["conv"]]
|
|
315
|
+
self.context.console.print(
|
|
316
|
+
f" [dim]✓ Restored fork [bold]{snap['name']}[/bold] "
|
|
317
|
+
f"({len(snap['conv'])} messages)[/dim]"
|
|
318
|
+
if self.context.has_rich else f"Restored fork '{snap['name']}'"
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def cmd_copy(self, args: str):
|
|
322
|
+
text = self.terminal._last_response
|
|
323
|
+
if not text:
|
|
324
|
+
self.context.console.print("[dim]No response to copy yet[/dim]" if self.context.has_rich else "Nothing to copy")
|
|
325
|
+
return
|
|
326
|
+
copied = False
|
|
327
|
+
try:
|
|
328
|
+
import subprocess as _sp
|
|
329
|
+
_sp.run(["pbcopy"], input=text.encode(), check=True, timeout=3)
|
|
330
|
+
copied = True
|
|
331
|
+
except Exception:
|
|
332
|
+
pass
|
|
333
|
+
if not copied:
|
|
334
|
+
try:
|
|
335
|
+
import subprocess as _sp
|
|
336
|
+
_sp.run(["xclip", "-selection", "clipboard"], input=text.encode(), check=True, timeout=3)
|
|
337
|
+
copied = True
|
|
338
|
+
except Exception:
|
|
339
|
+
pass
|
|
340
|
+
if not copied:
|
|
341
|
+
try:
|
|
342
|
+
import subprocess as _sp
|
|
343
|
+
_sp.run(["xdotool", "type", "--clearmodifiers", text], check=True, timeout=3)
|
|
344
|
+
copied = True
|
|
345
|
+
except Exception:
|
|
346
|
+
pass
|
|
347
|
+
if copied:
|
|
348
|
+
self.terminal._record_feedback("copy", text)
|
|
349
|
+
preview = text[:60].replace("\n", " ")
|
|
350
|
+
self.context.console.print(
|
|
351
|
+
f" [dim]✓ Copied to clipboard: \"{preview}{'…' if len(text) > 60 else ''}\"[/dim]"
|
|
352
|
+
if self.context.has_rich else f"Copied: \"{preview}\""
|
|
353
|
+
)
|
|
354
|
+
else:
|
|
355
|
+
self.context.console.print(
|
|
356
|
+
"[yellow]Could not reach clipboard (pbcopy/xclip not found). "
|
|
357
|
+
"Here is the response:[/yellow]\n" + text
|
|
358
|
+
if self.context.has_rich else "Clipboard unavailable. Response:\n" + text
|
|
359
|
+
)
|