Automated cleanup via pyflakes + autoflake with manual review.
Changes:
- Removed unused stdlib imports (os, sys, json, pathlib.Path, etc.)
- Removed unused typing imports (List, Dict, Any, Optional, Tuple, Set, etc.)
- Removed unused internal imports (hermes_cli.auth, hermes_cli.config, etc.)
- Fixed cli.py: removed 8 shadowed banner imports (imported from hermes_cli.banner
then immediately redefined locally — only build_welcome_banner is actually used)
- Added noqa comments to imports that appear unused but serve a purpose:
- Re-exports (gateway/session.py SessionResetPolicy, tools/terminal_tool.py
is_interrupted/_interrupt_event)
- SDK presence checks in try/except (daytona, fal_client, discord)
- Test mock targets (auxiliary_client.py Path, mcp_config.py get_hermes_home)
Zero behavioral changes. Full test suite passes (6162/6162, 2 pre-existing
streaming test failures unrelated to this change).
112 lines
3.0 KiB
Python
112 lines
3.0 KiB
Python
"""
|
|
Sticker description cache for Telegram.
|
|
|
|
When users send stickers, we describe them via the vision tool and cache
|
|
the descriptions keyed by file_unique_id so we don't re-analyze the same
|
|
sticker image on every send. Descriptions are concise (1-2 sentences).
|
|
|
|
Cache location: ~/.hermes/sticker_cache.json
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
from typing import Optional
|
|
|
|
from hermes_cli.config import get_hermes_home
|
|
|
|
|
|
CACHE_PATH = get_hermes_home() / "sticker_cache.json"
|
|
|
|
# Vision prompt for describing stickers -- kept concise to save tokens
|
|
STICKER_VISION_PROMPT = (
|
|
"Describe this sticker in 1-2 sentences. Focus on what it depicts -- "
|
|
"character, action, emotion. Be concise and objective."
|
|
)
|
|
|
|
|
|
def _load_cache() -> dict:
|
|
"""Load the sticker cache from disk."""
|
|
if CACHE_PATH.exists():
|
|
try:
|
|
return json.loads(CACHE_PATH.read_text(encoding="utf-8"))
|
|
except (json.JSONDecodeError, OSError):
|
|
return {}
|
|
return {}
|
|
|
|
|
|
def _save_cache(cache: dict) -> None:
|
|
"""Save the sticker cache to disk."""
|
|
CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
CACHE_PATH.write_text(
|
|
json.dumps(cache, indent=2, ensure_ascii=False),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
|
|
def get_cached_description(file_unique_id: str) -> Optional[dict]:
|
|
"""
|
|
Look up a cached sticker description.
|
|
|
|
Returns:
|
|
dict with keys {description, emoji, set_name, cached_at} or None.
|
|
"""
|
|
cache = _load_cache()
|
|
return cache.get(file_unique_id)
|
|
|
|
|
|
def cache_sticker_description(
|
|
file_unique_id: str,
|
|
description: str,
|
|
emoji: str = "",
|
|
set_name: str = "",
|
|
) -> None:
|
|
"""
|
|
Store a sticker description in the cache.
|
|
|
|
Args:
|
|
file_unique_id: Telegram's stable sticker identifier.
|
|
description: Vision-generated description text.
|
|
emoji: Associated emoji (e.g. "😀").
|
|
set_name: Sticker set name if available.
|
|
"""
|
|
cache = _load_cache()
|
|
cache[file_unique_id] = {
|
|
"description": description,
|
|
"emoji": emoji,
|
|
"set_name": set_name,
|
|
"cached_at": time.time(),
|
|
}
|
|
_save_cache(cache)
|
|
|
|
|
|
def build_sticker_injection(
|
|
description: str,
|
|
emoji: str = "",
|
|
set_name: str = "",
|
|
) -> str:
|
|
"""
|
|
Build the warm-style injection text for a sticker description.
|
|
|
|
Returns a string like:
|
|
[The user sent a sticker 😀 from "MyPack"~ It shows: "A cat waving" (=^.w.^=)]
|
|
"""
|
|
context = ""
|
|
if set_name and emoji:
|
|
context = f" {emoji} from \"{set_name}\""
|
|
elif emoji:
|
|
context = f" {emoji}"
|
|
|
|
return f"[The user sent a sticker{context}~ It shows: \"{description}\" (=^.w.^=)]"
|
|
|
|
|
|
def build_animated_sticker_injection(emoji: str = "") -> str:
|
|
"""
|
|
Build injection text for animated/video stickers we can't analyze.
|
|
"""
|
|
if emoji:
|
|
return (
|
|
f"[The user sent an animated sticker {emoji}~ "
|
|
f"I can't see animated ones yet, but the emoji suggests: {emoji}]"
|
|
)
|
|
return "[The user sent an animated sticker~ I can't see animated ones yet]"
|