diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index e3ae8c7ab4..6baa9f341e 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -523,9 +523,6 @@ def _read_claude_code_credentials_from_keychain() -> Optional[Dict[str, Any]]: Returns dict with {accessToken, refreshToken?, expiresAt?} or None. """ - import platform - import subprocess - if platform.system() != "Darwin": return None diff --git a/agent/credential_pool.py b/agent/credential_pool.py index 98534e902c..d11b0186e4 100644 --- a/agent/credential_pool.py +++ b/agent/credential_pool.py @@ -7,7 +7,6 @@ import random import threading import time import uuid -import os import re from dataclasses import dataclass, fields, replace from datetime import datetime diff --git a/agent/credential_sources.py b/agent/credential_sources.py index 8ad2fade0b..dce6293526 100644 --- a/agent/credential_sources.py +++ b/agent/credential_sources.py @@ -47,7 +47,6 @@ from __future__ import annotations import os from dataclasses import dataclass, field -from pathlib import Path from typing import Callable, List, Optional diff --git a/agent/gemini_cloudcode_adapter.py b/agent/gemini_cloudcode_adapter.py index 24866c3a53..64c51cf9d8 100644 --- a/agent/gemini_cloudcode_adapter.py +++ b/agent/gemini_cloudcode_adapter.py @@ -30,7 +30,6 @@ from __future__ import annotations import json import logging -import os import time import uuid from types import SimpleNamespace @@ -42,7 +41,6 @@ from agent import google_oauth from agent.gemini_schema import sanitize_gemini_tool_parameters from agent.google_code_assist import ( CODE_ASSIST_ENDPOINT, - FREE_TIER_ID, CodeAssistError, ProjectContext, resolve_project_context, diff --git a/agent/gemini_schema.py b/agent/gemini_schema.py index 3608837a18..7d5385063e 100644 --- a/agent/gemini_schema.py +++ b/agent/gemini_schema.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any, Dict, List +from typing import Any, Dict # Gemini's ``FunctionDeclaration.parameters`` field accepts the ``Schema`` # object, which is only a subset of OpenAPI 3.0 / JSON Schema. Strip fields diff --git a/agent/google_code_assist.py b/agent/google_code_assist.py index eba09b8f46..3e61d1b03e 100644 --- a/agent/google_code_assist.py +++ b/agent/google_code_assist.py @@ -29,7 +29,6 @@ from __future__ import annotations import json import logging -import os import time import urllib.error import urllib.parse diff --git a/agent/google_oauth.py b/agent/google_oauth.py index 231e7e1292..d6b96da6e5 100644 --- a/agent/google_oauth.py +++ b/agent/google_oauth.py @@ -49,14 +49,13 @@ import json import logging import os import secrets -import socket import stat import threading import time import urllib.error import urllib.parse import urllib.request -from dataclasses import dataclass, field +from dataclasses import dataclass from pathlib import Path from typing import Any, Dict, Optional, Tuple diff --git a/agent/memory_manager.py b/agent/memory_manager.py index a76cee4b5f..2831eb7bf8 100644 --- a/agent/memory_manager.py +++ b/agent/memory_manager.py @@ -28,7 +28,6 @@ Usage in run_agent.py: from __future__ import annotations -import json import logging import re import inspect diff --git a/agent/transports/codex.py b/agent/transports/codex.py index 783582d57b..7d6bed46de 100644 --- a/agent/transports/codex.py +++ b/agent/transports/codex.py @@ -8,7 +8,7 @@ streaming, or the _run_codex_stream() call path. from typing import Any, Dict, List, Optional from agent.transports.base import ProviderTransport -from agent.transports.types import NormalizedResponse, ToolCall, Usage +from agent.transports.types import NormalizedResponse, ToolCall class ResponsesApiTransport(ProviderTransport): @@ -151,8 +151,6 @@ class ResponsesApiTransport(ProviderTransport): """Normalize Codex Responses API response to NormalizedResponse.""" from agent.codex_responses_adapter import ( _normalize_codex_response, - _extract_responses_message_text, - _extract_responses_reasoning_text, ) # _normalize_codex_response returns (SimpleNamespace, finish_reason_str) diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index e0b2a64c67..903624a166 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -305,7 +305,7 @@ class VoiceReceiver: encrypted = bytes(payload_with_nonce[:-4]) try: - import nacl.secret # noqa: delayed import – only in voice path + import nacl.secret # noqa: E402 — delayed import, only in voice path box = nacl.secret.Aead(self._secret_key) decrypted = box.decrypt(encrypted, header, bytes(nonce)) except Exception as e: diff --git a/gateway/platforms/feishu_comment.py b/gateway/platforms/feishu_comment.py index 46807630ce..08cd35185c 100644 --- a/gateway/platforms/feishu_comment.py +++ b/gateway/platforms/feishu_comment.py @@ -974,7 +974,6 @@ def build_whole_comment_prompt( def _resolve_model_and_runtime() -> Tuple[str, dict]: """Resolve model and provider credentials, same as gateway message handling.""" - import os from gateway.run import _load_gateway_config, _resolve_gateway_model user_config = _load_gateway_config() diff --git a/gateway/platforms/helpers.py b/gateway/platforms/helpers.py index 17bc490174..64aead4b84 100644 --- a/gateway/platforms/helpers.py +++ b/gateway/platforms/helpers.py @@ -11,10 +11,10 @@ import logging import re import time from pathlib import Path -from typing import TYPE_CHECKING, Dict, Optional +from typing import TYPE_CHECKING, Dict if TYPE_CHECKING: - from gateway.platforms.base import BasePlatformAdapter, MessageEvent + from gateway.platforms.base import MessageEvent logger = logging.getLogger(__name__) diff --git a/gateway/platforms/mattermost.py b/gateway/platforms/mattermost.py index 0e6c9631d7..0fc72ca013 100644 --- a/gateway/platforms/mattermost.py +++ b/gateway/platforms/mattermost.py @@ -412,7 +412,6 @@ class MattermostAdapter(BasePlatformAdapter): import aiohttp - last_exc = None file_data = None ct = "application/octet-stream" fname = url.rsplit("/", 1)[-1].split("?")[0] or f"{kind}.png" diff --git a/gateway/platforms/qqbot/adapter.py b/gateway/platforms/qqbot/adapter.py index 9328464584..28a297944d 100644 --- a/gateway/platforms/qqbot/adapter.py +++ b/gateway/platforms/qqbot/adapter.py @@ -1957,7 +1957,7 @@ class QQAdapter(BasePlatformAdapter): self, openid: str, content: str, reply_to: Optional[str] = None ) -> SendResult: """Send text to a C2C user via REST API.""" - msg_seq = self._next_msg_seq(reply_to or openid) + self._next_msg_seq(reply_to or openid) body = self._build_text_body(content, reply_to) if reply_to: body["msg_id"] = reply_to @@ -1970,7 +1970,7 @@ class QQAdapter(BasePlatformAdapter): self, group_openid: str, content: str, reply_to: Optional[str] = None ) -> SendResult: """Send text to a group via REST API.""" - msg_seq = self._next_msg_seq(reply_to or group_openid) + self._next_msg_seq(reply_to or group_openid) body = self._build_text_body(content, reply_to) if reply_to: body["msg_id"] = reply_to @@ -2135,11 +2135,6 @@ class QQAdapter(BasePlatformAdapter): # Route chat_type = self._guess_chat_type(chat_id) - target_path = ( - f"/v2/users/{chat_id}/files" - if chat_type == "c2c" - else f"/v2/groups/{chat_id}/files" - ) if chat_type == "guild": # Guild channels don't support native media upload in the same way diff --git a/gateway/platforms/yuanbao.py b/gateway/platforms/yuanbao.py index 49df1b6c4a..83cd669565 100644 --- a/gateway/platforms/yuanbao.py +++ b/gateway/platforms/yuanbao.py @@ -90,7 +90,7 @@ from gateway.platforms.yuanbao_proto import ( encode_get_group_member_list, next_seq_no, ) -from gateway.session import SessionSource, build_session_key +from gateway.session import build_session_key logger = logging.getLogger(__name__) @@ -1897,7 +1897,7 @@ class OwnerCommandMiddleware(InboundMiddleware): return None, None, False # Sender identity check: bot owner <-> push.from_account == push.bot_owner_id - owner_id = (push or {}).get("bot_owner_id") or "" + # owner_id = (push or {}).get("bot_owner_id") or "" # is_owner = bool(owner_id) and owner_id == from_account is_owner = True return cmd, cmd_line, is_owner diff --git a/gateway/platforms/yuanbao_media.py b/gateway/platforms/yuanbao_media.py index 8d697a3a8c..39f8d88d8a 100644 --- a/gateway/platforms/yuanbao_media.py +++ b/gateway/platforms/yuanbao_media.py @@ -21,12 +21,10 @@ import hashlib import hmac import logging import os -import re import secrets import struct import time import urllib.parse -from datetime import datetime, timezone, timedelta from typing import Optional, Any import httpx diff --git a/gateway/platforms/yuanbao_proto.py b/gateway/platforms/yuanbao_proto.py index 3d4e56ce49..99af40aa18 100644 --- a/gateway/platforms/yuanbao_proto.py +++ b/gateway/platforms/yuanbao_proto.py @@ -19,9 +19,8 @@ yuanbao_proto.py - Yuanbao WebSocket 协议编解码(纯 Python 实现) from __future__ import annotations import logging -import struct import threading -from typing import Optional, Union +from typing import Optional logger = logging.getLogger(__name__) diff --git a/gateway/run.py b/gateway/run.py index bd9a552a1d..aa2ac75e84 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -7486,7 +7486,6 @@ class GatewayRunner: for m in history if m.get("role") in ("user", "assistant") and m.get("content") ] - original_count = len(msgs) approx_tokens = estimate_messages_tokens_rough(msgs) tmp_agent = AIAgent( diff --git a/gateway/session.py b/gateway/session.py index 0cd7fbca1f..6f35b95865 100644 --- a/gateway/session.py +++ b/gateway/session.py @@ -62,7 +62,6 @@ from .config import ( ) from .whatsapp_identity import ( canonical_whatsapp_identifier, - normalize_whatsapp_identifier, ) from utils import atomic_replace diff --git a/hermes_cli/azure_detect.py b/hermes_cli/azure_detect.py index 4ed4c1d0b7..8dd0d632a9 100644 --- a/hermes_cli/azure_detect.py +++ b/hermes_cli/azure_detect.py @@ -34,7 +34,7 @@ from dataclasses import dataclass, field from typing import Optional from urllib import request as urllib_request from urllib.error import HTTPError, URLError -from urllib.parse import urlparse, urlunparse +from urllib.parse import urlparse logger = logging.getLogger(__name__) diff --git a/hermes_cli/banner.py b/hermes_cli/banner.py index 0f792592f9..d46c853997 100644 --- a/hermes_cli/banner.py +++ b/hermes_cli/banner.py @@ -562,7 +562,6 @@ def build_welcome_banner(console: Console, model: str, cwd: str, right_content = "\n".join(right_lines) layout_table.add_row(left_content, right_content) - agent_name = _skin_branding("agent_name", "Hermes Agent") title_color = _skin_color("banner_title", "#FFD700") border_color = _skin_color("banner_border", "#CD7F32") version_label = format_banner_version_label() diff --git a/hermes_cli/debug.py b/hermes_cli/debug.py index 71c5443516..06be05a355 100644 --- a/hermes_cli/debug.py +++ b/hermes_cli/debug.py @@ -7,7 +7,6 @@ Currently supports: import io import json -import os import sys import time import urllib.error diff --git a/hermes_cli/dingtalk_auth.py b/hermes_cli/dingtalk_auth.py index e1034c53da..798ce46fcb 100644 --- a/hermes_cli/dingtalk_auth.py +++ b/hermes_cli/dingtalk_auth.py @@ -13,7 +13,6 @@ automatically. from __future__ import annotations -import io import os import sys import time diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index aede480bfe..a3896b5bbd 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -2953,7 +2953,7 @@ def _setup_sms(): def _setup_dingtalk(): """Configure DingTalk — QR scan (recommended) or manual credential entry.""" from hermes_cli.setup import ( - prompt_choice, prompt_yes_no, print_info, print_success, print_warning, + prompt_choice, prompt_yes_no, print_success, print_warning, ) dingtalk_platform = next(p for p in _PLATFORMS if p["key"] == "dingtalk") @@ -3504,7 +3504,6 @@ def _setup_qqbot(): method_idx = prompt_choice(" How would you like to set up QQ Bot?", method_choices, 0) credentials = None - used_qr = False if method_idx == 0: # ── QR scan-to-configure ── @@ -3515,8 +3514,6 @@ def _setup_qqbot(): print() print_warning(" QQ Bot setup cancelled.") return - if credentials: - used_qr = True if not credentials: print_info(" QR setup did not complete. Continuing with manual input.") diff --git a/hermes_cli/hooks.py b/hermes_cli/hooks.py index c39a692e63..de624f2461 100644 --- a/hermes_cli/hooks.py +++ b/hermes_cli/hooks.py @@ -19,9 +19,8 @@ format) lives there. from __future__ import annotations import json -import os from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List def hooks_command(args) -> None: diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 2e2a2f8f4d..2ec8e44481 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -4732,7 +4732,6 @@ def _model_flow_anthropic(config, current_model=""): read_claude_code_credentials, is_claude_code_token_valid, _is_oauth_token, - _resolve_claude_code_token_from_credentials, ) cc_creds = read_claude_code_credentials() @@ -7137,7 +7136,7 @@ def _cmd_update_impl(args, gateway_mode: bool): print( f" ⚠ {svc_name} died after restart, retrying..." ) - retry = subprocess.run( + subprocess.run( scope_cmd + ["restart", svc_name], capture_output=True, text=True, diff --git a/hermes_cli/model_catalog.py b/hermes_cli/model_catalog.py index 51873adf14..6ec7c4ec51 100644 --- a/hermes_cli/model_catalog.py +++ b/hermes_cli/model_catalog.py @@ -46,7 +46,6 @@ from __future__ import annotations import json import logging -import os import time import urllib.error import urllib.request diff --git a/hermes_cli/plugins_cmd.py b/hermes_cli/plugins_cmd.py index 230e134207..349a11de11 100644 --- a/hermes_cli/plugins_cmd.py +++ b/hermes_cli/plugins_cmd.py @@ -999,7 +999,6 @@ def _run_composite_ui(curses, plugin_names, plugin_labels, plugin_selected, # We need to map logical cursor positions to screen rows # accounting for non-navigable separator/headers - draw_row = 0 # tracks navigable item index # --- General Plugins section --- if n_plugins > 0: diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index 92d7c37cf6..011b4575e4 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -712,8 +712,6 @@ def setup_model_provider(config: dict, *, quick: bool = False): if isinstance(_m, dict): selected_provider = _m.get("provider") - nous_subscription_selected = selected_provider == "nous" - # ── Same-provider fallback & rotation setup (full setup only) ── if not quick and _supports_same_provider_pool_setup(selected_provider): try: diff --git a/hermes_cli/status.py b/hermes_cli/status.py index 0285752681..b4a6101885 100644 --- a/hermes_cli/status.py +++ b/hermes_cli/status.py @@ -6,7 +6,7 @@ Shows the status of all Hermes Agent components. import os import sys -import subprocess +import subprocess # noqa: F401 — re-exported for tests that monkeypatch status.subprocess to guard against regressions from pathlib import Path PROJECT_ROOT = Path(__file__).parent.parent.resolve() diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index 13337a7342..b91edc16d1 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -736,7 +736,7 @@ async def get_sessions(limit: int = 20, offset: int = 0): return {"sessions": sessions, "total": total, "limit": limit, "offset": offset} finally: db.close() - except Exception as e: + except Exception: _log.exception("GET /api/sessions failed") raise HTTPException(status_code=500, detail="Internal server error") @@ -968,7 +968,7 @@ async def update_config(body: ConfigUpdate): try: save_config(_denormalize_config_from_web(body.config)) return {"ok": True} - except Exception as e: + except Exception: _log.exception("PUT /api/config failed") raise HTTPException(status_code=500, detail="Internal server error") @@ -997,7 +997,7 @@ async def set_env_var(body: EnvVarUpdate): try: save_env_value(body.key, body.value) return {"ok": True, "key": body.key} - except Exception as e: + except Exception: _log.exception("PUT /api/env failed") raise HTTPException(status_code=500, detail="Internal server error") @@ -1011,7 +1011,7 @@ async def remove_env_var(body: EnvVarDelete): return {"ok": True, "key": body.key} except HTTPException: raise - except Exception as e: + except Exception: _log.exception("DELETE /api/env failed") raise HTTPException(status_code=500, detail="Internal server error") @@ -1568,7 +1568,6 @@ async def _start_device_code_flow(provider_id: str) -> Dict[str, Any]: then spawns a background poller. Returns the user-facing display fields so the UI can render the verification page link + user code. """ - from hermes_cli import auth as hauth if provider_id == "nous": from hermes_cli.auth import _request_device_code, PROVIDER_REGISTRY import httpx diff --git a/hermes_cli/webhook.py b/hermes_cli/webhook.py index 116464dde6..0ec4c6784b 100644 --- a/hermes_cli/webhook.py +++ b/hermes_cli/webhook.py @@ -11,7 +11,6 @@ hot-reloaded by the webhook adapter without a gateway restart. """ import json -import os import re import secrets import time diff --git a/rl_cli.py b/rl_cli.py index 03bf015c26..8054b627e9 100644 --- a/rl_cli.py +++ b/rl_cli.py @@ -27,6 +27,8 @@ from pathlib import Path import fire import yaml +from hermes_constants import OPENROUTER_BASE_URL, get_hermes_home + # Load .env from ~/.hermes/.env first, then project root as dev fallback. # User-managed env files should override stale shell exports on restart. _hermes_home = get_hermes_home() @@ -60,8 +62,6 @@ from tools.rl_training_tool import get_missing_keys # Config Loading # ============================================================================ -from hermes_constants import get_hermes_home, OPENROUTER_BASE_URL - DEFAULT_MODEL = "anthropic/claude-opus-4.5" DEFAULT_BASE_URL = OPENROUTER_BASE_URL @@ -412,7 +412,7 @@ def main( # Run the agent print("\n" + "=" * 60) - response = agent.run_conversation(user_input) + agent.run_conversation(user_input) print("\n" + "=" * 60) except KeyboardInterrupt: @@ -429,7 +429,7 @@ def main( print("-" * 40) try: - response = agent.run_conversation(task) + agent.run_conversation(task) print("\n" + "=" * 60) print("✅ Task completed") except KeyboardInterrupt: diff --git a/run_agent.py b/run_agent.py index 9156b39a6b..cc9df8e485 100644 --- a/run_agent.py +++ b/run_agent.py @@ -2720,7 +2720,6 @@ class AIAgent: eff_api_mode = api_mode if api_mode is not None else (self.api_mode or "") eff_model = (model if model is not None else self.model) or "" - base_lower = eff_base_url.lower() model_lower = eff_model.lower() provider_lower = eff_provider.lower() is_claude = "claude" in model_lower diff --git a/tools/browser_cdp_tool.py b/tools/browser_cdp_tool.py index f9099cbc89..d43d200b4a 100644 --- a/tools/browser_cdp_tool.py +++ b/tools/browser_cdp_tool.py @@ -20,7 +20,6 @@ from __future__ import annotations import asyncio import json import logging -import os from typing import Any, Dict, Optional from tools.registry import registry, tool_error diff --git a/tools/browser_supervisor.py b/tools/browser_supervisor.py index e230d92eda..91d7e78621 100644 --- a/tools/browser_supervisor.py +++ b/tools/browser_supervisor.py @@ -25,7 +25,7 @@ import json import logging import threading import time -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Dict, List, Optional, Tuple import websockets diff --git a/tools/browser_tool.py b/tools/browser_tool.py index 87ed56b270..39cdaf78d9 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -526,7 +526,6 @@ def _url_is_private(url: str) -> bool: backend is configured, which will surface the DNS error naturally). """ try: - from tools.url_safety import is_safe_url # is_safe_url returns False for private/loopback/link-local/CGNAT AND # for DNS failures. We only want the private-network case here, so # we parse + check the host shape as a DNS-failure sieve first. diff --git a/tools/delegate_tool.py b/tools/delegate_tool.py index 3fe0026efe..7d2bb197e0 100644 --- a/tools/delegate_tool.py +++ b/tools/delegate_tool.py @@ -27,7 +27,6 @@ import time from concurrent.futures import ( ThreadPoolExecutor, TimeoutError as FuturesTimeoutError, - as_completed, ) from typing import Any, Dict, List, Optional diff --git a/tools/file_operations.py b/tools/file_operations.py index 9e0b44c145..aa7a482509 100644 --- a/tools/file_operations.py +++ b/tools/file_operations.py @@ -32,7 +32,6 @@ from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import Optional, List, Dict, Any from pathlib import Path -from hermes_constants import get_hermes_home from tools.binary_extensions import BINARY_EXTENSIONS from agent.file_safety import ( diff --git a/tools/file_tools.py b/tools/file_tools.py index 38801362e9..7d81cd8f8e 100644 --- a/tools/file_tools.py +++ b/tools/file_tools.py @@ -7,7 +7,6 @@ import logging import os import threading from pathlib import Path -from typing import Optional from agent.file_safety import get_read_block_error from tools.binary_extensions import has_binary_extension diff --git a/tools/transcription_tools.py b/tools/transcription_tools.py index 9e8ad69271..bbc9a10e6a 100644 --- a/tools/transcription_tools.py +++ b/tools/transcription_tools.py @@ -836,7 +836,6 @@ def transcribe_audio(file_path: str, model: Optional[str] = None) -> Dict[str, A return _transcribe_mistral(file_path, model_name) if provider == "xai": - xai_cfg = stt_config.get("xai", {}) # xAI Grok STT doesn't use a model parameter — pass through for logging model_name = model or "grok-stt" return _transcribe_xai(file_path, model_name) diff --git a/tools/yuanbao_tools.py b/tools/yuanbao_tools.py index bdb36c8b85..e12307b85e 100644 --- a/tools/yuanbao_tools.py +++ b/tools/yuanbao_tools.py @@ -20,7 +20,7 @@ from __future__ import annotations import logging from pathlib import Path -from typing import TYPE_CHECKING, List, Optional, Tuple +from typing import List, Optional, Tuple logger = logging.getLogger(__name__) @@ -34,10 +34,6 @@ def _get_active_adapter(): return None -if TYPE_CHECKING: - from gateway.platforms.yuanbao import YuanbaoAdapter - - # --------------------------------------------------------------------------- # 角色标签 # --------------------------------------------------------------------------- @@ -418,7 +414,7 @@ async def send_dm( # Registry registration # --------------------------------------------------------------------------- -from tools.registry import registry, tool_result, tool_error # noqa: E402 +from tools.registry import registry, tool_result # noqa: E402 def _check_yuanbao(): diff --git a/trajectory_compressor.py b/trajectory_compressor.py index ff2dcc6266..2efdeaf165 100644 --- a/trajectory_compressor.py +++ b/trajectory_compressor.py @@ -37,7 +37,7 @@ import yaml import logging import asyncio from pathlib import Path -from typing import List, Dict, Any, Optional, Tuple, Callable +from typing import List, Dict, Any, Optional, Tuple from dataclasses import dataclass, field from datetime import datetime