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,184 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from ...config import ConfigError, load_config
|
|
8
|
+
from ...sandbox_doctor import (
|
|
9
|
+
SandboxDiagnostic,
|
|
10
|
+
configured_sandbox_images,
|
|
11
|
+
diagnose_sandbox,
|
|
12
|
+
format_sandbox_problem_message,
|
|
13
|
+
pull_sandbox_images,
|
|
14
|
+
sandbox_env_summary,
|
|
15
|
+
)
|
|
16
|
+
from . import _patchable
|
|
17
|
+
from ._shared import _console, _Table
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from rich.table import Table
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
sandbox_app = typer.Typer(add_completion=False, help="Sandbox setup and diagnostics.")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _sandbox_doctor_table(result: SandboxDiagnostic) -> Table:
|
|
27
|
+
table = _Table(title="alysis sandbox")
|
|
28
|
+
table.add_column("check")
|
|
29
|
+
table.add_column("status")
|
|
30
|
+
table.add_column("detail")
|
|
31
|
+
table.add_row("mode", result.configured_mode, "shell_sandbox.mode")
|
|
32
|
+
table.add_row("configured backend", result.configured_backend, "shell_sandbox.backend")
|
|
33
|
+
table.add_row("selected backend", result.selected_backend or "-", "")
|
|
34
|
+
table.add_row("sandbox image", result.docker_image, "dev shell/verify image")
|
|
35
|
+
table.add_row("server image", result.server_image, "server worker image")
|
|
36
|
+
for check in result.checks:
|
|
37
|
+
table.add_row(check.name, check.status, check.detail)
|
|
38
|
+
return table
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _print_sandbox_diagnostic(
|
|
42
|
+
*,
|
|
43
|
+
console: Any,
|
|
44
|
+
result: SandboxDiagnostic,
|
|
45
|
+
include_env: bool = False,
|
|
46
|
+
) -> None:
|
|
47
|
+
console.print(_sandbox_doctor_table(result))
|
|
48
|
+
console.print()
|
|
49
|
+
message_style = "green" if result.ready else "yellow"
|
|
50
|
+
console.print(format_sandbox_problem_message(result), style=message_style, highlight=False)
|
|
51
|
+
if include_env:
|
|
52
|
+
env_rows = sandbox_env_summary()
|
|
53
|
+
env_table = _Table(title="sandbox environment")
|
|
54
|
+
env_table.add_column("variable")
|
|
55
|
+
env_table.add_column("value")
|
|
56
|
+
for key, value in env_rows.items():
|
|
57
|
+
env_table.add_row(key, value if value is not None else "(unset)")
|
|
58
|
+
console.print()
|
|
59
|
+
console.print(env_table)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _run_sandbox_doctor_command(*, include_smoke: bool, include_env: bool = False) -> None:
|
|
63
|
+
console = _console()
|
|
64
|
+
try:
|
|
65
|
+
result = _patchable("diagnose_sandbox", diagnose_sandbox)(
|
|
66
|
+
_patchable("load_config", load_config)(),
|
|
67
|
+
include_smoke=include_smoke,
|
|
68
|
+
include_server_image=True,
|
|
69
|
+
)
|
|
70
|
+
except ConfigError as exc:
|
|
71
|
+
console.print(f"[red]Sandbox config error:[/red] {exc}")
|
|
72
|
+
raise typer.Exit(code=2) from exc
|
|
73
|
+
_print_sandbox_diagnostic(console=console, result=result, include_env=include_env)
|
|
74
|
+
if not result.ready:
|
|
75
|
+
raise typer.Exit(code=1)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _run_sandbox_pull_command(
|
|
79
|
+
*,
|
|
80
|
+
images: list[str] | None = None,
|
|
81
|
+
include_server: bool = True,
|
|
82
|
+
timeout_s: int = 900,
|
|
83
|
+
) -> None:
|
|
84
|
+
console = _console()
|
|
85
|
+
if images:
|
|
86
|
+
selected_images = tuple(images)
|
|
87
|
+
else:
|
|
88
|
+
try:
|
|
89
|
+
selected_images = _patchable("configured_sandbox_images", configured_sandbox_images)(
|
|
90
|
+
_patchable("load_config", load_config)(),
|
|
91
|
+
include_server=include_server,
|
|
92
|
+
)
|
|
93
|
+
except ConfigError as exc:
|
|
94
|
+
console.print(f"[red]Sandbox config error:[/red] {exc}")
|
|
95
|
+
raise typer.Exit(code=2) from exc
|
|
96
|
+
result = _patchable("pull_sandbox_images", pull_sandbox_images)(
|
|
97
|
+
selected_images, timeout_s=timeout_s
|
|
98
|
+
)
|
|
99
|
+
if result.error:
|
|
100
|
+
console.print(f"[red]Sandbox setup failed:[/red] {result.error}")
|
|
101
|
+
raise typer.Exit(code=1)
|
|
102
|
+
for item in result.results:
|
|
103
|
+
status = "pulled" if item.ok else "failed"
|
|
104
|
+
style = "green" if item.ok else "red"
|
|
105
|
+
console.print(f"[{style}]{status}[/{style}] {item.image}")
|
|
106
|
+
if not item.ok and item.output:
|
|
107
|
+
console.print(item.output)
|
|
108
|
+
if not result.ok:
|
|
109
|
+
raise typer.Exit(code=1)
|
|
110
|
+
_run_sandbox_doctor_command(include_smoke=True, include_env=False)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _run_sandbox_setup_command(*, pull: bool = True) -> None:
|
|
114
|
+
console = _console()
|
|
115
|
+
try:
|
|
116
|
+
result = _patchable("diagnose_sandbox", diagnose_sandbox)(
|
|
117
|
+
_patchable("load_config", load_config)(),
|
|
118
|
+
include_smoke=False,
|
|
119
|
+
include_server_image=True,
|
|
120
|
+
)
|
|
121
|
+
except ConfigError as exc:
|
|
122
|
+
console.print(f"[red]Sandbox config error:[/red] {exc}")
|
|
123
|
+
raise typer.Exit(code=2) from exc
|
|
124
|
+
if result.ready:
|
|
125
|
+
_print_sandbox_diagnostic(console=console, result=result)
|
|
126
|
+
return
|
|
127
|
+
if pull and result.can_pull:
|
|
128
|
+
console.print("[bold]Downloading Alysis Code sandbox images...[/bold]")
|
|
129
|
+
_patchable("_run_sandbox_pull_command", _run_sandbox_pull_command)(include_server=True)
|
|
130
|
+
return
|
|
131
|
+
_print_sandbox_diagnostic(console=console, result=result)
|
|
132
|
+
raise typer.Exit(code=1)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@sandbox_app.command("doctor")
|
|
136
|
+
def sandbox_doctor(
|
|
137
|
+
smoke: bool = typer.Option(
|
|
138
|
+
True,
|
|
139
|
+
"--smoke/--no-smoke",
|
|
140
|
+
help="Run a sandbox smoke command.",
|
|
141
|
+
),
|
|
142
|
+
env: bool = typer.Option(
|
|
143
|
+
False,
|
|
144
|
+
"--env",
|
|
145
|
+
help="Show sandbox-related environment variable overrides.",
|
|
146
|
+
),
|
|
147
|
+
) -> None:
|
|
148
|
+
"""Check whether Alysis Code's safe command runner is ready."""
|
|
149
|
+
_run_sandbox_doctor_command(include_smoke=smoke, include_env=env)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@sandbox_app.command("setup")
|
|
153
|
+
def sandbox_setup(
|
|
154
|
+
pull: bool = typer.Option(
|
|
155
|
+
True,
|
|
156
|
+
"--pull/--no-pull",
|
|
157
|
+
help="Download missing Docker sandbox images when Docker is ready.",
|
|
158
|
+
),
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Prepare Alysis Code's safe command runner."""
|
|
161
|
+
_run_sandbox_setup_command(pull=pull)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@sandbox_app.command("pull")
|
|
165
|
+
def sandbox_pull(
|
|
166
|
+
image: list[str] | None = typer.Option(
|
|
167
|
+
None,
|
|
168
|
+
"--image",
|
|
169
|
+
help="Specific sandbox image to pull. Repeat to pull more than one.",
|
|
170
|
+
),
|
|
171
|
+
include_server: bool = typer.Option(
|
|
172
|
+
True,
|
|
173
|
+
"--server/--no-server",
|
|
174
|
+
help="Also pull the server worker sandbox image.",
|
|
175
|
+
),
|
|
176
|
+
timeout_s: int = typer.Option(
|
|
177
|
+
900,
|
|
178
|
+
"--timeout",
|
|
179
|
+
min=1,
|
|
180
|
+
help="Per-image Docker pull timeout in seconds.",
|
|
181
|
+
),
|
|
182
|
+
) -> None:
|
|
183
|
+
"""Download Alysis Code's Docker sandbox image(s)."""
|
|
184
|
+
_run_sandbox_pull_command(images=image, include_server=include_server, timeout_s=timeout_s)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from platformdirs import user_data_dir
|
|
7
|
+
|
|
8
|
+
from ...config import ConfigError
|
|
9
|
+
from ._shared import _console
|
|
10
|
+
|
|
11
|
+
server_app = typer.Typer(add_completion=False, help="Server mode commands.")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@server_app.command("start")
|
|
15
|
+
def server_start(
|
|
16
|
+
host: str = typer.Option("127.0.0.1", "--host", help="Host to bind."),
|
|
17
|
+
port: int = typer.Option(7070, "--port", min=1, help="Port to bind."),
|
|
18
|
+
data_dir: Path | None = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
"--data-dir",
|
|
21
|
+
help="Server data directory (default: platform app data dir).",
|
|
22
|
+
),
|
|
23
|
+
) -> None:
|
|
24
|
+
console = _console()
|
|
25
|
+
try:
|
|
26
|
+
import fastapi # noqa: F401
|
|
27
|
+
import uvicorn
|
|
28
|
+
|
|
29
|
+
from ...server.app import create_app
|
|
30
|
+
from ...server.settings import resolve_server_settings
|
|
31
|
+
except ModuleNotFoundError as e:
|
|
32
|
+
console.print(
|
|
33
|
+
"[red]Server dependencies missing.[/red] "
|
|
34
|
+
"Install server extras: [bold]pip install .[server][/bold]"
|
|
35
|
+
)
|
|
36
|
+
raise typer.Exit(code=2) from e
|
|
37
|
+
|
|
38
|
+
default_data_dir = Path(user_data_dir("alysis-code-server", "alysis"))
|
|
39
|
+
effective_data_dir = data_dir if data_dir is not None else default_data_dir
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
settings = resolve_server_settings(
|
|
43
|
+
host=host,
|
|
44
|
+
port=port,
|
|
45
|
+
data_dir=effective_data_dir,
|
|
46
|
+
)
|
|
47
|
+
except ConfigError as e:
|
|
48
|
+
console.print(f"[red]Server config error:[/red] {e}")
|
|
49
|
+
raise typer.Exit(code=2) from e
|
|
50
|
+
|
|
51
|
+
def _app_factory(): # type: ignore[no-untyped-def]
|
|
52
|
+
return create_app(settings)
|
|
53
|
+
|
|
54
|
+
uvicorn.run(_app_factory, host=settings.host, port=settings.port, factory=True)
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ...config import load_config
|
|
12
|
+
from ...session_metrics import score_session_log
|
|
13
|
+
from ...session_store import (
|
|
14
|
+
filter_sessions_to_local_owner,
|
|
15
|
+
list_sessions,
|
|
16
|
+
read_session_events,
|
|
17
|
+
resolve_sessions_dir,
|
|
18
|
+
)
|
|
19
|
+
from ...usage_tracker import aggregate_usage_from_session_logs
|
|
20
|
+
from . import _patchable
|
|
21
|
+
from ._shared import _console, _Table
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _cli_module() -> Any:
|
|
25
|
+
module = sys.modules.get("alysis_code.cli")
|
|
26
|
+
if module is not None:
|
|
27
|
+
return module
|
|
28
|
+
from ... import cli
|
|
29
|
+
|
|
30
|
+
return cli
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
sessions_app = typer.Typer(add_completion=False, help="Session log commands.")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _usage_source_pair(row: dict[str, Any]) -> str:
|
|
37
|
+
provider = int(row.get("api_usage_calls") or 0)
|
|
38
|
+
fallback = int(row.get("estimate_usage_calls") or 0)
|
|
39
|
+
return f"{provider}/{fallback}"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _print_hidden_owner_notice(console: Any, hidden_count: int) -> None:
|
|
43
|
+
"""Say how many sessions the owner filter removed.
|
|
44
|
+
|
|
45
|
+
Silence here is what made "my session is gone" indistinguishable from "your
|
|
46
|
+
session is filtered": an empty list looks the same either way, so the count is
|
|
47
|
+
printed whenever anything was dropped -- including when nothing is left.
|
|
48
|
+
"""
|
|
49
|
+
if hidden_count <= 0:
|
|
50
|
+
return
|
|
51
|
+
suffix = "" if hidden_count == 1 else "s"
|
|
52
|
+
console.print(
|
|
53
|
+
f"[dim]{hidden_count} session{suffix} from other accounts hidden. "
|
|
54
|
+
"Use --all-owners to include.[/dim]"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@sessions_app.command("list")
|
|
59
|
+
def sessions_list(
|
|
60
|
+
all_owners: bool = typer.Option(
|
|
61
|
+
False,
|
|
62
|
+
"--all-owners",
|
|
63
|
+
"--all",
|
|
64
|
+
help="Include sessions recorded by other accounts (hidden by default).",
|
|
65
|
+
),
|
|
66
|
+
) -> None:
|
|
67
|
+
console = _console()
|
|
68
|
+
cfg = _patchable("load_config", load_config)()
|
|
69
|
+
sessions_dir = resolve_sessions_dir(cfg)
|
|
70
|
+
all_infos = _patchable("list_sessions", list_sessions)(sessions_dir)
|
|
71
|
+
infos = all_infos if all_owners else filter_sessions_to_local_owner(all_infos)
|
|
72
|
+
hidden_count = len(all_infos) - len(infos)
|
|
73
|
+
|
|
74
|
+
table = _Table(title=f"Sessions ({sessions_dir})")
|
|
75
|
+
table.add_column("session_id")
|
|
76
|
+
table.add_column("path")
|
|
77
|
+
for info in infos[:200]:
|
|
78
|
+
table.add_row(info.session_id, os.fspath(info.path))
|
|
79
|
+
console.print(table)
|
|
80
|
+
_print_hidden_owner_notice(console, hidden_count)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@sessions_app.command("show")
|
|
84
|
+
def sessions_show(
|
|
85
|
+
session_id: str = typer.Argument(..., help="Session id (filename stem)."),
|
|
86
|
+
) -> None:
|
|
87
|
+
console = _console()
|
|
88
|
+
cfg = _patchable("load_config", load_config)()
|
|
89
|
+
sessions_dir = resolve_sessions_dir(cfg)
|
|
90
|
+
path = sessions_dir / f"{session_id}.jsonl"
|
|
91
|
+
if not path.exists():
|
|
92
|
+
console.print(f"[red]Not found:[/red] {path}")
|
|
93
|
+
raise typer.Exit(code=2)
|
|
94
|
+
for ev in read_session_events(path):
|
|
95
|
+
console.print_json(json.dumps(ev))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@sessions_app.command("usage")
|
|
99
|
+
def sessions_usage(
|
|
100
|
+
session_id: str = typer.Argument(..., help="Session id (filename stem)."),
|
|
101
|
+
) -> None:
|
|
102
|
+
console = _console()
|
|
103
|
+
cfg = _patchable("load_config", load_config)()
|
|
104
|
+
sessions_dir = resolve_sessions_dir(cfg)
|
|
105
|
+
path = sessions_dir / f"{session_id}.jsonl"
|
|
106
|
+
if not path.exists():
|
|
107
|
+
console.print(f"[red]Not found:[/red] {path}")
|
|
108
|
+
raise typer.Exit(code=2)
|
|
109
|
+
summary = _patchable("aggregate_usage_from_session_logs", aggregate_usage_from_session_logs)(
|
|
110
|
+
[path]
|
|
111
|
+
)
|
|
112
|
+
rows = summary.by_model_rows()
|
|
113
|
+
if not rows:
|
|
114
|
+
console.print("No llm_usage events found in this session log.")
|
|
115
|
+
return
|
|
116
|
+
table = _Table(title=f"Session Usage ({session_id})")
|
|
117
|
+
table.add_column("model")
|
|
118
|
+
table.add_column("prompt_tokens", justify="right")
|
|
119
|
+
table.add_column("completion_tokens", justify="right")
|
|
120
|
+
table.add_column("total_tokens", justify="right")
|
|
121
|
+
table.add_column("cost_usd", justify="right")
|
|
122
|
+
table.add_column("unknown_pricing", justify="right")
|
|
123
|
+
table.add_column("usage(provider/fallback)", justify="right")
|
|
124
|
+
for row in rows:
|
|
125
|
+
unknown_count = int(row.get("unknown_cost_count") or 0)
|
|
126
|
+
cost_display = _cli_module()._format_cost_with_unknown(
|
|
127
|
+
known_cost=_cli_module()._known_cost_value(row),
|
|
128
|
+
unknown_calls=unknown_count,
|
|
129
|
+
style="table",
|
|
130
|
+
)
|
|
131
|
+
table.add_row(
|
|
132
|
+
str(row.get("model") or "-"),
|
|
133
|
+
str(int(row.get("prompt_tokens") or 0)),
|
|
134
|
+
str(int(row.get("completion_tokens") or 0)),
|
|
135
|
+
str(int(row.get("total_tokens") or 0)),
|
|
136
|
+
cost_display,
|
|
137
|
+
str(unknown_count),
|
|
138
|
+
_usage_source_pair(row),
|
|
139
|
+
)
|
|
140
|
+
totals = summary.totals()
|
|
141
|
+
total_cost = _cli_module()._format_cost_with_unknown(
|
|
142
|
+
known_cost=_cli_module()._known_cost_value(totals),
|
|
143
|
+
unknown_calls=int(totals.get("unknown_cost_calls") or 0),
|
|
144
|
+
style="table",
|
|
145
|
+
)
|
|
146
|
+
table.add_row(
|
|
147
|
+
"TOTAL",
|
|
148
|
+
str(int(totals.get("prompt_tokens") or 0)),
|
|
149
|
+
str(int(totals.get("completion_tokens") or 0)),
|
|
150
|
+
str(int(totals.get("total_tokens") or 0)),
|
|
151
|
+
total_cost,
|
|
152
|
+
str(int(totals.get("unknown_cost_calls") or 0)),
|
|
153
|
+
_usage_source_pair(totals),
|
|
154
|
+
)
|
|
155
|
+
console.print(table)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@sessions_app.command("score")
|
|
159
|
+
def sessions_score(
|
|
160
|
+
session_id: str | None = typer.Argument(
|
|
161
|
+
None,
|
|
162
|
+
help="Session id (filename stem). If omitted, scores latest session(s).",
|
|
163
|
+
),
|
|
164
|
+
latest: int = typer.Option(
|
|
165
|
+
0,
|
|
166
|
+
"--latest",
|
|
167
|
+
min=0,
|
|
168
|
+
help="Score latest N sessions (ignored when session_id is provided).",
|
|
169
|
+
),
|
|
170
|
+
all_owners: bool = typer.Option(
|
|
171
|
+
False,
|
|
172
|
+
"--all-owners",
|
|
173
|
+
help="Include sessions recorded by other accounts when picking the latest ones.",
|
|
174
|
+
),
|
|
175
|
+
json_output: bool = typer.Option(False, "--json", help="Emit JSON output."),
|
|
176
|
+
) -> None:
|
|
177
|
+
console = _console()
|
|
178
|
+
cfg = _patchable("load_config", load_config)()
|
|
179
|
+
sessions_dir = resolve_sessions_dir(cfg)
|
|
180
|
+
|
|
181
|
+
if session_id and latest > 0:
|
|
182
|
+
console.print("[red]Error:[/red] Use either session_id or --latest, not both.")
|
|
183
|
+
raise typer.Exit(code=2)
|
|
184
|
+
|
|
185
|
+
target_paths: list[Path] = []
|
|
186
|
+
if session_id:
|
|
187
|
+
path = sessions_dir / f"{session_id}.jsonl"
|
|
188
|
+
if not path.exists():
|
|
189
|
+
console.print(f"[red]Not found:[/red] {path}")
|
|
190
|
+
raise typer.Exit(code=2)
|
|
191
|
+
target_paths = [path]
|
|
192
|
+
else:
|
|
193
|
+
all_infos = _patchable("list_sessions", list_sessions)(sessions_dir)
|
|
194
|
+
infos = all_infos if all_owners else filter_sessions_to_local_owner(all_infos)
|
|
195
|
+
hidden_count = len(all_infos) - len(infos)
|
|
196
|
+
if not infos:
|
|
197
|
+
console.print(f"No sessions owned by this account found in {sessions_dir}")
|
|
198
|
+
_print_hidden_owner_notice(console, hidden_count)
|
|
199
|
+
return
|
|
200
|
+
_print_hidden_owner_notice(console, hidden_count)
|
|
201
|
+
count = latest if latest > 0 else 1
|
|
202
|
+
target_paths = [info.path for info in infos[:count]]
|
|
203
|
+
|
|
204
|
+
scores = [_patchable("score_session_log", score_session_log)(path) for path in target_paths]
|
|
205
|
+
|
|
206
|
+
if json_output:
|
|
207
|
+
payload: Any = scores[0] if len(scores) == 1 else scores
|
|
208
|
+
console.print_json(json.dumps(payload))
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
table = _Table(title=f"Session Score ({sessions_dir})")
|
|
212
|
+
table.add_column("session_id")
|
|
213
|
+
table.add_column("tools", justify="right")
|
|
214
|
+
table.add_column("errors", justify="right")
|
|
215
|
+
table.add_column("writes", justify="right")
|
|
216
|
+
table.add_column("blocked_writes", justify="right")
|
|
217
|
+
table.add_column("read_before_write")
|
|
218
|
+
table.add_column("shell_runs", justify="right")
|
|
219
|
+
table.add_column("test_runs", justify="right")
|
|
220
|
+
table.add_column("llm_calls", justify="right")
|
|
221
|
+
table.add_column("total_tokens", justify="right")
|
|
222
|
+
|
|
223
|
+
for score in scores:
|
|
224
|
+
rbw = score.get("read_before_first_write")
|
|
225
|
+
if isinstance(rbw, bool):
|
|
226
|
+
rbw_text = "yes" if rbw else "no"
|
|
227
|
+
else:
|
|
228
|
+
rbw_text = "n/a"
|
|
229
|
+
table.add_row(
|
|
230
|
+
str(score.get("session_id") or "-"),
|
|
231
|
+
str(int(score.get("tool_calls") or 0)),
|
|
232
|
+
str(int(score.get("tool_errors") or 0)),
|
|
233
|
+
str(int(score.get("write_calls") or 0)),
|
|
234
|
+
str(int(score.get("blocked_write_errors") or 0)),
|
|
235
|
+
rbw_text,
|
|
236
|
+
str(int(score.get("shell_runs") or 0)),
|
|
237
|
+
str(int(score.get("test_shell_runs") or 0)),
|
|
238
|
+
str(int(score.get("llm_usage_events") or 0)),
|
|
239
|
+
str(int(score.get("total_tokens") or 0)),
|
|
240
|
+
)
|
|
241
|
+
console.print(table)
|
|
242
|
+
|
|
243
|
+
if len(scores) == 1:
|
|
244
|
+
score = scores[0]
|
|
245
|
+
commands = score.get("test_shell_commands") or []
|
|
246
|
+
if commands:
|
|
247
|
+
console.print("Test commands: " + "; ".join(str(cmd) for cmd in commands))
|
|
248
|
+
repeated = score.get("repeated_tool_errors") or []
|
|
249
|
+
for item in repeated:
|
|
250
|
+
console.print(
|
|
251
|
+
f"Repeated tool error (x{int(item.get('count') or 0)}): {item.get('error') or ''}"
|
|
252
|
+
)
|