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
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..ide.protocol import redact_secrets
|
|
6
|
+
from ..session_artifacts import SessionArtifactLayout
|
|
7
|
+
|
|
8
|
+
DEFAULT_SESSION_ARTIFACT_READ_BYTES = 64 * 1024
|
|
9
|
+
MAX_SESSION_ARTIFACT_READ_BYTES = 1024 * 1024
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SessionArtifactReadError(RuntimeError):
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
message: str,
|
|
16
|
+
*,
|
|
17
|
+
error_code: str = "session_artifact_read_failed",
|
|
18
|
+
guidance: str | None = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
self.result_payload: dict[str, Any] = {
|
|
21
|
+
"error": message,
|
|
22
|
+
"error_code": error_code,
|
|
23
|
+
"terminal": True,
|
|
24
|
+
"retryable": False,
|
|
25
|
+
}
|
|
26
|
+
if guidance:
|
|
27
|
+
self.result_payload["guidance"] = guidance
|
|
28
|
+
super().__init__(message)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _invalid_locator_error(exc: BaseException) -> SessionArtifactReadError:
|
|
32
|
+
guidance = (
|
|
33
|
+
"Use only a locator returned by a tool in this session. Guessing a locator will not work."
|
|
34
|
+
)
|
|
35
|
+
return SessionArtifactReadError(
|
|
36
|
+
f"Invalid session artifact locator: {exc}. A valid locator starts with "
|
|
37
|
+
"session_artifacts/ and uses relative POSIX path segments. "
|
|
38
|
+
f"{guidance}",
|
|
39
|
+
error_code="invalid_session_artifact_locator",
|
|
40
|
+
guidance=guidance,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _bounded_max_bytes(value: Any) -> int:
|
|
45
|
+
if value is None or value == "":
|
|
46
|
+
return DEFAULT_SESSION_ARTIFACT_READ_BYTES
|
|
47
|
+
try:
|
|
48
|
+
parsed = int(value)
|
|
49
|
+
except (TypeError, ValueError) as exc:
|
|
50
|
+
raise SessionArtifactReadError("Session artifact max_bytes must be an integer.") from exc
|
|
51
|
+
return max(1, min(parsed, MAX_SESSION_ARTIFACT_READ_BYTES))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _bounded_offset(value: Any) -> int:
|
|
55
|
+
if value is None or value == "":
|
|
56
|
+
return 0
|
|
57
|
+
try:
|
|
58
|
+
parsed = int(value)
|
|
59
|
+
except (TypeError, ValueError) as exc:
|
|
60
|
+
raise SessionArtifactReadError("Session artifact offset must be an integer.") from exc
|
|
61
|
+
if parsed < 0:
|
|
62
|
+
raise SessionArtifactReadError("Session artifact offset must be non-negative.")
|
|
63
|
+
return parsed
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def session_artifact_read(
|
|
67
|
+
*,
|
|
68
|
+
artifact_layout: SessionArtifactLayout,
|
|
69
|
+
locator: str,
|
|
70
|
+
max_bytes: Any = DEFAULT_SESSION_ARTIFACT_READ_BYTES,
|
|
71
|
+
offset: Any = 0,
|
|
72
|
+
) -> dict[str, Any]:
|
|
73
|
+
"""Read one bounded artifact addressed only by its current-session locator."""
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
artifact_path = artifact_layout.resolve_locator(locator)
|
|
77
|
+
except (OSError, RuntimeError, ValueError) as exc:
|
|
78
|
+
raise _invalid_locator_error(exc) from exc
|
|
79
|
+
|
|
80
|
+
read_limit = _bounded_max_bytes(max_bytes)
|
|
81
|
+
read_offset = _bounded_offset(offset)
|
|
82
|
+
if not artifact_path.exists() or not artifact_path.is_file():
|
|
83
|
+
guidance = (
|
|
84
|
+
"The session that produced the locator must read it. Do not retry this "
|
|
85
|
+
"locator from the current session."
|
|
86
|
+
)
|
|
87
|
+
raise SessionArtifactReadError(
|
|
88
|
+
"Session artifact is not present in this session and may belong to a "
|
|
89
|
+
f"different session. {guidance}",
|
|
90
|
+
error_code="session_artifact_session_mismatch",
|
|
91
|
+
guidance=guidance,
|
|
92
|
+
)
|
|
93
|
+
try:
|
|
94
|
+
size = artifact_path.stat().st_size
|
|
95
|
+
if read_offset >= size:
|
|
96
|
+
payload = b""
|
|
97
|
+
else:
|
|
98
|
+
with artifact_path.open("rb") as handle:
|
|
99
|
+
handle.seek(read_offset)
|
|
100
|
+
payload = handle.read(read_limit)
|
|
101
|
+
except OSError as exc:
|
|
102
|
+
raise SessionArtifactReadError("Session artifact was not readable.") from exc
|
|
103
|
+
|
|
104
|
+
bytes_returned = len(payload)
|
|
105
|
+
has_more = read_offset + bytes_returned < size
|
|
106
|
+
content = payload.decode("utf-8", errors="replace")
|
|
107
|
+
return {
|
|
108
|
+
"locator": str(locator),
|
|
109
|
+
"offset": read_offset,
|
|
110
|
+
"bytes_returned": bytes_returned,
|
|
111
|
+
"size": size,
|
|
112
|
+
"size_bytes": size,
|
|
113
|
+
"has_more": has_more,
|
|
114
|
+
"next_offset": read_offset + bytes_returned if has_more else None,
|
|
115
|
+
"truncated": has_more,
|
|
116
|
+
"max_bytes": read_limit,
|
|
117
|
+
"encoding": "utf-8-replace",
|
|
118
|
+
"content": redact_secrets(content),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
__all__ = [
|
|
123
|
+
"DEFAULT_SESSION_ARTIFACT_READ_BYTES",
|
|
124
|
+
"MAX_SESSION_ARTIFACT_READ_BYTES",
|
|
125
|
+
"SessionArtifactReadError",
|
|
126
|
+
"session_artifact_read",
|
|
127
|
+
]
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from dataclasses import dataclass, replace
|
|
5
|
+
from threading import RLock
|
|
6
|
+
from typing import Any, Literal, TypedDict, TypeGuard
|
|
7
|
+
|
|
8
|
+
LOGGER = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ToolUnavailableResult(TypedDict):
|
|
12
|
+
"""Structured non-error result returned when an optional tool is unavailable."""
|
|
13
|
+
|
|
14
|
+
status: Literal["tool_unavailable"]
|
|
15
|
+
tool: str
|
|
16
|
+
reason: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
WEB_TOOL_NAMES = frozenset({"web_fetch", "web_search"})
|
|
20
|
+
WEB_UNAVAILABLE_OBSERVATION = (
|
|
21
|
+
"Web tools are unavailable for the rest of this turn — "
|
|
22
|
+
"continue with the information already gathered."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# A web-tool failure is *recoverable* when the model can fix it by changing its own
|
|
26
|
+
# arguments (input validation, provenance rejection with retry guidance). Those are
|
|
27
|
+
# returned to the model as plain errors; only unrecoverable failures (backend
|
|
28
|
+
# connectivity/availability after fallback exhaustion) disable web tools for the turn.
|
|
29
|
+
_WEB_RECOVERY_HINT_KEYS = ("guidance", "error_code", "fetchable_urls", "recoverable")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def is_recoverable_web_tool_error(error: BaseException) -> bool:
|
|
33
|
+
"""True when the exception marks itself as fixable by a corrected retry."""
|
|
34
|
+
|
|
35
|
+
return bool(getattr(error, "recoverable", False))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def is_recoverable_web_error_result(value: Any) -> bool:
|
|
39
|
+
"""True for structured web-tool error dicts that carry retry/recovery guidance."""
|
|
40
|
+
|
|
41
|
+
if not isinstance(value, dict) or "error" not in value:
|
|
42
|
+
return False
|
|
43
|
+
return any(key in value for key in _WEB_RECOVERY_HINT_KEYS)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class ToolAvailability:
|
|
48
|
+
name: str
|
|
49
|
+
optional: bool
|
|
50
|
+
unavailable_reason: str | None = None
|
|
51
|
+
unavailable_logged: bool = False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ToolSetupError(RuntimeError):
|
|
55
|
+
"""Raised when a required tool is unavailable at startup."""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
_AVAILABILITY_BY_NAME: dict[str, ToolAvailability] = {}
|
|
59
|
+
_LOCK = RLock()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _clean_tool_name(name: str) -> str:
|
|
63
|
+
clean = str(name or "").strip()
|
|
64
|
+
if not clean:
|
|
65
|
+
raise ValueError("tool name must be non-empty")
|
|
66
|
+
return clean
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _availability_key(name: str) -> str:
|
|
70
|
+
return _clean_tool_name(name).casefold()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _clean_unavailable_reason(reason: str) -> str:
|
|
74
|
+
clean = str(reason or "").strip()
|
|
75
|
+
if not clean or clean.casefold() == "unavailable":
|
|
76
|
+
raise ValueError("tool unavailable reason must be concrete and non-empty")
|
|
77
|
+
return clean
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def register_tool_availability(name: str, *, optional: bool) -> ToolAvailability:
|
|
81
|
+
clean_name = _clean_tool_name(name)
|
|
82
|
+
key = clean_name.casefold()
|
|
83
|
+
with _LOCK:
|
|
84
|
+
existing = _AVAILABILITY_BY_NAME.get(key)
|
|
85
|
+
if existing is None:
|
|
86
|
+
state = ToolAvailability(name=clean_name, optional=bool(optional))
|
|
87
|
+
else:
|
|
88
|
+
state = replace(existing, name=clean_name, optional=bool(optional))
|
|
89
|
+
_AVAILABILITY_BY_NAME[key] = state
|
|
90
|
+
if state.unavailable_reason and not state.optional:
|
|
91
|
+
raise ToolSetupError(
|
|
92
|
+
f"tool {state.name} is required but unavailable: {state.unavailable_reason}"
|
|
93
|
+
)
|
|
94
|
+
return state
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def mark_available(name: str) -> ToolAvailability:
|
|
98
|
+
clean_name = _clean_tool_name(name)
|
|
99
|
+
key = clean_name.casefold()
|
|
100
|
+
with _LOCK:
|
|
101
|
+
existing = _AVAILABILITY_BY_NAME.get(key)
|
|
102
|
+
optional = existing.optional if existing is not None else True
|
|
103
|
+
state = ToolAvailability(name=clean_name, optional=optional)
|
|
104
|
+
_AVAILABILITY_BY_NAME[key] = state
|
|
105
|
+
return state
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def mark_unavailable(name: str, reason: str) -> ToolAvailability:
|
|
109
|
+
clean_name = _clean_tool_name(name)
|
|
110
|
+
clean_reason = _clean_unavailable_reason(reason)
|
|
111
|
+
key = clean_name.casefold()
|
|
112
|
+
with _LOCK:
|
|
113
|
+
existing = _AVAILABILITY_BY_NAME.get(key)
|
|
114
|
+
state = existing or ToolAvailability(name=clean_name, optional=True)
|
|
115
|
+
if not state.optional:
|
|
116
|
+
raise ToolSetupError(f"tool {state.name} is required but unavailable: {clean_reason}")
|
|
117
|
+
should_log = not state.unavailable_logged
|
|
118
|
+
state = replace(
|
|
119
|
+
state,
|
|
120
|
+
name=clean_name,
|
|
121
|
+
unavailable_reason=clean_reason,
|
|
122
|
+
unavailable_logged=True,
|
|
123
|
+
)
|
|
124
|
+
_AVAILABILITY_BY_NAME[key] = state
|
|
125
|
+
if should_log:
|
|
126
|
+
LOGGER.info(
|
|
127
|
+
"optional_tool_unavailable tool=%s reason=%s",
|
|
128
|
+
state.name,
|
|
129
|
+
state.unavailable_reason,
|
|
130
|
+
)
|
|
131
|
+
return state
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def get_tool_availability(name: str) -> ToolAvailability | None:
|
|
135
|
+
key = _availability_key(name)
|
|
136
|
+
with _LOCK:
|
|
137
|
+
return _AVAILABILITY_BY_NAME.get(key)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def unavailable_tool_result(name: str) -> ToolUnavailableResult | None:
|
|
141
|
+
state = get_tool_availability(name)
|
|
142
|
+
if state is None or not state.optional or not state.unavailable_reason:
|
|
143
|
+
return None
|
|
144
|
+
return {
|
|
145
|
+
"status": "tool_unavailable",
|
|
146
|
+
"tool": state.name,
|
|
147
|
+
"reason": state.unavailable_reason,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def web_unavailable_result(name: str, *, detail: str | None = None) -> ToolUnavailableResult:
|
|
152
|
+
"""Return a non-error observation for a failed optional web tool.
|
|
153
|
+
|
|
154
|
+
``detail`` carries the underlying failure summary so the model (and the
|
|
155
|
+
user reading the transcript) can see *why* web tools were disabled — e.g.
|
|
156
|
+
a configuration remedy — instead of a silent generic notice.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
clean_name = _clean_tool_name(name)
|
|
160
|
+
if clean_name.casefold() not in WEB_TOOL_NAMES:
|
|
161
|
+
raise ValueError(f"not a web tool: {clean_name}")
|
|
162
|
+
reason = WEB_UNAVAILABLE_OBSERVATION
|
|
163
|
+
clean_detail = str(detail or "").strip()
|
|
164
|
+
if clean_detail:
|
|
165
|
+
reason = f"{WEB_UNAVAILABLE_OBSERVATION} Cause: {clean_detail}"
|
|
166
|
+
return {
|
|
167
|
+
"status": "tool_unavailable",
|
|
168
|
+
"tool": clean_name,
|
|
169
|
+
"reason": reason,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def is_tool_unavailable_result(value: Any) -> TypeGuard[ToolUnavailableResult]:
|
|
174
|
+
if not isinstance(value, dict):
|
|
175
|
+
return False
|
|
176
|
+
return (
|
|
177
|
+
value.get("status") == "tool_unavailable"
|
|
178
|
+
and isinstance(value.get("tool"), str)
|
|
179
|
+
and bool(str(value.get("tool") or "").strip())
|
|
180
|
+
and isinstance(value.get("reason"), str)
|
|
181
|
+
and bool(str(value.get("reason") or "").strip())
|
|
182
|
+
and "error" not in value
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _reset_tool_availability_for_tests() -> None:
|
|
187
|
+
with _LOCK:
|
|
188
|
+
_AVAILABILITY_BY_NAME.clear()
|