alysis-code 0.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- alysis_code/__init__.py +3 -0
- alysis_code/__main__.py +4 -0
- alysis_code/_build_info.py +14 -0
- alysis_code/account_login.py +468 -0
- alysis_code/agent/README.md +35 -0
- alysis_code/agent/__init__.py +11 -0
- alysis_code/agent/acceptance_contract.py +2217 -0
- alysis_code/agent/blast_radius.py +1403 -0
- alysis_code/agent/cache_keepalive.py +227 -0
- alysis_code/agent/completion_certificate.py +366 -0
- alysis_code/agent/completion_gate.py +306 -0
- alysis_code/agent/empty_response_stall.py +403 -0
- alysis_code/agent/errors.py +28 -0
- alysis_code/agent/llm_calls.py +475 -0
- alysis_code/agent/mutation_classification.py +227 -0
- alysis_code/agent/prompt_context.py +2508 -0
- alysis_code/agent/read_ledger.py +253 -0
- alysis_code/agent/regression_baseline.py +642 -0
- alysis_code/agent/reproduction_first.py +610 -0
- alysis_code/agent/sensitive_output.py +629 -0
- alysis_code/agent/session.py +3218 -0
- alysis_code/agent/steering.py +191 -0
- alysis_code/agent/subagent_execution.py +5177 -0
- alysis_code/agent/subagent_workspace.py +666 -0
- alysis_code/agent/tools_assembly.py +4728 -0
- alysis_code/agent/turn/__init__.py +101 -0
- alysis_code/agent/turn/core.py +8483 -0
- alysis_code/agent/turn/events.py +113 -0
- alysis_code/agent/turn/exploration.py +590 -0
- alysis_code/agent/turn/interventions.py +65 -0
- alysis_code/agent/turn/read_cache.py +420 -0
- alysis_code/agent/turn/snapshot.py +179 -0
- alysis_code/agent/turn_contract.py +661 -0
- alysis_code/agent/turn_path.py +129 -0
- alysis_code/agent/verification.py +2885 -0
- alysis_code/agent/verification_commands.py +512 -0
- alysis_code/agent/verification_evidence.py +738 -0
- alysis_code/agent_loop.py +693 -0
- alysis_code/agent_runtimes/__init__.py +51 -0
- alysis_code/agent_runtimes/base.py +114 -0
- alysis_code/agent_runtimes/builtins.py +129 -0
- alysis_code/agent_runtimes/codex_cli.py +664 -0
- alysis_code/agent_runtimes/host.py +263 -0
- alysis_code/agent_runtimes/registry.py +64 -0
- alysis_code/agent_runtimes/service.py +150 -0
- alysis_code/agentbox_client.py +416 -0
- alysis_code/agentbox_integration.py +310 -0
- alysis_code/alysis_cloud.py +152 -0
- alysis_code/approval_scope.py +276 -0
- alysis_code/assets/README.md +33 -0
- alysis_code/assets/__init__.py +126 -0
- alysis_code/assets/asset_read_core.py +281 -0
- alysis_code/assets/budget_allocator.py +456 -0
- alysis_code/assets/comprehender.py +759 -0
- alysis_code/assets/index.py +654 -0
- alysis_code/assets/ingestion.py +275 -0
- alysis_code/assets/legacy_migration.py +413 -0
- alysis_code/assets/models.py +263 -0
- alysis_code/assets/ocr.py +239 -0
- alysis_code/assets/owl/ascii/f-000.txt +13 -0
- alysis_code/assets/owl/ascii/f-001.txt +13 -0
- alysis_code/assets/owl/ascii/f-002.txt +13 -0
- alysis_code/assets/owl/ascii/f-003.txt +13 -0
- alysis_code/assets/owl/ascii/f-004.txt +13 -0
- alysis_code/assets/owl/ascii/f-005.txt +13 -0
- alysis_code/assets/owl/ascii/f-006.txt +13 -0
- alysis_code/assets/owl/ascii/f-007.txt +13 -0
- alysis_code/assets/owl/ascii/f-008.txt +13 -0
- alysis_code/assets/owl/ascii/f-009.txt +13 -0
- alysis_code/assets/owl/ascii/f-010.txt +13 -0
- alysis_code/assets/owl/ascii/f-011.txt +13 -0
- alysis_code/assets/owl/ascii/f-012.txt +13 -0
- alysis_code/assets/owl/ascii/f-013.txt +13 -0
- alysis_code/assets/owl/ascii/f-014.txt +13 -0
- alysis_code/assets/owl/ascii/f-015.txt +13 -0
- alysis_code/assets/owl/ascii/f-016.txt +13 -0
- alysis_code/assets/owl/ascii/f-017.txt +13 -0
- alysis_code/assets/owl/ascii/f-018.txt +13 -0
- alysis_code/assets/owl/ascii/f-019.txt +13 -0
- alysis_code/assets/owl/ascii/f-020.txt +13 -0
- alysis_code/assets/owl/index.html +98 -0
- alysis_code/assets/owl/show-owl.sh +761 -0
- alysis_code/assets/paths.py +49 -0
- alysis_code/assets/plan_binding.py +326 -0
- alysis_code/assets/planner_context.py +466 -0
- alysis_code/assets/planner_tools.py +184 -0
- alysis_code/assets/prompts.py +101 -0
- alysis_code/assets/replanner_context.py +239 -0
- alysis_code/assets/surface.py +521 -0
- alysis_code/assets/untrusted_content.py +48 -0
- alysis_code/assets/usage_logger.py +94 -0
- alysis_code/assets/worker_mirror.py +428 -0
- alysis_code/assets/worker_section.py +303 -0
- alysis_code/assets/worker_tools.py +468 -0
- alysis_code/atomic_io.py +83 -0
- alysis_code/auth_diagnostics.py +272 -0
- alysis_code/background_runner.py +366 -0
- alysis_code/branding.py +270 -0
- alysis_code/budget_policy.py +390 -0
- alysis_code/build_identity.py +465 -0
- alysis_code/builtin_hooks/__init__.py +7 -0
- alysis_code/builtin_hooks/notify_done_windows.py +65 -0
- alysis_code/bwrap_etc.py +76 -0
- alysis_code/cancellation.py +41 -0
- alysis_code/capabilities.py +137 -0
- alysis_code/chatgpt_codex_static_provider.py +133 -0
- alysis_code/cli.py +51 -0
- alysis_code/cli_impl/__init__.py +1 -0
- alysis_code/cli_impl/assets_cli.py +537 -0
- alysis_code/cli_impl/assets_modal.py +412 -0
- alysis_code/cli_impl/chat/__init__.py +156 -0
- alysis_code/cli_impl/chat/commands.py +2616 -0
- alysis_code/cli_impl/chat/loop.py +4508 -0
- alysis_code/cli_impl/chat/mid_turn_policy.py +125 -0
- alysis_code/cli_impl/chat/rendering.py +444 -0
- alysis_code/cli_impl/chat/state.py +124 -0
- alysis_code/cli_impl/chat_resume.py +830 -0
- alysis_code/cli_impl/chat_slash_completer.py +258 -0
- alysis_code/cli_impl/commands/__init__.py +11 -0
- alysis_code/cli_impl/commands/_shared.py +89 -0
- alysis_code/cli_impl/commands/auth.py +623 -0
- alysis_code/cli_impl/commands/chat_resume_helpers.py +1531 -0
- alysis_code/cli_impl/commands/chat_state.py +158 -0
- alysis_code/cli_impl/commands/chat_status.py +1248 -0
- alysis_code/cli_impl/commands/chat_terminal.py +942 -0
- alysis_code/cli_impl/commands/chat_tui_panels.py +1018 -0
- alysis_code/cli_impl/commands/cli_common.py +1223 -0
- alysis_code/cli_impl/commands/cli_surface.py +77 -0
- alysis_code/cli_impl/commands/config.py +131 -0
- alysis_code/cli_impl/commands/conventions.py +85 -0
- alysis_code/cli_impl/commands/execution_helpers.py +350 -0
- alysis_code/cli_impl/commands/extensions.py +401 -0
- alysis_code/cli_impl/commands/forge.py +1282 -0
- alysis_code/cli_impl/commands/forge_asset_view.py +121 -0
- alysis_code/cli_impl/commands/forge_helpers.py +1215 -0
- alysis_code/cli_impl/commands/hooks.py +737 -0
- alysis_code/cli_impl/commands/ide_bridge.py +31 -0
- alysis_code/cli_impl/commands/mcp.py +700 -0
- alysis_code/cli_impl/commands/profile.py +453 -0
- alysis_code/cli_impl/commands/prompt_helpers.py +307 -0
- alysis_code/cli_impl/commands/report.py +88 -0
- alysis_code/cli_impl/commands/root.py +1118 -0
- alysis_code/cli_impl/commands/sandbox.py +184 -0
- alysis_code/cli_impl/commands/server.py +54 -0
- alysis_code/cli_impl/commands/sessions.py +252 -0
- alysis_code/cli_impl/commands/skills.py +404 -0
- alysis_code/cli_impl/commands/startup.py +946 -0
- alysis_code/cli_impl/commands/tools.py +335 -0
- alysis_code/cli_impl/commands/update.py +364 -0
- alysis_code/cli_impl/commands/welcome.py +972 -0
- alysis_code/cli_impl/config_menu.py +3882 -0
- alysis_code/cli_impl/forge.py +4509 -0
- alysis_code/cli_impl/forge_recovery.py +485 -0
- alysis_code/cli_impl/setup_wizard.py +2409 -0
- alysis_code/cli_impl/tui/__init__.py +58 -0
- alysis_code/cli_impl/tui/app.py +4551 -0
- alysis_code/cli_impl/tui/config.py +32 -0
- alysis_code/cli_impl/tui/config_flow.py +2754 -0
- alysis_code/cli_impl/tui/config_overlay.py +566 -0
- alysis_code/cli_impl/tui/content.py +78 -0
- alysis_code/cli_impl/tui/footer.py +218 -0
- alysis_code/cli_impl/tui/forge_status.py +136 -0
- alysis_code/cli_impl/tui/markdown.py +244 -0
- alysis_code/cli_impl/tui/owl.py +109 -0
- alysis_code/cli_impl/tui/plan_meta.py +477 -0
- alysis_code/cli_impl/tui/setup_app.py +519 -0
- alysis_code/cli_impl/tui/setup_flow.py +1622 -0
- alysis_code/cli_impl/tui/state.py +101 -0
- alysis_code/cli_impl/tui/subagent_identity.py +66 -0
- alysis_code/cli_impl/tui/subagent_panel.py +186 -0
- alysis_code/cli_impl/tui/surface.py +796 -0
- alysis_code/cli_impl/tui/transcript.py +514 -0
- alysis_code/cli_impl/tui/update_prompt.py +79 -0
- alysis_code/cli_impl/tui/workspace_guard.py +384 -0
- alysis_code/clipboard.py +172 -0
- alysis_code/code_review.py +1211 -0
- alysis_code/compaction/__init__.py +28 -0
- alysis_code/compaction/conversation_compactor.py +2932 -0
- alysis_code/compaction/importance.py +177 -0
- alysis_code/compaction/settings.py +297 -0
- alysis_code/compaction/tool_output_offload.py +447 -0
- alysis_code/config.py +3509 -0
- alysis_code/conflict_auto_resolver.py +895 -0
- alysis_code/context/__init__.py +1 -0
- alysis_code/context/tool_schema_budgeter.py +220 -0
- alysis_code/crash_diagnostics.py +282 -0
- alysis_code/custom_tools/README.md +34 -0
- alysis_code/custom_tools/__init__.py +43 -0
- alysis_code/custom_tools/discovery.py +903 -0
- alysis_code/custom_tools/runtime.py +1516 -0
- alysis_code/custom_tools/session.py +227 -0
- alysis_code/custom_tools/trust.py +232 -0
- alysis_code/diff_paths.py +113 -0
- alysis_code/direction_change.py +293 -0
- alysis_code/dispatch_timing.py +306 -0
- alysis_code/durable_service_manager.py +1236 -0
- alysis_code/edit_discipline.py +659 -0
- alysis_code/error_text.py +73 -0
- alysis_code/execution_budget.py +411 -0
- alysis_code/execution_context.py +915 -0
- alysis_code/execution_deadline.py +1065 -0
- alysis_code/execution_shared.py +1904 -0
- alysis_code/extensions/README.md +30 -0
- alysis_code/extensions/__init__.py +93 -0
- alysis_code/extensions/activation.py +138 -0
- alysis_code/extensions/install.py +1436 -0
- alysis_code/extensions/manifest.py +487 -0
- alysis_code/extensions/models.py +74 -0
- alysis_code/extensions/paths.py +56 -0
- alysis_code/extensions/registry.json +4 -0
- alysis_code/extensions/registry.py +52 -0
- alysis_code/extensions/state.py +83 -0
- alysis_code/extensions/workspace_trust.py +101 -0
- alysis_code/failed_task_evidence.py +369 -0
- alysis_code/failure_category.py +315 -0
- alysis_code/feedback_report.py +1647 -0
- alysis_code/file_classification.py +485 -0
- alysis_code/forge.py +2064 -0
- alysis_code/forge_completion.py +362 -0
- alysis_code/forge_events.py +475 -0
- alysis_code/frontmatter_utils.py +95 -0
- alysis_code/git_evidence.py +1181 -0
- alysis_code/git_ops.py +560 -0
- alysis_code/git_safe.py +62 -0
- alysis_code/git_worktrees.py +190 -0
- alysis_code/hooks/README.md +33 -0
- alysis_code/hooks/__init__.py +67 -0
- alysis_code/hooks/audit.py +171 -0
- alysis_code/hooks/config.py +225 -0
- alysis_code/hooks/dispatcher.py +1110 -0
- alysis_code/hooks/models.py +447 -0
- alysis_code/hooks/trust.py +202 -0
- alysis_code/host_actions.py +543 -0
- alysis_code/host_browser.py +103 -0
- alysis_code/ide/__init__.py +5 -0
- alysis_code/ide/activity_events.py +399 -0
- alysis_code/ide/approvals.py +337 -0
- alysis_code/ide/artifacts.py +153 -0
- alysis_code/ide/browser_egress_proxy.py +1076 -0
- alysis_code/ide/cdp_websocket_transport.py +1192 -0
- alysis_code/ide/change_ledger.py +1721 -0
- alysis_code/ide/context_blocks.py +979 -0
- alysis_code/ide/event_stream.py +531 -0
- alysis_code/ide/forge_protocol.py +3112 -0
- alysis_code/ide/forge_request_ledger.py +737 -0
- alysis_code/ide/health.py +965 -0
- alysis_code/ide/managed_browser.py +2251 -0
- alysis_code/ide/management_protocol.py +3414 -0
- alysis_code/ide/mcp_oauth_coordinator.py +744 -0
- alysis_code/ide/mcp_oauth_lifecycle.py +1504 -0
- alysis_code/ide/prompt_queue.py +1070 -0
- alysis_code/ide/protocol.py +191 -0
- alysis_code/ide/resumable_swarm.py +1543 -0
- alysis_code/ide/session_search.py +295 -0
- alysis_code/ide/stdio_bridge.py +9935 -0
- alysis_code/ide/structured_state.py +1579 -0
- alysis_code/ide/swarm_protocol.py +816 -0
- alysis_code/integration_gate.py +506 -0
- alysis_code/interactive_input_guard.py +39 -0
- alysis_code/interactive_plan_mode.py +26 -0
- alysis_code/internal_artifacts.py +179 -0
- alysis_code/knowledge_base.py +1409 -0
- alysis_code/knowledge_capture.py +1190 -0
- alysis_code/knowledge_librarian.py +605 -0
- alysis_code/language_policy.py +34 -0
- alysis_code/litellm_static_provider.py +535 -0
- alysis_code/llm/__init__.py +1 -0
- alysis_code/llm/anthropic_messages.py +2288 -0
- alysis_code/llm/base.py +71 -0
- alysis_code/llm/cache_capabilities.py +985 -0
- alysis_code/llm/cache_control_blocks.py +244 -0
- alysis_code/llm/cache_policy.py +388 -0
- alysis_code/llm/factory.py +373 -0
- alysis_code/llm/gemini_generate_content.py +2652 -0
- alysis_code/llm/gemini_interactions.py +739 -0
- alysis_code/llm/metadata.py +450 -0
- alysis_code/llm/openai_compat.py +2947 -0
- alysis_code/llm/openai_responses.py +2604 -0
- alysis_code/llm/protocols.py +609 -0
- alysis_code/llm/provider_limits.py +525 -0
- alysis_code/llm/request_plan.py +389 -0
- alysis_code/llm/request_shape.py +238 -0
- alysis_code/llm/streaming.py +108 -0
- alysis_code/llm/temperature_compat.py +78 -0
- alysis_code/llm/types.py +195 -0
- alysis_code/llm/usage_normalization.py +222 -0
- alysis_code/llm_error_display.py +315 -0
- alysis_code/logging_redaction.py +326 -0
- alysis_code/managed_host_deadline.py +196 -0
- alysis_code/mcp/README.md +33 -0
- alysis_code/mcp/__init__.py +24 -0
- alysis_code/mcp/client.py +1137 -0
- alysis_code/mcp/config.py +597 -0
- alysis_code/mcp/errors.py +113 -0
- alysis_code/mcp/forge_scope.py +154 -0
- alysis_code/mcp/jsonrpc.py +214 -0
- alysis_code/mcp/manager.py +2308 -0
- alysis_code/mcp/models.py +666 -0
- alysis_code/mcp/oauth.py +972 -0
- alysis_code/mcp/oauth_runtime.py +310 -0
- alysis_code/mcp/oauth_store.py +276 -0
- alysis_code/mcp/prompts.py +329 -0
- alysis_code/mcp/resources.py +295 -0
- alysis_code/mcp/roots.py +106 -0
- alysis_code/mcp/server_requests.py +75 -0
- alysis_code/mcp/token_store.py +859 -0
- alysis_code/mcp/transport_http.py +1338 -0
- alysis_code/mcp/transport_stdio.py +1267 -0
- alysis_code/mcp/untrusted_content.py +119 -0
- alysis_code/merge_conflict_reviewer.py +729 -0
- alysis_code/model_catalog/__init__.py +1 -0
- alysis_code/model_catalog/chatgpt_codex_subscription_snapshot.json +186 -0
- alysis_code/model_catalog/litellm_model_prices_snapshot.json +44715 -0
- alysis_code/model_catalog/litellm_model_prices_snapshot.meta.json +17 -0
- alysis_code/model_metadata_policy.py +223 -0
- alysis_code/model_metadata_utils.py +103 -0
- alysis_code/model_registry.py +1420 -0
- alysis_code/model_router.py +147 -0
- alysis_code/permission_policy.py +1016 -0
- alysis_code/personas.py +451 -0
- alysis_code/pipeline_facts.py +233 -0
- alysis_code/plan_assistant.py +4763 -0
- alysis_code/plan_mode.py +393 -0
- alysis_code/plan_reconciliation.py +1228 -0
- alysis_code/plan_repair.py +652 -0
- alysis_code/plan_validation.py +1099 -0
- alysis_code/planning_constraints.py +904 -0
- alysis_code/policy.py +95 -0
- alysis_code/preview_server.py +457 -0
- alysis_code/process_reaping.py +566 -0
- alysis_code/profile_presets.py +1834 -0
- alysis_code/profiles.py +666 -0
- alysis_code/provider_auth/__init__.py +29 -0
- alysis_code/provider_auth/base.py +99 -0
- alysis_code/provider_auth/openai_codex.py +951 -0
- alysis_code/provider_auth/registry.py +76 -0
- alysis_code/provider_auth/store.py +125 -0
- alysis_code/provider_diagnostics.py +1209 -0
- alysis_code/provider_model_catalog.py +685 -0
- alysis_code/provider_telemetry.py +1699 -0
- alysis_code/provider_url.py +75 -0
- alysis_code/reasoning_contracts.py +911 -0
- alysis_code/remote_sync.py +350 -0
- alysis_code/replanning.py +1195 -0
- alysis_code/repo_scan.py +1152 -0
- alysis_code/request_estimation.py +296 -0
- alysis_code/review_gate.py +617 -0
- alysis_code/run_lock.py +1141 -0
- alysis_code/run_outcome.py +58 -0
- alysis_code/run_provenance.py +774 -0
- alysis_code/run_state.py +445 -0
- alysis_code/runtime_artifacts.py +116 -0
- alysis_code/runtime_context_features.py +78 -0
- alysis_code/runtime_kind.py +52 -0
- alysis_code/safety/__init__.py +11 -0
- alysis_code/safety/mcp_sanitize.py +29 -0
- alysis_code/safety/safe_http.py +297 -0
- alysis_code/safety/subagent_report.py +184 -0
- alysis_code/sandbox_doctor.py +682 -0
- alysis_code/sandbox_runner.py +1025 -0
- alysis_code/sandbox_settings.py +423 -0
- alysis_code/serialized_paths.py +355 -0
- alysis_code/server/__init__.py +3 -0
- alysis_code/server/app.py +367 -0
- alysis_code/server/auth.py +34 -0
- alysis_code/server/job_config.py +30 -0
- alysis_code/server/settings.py +215 -0
- alysis_code/server/store.py +193 -0
- alysis_code/server/worker_runner.py +657 -0
- alysis_code/service_persistence.py +355 -0
- alysis_code/session_artifacts.py +108 -0
- alysis_code/session_metrics.py +331 -0
- alysis_code/session_store.py +624 -0
- alysis_code/skills/README.md +34 -0
- alysis_code/skills/__init__.py +104 -0
- alysis_code/skills/conventions.py +84 -0
- alysis_code/skills/discovery.py +176 -0
- alysis_code/skills/eval_models.py +232 -0
- alysis_code/skills/eval_runner.py +372 -0
- alysis_code/skills/evals.py +1344 -0
- alysis_code/skills/install.py +293 -0
- alysis_code/skills/loader.py +118 -0
- alysis_code/skills/matching.py +103 -0
- alysis_code/skills/models.py +71 -0
- alysis_code/skills/paths.py +56 -0
- alysis_code/skills/prompting.py +500 -0
- alysis_code/skills/scaffold.py +142 -0
- alysis_code/skills/state.py +441 -0
- alysis_code/skills/transactions.py +125 -0
- alysis_code/skills/validation.py +304 -0
- alysis_code/step_budget.py +238 -0
- alysis_code/subagent_labels.py +49 -0
- alysis_code/subagents.py +1072 -0
- alysis_code/surface/__init__.py +80 -0
- alysis_code/surface/base.py +305 -0
- alysis_code/surface/console.py +387 -0
- alysis_code/surface/events.py +372 -0
- alysis_code/surface/hidden_surface.py +529 -0
- alysis_code/surface/noop_surface.py +219 -0
- alysis_code/surface/rich_surface.py +1555 -0
- alysis_code/surface/styles.py +67 -0
- alysis_code/surface/theme.py +455 -0
- alysis_code/surface/types.py +100 -0
- alysis_code/swarm_backend.py +926 -0
- alysis_code/swarm_orchestrator.py +4020 -0
- alysis_code/swarm_scheduler.py +441 -0
- alysis_code/swarm_trace.py +429 -0
- alysis_code/swarm_worker.py +2119 -0
- alysis_code/swarm_write_guard.py +348 -0
- alysis_code/task_dependencies.py +170 -0
- alysis_code/task_readiness.py +992 -0
- alysis_code/task_scope.py +2148 -0
- alysis_code/terminal_manager.py +762 -0
- alysis_code/terminal_ownership.py +460 -0
- alysis_code/text_normalization.py +30 -0
- alysis_code/token_budget.py +97 -0
- alysis_code/tools/README.md +34 -0
- alysis_code/tools/__init__.py +1 -0
- alysis_code/tools/artifacts.py +127 -0
- alysis_code/tools/availability.py +188 -0
- alysis_code/tools/fs.py +1456 -0
- alysis_code/tools/git.py +461 -0
- alysis_code/tools/history.py +229 -0
- alysis_code/tools/http_timeout.py +78 -0
- alysis_code/tools/image_generation.py +552 -0
- alysis_code/tools/registry.py +2936 -0
- alysis_code/tools/repo_map.py +476 -0
- alysis_code/tools/search.py +563 -0
- alysis_code/tools/shell.py +135 -0
- alysis_code/tools/symbols.py +1350 -0
- alysis_code/tools/test_discovery.py +643 -0
- alysis_code/tools/web.py +482 -0
- alysis_code/tools/web_search.py +2012 -0
- alysis_code/tools/web_search_dashscope.py +557 -0
- alysis_code/tools/web_search_ddgs.py +221 -0
- alysis_code/tools/web_search_provider_adapters.py +1429 -0
- alysis_code/tools/web_search_tavily.py +194 -0
- alysis_code/updates.py +933 -0
- alysis_code/usage_tracker.py +1990 -0
- alysis_code/verification_command_analysis.py +1004 -0
- alysis_code/verification_contract.py +574 -0
- alysis_code/verification_failure_summary.py +273 -0
- alysis_code/verification_repair.py +385 -0
- alysis_code/verify_gate.py +3129 -0
- alysis_code/web_research.py +1872 -0
- alysis_code/web_search_adapters.py +66 -0
- alysis_code/web_search_policy.py +27 -0
- alysis_code/workspace_binding.py +389 -0
- alysis_code/workspace_binding_ui.py +408 -0
- alysis_code/workspace_context.py +273 -0
- alysis_code/workspace_isolation.py +138 -0
- alysis_code/workspace_provisioning.py +455 -0
- alysis_code-0.13.0.dist-info/METADATA +507 -0
- alysis_code-0.13.0.dist-info/RECORD +458 -0
- alysis_code-0.13.0.dist-info/WHEEL +4 -0
- alysis_code-0.13.0.dist-info/entry_points.txt +3 -0
- alysis_code-0.13.0.dist-info/licenses/LICENSE +176 -0
- alysis_code-0.13.0.dist-info/licenses/NOTICE +4 -0
alysis_code/plan_mode.py
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .llm.types import LLMError
|
|
8
|
+
from .plan_assistant import compact_workspace_context_for_planner
|
|
9
|
+
from .usage_tracker import build_usage_record, usage_context_from_client_response
|
|
10
|
+
|
|
11
|
+
PLAN_CONTEXT_MAX_MESSAGES = 20
|
|
12
|
+
TOOL_RESULT_SUMMARY_CHARS = 200
|
|
13
|
+
_APPROVED_PLAN_MARKER = "Approved plan:\n"
|
|
14
|
+
_APPROVED_PLAN_EXECUTE_MARKER = "Now execute this task"
|
|
15
|
+
|
|
16
|
+
PLAN_MODE_SYSTEM_PROMPT = """You are an execution planner for a local coding agent.
|
|
17
|
+
|
|
18
|
+
Produce a concise, actionable draft implementation plan only.
|
|
19
|
+
|
|
20
|
+
Rules:
|
|
21
|
+
- Output 3-7 numbered steps.
|
|
22
|
+
- Mention likely files/modules to change when possible.
|
|
23
|
+
- Include verification/tests to run.
|
|
24
|
+
- If user-facing behavior changes, include docs/help/README updates.
|
|
25
|
+
- Keep scope reviewable and practical.
|
|
26
|
+
- Treat host-provided workspace context as the source of truth for repo structure and likely test commands.
|
|
27
|
+
- Mention repo-relative files, modules, frameworks, and markup only when they are supported by host-provided workspace context or prior conversation evidence.
|
|
28
|
+
- If the available context does not support an exact path/framework/file, describe the area generically instead of inventing details.
|
|
29
|
+
- Do not claim that commands were run or files were inspected.
|
|
30
|
+
- Do not execute tools or propose tool calls; planning text only.
|
|
31
|
+
- Choose the natural response language from the user's request and recent visible conversation.
|
|
32
|
+
- Follow explicit language/script requests when present.
|
|
33
|
+
- For empty, malformed, ambiguous, gibberish, or code-only input, use English with Latin script.
|
|
34
|
+
- Never translate code identifiers, file paths, CLI commands, config keys, or code blocks; keep them exactly as written.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _to_text(value: Any) -> str:
|
|
39
|
+
if isinstance(value, str):
|
|
40
|
+
return value
|
|
41
|
+
if value is None:
|
|
42
|
+
return ""
|
|
43
|
+
try:
|
|
44
|
+
return json.dumps(value, ensure_ascii=True)
|
|
45
|
+
except Exception:
|
|
46
|
+
return str(value)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _truncate(value: str, max_len: int) -> str:
|
|
50
|
+
text = value.strip()
|
|
51
|
+
if len(text) <= max_len:
|
|
52
|
+
return text
|
|
53
|
+
return text[:max_len].rstrip() + "..."
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _workspace_context_block(workspace_context: dict[str, Any] | None) -> str:
|
|
57
|
+
if workspace_context is None:
|
|
58
|
+
return ""
|
|
59
|
+
digest = compact_workspace_context_for_planner(workspace_context)
|
|
60
|
+
if not digest:
|
|
61
|
+
return ""
|
|
62
|
+
return (
|
|
63
|
+
"Workspace context JSON:\n"
|
|
64
|
+
f"{json.dumps(digest, ensure_ascii=False, sort_keys=True)}\n\n"
|
|
65
|
+
"Grounding rules:\n"
|
|
66
|
+
"- Only mention repo-relative files, modules, frameworks, or markup that this workspace context supports.\n"
|
|
67
|
+
"- Prefer the provided likely_test_commands when suggesting verification.\n"
|
|
68
|
+
"- If exact details are not supported here or in prior conversation context, describe the area generically."
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _normalize_plan_history_entries(
|
|
73
|
+
session_messages: list[dict[str, Any]],
|
|
74
|
+
*,
|
|
75
|
+
max_history_messages: int,
|
|
76
|
+
tool_result_chars: int,
|
|
77
|
+
) -> list[dict[str, str]]:
|
|
78
|
+
filtered: list[dict[str, str]] = []
|
|
79
|
+
tool_call_names: dict[str, str] = {}
|
|
80
|
+
|
|
81
|
+
for entry in session_messages:
|
|
82
|
+
if not isinstance(entry, dict):
|
|
83
|
+
continue
|
|
84
|
+
role = str(entry.get("role") or "").strip().lower()
|
|
85
|
+
|
|
86
|
+
if role == "user":
|
|
87
|
+
text = _to_text(entry.get("content"))
|
|
88
|
+
if text.strip():
|
|
89
|
+
filtered.append({"role": "user", "content": text})
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
if role == "assistant":
|
|
93
|
+
tool_calls_raw = entry.get("tool_calls")
|
|
94
|
+
tool_calls = tool_calls_raw if isinstance(tool_calls_raw, list) else []
|
|
95
|
+
if tool_calls:
|
|
96
|
+
for call in tool_calls:
|
|
97
|
+
if not isinstance(call, dict):
|
|
98
|
+
continue
|
|
99
|
+
call_id = str(call.get("id") or "").strip()
|
|
100
|
+
if not call_id:
|
|
101
|
+
continue
|
|
102
|
+
tool_call_names[call_id] = _extract_tool_call_name(call)
|
|
103
|
+
filtered.append(
|
|
104
|
+
{
|
|
105
|
+
"role": "assistant",
|
|
106
|
+
"content": _summarize_assistant_tool_calls(
|
|
107
|
+
entry,
|
|
108
|
+
tool_result_chars=tool_result_chars,
|
|
109
|
+
),
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
text = _to_text(entry.get("content"))
|
|
115
|
+
if text.strip():
|
|
116
|
+
filtered.append({"role": "assistant", "content": text})
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
if role == "tool":
|
|
120
|
+
filtered.append(
|
|
121
|
+
{
|
|
122
|
+
"role": "tool",
|
|
123
|
+
"content": _summarize_tool_result(
|
|
124
|
+
entry,
|
|
125
|
+
tool_call_names=tool_call_names,
|
|
126
|
+
tool_result_chars=tool_result_chars,
|
|
127
|
+
),
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if max_history_messages > 0 and len(filtered) > max_history_messages:
|
|
132
|
+
return filtered[-max_history_messages:]
|
|
133
|
+
return filtered
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _plan_context_user_prompt(
|
|
137
|
+
*,
|
|
138
|
+
history_entries: list[dict[str, str]],
|
|
139
|
+
workspace_context: dict[str, Any] | None,
|
|
140
|
+
user_message: str,
|
|
141
|
+
previous_plan: str | None = None,
|
|
142
|
+
feedback: str | None = None,
|
|
143
|
+
) -> str:
|
|
144
|
+
user_text = user_message.strip()
|
|
145
|
+
prompt_parts = [
|
|
146
|
+
"Recent conversation transcript JSON:",
|
|
147
|
+
json.dumps(history_entries, ensure_ascii=False, indent=2),
|
|
148
|
+
"",
|
|
149
|
+
]
|
|
150
|
+
workspace_block = _workspace_context_block(workspace_context)
|
|
151
|
+
if workspace_block:
|
|
152
|
+
prompt_parts.extend([workspace_block, ""])
|
|
153
|
+
prompt_parts.extend(
|
|
154
|
+
[
|
|
155
|
+
"Draft an execution plan for this request:",
|
|
156
|
+
user_text,
|
|
157
|
+
"",
|
|
158
|
+
"Return only the plan text in plain markdown.",
|
|
159
|
+
]
|
|
160
|
+
)
|
|
161
|
+
prev = (previous_plan or "").strip()
|
|
162
|
+
notes = (feedback or "").strip()
|
|
163
|
+
if prev and notes:
|
|
164
|
+
prompt_parts.extend(
|
|
165
|
+
[
|
|
166
|
+
"",
|
|
167
|
+
"Revise this previous draft plan based on user feedback.",
|
|
168
|
+
"Previous draft plan:",
|
|
169
|
+
prev,
|
|
170
|
+
"",
|
|
171
|
+
"User feedback:",
|
|
172
|
+
notes,
|
|
173
|
+
]
|
|
174
|
+
)
|
|
175
|
+
prompt_parts.extend(
|
|
176
|
+
[
|
|
177
|
+
"",
|
|
178
|
+
"Grounding rules:",
|
|
179
|
+
"- Base exact path/module/framework references only on host-provided workspace context or prior conversation evidence.",
|
|
180
|
+
"- If exact file/framework details are uncertain, keep the plan generic instead of guessing.",
|
|
181
|
+
]
|
|
182
|
+
)
|
|
183
|
+
return "\n".join(prompt_parts)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def extract_approved_plan_user_message(text: str) -> str | None:
|
|
187
|
+
clean = str(text or "").strip()
|
|
188
|
+
if not clean:
|
|
189
|
+
return None
|
|
190
|
+
plan_idx = clean.find(_APPROVED_PLAN_MARKER)
|
|
191
|
+
execute_idx = clean.find(_APPROVED_PLAN_EXECUTE_MARKER)
|
|
192
|
+
if plan_idx < 0 or execute_idx < 0 or plan_idx >= execute_idx:
|
|
193
|
+
return None
|
|
194
|
+
base = clean[:plan_idx].rstrip()
|
|
195
|
+
if not base:
|
|
196
|
+
return None
|
|
197
|
+
return base
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _extract_tool_call_name(raw_call: Any) -> str:
|
|
201
|
+
if not isinstance(raw_call, dict):
|
|
202
|
+
return "unknown_tool"
|
|
203
|
+
fn = raw_call.get("function")
|
|
204
|
+
if isinstance(fn, dict):
|
|
205
|
+
name = str(fn.get("name") or "").strip()
|
|
206
|
+
if name:
|
|
207
|
+
return name
|
|
208
|
+
name = str(raw_call.get("name") or "").strip()
|
|
209
|
+
return name or "unknown_tool"
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _summarize_assistant_tool_calls(
|
|
213
|
+
message: dict[str, Any],
|
|
214
|
+
*,
|
|
215
|
+
tool_result_chars: int,
|
|
216
|
+
) -> str:
|
|
217
|
+
tool_calls_raw = message.get("tool_calls")
|
|
218
|
+
tool_calls = tool_calls_raw if isinstance(tool_calls_raw, list) else []
|
|
219
|
+
names: list[str] = []
|
|
220
|
+
for item in tool_calls[:8]:
|
|
221
|
+
name = _extract_tool_call_name(item)
|
|
222
|
+
if name and name not in names:
|
|
223
|
+
names.append(name)
|
|
224
|
+
names_text = ", ".join(names) if names else "unknown_tool"
|
|
225
|
+
content = _to_text(message.get("content"))
|
|
226
|
+
if content.strip():
|
|
227
|
+
return (
|
|
228
|
+
f"Assistant requested tool calls: {names_text}. "
|
|
229
|
+
f"Assistant note: {_truncate(content, tool_result_chars)}"
|
|
230
|
+
)
|
|
231
|
+
return f"Assistant requested tool calls: {names_text}."
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _summarize_tool_result(
|
|
235
|
+
message: dict[str, Any],
|
|
236
|
+
*,
|
|
237
|
+
tool_call_names: dict[str, str],
|
|
238
|
+
tool_result_chars: int,
|
|
239
|
+
) -> str:
|
|
240
|
+
call_id = str(message.get("tool_call_id") or "").strip()
|
|
241
|
+
tool_name = tool_call_names.get(call_id) or "unknown_tool"
|
|
242
|
+
content = _to_text(message.get("content"))
|
|
243
|
+
if not content.strip():
|
|
244
|
+
return f"Tool result ({tool_name}): (empty)"
|
|
245
|
+
return f"Tool result ({tool_name}): {_truncate(content, tool_result_chars)}"
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def build_plan_context_messages(
|
|
249
|
+
session_messages: list[dict[str, Any]],
|
|
250
|
+
user_message: str,
|
|
251
|
+
previous_plan: str | None = None,
|
|
252
|
+
feedback: str | None = None,
|
|
253
|
+
workspace_context: dict[str, Any] | None = None,
|
|
254
|
+
*,
|
|
255
|
+
plan_system_prompt: str = PLAN_MODE_SYSTEM_PROMPT,
|
|
256
|
+
max_history_messages: int = PLAN_CONTEXT_MAX_MESSAGES,
|
|
257
|
+
tool_result_chars: int = TOOL_RESULT_SUMMARY_CHARS,
|
|
258
|
+
) -> list[dict[str, Any]]:
|
|
259
|
+
# Keep planner transport invariant simple and provider-safe: exactly one system
|
|
260
|
+
# message and one user message, with capped normalized history serialized into
|
|
261
|
+
# the final user prompt rather than flattened as chat-message turns.
|
|
262
|
+
history_entries = _normalize_plan_history_entries(
|
|
263
|
+
session_messages,
|
|
264
|
+
max_history_messages=max_history_messages,
|
|
265
|
+
tool_result_chars=tool_result_chars,
|
|
266
|
+
)
|
|
267
|
+
return [
|
|
268
|
+
{"role": "system", "content": plan_system_prompt},
|
|
269
|
+
{
|
|
270
|
+
"role": "user",
|
|
271
|
+
"content": _plan_context_user_prompt(
|
|
272
|
+
history_entries=history_entries,
|
|
273
|
+
workspace_context=workspace_context,
|
|
274
|
+
user_message=user_message,
|
|
275
|
+
previous_plan=previous_plan,
|
|
276
|
+
feedback=feedback,
|
|
277
|
+
),
|
|
278
|
+
},
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def generate_plan_draft(
|
|
283
|
+
client: Any,
|
|
284
|
+
session_messages: list[dict[str, Any]],
|
|
285
|
+
user_message: str,
|
|
286
|
+
previous_plan: str | None = None,
|
|
287
|
+
feedback: str | None = None,
|
|
288
|
+
workspace_context: dict[str, Any] | None = None,
|
|
289
|
+
stream: bool = False,
|
|
290
|
+
on_text_delta: Callable[[str], None] | None = None,
|
|
291
|
+
*,
|
|
292
|
+
details: dict[str, Any] | None = None,
|
|
293
|
+
) -> str:
|
|
294
|
+
if client is None:
|
|
295
|
+
raise RuntimeError("Plan generation unavailable: missing session client.")
|
|
296
|
+
|
|
297
|
+
request_messages = build_plan_context_messages(
|
|
298
|
+
session_messages=session_messages,
|
|
299
|
+
user_message=user_message,
|
|
300
|
+
previous_plan=previous_plan,
|
|
301
|
+
feedback=feedback,
|
|
302
|
+
workspace_context=workspace_context,
|
|
303
|
+
)
|
|
304
|
+
try:
|
|
305
|
+
response = client.chat(
|
|
306
|
+
messages=request_messages,
|
|
307
|
+
tools=None,
|
|
308
|
+
stream=bool(stream),
|
|
309
|
+
on_text_delta=on_text_delta if stream else None,
|
|
310
|
+
)
|
|
311
|
+
except LLMError as e:
|
|
312
|
+
raise RuntimeError(f"Plan generation failed: {e}") from e
|
|
313
|
+
|
|
314
|
+
plan_text = str(getattr(response, "content", "") or "").strip()
|
|
315
|
+
if not plan_text:
|
|
316
|
+
raise RuntimeError("Plan generation returned an empty response.")
|
|
317
|
+
|
|
318
|
+
if details is not None:
|
|
319
|
+
details["request_messages"] = request_messages
|
|
320
|
+
details["response"] = response
|
|
321
|
+
return plan_text
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def instruction_with_approved_plan(*, user_message: str, approved_plan: str) -> str:
|
|
325
|
+
base = user_message.strip()
|
|
326
|
+
plan_text = approved_plan.strip()
|
|
327
|
+
if not plan_text:
|
|
328
|
+
return base
|
|
329
|
+
return (
|
|
330
|
+
f"{base}\n\n"
|
|
331
|
+
f"{_APPROVED_PLAN_MARKER}{plan_text}\n\n"
|
|
332
|
+
"Now execute this task in the repository and follow the approved plan."
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def record_plan_usage(
|
|
337
|
+
*,
|
|
338
|
+
session: Any,
|
|
339
|
+
request_messages: list[dict[str, Any]],
|
|
340
|
+
response: Any,
|
|
341
|
+
) -> None:
|
|
342
|
+
try:
|
|
343
|
+
requested_model = str(getattr(getattr(session, "client", None), "model", "") or "").strip()
|
|
344
|
+
if not requested_model:
|
|
345
|
+
return
|
|
346
|
+
registry = getattr(session, "model_registry", None)
|
|
347
|
+
usage_summary = getattr(session, "usage_summary", None)
|
|
348
|
+
if registry is None or usage_summary is None:
|
|
349
|
+
return
|
|
350
|
+
response_tool_calls = []
|
|
351
|
+
for tc in list(getattr(response, "tool_calls", []) or []):
|
|
352
|
+
response_tool_calls.append(
|
|
353
|
+
{
|
|
354
|
+
"id": str(getattr(tc, "id", "") or ""),
|
|
355
|
+
"name": str(getattr(tc, "name", "") or ""),
|
|
356
|
+
"arguments": getattr(tc, "arguments", {}) or {},
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
usage = getattr(response, "usage", None)
|
|
360
|
+
usage_record = build_usage_record(
|
|
361
|
+
role="plan",
|
|
362
|
+
requested_model=requested_model,
|
|
363
|
+
response_model=getattr(response, "response_model", None),
|
|
364
|
+
messages=request_messages,
|
|
365
|
+
response_content=str(getattr(response, "content", "") or ""),
|
|
366
|
+
response_tool_calls=response_tool_calls,
|
|
367
|
+
api_prompt_tokens=(
|
|
368
|
+
getattr(usage, "prompt_tokens", None) if usage is not None else None
|
|
369
|
+
),
|
|
370
|
+
api_usage=usage,
|
|
371
|
+
api_cached_prompt_tokens=(
|
|
372
|
+
getattr(usage, "cached_prompt_tokens", None) if usage is not None else None
|
|
373
|
+
),
|
|
374
|
+
api_completion_tokens=(
|
|
375
|
+
getattr(usage, "completion_tokens", None) if usage is not None else None
|
|
376
|
+
),
|
|
377
|
+
api_total_tokens=(getattr(usage, "total_tokens", None) if usage is not None else None),
|
|
378
|
+
registry=registry,
|
|
379
|
+
**usage_context_from_client_response(
|
|
380
|
+
client=getattr(session, "client", None),
|
|
381
|
+
response=response,
|
|
382
|
+
operation="plan_llm",
|
|
383
|
+
),
|
|
384
|
+
)
|
|
385
|
+
add_record = getattr(usage_summary, "add_record", None)
|
|
386
|
+
if callable(add_record):
|
|
387
|
+
add_record(usage_record)
|
|
388
|
+
store = getattr(session, "store", None)
|
|
389
|
+
append = getattr(store, "append", None)
|
|
390
|
+
if callable(append):
|
|
391
|
+
append("llm_usage", usage_record.to_payload())
|
|
392
|
+
except Exception:
|
|
393
|
+
return
|