diff --git a/gateway/pairing.py b/gateway/pairing.py index 20b64b013..34b3d9023 100644 --- a/gateway/pairing.py +++ b/gateway/pairing.py @@ -25,7 +25,7 @@ import time from pathlib import Path from typing import Optional -from hermes_cli.config import get_hermes_home +from hermes_constants import get_hermes_dir # Unambiguous alphabet -- excludes 0/O, 1/I to prevent confusion @@ -41,7 +41,7 @@ LOCKOUT_SECONDS = 3600 # Lockout duration after too many failures MAX_PENDING_PER_PLATFORM = 3 # Max pending codes per platform MAX_FAILED_ATTEMPTS = 5 # Failed approvals before lockout -PAIRING_DIR = get_hermes_home() / "pairing" +PAIRING_DIR = get_hermes_dir("platforms/pairing", "pairing") def _secure_write(path: Path, data: str) -> None: diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index e3668774e..8ca1a2cfb 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -27,6 +27,7 @@ sys.path.insert(0, str(_Path(__file__).resolve().parents[2])) from gateway.config import Platform, PlatformConfig from gateway.session import SessionSource, build_session_key from hermes_cli.config import get_hermes_home +from hermes_constants import get_hermes_dir GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGE = ( @@ -44,8 +45,8 @@ GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGE = ( # (e.g. Telegram file URLs expire after ~1 hour). # --------------------------------------------------------------------------- -# Default location: {HERMES_HOME}/image_cache/ -IMAGE_CACHE_DIR = get_hermes_home() / "image_cache" +# Default location: {HERMES_HOME}/cache/images/ (legacy: image_cache/) +IMAGE_CACHE_DIR = get_hermes_dir("cache/images", "image_cache") def get_image_cache_dir() -> Path: @@ -147,7 +148,7 @@ def cleanup_image_cache(max_age_hours: int = 24) -> int: # here so the STT tool (OpenAI Whisper) can transcribe them from local files. # --------------------------------------------------------------------------- -AUDIO_CACHE_DIR = get_hermes_home() / "audio_cache" +AUDIO_CACHE_DIR = get_hermes_dir("cache/audio", "audio_cache") def get_audio_cache_dir() -> Path: @@ -206,7 +207,7 @@ async def cache_audio_from_url(url: str, ext: str = ".ogg") -> str: # here so the agent can reference them by local file path. # --------------------------------------------------------------------------- -DOCUMENT_CACHE_DIR = get_hermes_home() / "document_cache" +DOCUMENT_CACHE_DIR = get_hermes_dir("cache/documents", "document_cache") SUPPORTED_DOCUMENT_TYPES = { ".pdf": "application/pdf", diff --git a/gateway/platforms/matrix.py b/gateway/platforms/matrix.py index 30d4f633d..3d6a90502 100644 --- a/gateway/platforms/matrix.py +++ b/gateway/platforms/matrix.py @@ -41,8 +41,8 @@ MAX_MESSAGE_LENGTH = 4000 # Store directory for E2EE keys and sync state. # Uses get_hermes_home() so each profile gets its own Matrix store. -from hermes_constants import get_hermes_home as _get_hermes_home -_STORE_DIR = _get_hermes_home() / "matrix" / "store" +from hermes_constants import get_hermes_dir as _get_hermes_dir +_STORE_DIR = _get_hermes_dir("platforms/matrix/store", "matrix/store") # Grace period: ignore messages older than this many seconds before startup. _STARTUP_GRACE_SECONDS = 5 diff --git a/gateway/platforms/whatsapp.py b/gateway/platforms/whatsapp.py index 3ab4b7533..9337f9587 100644 --- a/gateway/platforms/whatsapp.py +++ b/gateway/platforms/whatsapp.py @@ -26,6 +26,7 @@ from pathlib import Path from typing import Dict, Optional, Any from hermes_cli.config import get_hermes_home +from hermes_constants import get_hermes_dir logger = logging.getLogger(__name__) @@ -134,7 +135,7 @@ class WhatsAppAdapter(BasePlatformAdapter): ) self._session_path: Path = Path(config.extra.get( "session_path", - get_hermes_home() / "whatsapp" / "session" + get_hermes_dir("platforms/whatsapp/session", "whatsapp/session") )) self._reply_prefix: Optional[str] = config.extra.get("reply_prefix") self._message_queue: asyncio.Queue = asyncio.Queue() diff --git a/hermes_constants.py b/hermes_constants.py index 518472023..a55914b58 100644 --- a/hermes_constants.py +++ b/hermes_constants.py @@ -17,6 +17,27 @@ def get_hermes_home() -> Path: return Path(os.getenv("HERMES_HOME", Path.home() / ".hermes")) +def get_hermes_dir(new_subpath: str, old_name: str) -> Path: + """Resolve a Hermes subdirectory with backward compatibility. + + New installs get the consolidated layout (e.g. ``cache/images``). + Existing installs that already have the old path (e.g. ``image_cache``) + keep using it — no migration required. + + Args: + new_subpath: Preferred path relative to HERMES_HOME (e.g. ``"cache/images"``). + old_name: Legacy path relative to HERMES_HOME (e.g. ``"image_cache"``). + + Returns: + Absolute ``Path`` — old location if it exists on disk, otherwise the new one. + """ + home = get_hermes_home() + old_path = home / old_name + if old_path.exists(): + return old_path + return home / new_subpath + + VALID_REASONING_EFFORTS = ("xhigh", "high", "medium", "low", "minimal") diff --git a/tools/browser_tool.py b/tools/browser_tool.py index e75025482..f71ba78d4 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -1523,8 +1523,8 @@ def browser_vision(question: str, annotate: bool = False, task_id: Optional[str] effective_task_id = task_id or "default" # Save screenshot to persistent location so it can be shared with users - hermes_home = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) - screenshots_dir = hermes_home / "browser_screenshots" + from hermes_constants import get_hermes_dir + screenshots_dir = get_hermes_dir("cache/screenshots", "browser_screenshots") screenshot_path = screenshots_dir / f"browser_screenshot_{uuid_mod.uuid4().hex}.png" try: diff --git a/tools/tts_tool.py b/tools/tts_tool.py index 879634cfa..0f25fc66e 100644 --- a/tools/tts_tool.py +++ b/tools/tts_tool.py @@ -74,7 +74,11 @@ DEFAULT_ELEVENLABS_MODEL_ID = "eleven_multilingual_v2" DEFAULT_ELEVENLABS_STREAMING_MODEL_ID = "eleven_flash_v2_5" DEFAULT_OPENAI_MODEL = "gpt-4o-mini-tts" DEFAULT_OPENAI_VOICE = "alloy" -DEFAULT_OUTPUT_DIR = str(get_hermes_home() / "audio_cache") +def _get_default_output_dir() -> str: + from hermes_constants import get_hermes_dir + return str(get_hermes_dir("cache/audio", "audio_cache")) + +DEFAULT_OUTPUT_DIR = _get_default_output_dir() MAX_TEXT_LENGTH = 4000 @@ -828,7 +832,7 @@ TTS_SCHEMA = { }, "output_path": { "type": "string", - "description": "Optional custom file path to save the audio. Defaults to ~/.hermes/audio_cache/.mp3" + "description": "Optional custom file path to save the audio. Defaults to ~/.hermes/cache/audio/.mp3" } }, "required": ["text"]