From ef268f47d25c6181b6fe0204d3f41d470bd4f73d Mon Sep 17 00:00:00 2001 From: chengyongru Date: Tue, 12 May 2026 16:45:27 +0800 Subject: [PATCH] chore: remove dead code identified by vulture + coverage cross-validation Remove unused code confirmed dead via vulture scan, grep verification, and coverage analysis: - _get_bridge_dir (cli/commands.py): 82-line function with zero callers - add_assistant_message (agent/context.py): method body never executed, also removed now-unused build_assistant_message import - _tool_parameters_schema (agent/tools/base.py): redundant copy of schema already exposed via the `parameters` property - MSTEAMS_REF_TTL_S (channels/msteams.py): unused constant (production uses config.ref_ttl_days directly); inlined in test - MESSAGE_TYPE_USER (channels/weixin.py): unused constant --- nanobot/agent/context.py | 16 ------- nanobot/agent/tools/base.py | 1 - nanobot/channels/msteams.py | 1 - nanobot/channels/weixin.py | 1 - nanobot/cli/commands.py | 84 ------------------------------------- tests/test_msteams.py | 2 +- 6 files changed, 1 insertion(+), 104 deletions(-) diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index 7415cdfcd..286aa4a38 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -11,7 +11,6 @@ from typing import Any from nanobot.agent.memory import MemoryStore from nanobot.agent.skills import SkillsLoader from nanobot.utils.helpers import ( - build_assistant_message, current_time_str, detect_image_mime, truncate_text, @@ -204,18 +203,3 @@ class ContextBuilder: messages.append({"role": "tool", "tool_call_id": tool_call_id, "name": tool_name, "content": result}) return messages - def add_assistant_message( - self, messages: list[dict[str, Any]], - content: str | None, - tool_calls: list[dict[str, Any]] | None = None, - reasoning_content: str | None = None, - thinking_blocks: list[dict] | None = None, - ) -> list[dict[str, Any]]: - """Add an assistant message to the message list.""" - messages.append(build_assistant_message( - content, - tool_calls=tool_calls, - reasoning_content=reasoning_content, - thinking_blocks=thinking_blocks, - )) - return messages diff --git a/nanobot/agent/tools/base.py b/nanobot/agent/tools/base.py index 18b77de1e..0bdff2d80 100644 --- a/nanobot/agent/tools/base.py +++ b/nanobot/agent/tools/base.py @@ -285,7 +285,6 @@ def tool_parameters(schema: dict[str, Any]) -> Callable[[type[_ToolT]], type[_To def parameters(self: Any) -> dict[str, Any]: return deepcopy(frozen) - cls._tool_parameters_schema = deepcopy(frozen) cls.parameters = parameters # type: ignore[assignment] abstract = getattr(cls, "__abstractmethods__", None) diff --git a/nanobot/channels/msteams.py b/nanobot/channels/msteams.py index cdb0ae904..3487c276f 100644 --- a/nanobot/channels/msteams.py +++ b/nanobot/channels/msteams.py @@ -52,7 +52,6 @@ if MSTEAMS_AVAILABLE: import jwt MSTEAMS_REF_TTL_DAYS = 30 -MSTEAMS_REF_TTL_S = MSTEAMS_REF_TTL_DAYS * 24 * 60 * 60 MSTEAMS_WEBCHAT_HOST = "webchat.botframework.com" MSTEAMS_REF_META_FILENAME = "msteams_conversations_meta.json" MSTEAMS_REF_LOCK_FILENAME = "msteams_conversations.lock" diff --git a/nanobot/channels/weixin.py b/nanobot/channels/weixin.py index 915305abc..41390f8b3 100644 --- a/nanobot/channels/weixin.py +++ b/nanobot/channels/weixin.py @@ -47,7 +47,6 @@ ITEM_FILE = 4 ITEM_VIDEO = 5 # MessageType (1 = inbound from user, 2 = outbound from bot) -MESSAGE_TYPE_USER = 1 MESSAGE_TYPE_BOT = 2 # MessageState diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 3e99e3b9a..0d71d91db 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -1280,90 +1280,6 @@ def channels_status( console.print(table) -def _get_bridge_dir() -> Path: - """Get the bridge directory, setting it up if needed.""" - import hashlib - import shutil - import subprocess - - # User's bridge location - from nanobot.config.paths import get_bridge_install_dir - - user_bridge = get_bridge_install_dir() - stamp_file = user_bridge / ".nanobot-bridge-source-hash" - - # Find source bridge: first check package data, then source dir - pkg_bridge = Path(__file__).parent.parent / "bridge" # nanobot/bridge (installed) - src_bridge = Path(__file__).parent.parent.parent / "bridge" # repo root/bridge (dev) - - source = None - if (pkg_bridge / "package.json").exists(): - source = pkg_bridge - elif (src_bridge / "package.json").exists(): - source = src_bridge - - if not source: - console.print("[red]Bridge source not found.[/red]") - console.print("Try reinstalling: pip install --force-reinstall nanobot") - raise typer.Exit(1) - - def source_hash(root: Path) -> str: - digest = hashlib.sha256() - for path in sorted(root.rglob("*")): - if not path.is_file(): - continue - rel = path.relative_to(root) - if rel.parts and rel.parts[0] in {"node_modules", "dist"}: - continue - digest.update(rel.as_posix().encode("utf-8")) - digest.update(b"\0") - digest.update(path.read_bytes()) - digest.update(b"\0") - return digest.hexdigest() - - expected_hash = source_hash(source) - current_hash = stamp_file.read_text().strip() if stamp_file.exists() else None - - # Reuse only a bridge built from the currently installed source. - if (user_bridge / "dist" / "index.js").exists() and current_hash == expected_hash: - return user_bridge - - if (user_bridge / "dist" / "index.js").exists() and current_hash != expected_hash: - console.print(f"{__logo__} WhatsApp bridge source changed; rebuilding bridge...") - - # Check for npm - npm_path = shutil.which("npm") - if not npm_path: - console.print("[red]npm not found. Please install Node.js >= 18.[/red]") - raise typer.Exit(1) - - console.print(f"{__logo__} Setting up bridge...") - - # Copy to user directory - user_bridge.parent.mkdir(parents=True, exist_ok=True) - if user_bridge.exists(): - shutil.rmtree(user_bridge) - shutil.copytree(source, user_bridge, ignore=shutil.ignore_patterns("node_modules", "dist")) - - # Install and build - try: - console.print(" Installing dependencies...") - subprocess.run([npm_path, "install"], cwd=user_bridge, check=True, capture_output=True) - - console.print(" Building...") - subprocess.run([npm_path, "run", "build"], cwd=user_bridge, check=True, capture_output=True) - stamp_file.write_text(expected_hash + "\n") - - console.print("[green]✓[/green] Bridge ready\n") - except subprocess.CalledProcessError as e: - console.print(f"[red]Build failed: {e}[/red]") - if e.stderr: - console.print(f"[dim]{e.stderr.decode()[:500]}[/dim]") - raise typer.Exit(1) - - return user_bridge - - @channels_app.command("login") def channels_login( channel_name: str = typer.Argument(..., help="Channel name (e.g. weixin, whatsapp)"), diff --git a/tests/test_msteams.py b/tests/test_msteams.py index fd71018b1..39202ba02 100644 --- a/tests/test_msteams.py +++ b/tests/test_msteams.py @@ -169,7 +169,7 @@ def test_init_prunes_stale_and_unsupported_conversation_refs(make_channel, tmp_p "conv-valid": {"updated_at": now - 60}, "conv-webchat": {"updated_at": now - 60}, "conv-group": {"updated_at": now - 60}, - "conv-stale": {"updated_at": now - msteams_module.MSTEAMS_REF_TTL_S - 1}, + "conv-stale": {"updated_at": now - 30 * 24 * 60 * 60 - 1}, }, indent=2, ),