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,522 @@
|
|
|
1
|
+
"""SQLite-backed run and event persistence for the Aria agent runtime."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import socket
|
|
9
|
+
import sqlite3
|
|
10
|
+
import time
|
|
11
|
+
import uuid
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, Iterable, Optional
|
|
15
|
+
|
|
16
|
+
from .run_state import (
|
|
17
|
+
ACTIVE_RUN_STATUSES,
|
|
18
|
+
RunStatus,
|
|
19
|
+
is_terminal,
|
|
20
|
+
normalize_run_status,
|
|
21
|
+
require_transition,
|
|
22
|
+
)
|
|
23
|
+
from aria_code.packages.aria_core.paths import aria_home
|
|
24
|
+
from .task_brief import TaskBrief, brief_digest
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# Compared with every non-alphanumeric character removed and lowercased, so
|
|
28
|
+
# apiKey, api-key and API_KEY are all the same field.
|
|
29
|
+
_SECRET_KEYS = {
|
|
30
|
+
"apikey",
|
|
31
|
+
"accesstoken",
|
|
32
|
+
"authtoken",
|
|
33
|
+
"refreshtoken",
|
|
34
|
+
"authorization",
|
|
35
|
+
"cookie",
|
|
36
|
+
"password",
|
|
37
|
+
"passwd",
|
|
38
|
+
"privatekey",
|
|
39
|
+
"secret",
|
|
40
|
+
"clientsecret",
|
|
41
|
+
"token",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Credentials inside free text: prompts, errors, tool output, commands. The
|
|
45
|
+
# shapes are those exec_events.py already masks on screen and in CI logs.
|
|
46
|
+
_SECRET_TEXT = (
|
|
47
|
+
(re.compile(r"(?i)\b(api[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|client[_-]?secret"
|
|
48
|
+
r"|token|password|passwd|secret)(\s*[=:]\s*)[\"']?[^\s'\",;]+"), r"\1\2[REDACTED]"),
|
|
49
|
+
(re.compile(r"(?i)\b(bearer|basic)(\s+)[A-Za-z0-9._~+/=-]+"), r"\1\2[REDACTED]"),
|
|
50
|
+
(re.compile(r"(?i)\b([a-z][a-z0-9+.-]*://)[^\s/:@]+:[^\s/@]+@"), r"\1[REDACTED]@"),
|
|
51
|
+
(re.compile(r"\b(?:sk|pk|rk)-[A-Za-z0-9_-]{8,}|\bgh[pousr]_[A-Za-z0-9]{12,}"
|
|
52
|
+
r"|\bAIza[0-9A-Za-z_-]{20,}|\bya29\.[0-9A-Za-z_-]+"), "[REDACTED]"),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _redact_text(value: str) -> str:
|
|
57
|
+
for pattern, replacement in _SECRET_TEXT:
|
|
58
|
+
value = pattern.sub(replacement, value)
|
|
59
|
+
return value
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _default_database_path() -> Path:
|
|
63
|
+
configured = os.getenv("ARIA_HOME")
|
|
64
|
+
if configured:
|
|
65
|
+
root = Path(configured).expanduser()
|
|
66
|
+
else:
|
|
67
|
+
legacy = aria_home()
|
|
68
|
+
root = legacy if legacy.exists() else Path.home() / ".aria-code"
|
|
69
|
+
return root / "runtime" / "runs.sqlite3"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _redact(value: Any) -> Any:
|
|
73
|
+
if isinstance(value, dict):
|
|
74
|
+
result = {}
|
|
75
|
+
for key, item in value.items():
|
|
76
|
+
normalized = re.sub(r"[^a-z0-9]", "", str(key).lower())
|
|
77
|
+
result[key] = "[REDACTED]" if normalized in _SECRET_KEYS else _redact(item)
|
|
78
|
+
return result
|
|
79
|
+
if isinstance(value, (list, tuple)):
|
|
80
|
+
return [_redact(item) for item in value]
|
|
81
|
+
if isinstance(value, str):
|
|
82
|
+
return _redact_text(value)
|
|
83
|
+
return value
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _json_dumps(value: Any) -> str:
|
|
87
|
+
return json.dumps(_redact(value), ensure_ascii=False, default=str, separators=(",", ":"))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _json_loads(value: str | None) -> Dict[str, Any]:
|
|
91
|
+
if not value:
|
|
92
|
+
return {}
|
|
93
|
+
try:
|
|
94
|
+
loaded = json.loads(value)
|
|
95
|
+
return loaded if isinstance(loaded, dict) else {"value": loaded}
|
|
96
|
+
except (TypeError, json.JSONDecodeError):
|
|
97
|
+
return {}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass(frozen=True)
|
|
101
|
+
class RunRecord:
|
|
102
|
+
run_id: str
|
|
103
|
+
session_id: str
|
|
104
|
+
status: RunStatus
|
|
105
|
+
prompt: str
|
|
106
|
+
workspace: str
|
|
107
|
+
provider: str
|
|
108
|
+
parent_run_id: Optional[str]
|
|
109
|
+
owner_pid: int
|
|
110
|
+
owner_host: str
|
|
111
|
+
created_at: float
|
|
112
|
+
updated_at: float
|
|
113
|
+
started_at: Optional[float]
|
|
114
|
+
finished_at: Optional[float]
|
|
115
|
+
error: str
|
|
116
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass(frozen=True)
|
|
120
|
+
class RunEventRecord:
|
|
121
|
+
event_id: str
|
|
122
|
+
run_id: str
|
|
123
|
+
sequence: int
|
|
124
|
+
event_type: str
|
|
125
|
+
timestamp: float
|
|
126
|
+
data: Dict[str, Any] = field(default_factory=dict)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class RunNotFoundError(KeyError):
|
|
130
|
+
"""Raised when a run identifier is not present in the durable store."""
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class RunStore:
|
|
134
|
+
"""Durable source of truth for runs and their append-only event streams."""
|
|
135
|
+
|
|
136
|
+
def __init__(self, database_path: Path | str | None = None) -> None:
|
|
137
|
+
self.database_path = Path(database_path or _default_database_path()).expanduser()
|
|
138
|
+
self.database_path.parent.mkdir(parents=True, exist_ok=True)
|
|
139
|
+
self._initialize()
|
|
140
|
+
|
|
141
|
+
def _connect(self) -> sqlite3.Connection:
|
|
142
|
+
connection = sqlite3.connect(str(self.database_path), timeout=10.0)
|
|
143
|
+
connection.row_factory = sqlite3.Row
|
|
144
|
+
connection.execute("PRAGMA foreign_keys = ON")
|
|
145
|
+
connection.execute("PRAGMA busy_timeout = 10000")
|
|
146
|
+
return connection
|
|
147
|
+
|
|
148
|
+
def _initialize(self) -> None:
|
|
149
|
+
with self._connect() as connection:
|
|
150
|
+
connection.execute("PRAGMA journal_mode = WAL")
|
|
151
|
+
connection.execute("PRAGMA synchronous = NORMAL")
|
|
152
|
+
connection.executescript(
|
|
153
|
+
"""
|
|
154
|
+
CREATE TABLE IF NOT EXISTS runs (
|
|
155
|
+
run_id TEXT PRIMARY KEY,
|
|
156
|
+
session_id TEXT NOT NULL,
|
|
157
|
+
parent_run_id TEXT,
|
|
158
|
+
status TEXT NOT NULL,
|
|
159
|
+
prompt TEXT NOT NULL,
|
|
160
|
+
workspace TEXT NOT NULL,
|
|
161
|
+
provider TEXT NOT NULL DEFAULT '',
|
|
162
|
+
owner_pid INTEGER NOT NULL,
|
|
163
|
+
owner_host TEXT NOT NULL,
|
|
164
|
+
created_at REAL NOT NULL,
|
|
165
|
+
updated_at REAL NOT NULL,
|
|
166
|
+
started_at REAL,
|
|
167
|
+
finished_at REAL,
|
|
168
|
+
error TEXT NOT NULL DEFAULT '',
|
|
169
|
+
metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
170
|
+
FOREIGN KEY(parent_run_id) REFERENCES runs(run_id)
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
CREATE TABLE IF NOT EXISTS run_events (
|
|
174
|
+
event_id TEXT PRIMARY KEY,
|
|
175
|
+
run_id TEXT NOT NULL,
|
|
176
|
+
sequence INTEGER NOT NULL,
|
|
177
|
+
event_type TEXT NOT NULL,
|
|
178
|
+
timestamp REAL NOT NULL,
|
|
179
|
+
data_json TEXT NOT NULL DEFAULT '{}',
|
|
180
|
+
UNIQUE(run_id, sequence),
|
|
181
|
+
FOREIGN KEY(run_id) REFERENCES runs(run_id) ON DELETE CASCADE
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
CREATE INDEX IF NOT EXISTS idx_runs_session_updated
|
|
185
|
+
ON runs(session_id, updated_at DESC);
|
|
186
|
+
CREATE INDEX IF NOT EXISTS idx_runs_status_updated
|
|
187
|
+
ON runs(status, updated_at DESC);
|
|
188
|
+
CREATE INDEX IF NOT EXISTS idx_run_events_run_sequence
|
|
189
|
+
ON run_events(run_id, sequence);
|
|
190
|
+
|
|
191
|
+
CREATE TABLE IF NOT EXISTS run_briefs (
|
|
192
|
+
run_id TEXT PRIMARY KEY REFERENCES runs(run_id) ON DELETE CASCADE,
|
|
193
|
+
brief_json TEXT NOT NULL,
|
|
194
|
+
sha256 TEXT NOT NULL
|
|
195
|
+
);
|
|
196
|
+
"""
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def _row_to_run(row: sqlite3.Row) -> RunRecord:
|
|
201
|
+
return RunRecord(
|
|
202
|
+
run_id=row["run_id"],
|
|
203
|
+
session_id=row["session_id"],
|
|
204
|
+
status=RunStatus(row["status"]),
|
|
205
|
+
prompt=row["prompt"],
|
|
206
|
+
workspace=row["workspace"],
|
|
207
|
+
provider=row["provider"],
|
|
208
|
+
parent_run_id=row["parent_run_id"],
|
|
209
|
+
owner_pid=int(row["owner_pid"]),
|
|
210
|
+
owner_host=row["owner_host"],
|
|
211
|
+
created_at=float(row["created_at"]),
|
|
212
|
+
updated_at=float(row["updated_at"]),
|
|
213
|
+
started_at=float(row["started_at"]) if row["started_at"] is not None else None,
|
|
214
|
+
finished_at=float(row["finished_at"]) if row["finished_at"] is not None else None,
|
|
215
|
+
error=row["error"],
|
|
216
|
+
metadata=_json_loads(row["metadata_json"]),
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
@staticmethod
|
|
220
|
+
def _row_to_event(row: sqlite3.Row) -> RunEventRecord:
|
|
221
|
+
return RunEventRecord(
|
|
222
|
+
event_id=row["event_id"],
|
|
223
|
+
run_id=row["run_id"],
|
|
224
|
+
sequence=int(row["sequence"]),
|
|
225
|
+
event_type=row["event_type"],
|
|
226
|
+
timestamp=float(row["timestamp"]),
|
|
227
|
+
data=_json_loads(row["data_json"]),
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
@staticmethod
|
|
231
|
+
def _append_event(
|
|
232
|
+
connection: sqlite3.Connection,
|
|
233
|
+
run_id: str,
|
|
234
|
+
event_type: str,
|
|
235
|
+
data: Dict[str, Any] | None = None,
|
|
236
|
+
*,
|
|
237
|
+
event_id: str | None = None,
|
|
238
|
+
timestamp: float | None = None,
|
|
239
|
+
) -> RunEventRecord:
|
|
240
|
+
sequence = int(connection.execute(
|
|
241
|
+
"SELECT COALESCE(MAX(sequence), 0) + 1 FROM run_events WHERE run_id = ?",
|
|
242
|
+
(run_id,),
|
|
243
|
+
).fetchone()[0])
|
|
244
|
+
record = RunEventRecord(
|
|
245
|
+
event_id=event_id or uuid.uuid4().hex,
|
|
246
|
+
run_id=run_id,
|
|
247
|
+
sequence=sequence,
|
|
248
|
+
event_type=event_type,
|
|
249
|
+
timestamp=timestamp or time.time(),
|
|
250
|
+
data=dict(data or {}),
|
|
251
|
+
)
|
|
252
|
+
connection.execute(
|
|
253
|
+
"""INSERT INTO run_events
|
|
254
|
+
(event_id, run_id, sequence, event_type, timestamp, data_json)
|
|
255
|
+
VALUES (?, ?, ?, ?, ?, ?)""",
|
|
256
|
+
(
|
|
257
|
+
record.event_id,
|
|
258
|
+
record.run_id,
|
|
259
|
+
record.sequence,
|
|
260
|
+
record.event_type,
|
|
261
|
+
record.timestamp,
|
|
262
|
+
_json_dumps(record.data),
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
connection.execute(
|
|
266
|
+
"UPDATE runs SET updated_at = ? WHERE run_id = ?",
|
|
267
|
+
(record.timestamp, run_id),
|
|
268
|
+
)
|
|
269
|
+
return record
|
|
270
|
+
|
|
271
|
+
def create_run(
|
|
272
|
+
self,
|
|
273
|
+
*,
|
|
274
|
+
session_id: str,
|
|
275
|
+
prompt: str,
|
|
276
|
+
workspace: str,
|
|
277
|
+
provider: str = "",
|
|
278
|
+
parent_run_id: str | None = None,
|
|
279
|
+
metadata: Dict[str, Any] | None = None,
|
|
280
|
+
run_id: str | None = None,
|
|
281
|
+
owner_pid: int | None = None,
|
|
282
|
+
owner_host: str | None = None,
|
|
283
|
+
task_brief: TaskBrief | None = None,
|
|
284
|
+
) -> RunRecord:
|
|
285
|
+
if task_brief is not None and not isinstance(task_brief, TaskBrief):
|
|
286
|
+
raise TypeError("task_brief must be a validated TaskBrief")
|
|
287
|
+
# Existing CLI callers automatically retain their initial goal. Preserve
|
|
288
|
+
# compatibility for empty/oversize legacy prompts without inventing one.
|
|
289
|
+
if task_brief is None and prompt.strip() and len(prompt.encode()) <= 65536:
|
|
290
|
+
task_brief = TaskBrief(goal=prompt)
|
|
291
|
+
brief_json = _json_dumps(task_brief.to_dict()) if task_brief is not None else None
|
|
292
|
+
digest = brief_digest(json.loads(brief_json)) if brief_json is not None else None
|
|
293
|
+
now = time.time()
|
|
294
|
+
identifier = run_id or uuid.uuid4().hex[:16]
|
|
295
|
+
pid = int(owner_pid if owner_pid is not None else os.getpid())
|
|
296
|
+
host = owner_host or socket.gethostname()
|
|
297
|
+
with self._connect() as connection:
|
|
298
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
299
|
+
connection.execute(
|
|
300
|
+
"""INSERT INTO runs
|
|
301
|
+
(run_id, session_id, parent_run_id, status, prompt, workspace,
|
|
302
|
+
provider, owner_pid, owner_host, created_at, updated_at,
|
|
303
|
+
started_at, finished_at, error, metadata_json)
|
|
304
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, '', ?)""",
|
|
305
|
+
(
|
|
306
|
+
identifier,
|
|
307
|
+
session_id,
|
|
308
|
+
parent_run_id,
|
|
309
|
+
RunStatus.QUEUED.value,
|
|
310
|
+
_redact_text(prompt),
|
|
311
|
+
workspace,
|
|
312
|
+
provider,
|
|
313
|
+
pid,
|
|
314
|
+
host,
|
|
315
|
+
now,
|
|
316
|
+
now,
|
|
317
|
+
_json_dumps(metadata or {}),
|
|
318
|
+
),
|
|
319
|
+
)
|
|
320
|
+
if brief_json is not None:
|
|
321
|
+
connection.execute("INSERT INTO run_briefs VALUES (?, ?, ?)",
|
|
322
|
+
(identifier, brief_json, digest))
|
|
323
|
+
self._append_event(connection, identifier, "run_created", {
|
|
324
|
+
"status": RunStatus.QUEUED.value,
|
|
325
|
+
"provider": provider,
|
|
326
|
+
"workspace": workspace,
|
|
327
|
+
"brief_sha256": digest,
|
|
328
|
+
}, timestamp=now)
|
|
329
|
+
record = self.get_run(identifier)
|
|
330
|
+
assert record is not None
|
|
331
|
+
return record
|
|
332
|
+
|
|
333
|
+
def get_task_brief(self, run_id: str) -> dict | None:
|
|
334
|
+
"""Read immutable intent; callers must apply their existing run access checks.
|
|
335
|
+
|
|
336
|
+
Missing brief means legacy/unrecorded intent, never inferred completion.
|
|
337
|
+
Hash checking detects corruption, not an adversary with database access.
|
|
338
|
+
"""
|
|
339
|
+
with self._connect() as connection:
|
|
340
|
+
row = connection.execute(
|
|
341
|
+
"""SELECT r.run_id, b.brief_json, b.sha256 FROM runs r
|
|
342
|
+
LEFT JOIN run_briefs b ON r.run_id=b.run_id WHERE r.run_id=?""",
|
|
343
|
+
(run_id,),
|
|
344
|
+
).fetchone()
|
|
345
|
+
if row is None:
|
|
346
|
+
raise RunNotFoundError(run_id)
|
|
347
|
+
if row["brief_json"] is None:
|
|
348
|
+
return None
|
|
349
|
+
try:
|
|
350
|
+
value = json.loads(row["brief_json"])
|
|
351
|
+
brief = TaskBrief.from_dict(value)
|
|
352
|
+
if brief_digest(value) != row["sha256"]:
|
|
353
|
+
raise ValueError("Digest mismatch")
|
|
354
|
+
except (TypeError, ValueError, UnicodeError) as exc:
|
|
355
|
+
raise ValueError("Stored task brief is invalid") from exc
|
|
356
|
+
return {"brief": brief.to_dict(), "sha256": row["sha256"],
|
|
357
|
+
"acceptance_defined": bool(brief.acceptance),
|
|
358
|
+
"verification_state": "unverified"}
|
|
359
|
+
|
|
360
|
+
def get_run(self, run_id: str) -> Optional[RunRecord]:
|
|
361
|
+
with self._connect() as connection:
|
|
362
|
+
row = connection.execute(
|
|
363
|
+
"SELECT * FROM runs WHERE run_id = ?", (run_id,)
|
|
364
|
+
).fetchone()
|
|
365
|
+
return self._row_to_run(row) if row is not None else None
|
|
366
|
+
|
|
367
|
+
def transition(
|
|
368
|
+
self,
|
|
369
|
+
run_id: str,
|
|
370
|
+
target: RunStatus | str,
|
|
371
|
+
*,
|
|
372
|
+
reason: str = "",
|
|
373
|
+
error: str | None = None,
|
|
374
|
+
provider: str | None = None,
|
|
375
|
+
data: Dict[str, Any] | None = None,
|
|
376
|
+
) -> RunRecord:
|
|
377
|
+
destination = normalize_run_status(target)
|
|
378
|
+
now = time.time()
|
|
379
|
+
with self._connect() as connection:
|
|
380
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
381
|
+
row = connection.execute(
|
|
382
|
+
"SELECT * FROM runs WHERE run_id = ?", (run_id,)
|
|
383
|
+
).fetchone()
|
|
384
|
+
if row is None:
|
|
385
|
+
raise RunNotFoundError(run_id)
|
|
386
|
+
current = RunStatus(row["status"])
|
|
387
|
+
require_transition(current, destination)
|
|
388
|
+
if current == destination:
|
|
389
|
+
return self._row_to_run(row)
|
|
390
|
+
|
|
391
|
+
started_at = row["started_at"]
|
|
392
|
+
if started_at is None and destination in {RunStatus.PLANNING, RunStatus.RUNNING}:
|
|
393
|
+
started_at = now
|
|
394
|
+
finished_at = now if is_terminal(destination) else None
|
|
395
|
+
if error is None and current is RunStatus.INTERRUPTED and destination in {
|
|
396
|
+
RunStatus.PLANNING,
|
|
397
|
+
RunStatus.RUNNING,
|
|
398
|
+
}:
|
|
399
|
+
next_error = ""
|
|
400
|
+
else:
|
|
401
|
+
next_error = row["error"] if error is None else _redact_text(str(error))
|
|
402
|
+
next_provider = row["provider"] if provider is None else str(provider)
|
|
403
|
+
connection.execute(
|
|
404
|
+
"""UPDATE runs
|
|
405
|
+
SET status = ?, provider = ?, updated_at = ?, started_at = ?,
|
|
406
|
+
finished_at = ?, error = ?
|
|
407
|
+
WHERE run_id = ?""",
|
|
408
|
+
(
|
|
409
|
+
destination.value,
|
|
410
|
+
next_provider,
|
|
411
|
+
now,
|
|
412
|
+
started_at,
|
|
413
|
+
finished_at,
|
|
414
|
+
next_error,
|
|
415
|
+
run_id,
|
|
416
|
+
),
|
|
417
|
+
)
|
|
418
|
+
event_data = {
|
|
419
|
+
"from": current.value,
|
|
420
|
+
"to": destination.value,
|
|
421
|
+
"reason": reason,
|
|
422
|
+
}
|
|
423
|
+
if data:
|
|
424
|
+
event_data.update(data)
|
|
425
|
+
self._append_event(connection, run_id, "run_state_changed", event_data, timestamp=now)
|
|
426
|
+
updated = connection.execute(
|
|
427
|
+
"SELECT * FROM runs WHERE run_id = ?", (run_id,)
|
|
428
|
+
).fetchone()
|
|
429
|
+
return self._row_to_run(updated)
|
|
430
|
+
|
|
431
|
+
def append_event(
|
|
432
|
+
self,
|
|
433
|
+
run_id: str,
|
|
434
|
+
event_type: str,
|
|
435
|
+
data: Dict[str, Any] | None = None,
|
|
436
|
+
*,
|
|
437
|
+
event_id: str | None = None,
|
|
438
|
+
timestamp: float | None = None,
|
|
439
|
+
) -> RunEventRecord:
|
|
440
|
+
with self._connect() as connection:
|
|
441
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
442
|
+
exists = connection.execute(
|
|
443
|
+
"SELECT 1 FROM runs WHERE run_id = ?", (run_id,)
|
|
444
|
+
).fetchone()
|
|
445
|
+
if exists is None:
|
|
446
|
+
raise RunNotFoundError(run_id)
|
|
447
|
+
return self._append_event(
|
|
448
|
+
connection,
|
|
449
|
+
run_id,
|
|
450
|
+
event_type,
|
|
451
|
+
data,
|
|
452
|
+
event_id=event_id,
|
|
453
|
+
timestamp=timestamp,
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
def events(self, run_id: str) -> list[RunEventRecord]:
|
|
457
|
+
with self._connect() as connection:
|
|
458
|
+
rows = connection.execute(
|
|
459
|
+
"SELECT * FROM run_events WHERE run_id = ? ORDER BY sequence",
|
|
460
|
+
(run_id,),
|
|
461
|
+
).fetchall()
|
|
462
|
+
return [self._row_to_event(row) for row in rows]
|
|
463
|
+
|
|
464
|
+
def list_runs(
|
|
465
|
+
self,
|
|
466
|
+
*,
|
|
467
|
+
session_id: str | None = None,
|
|
468
|
+
statuses: Iterable[RunStatus | str] | None = None,
|
|
469
|
+
limit: int = 50,
|
|
470
|
+
) -> list[RunRecord]:
|
|
471
|
+
clauses = []
|
|
472
|
+
values: list[Any] = []
|
|
473
|
+
if session_id:
|
|
474
|
+
clauses.append("session_id = ?")
|
|
475
|
+
values.append(session_id)
|
|
476
|
+
normalized = [normalize_run_status(status).value for status in (statuses or [])]
|
|
477
|
+
if normalized:
|
|
478
|
+
clauses.append(f"status IN ({','.join('?' for _ in normalized)})")
|
|
479
|
+
values.extend(normalized)
|
|
480
|
+
where = f" WHERE {' AND '.join(clauses)}" if clauses else ""
|
|
481
|
+
values.append(max(1, int(limit)))
|
|
482
|
+
with self._connect() as connection:
|
|
483
|
+
rows = connection.execute(
|
|
484
|
+
f"SELECT * FROM runs{where} ORDER BY updated_at DESC LIMIT ?",
|
|
485
|
+
values,
|
|
486
|
+
).fetchall()
|
|
487
|
+
return [self._row_to_run(row) for row in rows]
|
|
488
|
+
|
|
489
|
+
@staticmethod
|
|
490
|
+
def _pid_is_alive(pid: int) -> bool:
|
|
491
|
+
if pid <= 0:
|
|
492
|
+
return False
|
|
493
|
+
try:
|
|
494
|
+
os.kill(pid, 0)
|
|
495
|
+
except ProcessLookupError:
|
|
496
|
+
return False
|
|
497
|
+
except PermissionError:
|
|
498
|
+
return True
|
|
499
|
+
return True
|
|
500
|
+
|
|
501
|
+
def recover_orphaned_runs(self) -> list[str]:
|
|
502
|
+
"""Mark active runs from dead local processes as interrupted."""
|
|
503
|
+
host = socket.gethostname()
|
|
504
|
+
active_values = [status.value for status in ACTIVE_RUN_STATUSES]
|
|
505
|
+
placeholders = ",".join("?" for _ in active_values)
|
|
506
|
+
with self._connect() as connection:
|
|
507
|
+
rows = connection.execute(
|
|
508
|
+
f"SELECT run_id, owner_pid FROM runs "
|
|
509
|
+
f"WHERE owner_host = ? AND status IN ({placeholders})",
|
|
510
|
+
[host, *active_values],
|
|
511
|
+
).fetchall()
|
|
512
|
+
recovered = []
|
|
513
|
+
for row in rows:
|
|
514
|
+
if not self._pid_is_alive(int(row["owner_pid"])):
|
|
515
|
+
self.transition(
|
|
516
|
+
row["run_id"],
|
|
517
|
+
RunStatus.INTERRUPTED,
|
|
518
|
+
reason="owner_process_missing",
|
|
519
|
+
error="The process ended before the run reached a terminal state.",
|
|
520
|
+
)
|
|
521
|
+
recovered.append(row["run_id"])
|
|
522
|
+
return recovered
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Host-bound task reads on the existing RunStore, not a network auth service."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .run_store import RunNotFoundError, RunStore
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class RunGrant:
|
|
12
|
+
"""Construct only after host authentication and project/session authorization.
|
|
13
|
+
|
|
14
|
+
Never deserialize this grant from model arguments, HTTP bodies or headers.
|
|
15
|
+
Direct access to the underlying RunStore remains a trusted-host capability.
|
|
16
|
+
"""
|
|
17
|
+
organization: str
|
|
18
|
+
project: str
|
|
19
|
+
subject: str
|
|
20
|
+
session: str
|
|
21
|
+
workspace: str
|
|
22
|
+
|
|
23
|
+
def __post_init__(self):
|
|
24
|
+
for value in (self.organization, self.project, self.subject, self.session):
|
|
25
|
+
if not isinstance(value, str) or not value.strip() or len(value) > 128:
|
|
26
|
+
raise ValueError('Invalid host scope')
|
|
27
|
+
path = Path(self.workspace).resolve(strict=True)
|
|
28
|
+
if not path.is_dir():
|
|
29
|
+
raise ValueError('Workspace must be a directory')
|
|
30
|
+
object.__setattr__(self, 'workspace', str(path))
|
|
31
|
+
|
|
32
|
+
def values(self):
|
|
33
|
+
return (self.organization, self.project, self.subject, self.session, self.workspace)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ScopedRuns:
|
|
37
|
+
"""A session-owner-only adapter; does not execute or resume queued records.
|
|
38
|
+
|
|
39
|
+
Missing and out-of-scope IDs share one error. Bindings are immutable. Legacy
|
|
40
|
+
runs with no binding are denied, even when their metadata claims ownership.
|
|
41
|
+
"""
|
|
42
|
+
def __init__(self, store: RunStore, grant: RunGrant):
|
|
43
|
+
self._store = store
|
|
44
|
+
self._grant = grant
|
|
45
|
+
with store._connect() as connection:
|
|
46
|
+
connection.execute('''CREATE TABLE IF NOT EXISTS run_access (
|
|
47
|
+
run_id TEXT PRIMARY KEY REFERENCES runs(run_id) ON DELETE CASCADE,
|
|
48
|
+
organization TEXT NOT NULL, project TEXT NOT NULL,
|
|
49
|
+
subject TEXT NOT NULL, session TEXT NOT NULL, workspace TEXT NOT NULL
|
|
50
|
+
)''')
|
|
51
|
+
connection.execute('''CREATE INDEX IF NOT EXISTS idx_run_access_scope
|
|
52
|
+
ON run_access(organization, project, subject, session, workspace)''')
|
|
53
|
+
|
|
54
|
+
def create(self, prompt: str) -> dict:
|
|
55
|
+
if not isinstance(prompt, str) or not prompt.strip() or len(prompt.encode()) > 65536:
|
|
56
|
+
raise ValueError('Prompt must be 1..65536 UTF-8 bytes')
|
|
57
|
+
run = self._store.create_run(session_id=self._grant.session, prompt=prompt,
|
|
58
|
+
workspace=self._grant.workspace)
|
|
59
|
+
# A failure between these commits leaves an unbound record, which this
|
|
60
|
+
# adapter denies. Never infer a binding from existing run metadata.
|
|
61
|
+
with self._store._connect() as connection:
|
|
62
|
+
connection.execute('INSERT INTO run_access VALUES (?, ?, ?, ?, ?, ?)',
|
|
63
|
+
(run.run_id, *self._grant.values()))
|
|
64
|
+
return self.get(run.run_id)
|
|
65
|
+
|
|
66
|
+
def _require(self, run_id):
|
|
67
|
+
if not isinstance(run_id, str) or not run_id or len(run_id) > 128:
|
|
68
|
+
raise RunNotFoundError('Task not found')
|
|
69
|
+
with self._store._connect() as connection:
|
|
70
|
+
row = connection.execute('''SELECT run_id FROM run_access WHERE run_id=?
|
|
71
|
+
AND organization=? AND project=? AND subject=? AND session=? AND workspace=?''',
|
|
72
|
+
(run_id, *self._grant.values())).fetchone()
|
|
73
|
+
if row is None:
|
|
74
|
+
raise RunNotFoundError('Task not found')
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _view(run):
|
|
78
|
+
return {'version': 1, 'run_id': run.run_id, 'execution_state': run.status.value,
|
|
79
|
+
'verification_state': 'unverified', 'created_at': run.created_at,
|
|
80
|
+
'updated_at': run.updated_at, 'finished_at': run.finished_at}
|
|
81
|
+
|
|
82
|
+
def get(self, run_id: str) -> dict:
|
|
83
|
+
self._require(run_id)
|
|
84
|
+
record = self._store.get_run(run_id)
|
|
85
|
+
if record is None:
|
|
86
|
+
raise RunNotFoundError('Task not found')
|
|
87
|
+
return self._view(record)
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def _limit(limit):
|
|
91
|
+
if type(limit) is not int or not 1 <= limit <= 200:
|
|
92
|
+
raise ValueError('Limit must be an integer from 1 to 200')
|
|
93
|
+
return limit
|
|
94
|
+
|
|
95
|
+
def list(self, *, limit: int = 50) -> list[dict]:
|
|
96
|
+
self._limit(limit)
|
|
97
|
+
with self._store._connect() as connection:
|
|
98
|
+
rows = connection.execute('''SELECT r.* FROM runs r JOIN run_access a ON r.run_id=a.run_id
|
|
99
|
+
WHERE a.organization=? AND a.project=? AND a.subject=? AND a.session=? AND a.workspace=?
|
|
100
|
+
ORDER BY r.updated_at DESC, r.run_id LIMIT ?''',
|
|
101
|
+
(*self._grant.values(), limit)).fetchall()
|
|
102
|
+
return [self._view(self._store._row_to_run(row)) for row in rows]
|
|
103
|
+
|
|
104
|
+
def events(self, run_id: str, *, after: int = 0, limit: int = 50) -> list[dict]:
|
|
105
|
+
self._require(run_id)
|
|
106
|
+
self._limit(limit)
|
|
107
|
+
if type(after) is not int or after < 0:
|
|
108
|
+
raise ValueError('Cursor must be a nonnegative integer')
|
|
109
|
+
with self._store._connect() as connection:
|
|
110
|
+
rows = connection.execute('''SELECT sequence, event_type, timestamp FROM run_events
|
|
111
|
+
WHERE run_id=? AND sequence>? ORDER BY sequence LIMIT ?''',
|
|
112
|
+
(run_id, after, limit)).fetchall()
|
|
113
|
+
return [dict(row) for row in rows]
|