chore: prune unused imports and duplicate import redefinitions

Remove unused imports (F401) and duplicate/shadowed import
redefinitions (F811) across the codebase using ruff's safe
autofixes. No behavioral changes -- imports only.

- ~1400 safe autofixes applied across 644 files (net -1072 lines)
- __init__.py re-exports preserved (excluded from F401 removal so
  public re-export surfaces stay intact)
- Re-exports that are imported or monkeypatched by tests but look
  unused in their defining module are kept with explicit # noqa:
  F401 (gateway/run.py load_dotenv; run_agent re-exports from
  agent.message_sanitization, agent.context_compressor,
  agent.retry_utils, agent.prompt_builder, agent.process_bootstrap,
  agent.codex_responses_adapter)
- Unsafe F841 (unused-variable) fixes deliberately skipped -- those
  can change behavior when the RHS has side effects
- ruff lints remain disabled in pyproject.toml (only PLW1514 is
  selected); this is a one-time cleanup, not a config change

Verification:
- python -m compileall: clean
- pytest --collect-only: all 27161 tests collect (zero import errors)
- core entry points import clean (run_agent, model_tools, cli,
  toolsets, hermes_state, batch_runner, gateway)
- static scan: every name any test imports directly from an edited
  module still resolves
This commit is contained in:
kshitijk4poor 2026-05-29 02:04:58 +05:30 committed by Teknium
parent a4d8f0f62a
commit 66827f8947
644 changed files with 254 additions and 1326 deletions

View file

@ -27,7 +27,6 @@ import threading
import time
import uuid
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse, parse_qs, urlunparse
@ -37,7 +36,6 @@ from agent.memory_manager import StreamingContextScrubber
from agent.model_metadata import (
MINIMUM_CONTEXT_LENGTH,
fetch_model_metadata,
get_model_context_length,
is_local_endpoint,
query_ollama_num_ctx,
)
@ -52,7 +50,6 @@ from agent.tool_guardrails import (
from hermes_cli.config import cfg_get
from hermes_cli.timeouts import get_provider_request_timeout
from hermes_constants import get_hermes_home
from model_tools import check_toolset_requirements, get_tool_definitions
from utils import base_url_host_matches
# Use the same logger name as run_agent so tests patching ``run_agent.logger``
@ -1474,7 +1471,6 @@ def init_agent(
# Reject models whose context window is below the minimum required
# for reliable tool-calling workflows (64K tokens).
from agent.model_metadata import MINIMUM_CONTEXT_LENGTH
_ctx = getattr(agent.context_compressor, "context_length", 0)
if _ctx and _ctx < MINIMUM_CONTEXT_LENGTH:
raise ValueError(

View file

@ -25,24 +25,17 @@ from __future__ import annotations
import copy
import json
import logging
import os
import re
import threading
import time
import uuid
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional
from hermes_cli.timeouts import get_provider_request_timeout
from agent.message_sanitization import (
_repair_tool_call_arguments,
_sanitize_surrogates,
)
from agent.tool_dispatch_helpers import _trajectory_normalize_msg, make_tool_result_message
from agent.trajectory import convert_scratchpad_to_think
from agent.credential_pool import STATUS_EXHAUSTED
from agent.error_classifier import classify_api_error, FailoverReason
from agent.error_classifier import FailoverReason
from utils import base_url_host_matches, base_url_hostname, env_var_enabled, atomic_json_write
logger = logging.getLogger(__name__)

View file

@ -15,49 +15,23 @@ sites unchanged. Symbols that tests patch on ``run_agent`` (e.g.
from __future__ import annotations
import concurrent.futures
import contextvars
import copy
import json
import logging
import os
import random
import re
import sys
import threading
import time
import uuid
from datetime import datetime
from pathlib import Path
from types import SimpleNamespace
from typing import Any, Dict, List, Optional, Tuple
from urllib.parse import urlparse, parse_qs, urlunparse
from typing import Any, Dict, Optional
from hermes_cli.timeouts import get_provider_request_timeout, get_provider_stale_timeout
from hermes_constants import PARTIAL_STREAM_STUB_ID, FINISH_REASON_LENGTH
from agent.error_classifier import classify_api_error, FailoverReason
from agent.error_classifier import FailoverReason
from agent.model_metadata import is_local_endpoint
from agent.message_sanitization import (
_sanitize_surrogates,
_sanitize_messages_surrogates,
_sanitize_structure_surrogates,
_sanitize_messages_non_ascii,
_sanitize_tools_non_ascii,
_sanitize_structure_non_ascii,
_strip_images_from_messages,
_strip_non_ascii,
_repair_tool_call_arguments,
_escape_invalid_chars_in_json_strings,
)
from agent.tool_dispatch_helpers import (
_is_multimodal_tool_result,
_multimodal_text_summary,
)
from agent.retry_utils import jittered_backoff
from agent.tool_guardrails import (
ToolGuardrailDecision,
append_toolguard_guidance,
toolguard_synthetic_result,
)
from tools.terminal_tool import is_persistent_env
from utils import base_url_host_matches, base_url_hostname

View file

@ -16,7 +16,6 @@ compatibility.
from __future__ import annotations
import json
import logging
import os
import time

View file

@ -34,7 +34,7 @@ import tempfile
import uuid
from datetime import datetime
from pathlib import Path
from typing import Any, List, Optional, Tuple
from typing import Any, Optional, Tuple
from agent.model_metadata import estimate_request_tokens_rough

View file

@ -27,8 +27,6 @@ import time
import uuid
from typing import Any, Dict, List, Optional
from agent.anthropic_adapter import _is_oauth_token
from agent.auxiliary_client import set_runtime_main
from agent.codex_responses_adapter import _summarize_user_message_for_log
from agent.display import KawaiiSpinner
from agent.error_classifier import FailoverReason, classify_api_error
@ -53,20 +51,13 @@ from agent.model_metadata import (
parse_available_output_tokens_from_error,
save_context_length,
)
from agent.nous_rate_guard import (
clear_nous_rate_limit,
is_genuine_nous_rate_limit,
nous_rate_limit_remaining,
record_nous_rate_limit,
)
from agent.process_bootstrap import _install_safe_stdio
from agent.prompt_caching import apply_anthropic_cache_control
from agent.retry_utils import jittered_backoff
from agent.trajectory import has_incomplete_scratchpad
from agent.usage_pricing import estimate_usage_cost, normalize_usage
from hermes_constants import display_hermes_home as _dhh_fn, PARTIAL_STREAM_STUB_ID
from hermes_constants import PARTIAL_STREAM_STUB_ID
from hermes_logging import set_session_context
from tools.schema_sanitizer import strip_pattern_and_format
from tools.skill_provenance import set_current_write_origin
from utils import base_url_host_matches, env_var_enabled
@ -409,7 +400,6 @@ def run_conversation(
# Tag all log records on this thread with the session ID so
# ``hermes logs --session <id>`` can filter a single conversation.
from hermes_logging import set_session_context
set_session_context(agent.session_id)
# Bind the skill write-origin ContextVar for this thread so tool
@ -418,7 +408,6 @@ def run_conversation(
# a foreground user-directed turn. Set at the top of each call;
# the review fork runs on its own thread with a fresh context,
# so the foreground value here does not leak into it.
from tools.skill_provenance import set_current_write_origin
set_current_write_origin(getattr(agent, "_memory_write_origin", "assistant_tool"))
# If the previous turn activated fallback, restore the primary

View file

@ -14,7 +14,7 @@ from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Set, Tuple
from hermes_constants import OPENROUTER_BASE_URL
from hermes_cli.config import get_env_value, load_env
from hermes_cli.config import load_env
from agent.credential_persistence import (
is_borrowed_credential_source,
sanitize_borrowed_credential_payload,

View file

@ -39,12 +39,9 @@ from __future__ import annotations
import json
import logging
import os
import re
import shutil
import tarfile
import tempfile
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

View file

@ -31,7 +31,6 @@ import json
import logging
import time
import urllib.error
import urllib.parse
import urllib.request
import uuid
from dataclasses import dataclass, field

View file

@ -16,7 +16,6 @@ from __future__ import annotations
import argparse
import sys
from typing import Optional
def register_subparser(subparsers: argparse._SubParsersAction) -> None:
@ -249,7 +248,6 @@ def _cmd_restart() -> int:
def _cmd_which(server_id: str) -> int:
from agent.lsp.install import INSTALL_RECIPES, hermes_lsp_bin_dir
import os
import shutil as _shutil
recipe = INSTALL_RECIPES.get(server_id)

View file

@ -39,25 +39,20 @@ import logging
import os
import threading
import time
from concurrent.futures import Future as ConcurrentFuture
from typing import Any, Callable, Dict, List, Optional, Tuple
from agent.lsp import eventlog
from agent.lsp.client import (
DIAGNOSTICS_DOCUMENT_WAIT,
LSPClient,
file_uri,
)
from agent.lsp.servers import (
ServerContext,
ServerDef,
SpawnSpec,
find_server_for_file,
language_id_for,
)
from agent.lsp.workspace import (
clear_cache,
is_inside_workspace,
resolve_workspace_for_file,
)

View file

@ -25,7 +25,7 @@ import shutil
from dataclasses import dataclass, field
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
from agent.lsp.workspace import nearest_root, normalize_path
from agent.lsp.workspace import nearest_root
logger = logging.getLogger("agent.lsp.servers")

View file

@ -7,7 +7,6 @@ assemble pieces, then combines them with memory and ephemeral prompts.
import json
import logging
import os
import re
import threading
from collections import OrderedDict
from pathlib import Path

View file

@ -37,7 +37,6 @@ import platform
import shutil
import stat
import subprocess
import sys
import tempfile
import time
import urllib.error

View file

@ -20,7 +20,7 @@ import os
import random
import threading
import time
from typing import Any, Optional
from typing import Optional
from agent.display import (
KawaiiSpinner,

View file

@ -10,7 +10,7 @@ reasoning configuration, temperature handling, and extra_body assembly.
"""
import copy
from typing import Any, Dict, List, Optional
from typing import Any, Dict
from agent.lmstudio_reasoning import resolve_lmstudio_effort
from agent.moonshot_schema import is_moonshot_model, sanitize_moonshot_tools

View file

@ -23,7 +23,7 @@ import subprocess
import threading
import time
from dataclasses import dataclass, field
from typing import Any, Callable, Optional
from typing import Any, Optional
# Default minimum codex version we test against. The PR sets this from the
# `codex --version` parsed at install time; bumping is a one-line change here.

View file

@ -126,7 +126,6 @@ from gateway.platforms.qqbot.chunked_upload import (
)
from gateway.platforms.qqbot.keyboards import (
ApprovalRequest,
ApprovalSender,
InlineKeyboard,
InteractionEvent,
build_approval_keyboard,

View file

@ -37,7 +37,7 @@ import asyncio
import functools
import hashlib
import logging
from dataclasses import dataclass, field
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Awaitable, Callable, Dict, List, Optional

View file

@ -1690,7 +1690,6 @@ class TelegramAdapter(BasePlatformAdapter):
BotCommandScopeAllPrivateChats,
BotCommandScopeAllGroupChats,
BotCommandScopeDefault,
BotCommandScopeChat,
)
from hermes_cli.commands import telegram_menu_commands
# Telegram allows up to 100 commands but has an undocumented

View file

@ -751,7 +751,7 @@ _hermes_home = get_hermes_home()
# Load environment variables from ~/.hermes/.env first.
# User-managed env files should override stale shell exports on restart.
from dotenv import load_dotenv # backward-compat for tests that monkeypatch this symbol
from dotenv import load_dotenv # noqa: F401 # backward-compat for tests that monkeypatch this symbol
from hermes_cli.env_loader import load_hermes_dotenv
_env_path = _hermes_home / '.env'
load_hermes_dotenv(hermes_home=_hermes_home, project_env=Path(__file__).resolve().parents[1] / '.env')

View file

@ -26,7 +26,6 @@ piecemeal, the footer is sent as a separate trailing message via
from __future__ import annotations
import os
from pathlib import Path
from typing import Any, Iterable, Optional
_DEFAULT_FIELDS: tuple[str, ...] = ("model", "context_pct", "cwd")

View file

@ -27,11 +27,9 @@ guarantee.
from __future__ import annotations
import os
import shutil
import subprocess
import sys
from typing import Optional, Sequence
from typing import Sequence
__all__ = [
"IS_WINDOWS",

View file

@ -45,7 +45,6 @@ from typing import Any, Callable, Dict, FrozenSet, List, Optional, Tuple
from urllib.parse import parse_qs, urlencode, urlparse
import httpx
import yaml
from hermes_cli.config import get_hermes_home, get_config_path, read_raw_config
from hermes_constants import OPENROUTER_BASE_URL, secure_parent_dir

View file

@ -15,7 +15,7 @@ Subcommands:
from __future__ import annotations
import sys
from typing import List, Optional
from typing import List
from rich.console import Console
from rich.table import Table

View file

@ -25,7 +25,7 @@ import argparse
import time
from datetime import datetime
from pathlib import Path
from typing import Any, Dict
from typing import Any
def _fmt_bytes(n: int) -> str:

View file

@ -17,8 +17,6 @@ import logging
import re
import sys
import time
import urllib.error
import urllib.parse
import urllib.request
from dataclasses import dataclass
from pathlib import Path

View file

@ -8,7 +8,6 @@ import os
import sys
import subprocess
import shutil
import importlib.util
from pathlib import Path
from hermes_cli.config import get_project_root, get_hermes_home, get_env_path

View file

@ -84,7 +84,6 @@ import threading
import logging
import time
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Any, Iterable, Optional
@ -4743,7 +4742,6 @@ def detect_stale_running(
if stale_timeout_seconds <= 0:
return []
import signal as _signal_mod
now = int(time.time())
host_prefix = f"{_claimer_id().split(':', 1)[0]}:"
@ -6483,7 +6481,7 @@ def _to_epoch(val) -> Optional[int]:
pass
# ISO-8601 fallback (e.g. '2026-05-10T15:00:00Z')
try:
from datetime import datetime, timezone
from datetime import datetime
dt = datetime.fromisoformat(s.replace("Z", "+00:00"))
return int(dt.timestamp())
except (ValueError, OSError):

View file

@ -5593,7 +5593,6 @@ def _model_flow_bedrock(config, current_model=""):
def _model_flow_api_key_provider(config, provider_id, current_model=""):
"""Generic flow for API-key providers (z.ai, MiniMax, OpenCode, etc.)."""
from hermes_cli.auth import (
LMSTUDIO_NOAUTH_PLACEHOLDER,
PROVIDER_REGISTRY,
_prompt_model_selection,
_save_model_choice,

View file

@ -23,7 +23,6 @@ See references/mcp-catalog.md (this repo's skill) for the manifest schema.
from __future__ import annotations
import os
import re
import shutil
import subprocess
@ -41,7 +40,7 @@ from hermes_cli.config import (
get_env_value,
save_env_value,
)
from hermes_cli.cli_output import prompt as _prompt_input, prompt_yes_no
from hermes_cli.cli_output import prompt as _prompt_input
_MANIFEST_VERSION = 1

View file

@ -1085,8 +1085,7 @@ def list_authenticated_providers(
from hermes_cli.auth import PROVIDER_REGISTRY
from hermes_cli.models import (
OPENROUTER_MODELS, _PROVIDER_MODELS,
_MODELS_DEV_PREFERRED, _merge_with_models_dev, provider_model_ids,
cached_provider_model_ids,
_MODELS_DEV_PREFERRED, _merge_with_models_dev, cached_provider_model_ids,
get_curated_nous_model_ids,
)

View file

@ -34,7 +34,6 @@ so plugin-defined tools appear alongside the built-in tools.
from __future__ import annotations
import asyncio
import importlib
import importlib.metadata
import importlib.util
import inspect

View file

@ -13,7 +13,6 @@ from __future__ import annotations
import sys
import webbrowser
from typing import Optional
from hermes_cli.colors import Colors, color
from hermes_cli.config import load_config

View file

@ -28,7 +28,6 @@ from __future__ import annotations
import json
import logging
import os
import re
from dataclasses import dataclass
from pathlib import Path

View file

@ -940,7 +940,6 @@ def delete_profile(name: str, yes: bool = False) -> Path:
``sys.exc_info()`` tuple).
"""
import stat as _stat
import sys as _sys
# Normalise the two callback signatures:
# onexc(func, path, exc_instance) — 3.12+

View file

@ -12,7 +12,6 @@ or rewrite request/response bodies. It's a credential-attaching forwarder.
from __future__ import annotations
import asyncio
import json
import logging
import signal
from typing import Optional

View file

@ -14,9 +14,8 @@ import argparse
import json
import os
import subprocess
import sys
from pathlib import Path
from typing import List, Optional, Tuple
from typing import List, Optional
from rich.console import Console
from rich.panel import Panel

View file

@ -36,7 +36,7 @@ from __future__ import annotations
import logging
import os
import sys
from dataclasses import dataclass, field
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable, Optional

View file

@ -28,7 +28,7 @@ import urllib.error
import urllib.request
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Iterable, Optional
from typing import Iterable, Optional
from hermes_constants import get_hermes_home

View file

@ -12,7 +12,6 @@ Config files are stored in ~/.hermes/ for easy access.
"""
import importlib.util
import json
import logging
import os
import re

View file

@ -7,7 +7,6 @@ Shows the status of all Hermes Agent components.
import os
import sys
import subprocess # noqa: F401 — re-exported for tests that monkeypatch status.subprocess to guard against regressions
import importlib.util
from pathlib import Path
PROJECT_ROOT = Path(__file__).parent.parent.resolve()

View file

@ -216,7 +216,6 @@ def _augment_path_with_known_tools() -> None:
if not is_windows():
return
import shutil as _shutil
local_appdata = os.environ.get("LOCALAPPDATA", "")
if not local_appdata:

View file

@ -3351,7 +3351,6 @@ async def get_models_analytics(days: int = 30):
# ---------------------------------------------------------------------------
import re
import asyncio
# PTY bridge is POSIX-only (depends on fcntl/termios/ptyprocess). On native
# Windows the import raises; catch and leave PtyBridge=None so the rest of

View file

@ -29,12 +29,8 @@ Usage:
import json
import logging
import os
import sys
import time
import uuid
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Any, Optional, Literal
from typing import List, Dict, Any, Optional
import fire
from dotenv import load_dotenv

View file

@ -18,7 +18,6 @@ unknown templates get smart default text positioning based on their box_count.
import json
import os
import sys
import textwrap
from io import BytesIO
from pathlib import Path

View file

@ -7,7 +7,6 @@ Validates Excel DCF models for formula errors and common DCF mistakes
import sys
import json
from pathlib import Path
from typing import Optional
class DCFModelValidator:

View file

@ -16,7 +16,6 @@ import json
import time
import urllib.request
import urllib.parse
import urllib.error
API_KEY = os.environ.get("USDA_API_KEY", "DEMO_KEY")
BASE = "https://api.nal.usda.gov/fdc/v1"

View file

@ -5,7 +5,7 @@ Usage: python3 chembl_target.py "EGFR" --min-pchembl 7 --limit 20
No external dependencies.
"""
import sys, json, time, argparse
import urllib.request, urllib.parse, urllib.error
import urllib.request, urllib.parse
BASE = "https://www.ebi.ac.uk/chembl/api/data"

View file

@ -4,8 +4,8 @@ ro5_screen.py — Batch Lipinski Ro5 + Veber screening via PubChem API.
Usage: python3 ro5_screen.py aspirin ibuprofen paracetamol
No external dependencies beyond stdlib.
"""
import sys, json, time, argparse
import urllib.request, urllib.parse, urllib.error
import sys, json, time
import urllib.request, urllib.parse
BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name"
PROPS = "MolecularWeight,XLogP,HBondDonorCount,HBondAcceptorCount,RotatableBondCount,TPSA"

View file

@ -11,7 +11,6 @@ from __future__ import annotations
import argparse
import csv
import json
import sys
import time
import urllib.parse

View file

@ -12,7 +12,6 @@ from __future__ import annotations
import argparse
import csv
import json
import os
import re
import sys

View file

@ -12,7 +12,6 @@ from __future__ import annotations
import argparse
import csv
import json
import re
import sys
import urllib.parse

View file

@ -19,7 +19,6 @@ import argparse
import csv
import datetime as dt
import json
import math
import random
import statistics
from collections import defaultdict

View file

@ -13,7 +13,6 @@ from __future__ import annotations
import argparse
import json
import os
import sys
from pathlib import Path
from typing import Optional

View file

@ -49,8 +49,7 @@ from gateway.platforms.base import (
MessageEvent,
MessageType,
)
from gateway.session import SessionSource
from gateway.config import PlatformConfig, Platform
from gateway.config import Platform
# ---------------------------------------------------------------------------

View file

@ -76,7 +76,7 @@ import time
import uuid
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Tuple
from typing import Any, Dict, List, Optional, Set, Tuple
from urllib.parse import quote as _urlquote
logger = logging.getLogger(__name__)
@ -95,7 +95,6 @@ from gateway.platforms.base import (
cache_image_from_bytes,
)
from gateway.config import Platform
from gateway.session import SessionSource
# ---------------------------------------------------------------------------

View file

@ -2,7 +2,7 @@
from __future__ import annotations
from typing import Any, Dict, List
from typing import Any, List
from hermes_cli.auth import get_auth_status
from plugins.spotify.client import (

View file

@ -24,7 +24,6 @@ from plugins.teams_pipeline.store import TeamsPipelineStore, resolve_teams_pipel
from plugins.teams_pipeline.subscriptions import (
build_graph_client,
maintain_graph_subscriptions,
sync_graph_subscription_record,
)
from tools.microsoft_graph_auth import MicrosoftGraphConfigError, MicrosoftGraphTokenProvider

View file

@ -7,7 +7,6 @@ import json
import logging
import os
import shutil
import subprocess
import tempfile
import uuid
from dataclasses import dataclass
@ -19,7 +18,6 @@ import httpx
from agent.auxiliary_client import async_call_llm, extract_content_or_reasoning
from hermes_constants import get_hermes_home
from plugins.teams_pipeline.meetings import (
TeamsMeetingArtifactNotFoundError,
download_recording_artifact,
enrich_meeting_with_call_record,
fetch_preferred_transcript_text,

View file

@ -33,26 +33,19 @@ except ModuleNotFoundError:
import asyncio
import base64
import concurrent.futures
import contextvars
import copy
import hashlib
import json
import logging
logger = logging.getLogger(__name__)
import os
import random
import re
import ssl
import sys
import tempfile
import time
import threading
from types import SimpleNamespace
import urllib.request
import uuid
from typing import List, Dict, Any, Optional
from urllib.parse import urlparse, parse_qs, urlunparse
# NOTE: `from openai import OpenAI` is deliberately NOT at module top — the
# SDK pulls ~240 ms of imports. We expose `OpenAI` as a thin proxy object
# that imports the SDK on first call/isinstance check. This preserves:
@ -73,12 +66,6 @@ from hermes_constants import get_hermes_home
# OpenAI lazy proxy + safe stdio + proxy URL helpers — see agent/process_bootstrap.py.
# `OpenAI` is re-exported here so `patch("run_agent.OpenAI", ...)` in tests works.
from agent.process_bootstrap import (
OpenAI,
_OpenAIProxy,
_load_openai_cls,
_SafeWriter,
_install_safe_stdio,
_get_proxy_from_env,
_get_proxy_for_base_url,
)
from agent.iteration_budget import IterationBudget
@ -102,77 +89,27 @@ else:
# Import our tool system
from model_tools import (
get_tool_definitions,
get_toolset_for_tool,
handle_function_call,
check_toolset_requirements,
)
from tools.terminal_tool import cleanup_vm, get_active_env, is_persistent_env
from tools.terminal_tool import (
set_approval_callback as _set_approval_callback,
set_sudo_password_callback as _set_sudo_password_callback,
_get_approval_callback,
_get_sudo_password_callback,
)
from tools.tool_result_storage import maybe_persist_tool_result, enforce_turn_budget
from tools.terminal_tool import cleanup_vm
from tools.interrupt import set_interrupt as _set_interrupt
from tools.browser_tool import cleanup_browser
# Agent internals extracted to agent/ package for modularity
from agent.memory_manager import StreamingContextScrubber, build_memory_context_block, sanitize_context
from agent.think_scrubber import StreamingThinkScrubber
from agent.retry_utils import jittered_backoff
from agent.error_classifier import classify_api_error, FailoverReason
from agent.memory_manager import sanitize_context
from agent.error_classifier import FailoverReason
from agent.redact import redact_sensitive_text
from agent.prompt_builder import (
DEFAULT_AGENT_IDENTITY, PLATFORM_HINTS,
MEMORY_GUIDANCE, SESSION_SEARCH_GUIDANCE, SKILLS_GUIDANCE,
HERMES_AGENT_HELP_GUIDANCE,
KANBAN_GUIDANCE,
build_nous_subscription_prompt,
)
from agent.model_metadata import (
fetch_model_metadata,
estimate_tokens_rough, estimate_messages_tokens_rough, estimate_request_tokens_rough,
get_next_probe_tier, parse_context_limit_from_error,
parse_available_output_tokens_from_error,
save_context_length, is_local_endpoint,
query_ollama_num_ctx,
is_local_endpoint,
)
from agent.context_compressor import ContextCompressor
from agent.subdirectory_hints import SubdirectoryHintTracker
from agent.prompt_caching import apply_anthropic_cache_control
from agent.prompt_builder import build_skills_system_prompt, build_context_files_prompt, build_environment_hints, load_soul_md, TOOL_USE_ENFORCEMENT_GUIDANCE, TOOL_USE_ENFORCEMENT_MODELS, GOOGLE_MODEL_OPERATIONAL_GUIDANCE, OPENAI_MODEL_EXECUTION_GUIDANCE
from agent.usage_pricing import estimate_usage_cost, normalize_usage
from agent.codex_responses_adapter import (
_derive_responses_function_call_id as _codex_derive_responses_function_call_id,
_deterministic_call_id as _codex_deterministic_call_id,
_split_responses_tool_id as _codex_split_responses_tool_id,
_summarize_user_message_for_log,
)
from agent.display import (
KawaiiSpinner, build_tool_preview as _build_tool_preview,
get_cute_tool_message as _get_cute_tool_message_impl,
_detect_tool_failure,
get_tool_emoji as _get_tool_emoji,
)
from agent.tool_guardrails import (
ToolCallGuardrailConfig,
ToolCallGuardrailController,
ToolGuardrailDecision,
append_toolguard_guidance,
toolguard_synthetic_result,
)
from agent.tool_result_classification import (
FILE_MUTATING_TOOL_NAMES as _FILE_MUTATING_TOOLS,
file_mutation_result_landed,
)
from agent.trajectory import (
convert_scratchpad_to_think,
save_trajectory as _save_trajectory_to_file,
)
from agent.message_sanitization import (
from agent.usage_pricing import normalize_usage
# Re-exported for tests that monkeypatch these symbols on run_agent.
from agent.context_compressor import ContextCompressor # noqa: F401
from agent.retry_utils import jittered_backoff # noqa: F401
from agent.prompt_builder import build_skills_system_prompt, load_soul_md # noqa: F401
from agent.process_bootstrap import _get_proxy_from_env # noqa: F401
from agent.message_sanitization import ( # noqa: F401
_SURROGATE_RE,
_sanitize_surrogates,
_sanitize_structure_surrogates,
@ -185,25 +122,33 @@ from agent.message_sanitization import (
_strip_images_from_messages,
_sanitize_structure_non_ascii,
)
from agent.codex_responses_adapter import (
_derive_responses_function_call_id as _codex_derive_responses_function_call_id,
_deterministic_call_id as _codex_deterministic_call_id,
_split_responses_tool_id as _codex_split_responses_tool_id,
_summarize_user_message_for_log, # noqa: F401 # re-exported for tests
)
from agent.tool_guardrails import (
ToolGuardrailDecision,
append_toolguard_guidance,
toolguard_synthetic_result,
)
from agent.tool_result_classification import (
FILE_MUTATING_TOOL_NAMES as _FILE_MUTATING_TOOLS,
file_mutation_result_landed,
)
from agent.trajectory import (
convert_scratchpad_to_think,
save_trajectory as _save_trajectory_to_file,
)
from agent.tool_dispatch_helpers import (
_NEVER_PARALLEL_TOOLS,
_PARALLEL_SAFE_TOOLS,
_PATH_SCOPED_TOOLS,
_DESTRUCTIVE_PATTERNS,
_REDIRECT_OVERWRITE,
_is_destructive_command,
_should_parallelize_tool_batch,
_extract_parallel_scope_path,
_paths_overlap,
_is_multimodal_tool_result,
_multimodal_text_summary,
_append_subdir_hint_to_multimodal,
_extract_file_mutation_targets,
_extract_error_preview,
_trajectory_normalize_msg,
)
from utils import atomic_json_write, base_url_host_matches, base_url_hostname, env_var_enabled, normalize_proxy_url
from hermes_cli.config import cfg_get
from utils import atomic_json_write, base_url_host_matches, base_url_hostname

View file

@ -17,7 +17,6 @@ Usage:
import argparse
import json
import os
import re
import subprocess
import sys
@ -30,7 +29,7 @@ from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(SCRIPT_DIR))
from release import AUTHOR_MAP, resolve_author # noqa: E402
from release import resolve_author # noqa: E402
REPO_ROOT = SCRIPT_DIR.parent

View file

@ -15,7 +15,6 @@ Usage:
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path

View file

@ -2,15 +2,11 @@
from __future__ import annotations
from pathlib import Path
import pytest
from _common import (
DEFAULT_LOCAL_HOST,
EMBEDDING_REGEX,
FOLDER_ALIASES,
build_cloud_aware_url,
cloud_endpoint,
coerce_seed,
folder_aliases_for,

View file

@ -2,7 +2,6 @@
from __future__ import annotations
import pytest
from extract_schema import (
extract_schema,

View file

@ -2,10 +2,7 @@
from __future__ import annotations
import copy
import json
import pytest
from extract_schema import extract_schema
from run_workflow import (

View file

@ -18,7 +18,6 @@ Commands:
import argparse
import json
import math
import os
import sys
import time
import urllib.error

View file

@ -13,11 +13,8 @@ Both fixed together by:
threads don't collide.
"""
import os
import threading
from unittest.mock import MagicMock
import pytest
class TestThreadLocalApprovalCallback:

View file

@ -9,7 +9,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
import acp
from acp.schema import AgentPlanUpdate, ToolCallStart, ToolCallProgress, AgentThoughtChunk, AgentMessageChunk
from acp.schema import AgentPlanUpdate
from acp_adapter.events import (
_build_plan_update_from_todo_result,

View file

@ -7,9 +7,6 @@ Exercises the full flow through the ACP server layer:
session_update events arrive at the mock client
"""
import asyncio
from collections import deque
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock, patch
import pytest

View file

@ -18,7 +18,6 @@ from acp.schema import (
AvailableCommandsUpdate,
Implementation,
InitializeResponse,
ListSessionsResponse,
LoadSessionResponse,
NewSessionResponse,
PromptResponse,
@ -33,7 +32,6 @@ from acp.schema import (
TextContentBlock,
ToolCallProgress,
ToolCallStart,
Usage,
UsageUpdate,
UserMessageChunk,
)

View file

@ -1,6 +1,5 @@
"""Tests for acp_adapter.tools — tool kind mapping and ACP content building."""
import pytest
from acp_adapter.edit_approval import EditProposal
from acp_adapter.tools import (

View file

@ -8,8 +8,6 @@ syntax check exactly as if LSP were disabled.
"""
from __future__ import annotations
import os
import sys
from unittest.mock import MagicMock
import pytest

View file

@ -14,15 +14,12 @@ This module verifies:
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch
from unittest.mock import patch
import pytest
from agent.lsp.manager import LSPService
from agent.lsp.servers import SERVERS, ServerContext, ServerDef, SpawnSpec
from agent.lsp.workspace import clear_cache

View file

@ -6,12 +6,8 @@ having LSP output prepended to the lint string.
"""
from __future__ import annotations
import os
import sys
import tempfile
from unittest.mock import MagicMock, patch
from unittest.mock import patch
import pytest
from tools.environments.local import LocalEnvironment
from tools.file_operations import (

View file

@ -7,7 +7,7 @@ pyright/gopls/etc. are still alive on the host.
from __future__ import annotations
import atexit
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock
import pytest

View file

@ -2,7 +2,6 @@
from __future__ import annotations
from agent.lsp.reporter import (
DEFAULT_SEVERITIES,
MAX_PER_FILE,
format_diagnostic,
report_for_file,

View file

@ -7,7 +7,6 @@ on.
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
@ -19,7 +18,6 @@ from agent.lsp.servers import (
ServerContext,
ServerDef,
SpawnSpec,
find_server_for_file,
)

View file

@ -1,10 +1,8 @@
"""Tests for Bug #12905 fixes in agent/anthropic_adapter.py — macOS Keychain support."""
import json
import platform
from unittest.mock import patch, MagicMock
import pytest
from agent.anthropic_adapter import (
_read_claude_code_credentials_from_keychain,

View file

@ -8,11 +8,9 @@ name in the tool registry.
from __future__ import annotations
import json
from types import SimpleNamespace
from unittest.mock import patch
import pytest
# ---------------------------------------------------------------------------

View file

@ -15,7 +15,6 @@ History:
from __future__ import annotations
import io
import json
from typing import Any, Dict
from urllib.parse import parse_qs, urlparse

View file

@ -8,7 +8,6 @@ import warnings
from concurrent.futures import Future
from unittest.mock import patch
import pytest
from agent.async_utils import safe_schedule_threadsafe

View file

@ -2,9 +2,7 @@
import json
import logging
import os
import time
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch, MagicMock, AsyncMock
@ -609,7 +607,7 @@ class TestExpiredCodexFallback:
monkeypatch.setenv("ANTHROPIC_TOKEN", "sk-ant-oat01-test-fallback")
with patch("agent.anthropic_adapter.build_anthropic_client") as mock_build:
mock_build.return_value = MagicMock()
from agent.auxiliary_client import _resolve_auto, AnthropicAuxiliaryClient
from agent.auxiliary_client import _resolve_auto
client, model = _resolve_auto()
# Should NOT be Codex, should be Anthropic (or another available provider)
assert not isinstance(client, type(None)), "Should find a provider after expired Codex"
@ -696,7 +694,7 @@ class TestExpiredCodexFallback:
patch("agent.anthropic_adapter.build_anthropic_client") as mock_build, \
patch("agent.auxiliary_client._select_pool_entry", return_value=(False, None)):
mock_build.return_value = MagicMock()
from agent.auxiliary_client import _try_anthropic, AnthropicAuxiliaryClient
from agent.auxiliary_client import _try_anthropic
client, model = _try_anthropic()
assert client is not None, "Should resolve token"
adapter = client.chat.completions
@ -751,7 +749,7 @@ class TestExpiredCodexFallback:
monkeypatch.delenv("ANTHROPIC_TOKEN", raising=False)
with patch("agent.anthropic_adapter.build_anthropic_client") as mock_build:
mock_build.return_value = MagicMock()
from agent.auxiliary_client import _try_anthropic, AnthropicAuxiliaryClient
from agent.auxiliary_client import _try_anthropic
client, model = _try_anthropic()
assert client is not None
adapter = client.chat.completions

View file

@ -27,7 +27,6 @@ from __future__ import annotations
import sys
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest

View file

@ -4,14 +4,11 @@ are properly mapped to environment variables by both CLI and gateway loaders.
Also tests the vision_tools and browser_tool model override env vars.
"""
import json
import os
import sys
from pathlib import Path
from unittest.mock import patch, MagicMock
import pytest
import yaml
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))

View file

@ -15,7 +15,6 @@ from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
# ── Text aux tasks — _resolve_auto ──────────────────────────────────────────

View file

@ -1,6 +1,5 @@
"""Tests for named custom provider and 'main' alias resolution in auxiliary_client."""
import os
from unittest.mock import patch, MagicMock
import pytest

View file

@ -23,7 +23,6 @@ import sys
from collections.abc import Callable
from types import SimpleNamespace
from typing import cast
from unittest.mock import MagicMock, patch
import pytest

View file

@ -10,11 +10,9 @@ Covers:
"""
import json
import os
import time
from contextlib import contextmanager
from types import ModuleType, SimpleNamespace
from unittest.mock import MagicMock, patch, PropertyMock
from types import ModuleType
from unittest.mock import MagicMock, patch
import pytest
@ -129,7 +127,7 @@ class TestResolveBedrocRegion:
def test_defaults_to_us_east_1(self):
from agent.bedrock_adapter import resolve_bedrock_region
from unittest.mock import patch, MagicMock
from unittest.mock import MagicMock
mock_session = MagicMock()
mock_session.get_config_variable.return_value = None
with _mock_botocore_session(return_value=mock_session):
@ -137,7 +135,7 @@ class TestResolveBedrocRegion:
def test_falls_back_to_botocore_profile_region(self):
from agent.bedrock_adapter import resolve_bedrock_region
from unittest.mock import patch, MagicMock
from unittest.mock import MagicMock
mock_session = MagicMock()
mock_session.get_config_variable.return_value = "eu-central-1"
with _mock_botocore_session(return_value=mock_session):
@ -145,7 +143,6 @@ class TestResolveBedrocRegion:
def test_botocore_failure_falls_back_to_us_east_1(self):
from agent.bedrock_adapter import resolve_bedrock_region
from unittest.mock import patch
with _mock_botocore_session(side_effect=Exception("no botocore")):
assert resolve_bedrock_region({}) == "us-east-1"

View file

@ -9,7 +9,6 @@ Note: Tests that import ``hermes_cli.auth`` or ``hermes_cli.runtime_provider``
require Python 3.10+ due to ``str | None`` type syntax in the import chain.
"""
import os
from unittest.mock import MagicMock, patch
import pytest
@ -93,7 +92,6 @@ class TestResolveProvider:
def test_explicit_bedrock_resolves(self, monkeypatch):
"""When user explicitly requests 'bedrock', it should resolve."""
from hermes_cli.auth import PROVIDER_REGISTRY
# bedrock is in the registry, so resolve_provider should return it
from hermes_cli.auth import resolve_provider
result = resolve_provider("bedrock")

View file

@ -29,7 +29,6 @@ import base64
import json
from unittest.mock import MagicMock, patch
import pytest
# ---------------------------------------------------------------------------

View file

@ -8,7 +8,6 @@ creative workflows that iterate on images across many turns.
from __future__ import annotations
import pytest
from agent.context_compressor import (
_CHARS_PER_TOKEN,

View file

@ -232,7 +232,7 @@ class TestPluginContextEngineSlot:
assert mgr._context_engine is None
def test_get_plugin_context_engine(self):
from hermes_cli.plugins import PluginManager, PluginContext, PluginManifest, get_plugin_context_engine, _plugin_manager
from hermes_cli.plugins import PluginManager, get_plugin_context_engine
import hermes_cli.plugins as plugins_mod
# Inject a test manager

View file

@ -28,7 +28,6 @@ from __future__ import annotations
from unittest.mock import MagicMock
import pytest
from run_agent import AIAgent

View file

@ -10,9 +10,7 @@ so it can run without optional dependencies like firecrawl.
import asyncio
import threading
from concurrent.futures import ThreadPoolExecutor
from unittest.mock import patch, MagicMock
from types import SimpleNamespace
import pytest
@ -32,7 +30,6 @@ def _stub_resolve_provider_client(provider, model, async_mode, **kw):
@pytest.fixture(autouse=True)
def _clean_client_cache():
"""Clear the client cache before each test."""
import importlib
# We need to patch before importing
with patch.dict("sys.modules", {}):
pass
@ -48,7 +45,7 @@ class TestCrossLoopCacheIsolation:
def test_same_loop_reuses_client(self):
"""Within a single event loop, the same client should be returned."""
from agent.auxiliary_client import _get_cached_client, _client_cache
from agent.auxiliary_client import _get_cached_client
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

View file

@ -7,7 +7,6 @@ tests run fully offline and the curator module doesn't need real credentials.
from __future__ import annotations
import importlib
import json
from datetime import datetime, timedelta, timezone
from pathlib import Path

View file

@ -7,8 +7,7 @@ the standard log dir, not inside the user's ``skills/`` data directory.
from __future__ import annotations
import json
import os
from datetime import datetime, timezone, timedelta
from datetime import datetime, timezone
from pathlib import Path
import pytest

View file

@ -1,9 +1,8 @@
"""Tests for agent/display.py — build_tool_preview() and inline diff previews."""
import os
import json
import pytest
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock
from agent.display import (
build_tool_preview,

View file

@ -5,7 +5,6 @@ todo tool call paths: read, create (merge=False), update (merge=True).
"""
import json
import pytest
from agent.display import get_cute_tool_message

View file

@ -7,7 +7,6 @@ not a generic "[error]".
"""
import json
import pytest
from agent.display import (
_detect_tool_failure,

Some files were not shown because too many files have changed in this diff Show more