perf(cli): ~10x faster startup via lazy imports (#920)

* perf(cli): fast startup — lazy heavy imports + onedir standalone build

* perf(cli): drop legacy single-file compat from install/self-update

* perf(cli): simplify — drop constants module and extra lazy-import refactors

* refactor(update): strix --update just re-runs the install script

* perf(cli): drop packaging/install/update changes; deepen lazy imports instead

Reverts the onedir build, install.sh, and self-update changes so release
mechanics stay untouched. Startup cost is addressed purely by deferring
heavy imports (agents/openai, config.models, report state/writer, docker)
until a scan actually runs; DEFAULT_MAX_TURNS moves to strix.config.settings
so argparse no longer pulls the agents SDK.

---------

Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
This commit is contained in:
devin-ai-integration[bot]
2026-08-02 06:24:31 +03:00
committed by GitHub
co-authored by Ahmed Allam
parent c240068c2c
commit 797b37467e
7 changed files with 37 additions and 26 deletions
+2
View File
@@ -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,
-3
View File
@@ -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/"):
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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
+27 -15
View File
@@ -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"
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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