diff --git a/strix/config/settings.py b/strix/config/settings.py index 0f26cd62..60b0e321 100644 --- a/strix/config/settings.py +++ b/strix/config/settings.py @@ -10,6 +10,8 @@ from pydantic_settings import BaseSettings, SettingsConfigDict ReasoningEffort = Literal["none", "minimal", "low", "medium", "high", "xhigh", "max"] +DEFAULT_MAX_TURNS = 500 + _BASE_CONFIG = SettingsConfigDict( case_sensitive=False, populate_by_name=True, diff --git a/strix/core/inputs.py b/strix/core/inputs.py index 81f46076..26aebb39 100644 --- a/strix/core/inputs.py +++ b/strix/core/inputs.py @@ -24,9 +24,6 @@ if TYPE_CHECKING: from strix.config.settings import ReasoningEffort -DEFAULT_MAX_TURNS = 500 - - def _accepts_required_tool_choice(model_name: str | None) -> bool: name = (model_name or "").strip().lower() for prefix in ("litellm/", "any-llm/"): diff --git a/strix/core/runner.py b/strix/core/runner.py index ec439866..ce099643 100644 --- a/strix/core/runner.py +++ b/strix/core/runner.py @@ -23,6 +23,7 @@ from strix.config.models import ( configure_sdk_model_defaults, uses_chat_completions_tool_schema, ) +from strix.config.settings import DEFAULT_MAX_TURNS from strix.core.agents import AgentCoordinator from strix.core.execution import ( respawn_subagents, @@ -33,7 +34,6 @@ from strix.core.execution import ( ) from strix.core.hooks import BudgetExceededError, ReportUsageHooks, recomputed_budget_flags from strix.core.inputs import ( - DEFAULT_MAX_TURNS, build_root_task, build_scope_context, make_model_settings, diff --git a/strix/interface/cli.py b/strix/interface/cli.py index c03e8c86..9f8fdbdd 100644 --- a/strix/interface/cli.py +++ b/strix/interface/cli.py @@ -13,7 +13,7 @@ from rich.panel import Panel from rich.text import Text from strix.config import load_settings -from strix.core.inputs import DEFAULT_MAX_TURNS +from strix.config.settings import DEFAULT_MAX_TURNS from strix.core.runner import run_strix_scan from strix.report.state import ReportState, set_global_report_state from strix.runtime import session_manager diff --git a/strix/interface/main.py b/strix/interface/main.py index abe77fa3..6a5ebc4d 100644 --- a/strix/interface/main.py +++ b/strix/interface/main.py @@ -11,9 +11,6 @@ import sys from datetime import UTC, datetime from pathlib import Path -from agents.model_settings import ModelSettings -from agents.models.interface import ModelTracing -from docker.errors import DockerException from rich.console import Console from rich.panel import Panel from rich.text import Text @@ -24,17 +21,8 @@ from strix.config import ( load_settings, persist_current, ) -from strix.config.models import ( - RECOMMENDED_MODEL_NAMES, - StrixProvider, - configure_sdk_model_defaults, - is_known_openai_bare_model, - is_recommended_or_frontier_model, -) -from strix.core.inputs import DEFAULT_MAX_TURNS, make_model_settings +from strix.config.settings import DEFAULT_MAX_TURNS from strix.core.paths import run_dir_for, runtime_state_dir -from strix.interface.cli import run_cli -from strix.interface.tui import run_tui from strix.interface.update_check import ( is_binary_install, notify_update, @@ -61,8 +49,6 @@ from strix.interface.utils import ( rewrite_localhost_targets, validate_config_file, ) -from strix.report.state import get_global_report_state -from strix.report.writer import read_run_record, write_run_record from strix.telemetry import posthog, scarf from strix.telemetry.logging import configure_dependency_logging @@ -310,6 +296,18 @@ def _subscription_error_hint(exc: BaseException) -> str | None: async def warm_up_llm(show_model_warning: bool = True) -> None: + from agents.model_settings import ModelSettings + from agents.models.interface import ModelTracing + + from strix.config.models import ( + RECOMMENDED_MODEL_NAMES, + StrixProvider, + configure_sdk_model_defaults, + is_known_openai_bare_model, + is_recommended_or_frontier_model, + ) + from strix.core.inputs import make_model_settings + console = Console() logger.info("Warming up LLM connection") @@ -794,6 +792,8 @@ Examples: def _persist_run_record(args: argparse.Namespace) -> None: + from strix.report.writer import write_run_record + run_dir = run_dir_for(args.run_name) run_dir.mkdir(parents=True, exist_ok=True) run_record = { @@ -817,6 +817,8 @@ def _persist_run_record(args: argparse.Namespace) -> None: def _load_resume_state(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None: """Populate ``args.targets_info`` and friends from a prior run's run.json.""" + from strix.report.writer import read_run_record + run_dir = run_dir_for(args.resume) state_path = run_dir / "run.json" if not state_path.exists(): @@ -861,6 +863,8 @@ def _load_resume_state(args: argparse.Namespace, parser: argparse.ArgumentParser def display_completion_message(args: argparse.Namespace, results_path: Path) -> None: + from strix.report.state import get_global_report_state + console = Console() report_state = get_global_report_state() @@ -940,6 +944,8 @@ def display_completion_message(args: argparse.Namespace, results_path: Path) -> def pull_docker_image() -> None: + from docker.errors import DockerException + console = Console() client = check_docker_connection() @@ -1086,11 +1092,17 @@ def main() -> None: posthog.start(**_telemetry_start_kwargs) scarf.start(**_telemetry_start_kwargs) + from strix.report.state import get_global_report_state + exit_reason = "user_exit" try: if args.non_interactive: + from strix.interface.cli import run_cli + asyncio.run(run_cli(args)) else: + from strix.interface.tui import run_tui + asyncio.run(run_tui(args)) except KeyboardInterrupt: exit_reason = "interrupted" diff --git a/strix/interface/tui/app.py b/strix/interface/tui/app.py index 21715d0c..d4c51b20 100644 --- a/strix/interface/tui/app.py +++ b/strix/interface/tui/app.py @@ -34,8 +34,8 @@ from textual.widgets.tree import TreeNode from strix.config import load_settings from strix.config.models import is_recommended_or_frontier_model +from strix.config.settings import DEFAULT_MAX_TURNS from strix.core.hooks import BudgetExceededError -from strix.core.inputs import DEFAULT_MAX_TURNS from strix.core.runner import run_strix_scan from strix.interface.tui.live_view import TuiLiveView from strix.interface.tui.messages import send_user_message_to_agent diff --git a/strix/telemetry/logging.py b/strix/telemetry/logging.py index 53945f12..6685eac0 100644 --- a/strix/telemetry/logging.py +++ b/strix/telemetry/logging.py @@ -5,6 +5,7 @@ from __future__ import annotations import contextlib import logging import os +import sys import warnings from contextvars import ContextVar from pathlib import Path # noqa: TC003 used at runtime by ``setup_scan_logging`` @@ -78,11 +79,10 @@ class _StdoutQuietFilter(logging.Filter): def configure_dependency_logging() -> None: """Quiet dependency logging/warnings that obscure Strix scan logs.""" - with contextlib.suppress(Exception): - import litellm - - litellm_logging = litellm._logging - litellm_logging._disable_debugging() # type: ignore[no-untyped-call] + litellm = sys.modules.get("litellm") + if litellm is not None: + with contextlib.suppress(Exception): + litellm._logging._disable_debugging() logging.getLogger("asyncio").setLevel(logging.CRITICAL) logging.getLogger("asyncio").propagate = False