aria-code 0.167.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aria_bots/__init__.py +7 -0
- aria_bots/channels/README.md +97 -0
- aria_bots/channels/__init__.py +1 -0
- aria_bots/channels/approvals.py +263 -0
- aria_bots/channels/conversation.py +280 -0
- aria_bots/channels/digest.py +186 -0
- aria_bots/channels/registry.py +95 -0
- aria_bots/engine.py +144 -0
- aria_bots/feishu_bot.py +1385 -0
- aria_bots/logistics/__init__.py +1 -0
- aria_bots/logistics/carriers.py +253 -0
- aria_bots/logistics/freight.py +154 -0
- aria_bots/logistics/inventory.py +242 -0
- aria_bots/logistics/mcp_server.py +156 -0
- aria_bots/logistics/records.py +119 -0
- aria_bots/logistics/tenancy.py +152 -0
- aria_bots/market.py +91 -0
- aria_bots/relay_client.py +326 -0
- aria_bots/telegram_bot.py +299 -0
- aria_code/__init__.py +111 -0
- aria_code/_bin/aria-native.exe +0 -0
- aria_code/_bin/aria-runtime.exe +0 -0
- aria_code/_version.py +20 -0
- aria_code/account_memory.py +296 -0
- aria_code/account_session.py +166 -0
- aria_code/adk_apps/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/__init__.py +1 -0
- aria_code/adk_apps/aria_code_review/agent.py +32 -0
- aria_code/adk_apps/aria_research/__init__.py +1 -0
- aria_code/adk_apps/aria_research/agent.py +31 -0
- aria_code/agents/__init__.py +49 -0
- aria_code/agents/base.py +329 -0
- aria_code/agents/code_review.py +200 -0
- aria_code/agents/deep/__init__.py +37 -0
- aria_code/agents/deep/calibration_loop.py +144 -0
- aria_code/agents/deep/critic.py +125 -0
- aria_code/agents/deep/deepen.py +193 -0
- aria_code/agents/deep/models.py +149 -0
- aria_code/agents/deep/pipeline.py +164 -0
- aria_code/agents/deep/quant_fusion.py +192 -0
- aria_code/agents/deep/themes.py +95 -0
- aria_code/agents/deep/tiers.py +106 -0
- aria_code/agents/engineering/__init__.py +14 -0
- aria_code/agents/engineering/coder.py +222 -0
- aria_code/agents/engineering/tester.py +145 -0
- aria_code/agents/financial/__init__.py +21 -0
- aria_code/agents/financial/cashflow_burn.py +119 -0
- aria_code/agents/financial/catalyst.py +279 -0
- aria_code/agents/financial/corporate_finance.py +175 -0
- aria_code/agents/financial/debate.py +224 -0
- aria_code/agents/financial/earnings.py +315 -0
- aria_code/agents/financial/fundamental.py +178 -0
- aria_code/agents/financial/macro.py +111 -0
- aria_code/agents/financial/news.py +231 -0
- aria_code/agents/financial/risk.py +146 -0
- aria_code/agents/financial/sector.py +279 -0
- aria_code/agents/financial/strategist.py +121 -0
- aria_code/agents/financial/stripe_revenue.py +127 -0
- aria_code/agents/financial/synthesis.py +274 -0
- aria_code/agents/financial/technical.py +277 -0
- aria_code/agents/orchestrator.py +44 -0
- aria_code/agents/portfolio_agent.py +392 -0
- aria_code/agents/realty/__init__.py +62 -0
- aria_code/agents/realty/asset_diagnosis.py +152 -0
- aria_code/agents/realty/business_match.py +166 -0
- aria_code/agents/realty/cashflow_verify.py +209 -0
- aria_code/agents/realty/contract_rules.py +210 -0
- aria_code/agents/realty/energy_anomaly.py +189 -0
- aria_code/agents/realty/exit_settlement.py +208 -0
- aria_code/agents/realty/fulfillment_risk.py +206 -0
- aria_code/agents/realty/ops_optimize.py +160 -0
- aria_code/agents/realty/revenue_share.py +215 -0
- aria_code/agents/registry.py +168 -0
- aria_code/agents/signal_scheme.py +111 -0
- aria_code/agents/sports/__init__.py +0 -0
- aria_code/agents/sports/football_agent.py +197 -0
- aria_code/agents/supervisor.py +113 -0
- aria_code/agents/team.py +500 -0
- aria_code/agents/video/__init__.py +16 -0
- aria_code/agents/video/director.py +376 -0
- aria_code/agents/video/qa_agent.py +143 -0
- aria_code/agents/video/script_doctor.py +112 -0
- aria_code/agents/warehouse/__init__.py +25 -0
- aria_code/agents/warehouse/contracts.py +26 -0
- aria_code/agents/warehouse/dashboard.py +155 -0
- aria_code/agents/warehouse/fulfillment_leadtime.py +95 -0
- aria_code/agents/warehouse/inbound_exceptions.py +25 -0
- aria_code/agents/warehouse/inventory_health.py +24 -0
- aria_code/agents/warehouse/local_run.py +71 -0
- aria_code/agents/warehouse/local_snapshot.py +132 -0
- aria_code/agents/warehouse/logistics_cost.py +84 -0
- aria_code/agents/warehouse/logistics_sync.py +21 -0
- aria_code/agents/warehouse/navigation.schema.json +110 -0
- aria_code/agents/warehouse/task_agent.py +172 -0
- aria_code/agents/warehouse/workflow.py +31 -0
- aria_code/aliyun_data_client.py +4 -0
- aria_code/apps/README.md +12 -0
- aria_code/apps/__init__.py +2 -0
- aria_code/apps/channels/README.md +9 -0
- aria_code/apps/channels/__init__.py +17 -0
- aria_code/apps/channels/approvals.py +11 -0
- aria_code/apps/channels/conversation.py +11 -0
- aria_code/apps/channels/digest.py +11 -0
- aria_code/apps/channels/intake.py +92 -0
- aria_code/apps/channels/registry.py +11 -0
- aria_code/apps/channels/tradingview.py +94 -0
- aria_code/apps/cli/README.md +13 -0
- aria_code/apps/cli/__init__.py +2 -0
- aria_code/apps/cli/_optional.py +120 -0
- aria_code/apps/cli/app_server.py +656 -0
- aria_code/apps/cli/auto_update.py +125 -0
- aria_code/apps/cli/bootstrap.py +206 -0
- aria_code/apps/cli/broker_render.py +206 -0
- aria_code/apps/cli/chat_turn.py +1327 -0
- aria_code/apps/cli/cloud_models.py +231 -0
- aria_code/apps/cli/codegen_paths.py +29 -0
- aria_code/apps/cli/commands/__init__.py +34 -0
- aria_code/apps/cli/commands/_business_render.py +78 -0
- aria_code/apps/cli/commands/_ui.py +71 -0
- aria_code/apps/cli/commands/analysis_cmds.py +378 -0
- aria_code/apps/cli/commands/ashare_prediction_cmds.py +327 -0
- aria_code/apps/cli/commands/auth_cmds.py +215 -0
- aria_code/apps/cli/commands/backtest_cmds.py +2518 -0
- aria_code/apps/cli/commands/broker_cmds.py +1236 -0
- aria_code/apps/cli/commands/business_workflow_cmds.py +379 -0
- aria_code/apps/cli/commands/canvas_cmds.py +77 -0
- aria_code/apps/cli/commands/catalog.py +189 -0
- aria_code/apps/cli/commands/core_cmds.py +2748 -0
- aria_code/apps/cli/commands/data_cmds.py +521 -0
- aria_code/apps/cli/commands/diagnostic_cmds.py +285 -0
- aria_code/apps/cli/commands/diagnostic_ops_cmds.py +813 -0
- aria_code/apps/cli/commands/engineering_cmds.py +399 -0
- aria_code/apps/cli/commands/file_cmds.py +312 -0
- aria_code/apps/cli/commands/finance_service_cmds.py +60 -0
- aria_code/apps/cli/commands/fx_commodity_cmds.py +123 -0
- aria_code/apps/cli/commands/market.py +544 -0
- aria_code/apps/cli/commands/market_cmds.py +1419 -0
- aria_code/apps/cli/commands/market_context.py +432 -0
- aria_code/apps/cli/commands/market_render.py +7 -0
- aria_code/apps/cli/commands/model_cmds.py +2374 -0
- aria_code/apps/cli/commands/ops_cmds.py +721 -0
- aria_code/apps/cli/commands/orchestrator_cmds.py +181 -0
- aria_code/apps/cli/commands/pdf_export_cmds.py +125 -0
- aria_code/apps/cli/commands/portfolio_cmds.py +1316 -0
- aria_code/apps/cli/commands/report.py +476 -0
- aria_code/apps/cli/commands/scaffold_templates.py +617 -0
- aria_code/apps/cli/commands/session_cmds.py +236 -0
- aria_code/apps/cli/commands/session_ux_cmds.py +359 -0
- aria_code/apps/cli/commands/team.py +723 -0
- aria_code/apps/cli/commands/team_render.py +8 -0
- aria_code/apps/cli/commands/ui_cmds.py +401 -0
- aria_code/apps/cli/commands/warehouse_cmds.py +297 -0
- aria_code/apps/cli/commands/workflow_cmds.py +629 -0
- aria_code/apps/cli/commands/workspace_cmds.py +1543 -0
- aria_code/apps/cli/config_paths.py +73 -0
- aria_code/apps/cli/config_store.py +158 -0
- aria_code/apps/cli/constants.py +88 -0
- aria_code/apps/cli/context.py +34 -0
- aria_code/apps/cli/conversation_policy.py +53 -0
- aria_code/apps/cli/deterministic.py +200 -0
- aria_code/apps/cli/direct.py +48 -0
- aria_code/apps/cli/earnings_view.py +172 -0
- aria_code/apps/cli/endpoint_migration.py +64 -0
- aria_code/apps/cli/exec_events.py +255 -0
- aria_code/apps/cli/file_references.py +155 -0
- aria_code/apps/cli/finance_service_catalog.py +111 -0
- aria_code/apps/cli/football_reports.py +231 -0
- aria_code/apps/cli/github_app_auth.py +135 -0
- aria_code/apps/cli/google_login.py +239 -0
- aria_code/apps/cli/handlers/__init__.py +11 -0
- aria_code/apps/cli/handlers/broker_handlers.py +122 -0
- aria_code/apps/cli/handlers/chart_handlers.py +1314 -0
- aria_code/apps/cli/handlers/market_handlers.py +2570 -0
- aria_code/apps/cli/handlers/realty_handlers.py +114 -0
- aria_code/apps/cli/handlers/sports_handlers.py +22 -0
- aria_code/apps/cli/handlers/strategy_advice.py +82 -0
- aria_code/apps/cli/headless.py +352 -0
- aria_code/apps/cli/helpers.py +326 -0
- aria_code/apps/cli/hooks.py +180 -0
- aria_code/apps/cli/i18n.py +310 -0
- aria_code/apps/cli/intent.py +136 -0
- aria_code/apps/cli/intent_router.py +305 -0
- aria_code/apps/cli/intent_shadow.py +72 -0
- aria_code/apps/cli/intent_signals.py +347 -0
- aria_code/apps/cli/lifecycle_hooks.py +48 -0
- aria_code/apps/cli/local_tool_schemas.py +550 -0
- aria_code/apps/cli/main.py +39 -0
- aria_code/apps/cli/market_hours.py +100 -0
- aria_code/apps/cli/market_metadata.py +135 -0
- aria_code/apps/cli/market_universe.py +487 -0
- aria_code/apps/cli/message_processing.py +310 -0
- aria_code/apps/cli/mixin_binding.py +32 -0
- aria_code/apps/cli/model_catalog.py +652 -0
- aria_code/apps/cli/model_probe.py +169 -0
- aria_code/apps/cli/model_retirement.py +65 -0
- aria_code/apps/cli/native_branding.py +12 -0
- aria_code/apps/cli/native_bridge.py +118 -0
- aria_code/apps/cli/native_entry.py +58 -0
- aria_code/apps/cli/pdf_report.py +977 -0
- aria_code/apps/cli/plan_mode.py +139 -0
- aria_code/apps/cli/plotly_html.py +15 -0
- aria_code/apps/cli/prediction_feedback.py +202 -0
- aria_code/apps/cli/preflight.py +502 -0
- aria_code/apps/cli/project_aria.py +60 -0
- aria_code/apps/cli/prompt_assembly.py +78 -0
- aria_code/apps/cli/prompts/__init__.py +0 -0
- aria_code/apps/cli/prompts/coding.py +71 -0
- aria_code/apps/cli/prompts/select.py +193 -0
- aria_code/apps/cli/prompts/system_prompts.py +562 -0
- aria_code/apps/cli/prompts/ui.py +436 -0
- aria_code/apps/cli/provider_endpoints.py +237 -0
- aria_code/apps/cli/provider_keys.py +73 -0
- aria_code/apps/cli/providers/__init__.py +1 -0
- aria_code/apps/cli/providers/base.py +775 -0
- aria_code/apps/cli/providers/chat_routing.py +139 -0
- aria_code/apps/cli/providers/collaboration.py +98 -0
- aria_code/apps/cli/providers/llm/__init__.py +1 -0
- aria_code/apps/cli/providers/llm/offline_responses.py +68 -0
- aria_code/apps/cli/providers/llm/ollama_stream.py +1574 -0
- aria_code/apps/cli/providers/llm/response_cache.py +60 -0
- aria_code/apps/cli/providers/llm/sse_stream.py +298 -0
- aria_code/apps/cli/providers/runtime_bridge.py +586 -0
- aria_code/apps/cli/providers/vertexai_stream.py +592 -0
- aria_code/apps/cli/release_download.py +159 -0
- aria_code/apps/cli/review_runner.py +111 -0
- aria_code/apps/cli/runtime_consumer.py +769 -0
- aria_code/apps/cli/sandbox.py +32 -0
- aria_code/apps/cli/session_export.py +120 -0
- aria_code/apps/cli/session_jsonl.py +208 -0
- aria_code/apps/cli/session_refresh.py +123 -0
- aria_code/apps/cli/session_store.py +125 -0
- aria_code/apps/cli/skills_catalog.py +273 -0
- aria_code/apps/cli/task_isolation.py +211 -0
- aria_code/apps/cli/terminal_chrome.py +412 -0
- aria_code/apps/cli/todo_tracker.py +190 -0
- aria_code/apps/cli/tool_executor.py +932 -0
- aria_code/apps/cli/tool_registry.py +34 -0
- aria_code/apps/cli/tool_scope.py +113 -0
- aria_code/apps/cli/tools/__init__.py +40 -0
- aria_code/apps/cli/tools/context.py +46 -0
- aria_code/apps/cli/tools/file_tools.py +181 -0
- aria_code/apps/cli/tools/market_tools.py +626 -0
- aria_code/apps/cli/tools/notebook_tools.py +111 -0
- aria_code/apps/cli/tools/system_tools.py +656 -0
- aria_code/apps/cli/tools/write_tools.py +961 -0
- aria_code/apps/cli/tradingview_bridge.py +529 -0
- aria_code/apps/cli/transactions.py +269 -0
- aria_code/apps/cli/turn_planning.py +137 -0
- aria_code/apps/cli/update_check.py +257 -0
- aria_code/apps/cli/updater.py +373 -0
- aria_code/apps/cli/utils/__init__.py +0 -0
- aria_code/apps/cli/utils/market_detect.py +1663 -0
- aria_code/apps/cli/web_login.py +136 -0
- aria_code/apps/cli/workflow_runner.py +127 -0
- aria_code/apps/cli/workspace_route.py +121 -0
- aria_code/apps/daemon/README.md +14 -0
- aria_code/apps/vscode/README.md +115 -0
- aria_code/apps/vscode/package.json +70 -0
- aria_code/aria_cli.py +5244 -0
- aria_code/aria_daemon.py +1372 -0
- aria_code/aria_feishu_bot.py +16 -0
- aria_code/aria_mcp_server.py +61 -0
- aria_code/aria_relay_client.py +4 -0
- aria_code/aria_telegram_bot.py +11 -0
- aria_code/ariarc.py +385 -0
- aria_code/artifacts.py +581 -0
- aria_code/backtest_engine.py +4 -0
- aria_code/backtest_report.py +4 -0
- aria_code/brokers/__init__.py +78 -0
- aria_code/brokers/automation.py +193 -0
- aria_code/brokers/base.py +231 -0
- aria_code/brokers/capabilities.py +264 -0
- aria_code/brokers/cn/__init__.py +10 -0
- aria_code/brokers/cn/easytrader_broker.py +193 -0
- aria_code/brokers/cn/futu_broker.py +194 -0
- aria_code/brokers/cn/longbridge_broker.py +190 -0
- aria_code/brokers/cn/tiger_broker.py +196 -0
- aria_code/brokers/cn/xtquant_broker.py +225 -0
- aria_code/brokers/config.py +414 -0
- aria_code/brokers/intl/__init__.py +5 -0
- aria_code/brokers/intl/alpaca_broker.py +183 -0
- aria_code/brokers/intl/ibkr_broker.py +215 -0
- aria_code/brokers/intl/trading212_broker.py +183 -0
- aria_code/brokers/intl/webull_broker.py +156 -0
- aria_code/brokers/paper_broker.py +266 -0
- aria_code/brokers/planning.py +296 -0
- aria_code/brokers/registry.py +213 -0
- aria_code/brokers/trading.py +267 -0
- aria_code/canva_client.py +4 -0
- aria_code/change_store.py +127 -0
- aria_code/clients/__init__.py +0 -0
- aria_code/clients/aliyun_data_client.py +660 -0
- aria_code/clients/aria_relay_client.py +16 -0
- aria_code/clients/canva_client.py +284 -0
- aria_code/clients/figma_client.py +100 -0
- aria_code/clients/football_data_client.py +1671 -0
- aria_code/clients/kling_video_client.py +182 -0
- aria_code/clients/market_data_client.py +1985 -0
- aria_code/clients/openai_image_client.py +242 -0
- aria_code/clients/runway_video_client.py +157 -0
- aria_code/clients/warehouse_erp_client.py +105 -0
- aria_code/cloud_memory.py +190 -0
- aria_code/command_safety.py +19 -0
- aria_code/computer_use_server.py +276 -0
- aria_code/computer_use_tools.py +4 -0
- aria_code/dashboard_generator.py +579 -0
- aria_code/data_analysis_tools.py +4 -0
- aria_code/data_cleaner.py +483 -0
- aria_code/data_service.py +513 -0
- aria_code/datasources/__init__.py +23 -0
- aria_code/datasources/base.py +166 -0
- aria_code/datasources/router.py +253 -0
- aria_code/datasources/sec_statements.py +217 -0
- aria_code/datasources/sources/__init__.py +15 -0
- aria_code/datasources/sources/akshare_source.py +269 -0
- aria_code/datasources/sources/alpha_vantage_source.py +203 -0
- aria_code/datasources/sources/edgar_source.py +219 -0
- aria_code/datasources/sources/finnhub_source.py +198 -0
- aria_code/datasources/sources/fred_source.py +223 -0
- aria_code/datasources/sources/tushare_source.py +143 -0
- aria_code/datasources/sources/web_scraper_source.py +278 -0
- aria_code/datasources/sources/world_bank_source.py +206 -0
- aria_code/datasources/sources/yfinance_source.py +152 -0
- aria_code/doctor.py +860 -0
- aria_code/domain/__init__.py +0 -0
- aria_code/domain/_finance_core/__init__.py +5 -0
- aria_code/domain/_finance_core/backtest_engine.py +325 -0
- aria_code/domain/_finance_core/performance_stats.py +101 -0
- aria_code/domain/backtest_engine.py +75 -0
- aria_code/domain/backtest_report.py +488 -0
- aria_code/domain/finance_formulas.py +389 -0
- aria_code/domain/performance_stats.py +6 -0
- aria_code/domain/portfolio_ledger.py +307 -0
- aria_code/domain/strategy_vault.py +421 -0
- aria_code/evals/__init__.py +37 -0
- aria_code/evals/behavior.py +113 -0
- aria_code/evals/gap.py +93 -0
- aria_code/evals/harness.py +949 -0
- aria_code/evals/review_probe.py +132 -0
- aria_code/evals/runner.py +425 -0
- aria_code/evals/scorecard.py +322 -0
- aria_code/evals/summary.py +125 -0
- aria_code/external_agent_runner.py +115 -0
- aria_code/figma_client.py +4 -0
- aria_code/file_analysis_tools.py +4 -0
- aria_code/finance_formulas.py +4 -0
- aria_code/football_data_client.py +4 -0
- aria_code/image_gen_tools.py +4 -0
- aria_code/intent_classifier.py +459 -0
- aria_code/kling_video_client.py +4 -0
- aria_code/licensing.py +151 -0
- aria_code/local_finance_tools.py +4 -0
- aria_code/local_image_provider.py +4 -0
- aria_code/local_llm_provider.py +4 -0
- aria_code/macro_tools.py +4 -0
- aria_code/markdown_pdf.py +289 -0
- aria_code/market_data_client.py +4 -0
- aria_code/mcp_client.py +744 -0
- aria_code/memory_manager.py +273 -0
- aria_code/model_capability.py +512 -0
- aria_code/notification_tools.py +4 -0
- aria_code/openai_image_client.py +4 -0
- aria_code/packages/__init__.py +26 -0
- aria_code/packages/adk_bridge/__init__.py +11 -0
- aria_code/packages/adk_bridge/code_review_tools.py +49 -0
- aria_code/packages/adk_bridge/market_tools.py +125 -0
- aria_code/packages/aria_agents/__init__.py +5 -0
- aria_code/packages/aria_agents/manifest.py +78 -0
- aria_code/packages/aria_core/__init__.py +34 -0
- aria_code/packages/aria_core/architecture.py +269 -0
- aria_code/packages/aria_core/export.py +147 -0
- aria_code/packages/aria_core/manifest.py +65 -0
- aria_code/packages/aria_core/paths.py +57 -0
- aria_code/packages/aria_core/secure_file.py +68 -0
- aria_code/packages/aria_infra/__init__.py +15 -0
- aria_code/packages/aria_infra/arthera.py +58 -0
- aria_code/packages/aria_infra/doctor.py +246 -0
- aria_code/packages/aria_infra/product.py +40 -0
- aria_code/packages/aria_mcp/__init__.py +25 -0
- aria_code/packages/aria_mcp/bridge.py +232 -0
- aria_code/packages/aria_mcp/circuit.py +82 -0
- aria_code/packages/aria_mcp/config.py +162 -0
- aria_code/packages/aria_mcp/installer.py +95 -0
- aria_code/packages/aria_mcp/server.py +1705 -0
- aria_code/packages/aria_mcp/tools.py +81 -0
- aria_code/packages/aria_sdk/__init__.py +19 -0
- aria_code/packages/aria_sdk/client.py +393 -0
- aria_code/packages/aria_sdk/providers.py +70 -0
- aria_code/packages/aria_sdk/streaming.py +75 -0
- aria_code/packages/aria_sdk/types.py +86 -0
- aria_code/packages/aria_services/__init__.py +92 -0
- aria_code/packages/aria_services/cache.py +60 -0
- aria_code/packages/aria_services/context.py +356 -0
- aria_code/packages/aria_services/context_checkpoints.py +157 -0
- aria_code/packages/aria_services/data.py +11 -0
- aria_code/packages/aria_services/provider_health.py +304 -0
- aria_code/packages/aria_services/references.py +247 -0
- aria_code/packages/aria_services/registry.py +249 -0
- aria_code/packages/aria_services/research_protocol.py +137 -0
- aria_code/packages/aria_services/research_quality.py +186 -0
- aria_code/packages/aria_services/settings.py +160 -0
- aria_code/packages/aria_services/usage.py +151 -0
- aria_code/packages/aria_skills/__init__.py +46 -0
- aria_code/packages/aria_skills/catalog.py +149 -0
- aria_code/packages/aria_skills/loader.py +455 -0
- aria_code/packages/aria_skills/registry.py +84 -0
- aria_code/packages/aria_tools/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/__init__.py +5 -0
- aria_code/packages/aria_tools/financial/_paths.py +92 -0
- aria_code/packages/aria_tools/registry.py +129 -0
- aria_code/packages/quant_engine/__init__.py +33 -0
- aria_code/packages/quant_engine/_namespace.py +24 -0
- aria_code/packages/quant_engine/backtest/__init__.py +10 -0
- aria_code/packages/quant_engine/backtest/core.py +53 -0
- aria_code/packages/quant_engine/backtest/engine.py +102 -0
- aria_code/packages/quant_engine/portfolio/__init__.py +9 -0
- aria_code/packages/quant_engine/portfolio/optimizer.py +85 -0
- aria_code/packages/quant_engine/sports/__init__.py +76 -0
- aria_code/packages/quant_engine/sports/calibrator.py +354 -0
- aria_code/packages/quant_engine/sports/dixon_coles.py +234 -0
- aria_code/packages/quant_engine/sports/elo.py +300 -0
- aria_code/packages/quant_engine/sports/form.py +188 -0
- aria_code/packages/quant_engine/sports/h2h.py +195 -0
- aria_code/packages/quant_engine/sports/predictor.py +312 -0
- aria_code/packages/quant_engine/sports/tracker.py +665 -0
- aria_code/packages/quant_engine/stochastic/__init__.py +31 -0
- aria_code/packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- aria_code/packages/quant_engine/stochastic/ito_calculus.py +477 -0
- aria_code/packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- aria_code/packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- aria_code/packages/quant_engine/stochastic/options_pricing.py +576 -0
- aria_code/packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- aria_code/packs/__init__.py +85 -0
- aria_code/packs/base.py +168 -0
- aria_code/packs/finance/__init__.py +250 -0
- aria_code/packs/healthcare/__init__.py +40 -0
- aria_code/packs/logistics/__init__.py +171 -0
- aria_code/packs/payments/__init__.py +139 -0
- aria_code/packs/realty/__init__.py +190 -0
- aria_code/packs/registry.py +202 -0
- aria_code/packs/rules.py +90 -0
- aria_code/plan_utils.py +194 -0
- aria_code/plugin_loader.py +328 -0
- aria_code/portfolio_ledger.py +4 -0
- aria_code/preview_server.py +449 -0
- aria_code/privacy/__init__.py +5 -0
- aria_code/privacy/feedback.py +123 -0
- aria_code/project_review.py +278 -0
- aria_code/project_review_api.py +235 -0
- aria_code/project_review_server.py +18 -0
- aria_code/project_tools.py +4 -0
- aria_code/providers/__init__.py +30 -0
- aria_code/providers/google_video_provider.py +256 -0
- aria_code/providers/llm/__init__.py +19 -0
- aria_code/providers/llm/anthropic.py +184 -0
- aria_code/providers/llm/arthera_gateway.py +90 -0
- aria_code/providers/llm/autoconfig.py +213 -0
- aria_code/providers/llm/base.py +139 -0
- aria_code/providers/llm/custom.py +158 -0
- aria_code/providers/llm/ollama.py +137 -0
- aria_code/providers/llm/openai_compat.py +350 -0
- aria_code/providers/llm/registry.py +457 -0
- aria_code/providers/local_image_provider.py +202 -0
- aria_code/providers/local_llm_provider.py +549 -0
- aria_code/providers/ollama_models.py +79 -0
- aria_code/providers/openai_params.py +32 -0
- aria_code/providers/tool_messages.py +100 -0
- aria_code/realty_data_tools.py +4 -0
- aria_code/report_exporters.py +150 -0
- aria_code/report_generator.py +1764 -0
- aria_code/review_service.py +497 -0
- aria_code/runtime/__init__.py +176 -0
- aria_code/runtime/acceptance.py +632 -0
- aria_code/runtime/agent_loop.py +1851 -0
- aria_code/runtime/agent_profiles.py +75 -0
- aria_code/runtime/approval.py +71 -0
- aria_code/runtime/baseline.py +219 -0
- aria_code/runtime/budget.py +232 -0
- aria_code/runtime/checkpoints.py +481 -0
- aria_code/runtime/consult.py +65 -0
- aria_code/runtime/contract.py +282 -0
- aria_code/runtime/delivery.py +432 -0
- aria_code/runtime/events.py +113 -0
- aria_code/runtime/gateway.py +167 -0
- aria_code/runtime/lsp.py +484 -0
- aria_code/runtime/native_index.py +153 -0
- aria_code/runtime/orchestrator.py +55 -0
- aria_code/runtime/processes.py +343 -0
- aria_code/runtime/project_graph.py +614 -0
- aria_code/runtime/repo_map.py +712 -0
- aria_code/runtime/research_bundle.py +105 -0
- aria_code/runtime/review.py +269 -0
- aria_code/runtime/run_state.py +127 -0
- aria_code/runtime/run_store.py +522 -0
- aria_code/runtime/scoped_runs.py +113 -0
- aria_code/runtime/self_healing.py +422 -0
- aria_code/runtime/semantic_diff.py +171 -0
- aria_code/runtime/subagent.py +721 -0
- aria_code/runtime/symbol_edit.py +117 -0
- aria_code/runtime/task_brief.py +46 -0
- aria_code/runtime/task_context.py +145 -0
- aria_code/runtime/task_ledger.py +108 -0
- aria_code/runtime/task_orchestrator.py +90 -0
- aria_code/runtime/task_outcome.py +33 -0
- aria_code/runtime/task_verification.py +266 -0
- aria_code/runtime/task_worktree.py +448 -0
- aria_code/runtime/tool_executor.py +329 -0
- aria_code/runtime/tool_policy.py +107 -0
- aria_code/runtime/transactions.py +216 -0
- aria_code/runtime/windows_job.py +115 -0
- aria_code/runtime/workflows.py +222 -0
- aria_code/runtime/worktrees.py +215 -0
- aria_code/runway_video_client.py +4 -0
- aria_code/safety/__init__.py +27 -0
- aria_code/safety/client_isolation.py +178 -0
- aria_code/safety/permissions.py +339 -0
- aria_code/safety/risk.py +699 -0
- aria_code/safety/sandbox.py +148 -0
- aria_code/safety/service.py +102 -0
- aria_code/service_endpoints.py +14 -0
- aria_code/setup_wizard.py +684 -0
- aria_code/spreadsheet_tools.py +4 -0
- aria_code/strategy_vault.py +4 -0
- aria_code/tools/__init__.py +0 -0
- aria_code/tools/artifact_tools.py +252 -0
- aria_code/tools/broker_tools.py +92 -0
- aria_code/tools/build_quant_engine.py +97 -0
- aria_code/tools/code_audit_tools.py +192 -0
- aria_code/tools/computer_use_tools.py +509 -0
- aria_code/tools/data_analysis_tools.py +831 -0
- aria_code/tools/enterprise_finance_tools.py +202 -0
- aria_code/tools/extended_tools.py +240 -0
- aria_code/tools/file_analysis_tools.py +880 -0
- aria_code/tools/image_gen_tools.py +114 -0
- aria_code/tools/local_finance_tools.py +3488 -0
- aria_code/tools/logistics_carriers.py +11 -0
- aria_code/tools/logistics_inventory.py +11 -0
- aria_code/tools/logistics_io.py +11 -0
- aria_code/tools/logistics_tenancy.py +11 -0
- aria_code/tools/logistics_tools.py +11 -0
- aria_code/tools/macro_tools.py +412 -0
- aria_code/tools/notification_tools.py +249 -0
- aria_code/tools/project_tools.py +525 -0
- aria_code/tools/realty_data_tools.py +662 -0
- aria_code/tools/spreadsheet_tools.py +399 -0
- aria_code/tools/stripe_tools.py +115 -0
- aria_code/tools/video_tools.py +500 -0
- aria_code/training/__init__.py +1 -0
- aria_code/training/compare.py +117 -0
- aria_code/training/prelude_commands.py +111 -0
- aria_code/training/prelude_eval.py +390 -0
- aria_code/training/prelude_real.py +183 -0
- aria_code/training/prelude_train.py +248 -0
- aria_code/training/sft_dataset.py +230 -0
- aria_code/training/trajectory_dataset.py +263 -0
- aria_code/ui/__init__.py +105 -0
- aria_code/ui/banner.py +404 -0
- aria_code/ui/completer.py +571 -0
- aria_code/ui/console.py +285 -0
- aria_code/ui/input_box.py +505 -0
- aria_code/ui/mentions.py +206 -0
- aria_code/ui/picker.py +248 -0
- aria_code/ui/render/__init__.py +11 -0
- aria_code/ui/render/actions.py +297 -0
- aria_code/ui/render/finance.py +1732 -0
- aria_code/ui/render/market.py +253 -0
- aria_code/ui/render/output.py +954 -0
- aria_code/ui/render/responsive.py +75 -0
- aria_code/ui/render/team.py +367 -0
- aria_code/ui/robot.py +239 -0
- aria_code/ui/startup_dashboard.py +110 -0
- aria_code/video_analysis.py +147 -0
- aria_code/video_editor.py +518 -0
- aria_code/video_workflow/__init__.py +8 -0
- aria_code/video_workflow/__main__.py +61 -0
- aria_code/video_workflow/engines/__init__.py +18 -0
- aria_code/video_workflow/engines/base.py +69 -0
- aria_code/video_workflow/engines/custom_model.py +204 -0
- aria_code/video_workflow/engines/google_veo.py +94 -0
- aria_code/video_workflow/engines/local_engine.py +71 -0
- aria_code/video_workflow/engines/registry.py +98 -0
- aria_code/video_workflow/google_models.py +278 -0
- aria_code/video_workflow/music/__init__.py +5 -0
- aria_code/video_workflow/music/foley_service.py +132 -0
- aria_code/video_workflow/music/service.py +212 -0
- aria_code/video_workflow/pipeline.py +620 -0
- aria_code/video_workflow/plan.py +202 -0
- aria_code/video_workflow/session.py +297 -0
- aria_code/workspace/__init__.py +6 -0
- aria_code/workspace/files.py +219 -0
- aria_code/workspace/verify.py +167 -0
- aria_code/workspace_changes.py +199 -0
- aria_code/workspace_service.py +196 -0
- aria_code/workspace_tools.py +150 -0
- aria_code-0.167.0.dist-info/METADATA +330 -0
- aria_code-0.167.0.dist-info/RECORD +601 -0
- aria_code-0.167.0.dist-info/WHEEL +5 -0
- aria_code-0.167.0.dist-info/entry_points.txt +5 -0
- aria_code-0.167.0.dist-info/licenses/LICENSE +201 -0
- aria_code-0.167.0.dist-info/licenses/NOTICE +49 -0
- aria_code-0.167.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"""preview_server.py — local, opt-in live-preview server for generated
|
|
2
|
+
artifacts (the aria-code half of the "Canvas/Artifacts" feature).
|
|
3
|
+
|
|
4
|
+
Off by default: nothing in this module runs until a human types `/canvas`
|
|
5
|
+
at the terminal (see apps/cli/commands/canvas_cmds.py). Binds to 127.0.0.1
|
|
6
|
+
only — never 0.0.0.0 — since this exists purely to open a local browser tab
|
|
7
|
+
next to the terminal, not to serve anything over the network.
|
|
8
|
+
|
|
9
|
+
Wire-up: artifacts.write_artifact_metadata() calls notify_new_version()
|
|
10
|
+
on the active session (a no-op when no session is running, which is the
|
|
11
|
+
overwhelmingly common case — every headless MCP tool call goes through that
|
|
12
|
+
function without a preview session ever existing). Versions are grouped by
|
|
13
|
+
a thread_id derived from the artifact's category+topic, so re-running the
|
|
14
|
+
same report for the same symbol appends to one thread's history instead of
|
|
15
|
+
starting a new one each time.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import asyncio
|
|
21
|
+
import json
|
|
22
|
+
import logging
|
|
23
|
+
import mimetypes
|
|
24
|
+
import os
|
|
25
|
+
import time
|
|
26
|
+
import webbrowser
|
|
27
|
+
from dataclasses import dataclass, field
|
|
28
|
+
from datetime import datetime
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
from typing import Any, Dict, List, Optional
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger("aria_preview_server")
|
|
33
|
+
|
|
34
|
+
_DEFAULT_HOST = "127.0.0.1"
|
|
35
|
+
_PORT_CANDIDATES = list(range(8765, 8775))
|
|
36
|
+
|
|
37
|
+
_active_session: Optional["PreviewSession"] = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def discovery_path() -> Path:
|
|
41
|
+
"""Where a running canvas advertises its URL.
|
|
42
|
+
|
|
43
|
+
The port is picked from a range at bind time, so a *separate* process
|
|
44
|
+
(notably Arthera's Electron terminal, which embeds this server's output
|
|
45
|
+
in its artifact preview panel) cannot guess it. This file is the
|
|
46
|
+
handshake: written on start, removed on stop.
|
|
47
|
+
"""
|
|
48
|
+
from aria_code.brokers.config import BROKERS_CONFIG_PATH # same ~/.aria-code|.arthera home
|
|
49
|
+
|
|
50
|
+
return BROKERS_CONFIG_PATH.parent / "canvas.json"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _write_discovery(url: str) -> None:
|
|
54
|
+
try:
|
|
55
|
+
path = discovery_path()
|
|
56
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
path.write_text(
|
|
58
|
+
json.dumps({"url": url, "pid": os.getpid(), "started_at": time.time()}, indent=2),
|
|
59
|
+
encoding="utf-8",
|
|
60
|
+
)
|
|
61
|
+
except Exception as exc: # discovery is a convenience, never fatal
|
|
62
|
+
logger.warning("Could not write canvas discovery file: %s", exc)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _clear_discovery() -> None:
|
|
66
|
+
try:
|
|
67
|
+
discovery_path().unlink(missing_ok=True)
|
|
68
|
+
except Exception as exc:
|
|
69
|
+
logger.warning("Could not remove canvas discovery file: %s", exc)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def read_discovery() -> Optional[Dict[str, Any]]:
|
|
73
|
+
"""Read another process's advertised canvas URL, or None.
|
|
74
|
+
|
|
75
|
+
Returns None for a stale file — one whose PID is no longer alive, which
|
|
76
|
+
is what a crash or `kill -9` leaves behind. Without that check a consumer
|
|
77
|
+
would keep pointing an iframe at a dead port indefinitely.
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
path = discovery_path()
|
|
81
|
+
if not path.exists():
|
|
82
|
+
return None
|
|
83
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
84
|
+
pid = data.get("pid")
|
|
85
|
+
if isinstance(pid, int):
|
|
86
|
+
try:
|
|
87
|
+
os.kill(pid, 0) # signal 0 = liveness probe, does not kill
|
|
88
|
+
except ProcessLookupError:
|
|
89
|
+
return None
|
|
90
|
+
except PermissionError:
|
|
91
|
+
pass # alive, owned by another user
|
|
92
|
+
return data
|
|
93
|
+
except Exception:
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_active_session() -> Optional["PreviewSession"]:
|
|
98
|
+
return _active_session
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def thread_id_for(record: Any) -> str:
|
|
102
|
+
"""Group versions of "the same logical artifact" together — same
|
|
103
|
+
category+topic (e.g. a market report for AAPL) is one thread across
|
|
104
|
+
repeated runs, not a new thread every time."""
|
|
105
|
+
return f"{record.category}:{record.topic}"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class _Version:
|
|
110
|
+
index: int
|
|
111
|
+
path: Path
|
|
112
|
+
created_at: str
|
|
113
|
+
kind: str
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class _Thread:
|
|
118
|
+
id: str
|
|
119
|
+
versions: List[_Version] = field(default_factory=list)
|
|
120
|
+
updated_at: float = 0.0
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class PreviewSession:
|
|
124
|
+
"""One running local preview server. Create via `start()`, not directly."""
|
|
125
|
+
|
|
126
|
+
def __init__(self) -> None:
|
|
127
|
+
self.threads: Dict[str, _Thread] = {}
|
|
128
|
+
self.active_thread_id: Optional[str] = None
|
|
129
|
+
self.url: str = ""
|
|
130
|
+
self._runner = None
|
|
131
|
+
self._sse_clients: List[Any] = []
|
|
132
|
+
|
|
133
|
+
# -- lifecycle ----------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
async def start(self, host: str = _DEFAULT_HOST) -> str:
|
|
136
|
+
from aiohttp import web
|
|
137
|
+
|
|
138
|
+
app = web.Application()
|
|
139
|
+
app.router.add_get("/", self._handle_index)
|
|
140
|
+
app.router.add_get("/events", self._handle_events)
|
|
141
|
+
app.router.add_get("/state", self._handle_state)
|
|
142
|
+
app.router.add_get("/artifact/{thread_id:.*}", self._handle_artifact)
|
|
143
|
+
|
|
144
|
+
runner = web.AppRunner(app)
|
|
145
|
+
await runner.setup()
|
|
146
|
+
|
|
147
|
+
last_error: Optional[Exception] = None
|
|
148
|
+
for port in _PORT_CANDIDATES:
|
|
149
|
+
site = web.TCPSite(runner, host, port)
|
|
150
|
+
try:
|
|
151
|
+
await site.start()
|
|
152
|
+
except OSError as exc:
|
|
153
|
+
last_error = exc
|
|
154
|
+
continue
|
|
155
|
+
self._runner = runner
|
|
156
|
+
self.url = f"http://{host}:{port}/"
|
|
157
|
+
return self.url
|
|
158
|
+
await runner.cleanup()
|
|
159
|
+
raise RuntimeError(
|
|
160
|
+
f"Could not bind any port in {_PORT_CANDIDATES[0]}-{_PORT_CANDIDATES[-1]} "
|
|
161
|
+
f"for the preview server: {last_error}"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
async def stop(self) -> None:
|
|
165
|
+
if self._runner is not None:
|
|
166
|
+
await self._runner.cleanup()
|
|
167
|
+
self._runner = None
|
|
168
|
+
self.url = ""
|
|
169
|
+
self.threads.clear()
|
|
170
|
+
self.active_thread_id = None
|
|
171
|
+
self._sse_clients.clear()
|
|
172
|
+
|
|
173
|
+
# -- artifact notification ----------------------------------------------
|
|
174
|
+
|
|
175
|
+
async def notify_new_version(self, thread_id: str, record: Any) -> None:
|
|
176
|
+
thread = self.threads.setdefault(thread_id, _Thread(id=thread_id))
|
|
177
|
+
version = _Version(
|
|
178
|
+
index=len(thread.versions),
|
|
179
|
+
path=Path(record.path),
|
|
180
|
+
created_at=datetime.now().isoformat(timespec="seconds"),
|
|
181
|
+
kind=_kind_for_suffix(Path(record.path).suffix),
|
|
182
|
+
)
|
|
183
|
+
thread.versions.append(version)
|
|
184
|
+
thread.updated_at = time.time()
|
|
185
|
+
self.active_thread_id = thread_id
|
|
186
|
+
await self._broadcast({
|
|
187
|
+
"type": "new-version",
|
|
188
|
+
"thread_id": thread_id,
|
|
189
|
+
"version_index": version.index,
|
|
190
|
+
"url": f"/artifact/{thread_id}?v={version.index}",
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
async def _broadcast(self, payload: Dict[str, Any]) -> None:
|
|
194
|
+
if not self._sse_clients:
|
|
195
|
+
return
|
|
196
|
+
data = f"data: {json.dumps(payload, ensure_ascii=False)}\n\n".encode("utf-8")
|
|
197
|
+
dead = []
|
|
198
|
+
for resp in self._sse_clients:
|
|
199
|
+
try:
|
|
200
|
+
await resp.write(data)
|
|
201
|
+
except Exception:
|
|
202
|
+
dead.append(resp)
|
|
203
|
+
for resp in dead:
|
|
204
|
+
self._sse_clients.remove(resp)
|
|
205
|
+
|
|
206
|
+
# -- HTTP handlers --------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
async def _handle_index(self, request):
|
|
209
|
+
from aiohttp import web
|
|
210
|
+
return web.Response(text=_SHELL_HTML, content_type="text/html")
|
|
211
|
+
|
|
212
|
+
async def _handle_events(self, request):
|
|
213
|
+
from aiohttp import web
|
|
214
|
+
|
|
215
|
+
resp = web.StreamResponse(
|
|
216
|
+
status=200,
|
|
217
|
+
headers={
|
|
218
|
+
"Content-Type": "text/event-stream",
|
|
219
|
+
"Cache-Control": "no-cache",
|
|
220
|
+
"Connection": "keep-alive",
|
|
221
|
+
},
|
|
222
|
+
)
|
|
223
|
+
await resp.prepare(request)
|
|
224
|
+
self._sse_clients.append(resp)
|
|
225
|
+
try:
|
|
226
|
+
# Keep the connection open; aiohttp closes it when the client
|
|
227
|
+
# disconnects, which surfaces here as a ConnectionResetError on
|
|
228
|
+
# the next write() from _broadcast (handled there, not here).
|
|
229
|
+
while True:
|
|
230
|
+
await asyncio.sleep(15)
|
|
231
|
+
try:
|
|
232
|
+
await resp.write(b": ping\n\n")
|
|
233
|
+
except Exception:
|
|
234
|
+
break
|
|
235
|
+
finally:
|
|
236
|
+
if resp in self._sse_clients:
|
|
237
|
+
self._sse_clients.remove(resp)
|
|
238
|
+
return resp
|
|
239
|
+
|
|
240
|
+
async def _handle_state(self, request):
|
|
241
|
+
from aiohttp import web
|
|
242
|
+
|
|
243
|
+
threads_payload = {
|
|
244
|
+
tid: {
|
|
245
|
+
"versions": [
|
|
246
|
+
{"index": v.index, "created_at": v.created_at, "kind": v.kind}
|
|
247
|
+
for v in thread.versions
|
|
248
|
+
],
|
|
249
|
+
}
|
|
250
|
+
for tid, thread in self.threads.items()
|
|
251
|
+
}
|
|
252
|
+
return web.json_response({
|
|
253
|
+
"threads": threads_payload,
|
|
254
|
+
"active_thread_id": self.active_thread_id,
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
async def _handle_artifact(self, request):
|
|
258
|
+
from aiohttp import web
|
|
259
|
+
|
|
260
|
+
thread_id = request.match_info["thread_id"]
|
|
261
|
+
thread = self.threads.get(thread_id)
|
|
262
|
+
if thread is None or not thread.versions:
|
|
263
|
+
return web.Response(status=404, text=f"Unknown thread: {thread_id}")
|
|
264
|
+
|
|
265
|
+
v_param = request.query.get("v")
|
|
266
|
+
try:
|
|
267
|
+
idx = int(v_param) if v_param is not None else len(thread.versions) - 1
|
|
268
|
+
except ValueError:
|
|
269
|
+
idx = len(thread.versions) - 1
|
|
270
|
+
idx = max(0, min(idx, len(thread.versions) - 1))
|
|
271
|
+
version = thread.versions[idx]
|
|
272
|
+
|
|
273
|
+
if not version.path.exists():
|
|
274
|
+
return web.Response(status=404, text=f"Artifact file missing: {version.path}")
|
|
275
|
+
content_type = mimetypes.guess_type(str(version.path))[0] or "application/octet-stream"
|
|
276
|
+
return web.Response(
|
|
277
|
+
body=version.path.read_bytes(),
|
|
278
|
+
content_type=content_type,
|
|
279
|
+
headers=_ARTIFACT_HEADERS,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# Sent with every artifact response. The iframe sandbox already gives the
|
|
284
|
+
# document an opaque origin; this is the second half — it stops the page from
|
|
285
|
+
# reaching the network at all.
|
|
286
|
+
#
|
|
287
|
+
# `connect-src 'none'` is the important line: without it, model-generated
|
|
288
|
+
# JavaScript in an artifact can POST the contents of the page (which may hold
|
|
289
|
+
# whatever data the agent just analysed) to any host on the internet, and an
|
|
290
|
+
# opaque origin does nothing to prevent that. Google Fonts is the one exception
|
|
291
|
+
# because a dashboard that silently loses its typeface looks broken rather than
|
|
292
|
+
# secured; nothing else is reachable.
|
|
293
|
+
_ARTIFACT_HEADERS = {
|
|
294
|
+
"Content-Security-Policy": "; ".join((
|
|
295
|
+
"default-src 'none'",
|
|
296
|
+
"script-src 'unsafe-inline' 'unsafe-eval'",
|
|
297
|
+
"style-src 'unsafe-inline' https://fonts.googleapis.com",
|
|
298
|
+
"font-src https://fonts.gstatic.com data:",
|
|
299
|
+
"img-src data: blob:",
|
|
300
|
+
"media-src data: blob:",
|
|
301
|
+
"connect-src 'none'",
|
|
302
|
+
"form-action 'none'",
|
|
303
|
+
"base-uri 'none'",
|
|
304
|
+
"frame-ancestors 'self'",
|
|
305
|
+
)),
|
|
306
|
+
"X-Content-Type-Options": "nosniff",
|
|
307
|
+
"Referrer-Policy": "no-referrer",
|
|
308
|
+
# A generated report is a snapshot of one moment; a cached copy shown after
|
|
309
|
+
# the next version lands is worse than no preview.
|
|
310
|
+
"Cache-Control": "no-store",
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _kind_for_suffix(suffix: str) -> str:
|
|
315
|
+
suffix = suffix.lower()
|
|
316
|
+
if suffix in (".html", ".htm"):
|
|
317
|
+
return "html"
|
|
318
|
+
if suffix in (".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"):
|
|
319
|
+
return "image"
|
|
320
|
+
if suffix in (".md", ".markdown"):
|
|
321
|
+
return "markdown"
|
|
322
|
+
return "file"
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
async def start_session() -> "PreviewSession":
|
|
326
|
+
"""Start (or return the already-running) preview session. Idempotent —
|
|
327
|
+
calling /canvas twice does not open a second server."""
|
|
328
|
+
global _active_session
|
|
329
|
+
if _active_session is not None and _active_session.url:
|
|
330
|
+
return _active_session
|
|
331
|
+
session = PreviewSession()
|
|
332
|
+
await session.start()
|
|
333
|
+
_active_session = session
|
|
334
|
+
_write_discovery(session.url)
|
|
335
|
+
return session
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
async def stop_session() -> None:
|
|
339
|
+
global _active_session
|
|
340
|
+
if _active_session is not None:
|
|
341
|
+
await _active_session.stop()
|
|
342
|
+
_active_session = None
|
|
343
|
+
_clear_discovery()
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def open_in_browser(url: str) -> None:
|
|
347
|
+
try:
|
|
348
|
+
webbrowser.open(url)
|
|
349
|
+
except Exception as exc:
|
|
350
|
+
logger.warning("Could not auto-open browser for %s: %s", url, exc)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
_SHELL_HTML = """<!doctype html>
|
|
354
|
+
<html>
|
|
355
|
+
<head>
|
|
356
|
+
<meta charset="utf-8">
|
|
357
|
+
<title>aria-code canvas</title>
|
|
358
|
+
<style>
|
|
359
|
+
:root { color-scheme: dark; }
|
|
360
|
+
* { box-sizing: border-box; }
|
|
361
|
+
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
362
|
+
background: #0d1117; color: #c9d1d9; height: 100vh; display: flex; flex-direction: column; }
|
|
363
|
+
header { display: flex; align-items: center; gap: 12px; padding: 10px 16px;
|
|
364
|
+
border-bottom: 1px solid #21262d; background: #161b22; }
|
|
365
|
+
header .title { font-weight: 600; font-size: 14px; }
|
|
366
|
+
header .empty { color: #8b949e; font-size: 13px; }
|
|
367
|
+
.stepper { display: flex; align-items: center; gap: 6px; margin-left: auto; }
|
|
368
|
+
.stepper button { background: #21262d; color: #c9d1d9; border: 1px solid #30363d;
|
|
369
|
+
border-radius: 6px; padding: 4px 10px; cursor: pointer; font-size: 13px; }
|
|
370
|
+
.stepper button:disabled { opacity: 0.4; cursor: default; }
|
|
371
|
+
.stepper span { font-size: 12px; color: #8b949e; min-width: 48px; text-align: center; }
|
|
372
|
+
main { flex: 1; position: relative; }
|
|
373
|
+
iframe, img { width: 100%; height: 100%; border: none; display: block; object-fit: contain; background: #fff; }
|
|
374
|
+
.placeholder { display: flex; align-items: center; justify-content: center;
|
|
375
|
+
height: 100%; color: #8b949e; font-size: 14px; }
|
|
376
|
+
</style>
|
|
377
|
+
</head>
|
|
378
|
+
<body>
|
|
379
|
+
<header>
|
|
380
|
+
<span class="title">aria-code canvas</span>
|
|
381
|
+
<span class="empty" id="status">waiting for the first artifact…</span>
|
|
382
|
+
<div class="stepper" id="stepper" style="display:none">
|
|
383
|
+
<button id="prev">‹</button>
|
|
384
|
+
<span id="pos"></span>
|
|
385
|
+
<button id="next">›</button>
|
|
386
|
+
</div>
|
|
387
|
+
</header>
|
|
388
|
+
<main id="main"><div class="placeholder">Run a report/chart command in aria-code — it will show up here automatically.</div></main>
|
|
389
|
+
<script>
|
|
390
|
+
let state = { threads: {}, active_thread_id: null };
|
|
391
|
+
let activeIndex = 0;
|
|
392
|
+
|
|
393
|
+
function render() {
|
|
394
|
+
const main = document.getElementById('main');
|
|
395
|
+
const status = document.getElementById('status');
|
|
396
|
+
const stepper = document.getElementById('stepper');
|
|
397
|
+
const thread = state.active_thread_id ? state.threads[state.active_thread_id] : null;
|
|
398
|
+
if (!thread || thread.versions.length === 0) {
|
|
399
|
+
main.innerHTML = '<div class="placeholder">Run a report/chart command in aria-code — it will show up here automatically.</div>';
|
|
400
|
+
status.textContent = 'waiting for the first artifact\\u2026';
|
|
401
|
+
stepper.style.display = 'none';
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
status.textContent = state.active_thread_id;
|
|
405
|
+
stepper.style.display = 'flex';
|
|
406
|
+
activeIndex = Math.max(0, Math.min(activeIndex, thread.versions.length - 1));
|
|
407
|
+
document.getElementById('pos').textContent = (activeIndex + 1) + ' / ' + thread.versions.length;
|
|
408
|
+
document.getElementById('prev').disabled = activeIndex <= 0;
|
|
409
|
+
document.getElementById('next').disabled = activeIndex >= thread.versions.length - 1;
|
|
410
|
+
const version = thread.versions[activeIndex];
|
|
411
|
+
const url = '/artifact/' + encodeURIComponent(state.active_thread_id) + '?v=' + version.index + '&_=' + Date.now();
|
|
412
|
+
if (version.kind === 'image') {
|
|
413
|
+
main.innerHTML = '<img src="' + url + '">';
|
|
414
|
+
} else {
|
|
415
|
+
// allow-scripts WITHOUT allow-same-origin. The two together are not
|
|
416
|
+
// additive — they cancel the sandbox: the framed document would run in
|
|
417
|
+
// this page's origin and could read /state, open /events, and reach the
|
|
418
|
+
// parent DOM. Artifact HTML is model-generated, so it gets an opaque
|
|
419
|
+
// origin and nothing else.
|
|
420
|
+
main.innerHTML = '<iframe src="' + url + '" sandbox="allow-scripts"></iframe>';
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async function refreshState(jumpToLatest) {
|
|
425
|
+
const resp = await fetch('/state');
|
|
426
|
+
state = await resp.json();
|
|
427
|
+
if (jumpToLatest && state.active_thread_id) {
|
|
428
|
+
const thread = state.threads[state.active_thread_id];
|
|
429
|
+
activeIndex = thread ? thread.versions.length - 1 : 0;
|
|
430
|
+
}
|
|
431
|
+
render();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
document.getElementById('prev').onclick = () => { activeIndex--; render(); };
|
|
435
|
+
document.getElementById('next').onclick = () => { activeIndex++; render(); };
|
|
436
|
+
|
|
437
|
+
const es = new EventSource('/events');
|
|
438
|
+
es.onmessage = (event) => {
|
|
439
|
+
const msg = JSON.parse(event.data);
|
|
440
|
+
if (msg.type === 'new-version') {
|
|
441
|
+
refreshState(true);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
refreshState(true);
|
|
446
|
+
</script>
|
|
447
|
+
</body>
|
|
448
|
+
</html>
|
|
449
|
+
"""
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Local-first feedback storage and privacy settings."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
from dataclasses import asdict, dataclass
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Dict, Iterable, List
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class PrivacySettings:
|
|
15
|
+
"""User-controlled data sharing settings."""
|
|
16
|
+
|
|
17
|
+
data_sharing: bool = False
|
|
18
|
+
feedback_upload: bool = False
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_config(cls, config: Dict[str, Any]) -> "PrivacySettings":
|
|
22
|
+
return cls(
|
|
23
|
+
data_sharing=bool(config.get("data_sharing", False)),
|
|
24
|
+
feedback_upload=bool(config.get("feedback_upload", False)),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def apply_to_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
28
|
+
config["data_sharing"] = self.data_sharing
|
|
29
|
+
config["feedback_upload"] = self.feedback_upload
|
|
30
|
+
return config
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class FeedbackRecord:
|
|
35
|
+
"""One local feedback event for a model response."""
|
|
36
|
+
|
|
37
|
+
rating: str
|
|
38
|
+
message: str
|
|
39
|
+
comment: str = ""
|
|
40
|
+
model: str = ""
|
|
41
|
+
session_id: str = ""
|
|
42
|
+
timestamp: str = ""
|
|
43
|
+
message_index: int | None = None
|
|
44
|
+
shared: bool = False
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def create(
|
|
48
|
+
cls,
|
|
49
|
+
*,
|
|
50
|
+
rating: str,
|
|
51
|
+
message: str,
|
|
52
|
+
comment: str = "",
|
|
53
|
+
model: str = "",
|
|
54
|
+
session_id: str = "",
|
|
55
|
+
message_index: int | None = None,
|
|
56
|
+
shared: bool = False,
|
|
57
|
+
) -> "FeedbackRecord":
|
|
58
|
+
return cls(
|
|
59
|
+
rating=rating,
|
|
60
|
+
message=message,
|
|
61
|
+
comment=comment,
|
|
62
|
+
model=model,
|
|
63
|
+
session_id=session_id,
|
|
64
|
+
timestamp=datetime.now().isoformat(),
|
|
65
|
+
message_index=message_index,
|
|
66
|
+
shared=shared,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def to_json(self) -> str:
|
|
70
|
+
return json.dumps(asdict(self), ensure_ascii=False)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class FeedbackStore:
|
|
74
|
+
"""Append-only local feedback store with explicit export/delete actions."""
|
|
75
|
+
|
|
76
|
+
def __init__(self, config_dir: str | Path) -> None:
|
|
77
|
+
self.config_dir = Path(config_dir).expanduser()
|
|
78
|
+
self.feedback_dir = self.config_dir / "feedback"
|
|
79
|
+
self.feedback_file = self.feedback_dir / "feedback.jsonl"
|
|
80
|
+
self.export_dir = self.feedback_dir / "exports"
|
|
81
|
+
|
|
82
|
+
def append(self, record: FeedbackRecord) -> Path:
|
|
83
|
+
self.feedback_dir.mkdir(parents=True, exist_ok=True)
|
|
84
|
+
with self.feedback_file.open("a", encoding="utf-8") as handle:
|
|
85
|
+
handle.write(record.to_json() + "\n")
|
|
86
|
+
return self.feedback_file
|
|
87
|
+
|
|
88
|
+
def iter_records(self) -> Iterable[Dict[str, Any]]:
|
|
89
|
+
if not self.feedback_file.exists():
|
|
90
|
+
return []
|
|
91
|
+
rows: List[Dict[str, Any]] = []
|
|
92
|
+
with self.feedback_file.open("r", encoding="utf-8") as handle:
|
|
93
|
+
for line in handle:
|
|
94
|
+
line = line.strip()
|
|
95
|
+
if not line:
|
|
96
|
+
continue
|
|
97
|
+
try:
|
|
98
|
+
rows.append(json.loads(line))
|
|
99
|
+
except json.JSONDecodeError:
|
|
100
|
+
continue
|
|
101
|
+
return rows
|
|
102
|
+
|
|
103
|
+
def count(self) -> int:
|
|
104
|
+
return sum(1 for _ in self.iter_records())
|
|
105
|
+
|
|
106
|
+
def export_jsonl(self, destination: str | Path | None = None) -> Path:
|
|
107
|
+
self.export_dir.mkdir(parents=True, exist_ok=True)
|
|
108
|
+
if destination is None:
|
|
109
|
+
stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
110
|
+
destination = self.export_dir / f"feedback_export_{stamp}.jsonl"
|
|
111
|
+
dest = Path(destination).expanduser()
|
|
112
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
113
|
+
if self.feedback_file.exists():
|
|
114
|
+
shutil.copyfile(self.feedback_file, dest)
|
|
115
|
+
else:
|
|
116
|
+
dest.write_text("", encoding="utf-8")
|
|
117
|
+
return dest
|
|
118
|
+
|
|
119
|
+
def delete_all(self) -> int:
|
|
120
|
+
count = self.count()
|
|
121
|
+
if self.feedback_file.exists():
|
|
122
|
+
self.feedback_file.unlink()
|
|
123
|
+
return count
|