diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index e274e65ac..13efa8db1 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -41,6 +41,7 @@ from typing import Any, Dict, List, Optional, Tuple from openai import OpenAI +from hermes_cli.config import get_hermes_home from hermes_constants import OPENROUTER_BASE_URL logger = logging.getLogger(__name__) @@ -73,7 +74,7 @@ auxiliary_is_nous: bool = False _OPENROUTER_MODEL = "google/gemini-3-flash-preview" _NOUS_MODEL = "gemini-3-flash" _NOUS_DEFAULT_BASE_URL = "https://inference-api.nousresearch.com/v1" -_AUTH_JSON_PATH = Path.home() / ".hermes" / "auth.json" +_AUTH_JSON_PATH = get_hermes_home() / "auth.json" # Codex fallback: uses the Responses API (the only endpoint the Codex # OAuth token can access) with a fast model for auxiliary tasks. diff --git a/agent/prompt_builder.py b/agent/prompt_builder.py index 0dfedc628..e5b3e01a5 100644 --- a/agent/prompt_builder.py +++ b/agent/prompt_builder.py @@ -420,7 +420,7 @@ def build_context_files_prompt(cwd: Optional[str] = None) -> str: soul_path = candidate break if not soul_path: - global_soul = Path.home() / ".hermes" / "SOUL.md" + global_soul = Path(os.getenv("HERMES_HOME", Path.home() / ".hermes")) / "SOUL.md" if global_soul.exists(): soul_path = global_soul diff --git a/cli.py b/cli.py index 1208c558e..0c0594500 100755 --- a/cli.py +++ b/cli.py @@ -96,7 +96,7 @@ def _load_prefill_messages(file_path: str) -> List[Dict[str, Any]]: return [] path = Path(file_path).expanduser() if not path.is_absolute(): - path = Path.home() / ".hermes" / path + path = _hermes_home / path if not path.exists(): logger.warning("Prefill messages file not found: %s", path) return [] @@ -141,16 +141,16 @@ def load_cli_config() -> Dict[str, Any]: Environment variables take precedence over config file values. Returns default values if no config file exists. """ - # Check user config first (~/.hermes/config.yaml) - user_config_path = Path.home() / '.hermes' / 'config.yaml' + # Check user config first ({HERMES_HOME}/config.yaml) + user_config_path = _hermes_home / 'config.yaml' project_config_path = Path(__file__).parent / 'cli-config.yaml' - + # Use user config if it exists, otherwise project config if user_config_path.exists(): config_path = user_config_path else: config_path = project_config_path - + # Default configuration defaults = { "model": { @@ -1037,7 +1037,7 @@ def save_config_value(key_path: str, value: any) -> bool: True if successful, False otherwise """ # Use the same precedence as load_cli_config: user config first, then project config - user_config_path = Path.home() / '.hermes' / 'config.yaml' + user_config_path = _hermes_home / 'config.yaml' project_config_path = Path(__file__).parent / 'cli-config.yaml' config_path = user_config_path if user_config_path.exists() else project_config_path @@ -1259,7 +1259,7 @@ class HermesCLI: self.session_id = f"{timestamp_str}_{short_uuid}" # History file for persistent input recall across sessions - self._history_file = Path.home() / ".hermes_history" + self._history_file = _hermes_home / ".hermes_history" self._last_invalidate: float = 0.0 # throttle UI repaints self._app = None self._secret_state = None @@ -1778,7 +1778,7 @@ class HermesCLI: """ from hermes_cli.clipboard import save_clipboard_image - img_dir = Path.home() / ".hermes" / "images" + img_dir = Path(os.getenv("HERMES_HOME", Path.home() / ".hermes")) / "images" self._image_counter += 1 ts = datetime.now().strftime("%Y%m%d_%H%M%S") img_path = img_dir / f"clip_{ts}_{self._image_counter}.png" @@ -2074,7 +2074,7 @@ class HermesCLI: terminal_cwd = os.getenv("TERMINAL_CWD", os.getcwd()) terminal_timeout = os.getenv("TERMINAL_TIMEOUT", "60") - user_config_path = Path.home() / '.hermes' / 'config.yaml' + user_config_path = _hermes_home / 'config.yaml' project_config_path = Path(__file__).parent / 'cli-config.yaml' if user_config_path.exists(): config_path = user_config_path @@ -4255,7 +4255,7 @@ class HermesCLI: if line_count >= 5 and chars_added > 1 and not text.startswith('/'): _paste_counter[0] += 1 # Save to temp file - paste_dir = Path(os.path.expanduser("~/.hermes/pastes")) + paste_dir = _hermes_home / "pastes" paste_dir.mkdir(parents=True, exist_ok=True) paste_file = paste_dir / f"paste_{_paste_counter[0]}_{datetime.now().strftime('%H%M%S')}.txt" paste_file.write_text(text, encoding="utf-8") diff --git a/gateway/channel_directory.py b/gateway/channel_directory.py index 4d11c3a91..9154741f6 100644 --- a/gateway/channel_directory.py +++ b/gateway/channel_directory.py @@ -12,9 +12,11 @@ from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional +from hermes_cli.config import get_hermes_home + logger = logging.getLogger(__name__) -DIRECTORY_PATH = Path.home() / ".hermes" / "channel_directory.json" +DIRECTORY_PATH = get_hermes_home() / "channel_directory.json" def _session_entry_id(origin: Dict[str, Any]) -> Optional[str]: @@ -129,7 +131,7 @@ def _build_slack(adapter) -> List[Dict[str, str]]: def _build_from_sessions(platform_name: str) -> List[Dict[str, str]]: """Pull known channels/contacts from sessions.json origin data.""" - sessions_path = Path.home() / ".hermes" / "sessions" / "sessions.json" + sessions_path = get_hermes_home() / "sessions" / "sessions.json" if not sessions_path.exists(): return [] diff --git a/gateway/config.py b/gateway/config.py index ec7d2b5cc..e45eede7c 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -16,6 +16,8 @@ from dataclasses import dataclass, field from typing import Dict, List, Optional, Any from enum import Enum +from hermes_cli.config import get_hermes_home + logger = logging.getLogger(__name__) @@ -151,7 +153,7 @@ class GatewayConfig: reset_triggers: List[str] = field(default_factory=lambda: ["/new", "/reset"]) # Storage paths - sessions_dir: Path = field(default_factory=lambda: Path.home() / ".hermes" / "sessions") + sessions_dir: Path = field(default_factory=lambda: get_hermes_home() / "sessions") # Delivery settings always_log_local: bool = True # Always save cron outputs to local files @@ -246,7 +248,7 @@ class GatewayConfig: if "default_reset_policy" in data: default_policy = SessionResetPolicy.from_dict(data["default_reset_policy"]) - sessions_dir = Path.home() / ".hermes" / "sessions" + sessions_dir = get_hermes_home() / "sessions" if "sessions_dir" in data: sessions_dir = Path(data["sessions_dir"]) @@ -274,7 +276,8 @@ def load_gateway_config() -> GatewayConfig: config = GatewayConfig() # Try loading from ~/.hermes/gateway.json - gateway_config_path = Path.home() / ".hermes" / "gateway.json" + _home = get_hermes_home() + gateway_config_path = _home / "gateway.json" if gateway_config_path.exists(): try: with open(gateway_config_path, "r", encoding="utf-8") as f: @@ -282,13 +285,13 @@ def load_gateway_config() -> GatewayConfig: config = GatewayConfig.from_dict(data) except Exception as e: print(f"[gateway] Warning: Failed to load {gateway_config_path}: {e}") - + # Bridge session_reset from config.yaml (the user-facing config file) # into the gateway config. config.yaml takes precedence over gateway.json # for session reset policy since that's where hermes setup writes it. try: import yaml - config_yaml_path = Path.home() / ".hermes" / "config.yaml" + config_yaml_path = _home / "config.yaml" if config_yaml_path.exists(): with open(config_yaml_path, encoding="utf-8") as f: yaml_cfg = yaml.safe_load(f) or {} @@ -481,7 +484,7 @@ def _apply_env_overrides(config: GatewayConfig) -> None: def save_gateway_config(config: GatewayConfig) -> None: """Save gateway configuration to ~/.hermes/gateway.json.""" - gateway_config_path = Path.home() / ".hermes" / "gateway.json" + gateway_config_path = get_hermes_home() / "gateway.json" gateway_config_path.parent.mkdir(parents=True, exist_ok=True) with open(gateway_config_path, "w", encoding="utf-8") as f: diff --git a/gateway/delivery.py b/gateway/delivery.py index 5bcd58f4c..630ab638e 100644 --- a/gateway/delivery.py +++ b/gateway/delivery.py @@ -15,6 +15,8 @@ from dataclasses import dataclass from typing import Dict, List, Optional, Any, Union from enum import Enum +from hermes_cli.config import get_hermes_home + logger = logging.getLogger(__name__) MAX_PLATFORM_OUTPUT = 4000 @@ -116,7 +118,7 @@ class DeliveryRouter: """ self.config = config self.adapters = adapters or {} - self.output_dir = Path.home() / ".hermes" / "cron" / "output" + self.output_dir = get_hermes_home() / "cron" / "output" def resolve_targets( self, @@ -256,7 +258,7 @@ class DeliveryRouter: def _save_full_output(self, content: str, job_id: str) -> Path: """Save full cron output to disk and return the file path.""" timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - out_dir = Path.home() / ".hermes" / "cron" / "output" + out_dir = get_hermes_home() / "cron" / "output" out_dir.mkdir(parents=True, exist_ok=True) path = out_dir / f"{job_id}_{timestamp}.txt" path.write_text(content) diff --git a/gateway/hooks.py b/gateway/hooks.py index d2face15c..2274b5b91 100644 --- a/gateway/hooks.py +++ b/gateway/hooks.py @@ -26,8 +26,10 @@ from typing import Any, Callable, Dict, List, Optional import yaml +from hermes_cli.config import get_hermes_home -HOOKS_DIR = Path(os.path.expanduser("~/.hermes/hooks")) + +HOOKS_DIR = get_hermes_home() / "hooks" class HookRegistry: diff --git a/gateway/mirror.py b/gateway/mirror.py index f54e6e1a3..4f9574631 100644 --- a/gateway/mirror.py +++ b/gateway/mirror.py @@ -15,9 +15,11 @@ from datetime import datetime from pathlib import Path from typing import Optional +from hermes_cli.config import get_hermes_home + logger = logging.getLogger(__name__) -_SESSIONS_DIR = Path.home() / ".hermes" / "sessions" +_SESSIONS_DIR = get_hermes_home() / "sessions" _SESSIONS_INDEX = _SESSIONS_DIR / "sessions.json" diff --git a/gateway/pairing.py b/gateway/pairing.py index b1e066ffe..20b64b013 100644 --- a/gateway/pairing.py +++ b/gateway/pairing.py @@ -25,6 +25,8 @@ import time from pathlib import Path from typing import Optional +from hermes_cli.config import get_hermes_home + # Unambiguous alphabet -- excludes 0/O, 1/I to prevent confusion ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" @@ -39,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 = Path(os.path.expanduser("~/.hermes/pairing")) +PAIRING_DIR = get_hermes_home() / "pairing" def _secure_write(path: Path, data: str) -> None: diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index e2eb2e49f..718f99795 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -25,6 +25,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 GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGE = ( @@ -42,8 +43,8 @@ GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGE = ( # (e.g. Telegram file URLs expire after ~1 hour). # --------------------------------------------------------------------------- -# Default location: ~/.hermes/image_cache/ -IMAGE_CACHE_DIR = Path(os.path.expanduser("~/.hermes/image_cache")) +# Default location: {HERMES_HOME}/image_cache/ +IMAGE_CACHE_DIR = get_hermes_home() / "image_cache" def get_image_cache_dir() -> Path: @@ -125,7 +126,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 = Path(os.path.expanduser("~/.hermes/audio_cache")) +AUDIO_CACHE_DIR = get_hermes_home() / "audio_cache" def get_audio_cache_dir() -> Path: @@ -184,7 +185,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 = Path(os.path.expanduser("~/.hermes/document_cache")) +DOCUMENT_CACHE_DIR = get_hermes_home() / "document_cache" SUPPORTED_DOCUMENT_TYPES = { ".pdf": "application/pdf", diff --git a/gateway/platforms/whatsapp.py b/gateway/platforms/whatsapp.py index 9d140bba3..2464a4332 100644 --- a/gateway/platforms/whatsapp.py +++ b/gateway/platforms/whatsapp.py @@ -26,6 +26,8 @@ _IS_WINDOWS = platform.system() == "Windows" from pathlib import Path from typing import Dict, List, Optional, Any +from hermes_cli.config import get_hermes_home + logger = logging.getLogger(__name__) @@ -132,7 +134,7 @@ class WhatsAppAdapter(BasePlatformAdapter): ) self._session_path: Path = Path(config.extra.get( "session_path", - Path.home() / ".hermes" / "whatsapp" / "session" + get_hermes_home() / "whatsapp" / "session" )) self._message_queue: asyncio.Queue = asyncio.Queue() self._bridge_log_fh = None diff --git a/gateway/sticker_cache.py b/gateway/sticker_cache.py index 597f672ef..673478f96 100644 --- a/gateway/sticker_cache.py +++ b/gateway/sticker_cache.py @@ -14,8 +14,10 @@ import time from pathlib import Path from typing import Optional +from hermes_cli.config import get_hermes_home -CACHE_PATH = Path(os.path.expanduser("~/.hermes/sticker_cache.json")) + +CACHE_PATH = get_hermes_home() / "sticker_cache.json" # Vision prompt for describing stickers -- kept concise to save tokens STICKER_VISION_PROMPT = ( diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 5ba2f64bd..1e2002f2a 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -13,7 +13,7 @@ from pathlib import Path PROJECT_ROOT = Path(__file__).parent.parent.resolve() -from hermes_cli.config import get_env_value, save_env_value +from hermes_cli.config import get_env_value, get_hermes_home, save_env_value from hermes_cli.setup import ( print_header, print_info, print_success, print_warning, print_error, prompt, prompt_choice, prompt_yes_no, @@ -283,7 +283,7 @@ def systemd_status(deep: bool = False): def generate_launchd_plist() -> str: python_path = get_python_path() working_dir = str(PROJECT_ROOT) - log_dir = Path.home() / ".hermes" / "logs" + log_dir = get_hermes_home() / "logs" log_dir.mkdir(parents=True, exist_ok=True) return f""" @@ -380,7 +380,7 @@ def launchd_status(deep: bool = False): print("✗ Gateway service is not loaded") if deep: - log_file = Path.home() / ".hermes" / "logs" / "gateway.log" + log_file = get_hermes_home() / "logs" / "gateway.log" if log_file.exists(): print() print("Recent logs:") @@ -557,7 +557,7 @@ def _platform_status(platform: dict) -> str: val = get_env_value(token_var) if token_var == "WHATSAPP_ENABLED": if val and val.lower() == "true": - session_file = Path.home() / ".hermes" / "whatsapp" / "session" / "creds.json" + session_file = get_hermes_home() / "whatsapp" / "session" / "creds.json" if session_file.exists(): return "configured + paired" return "enabled, not paired" diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 14706f23b..b83c5b320 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -648,7 +648,7 @@ def cmd_whatsapp(args): print("✓ Bridge dependencies already installed") # ── Step 5: Check for existing session ─────────────────────────────── - session_dir = Path.home() / ".hermes" / "whatsapp" / "session" + session_dir = get_hermes_home() / "whatsapp" / "session" session_dir.mkdir(parents=True, exist_ok=True) if (session_dir / "creds.json").exists(): diff --git a/hermes_cli/status.py b/hermes_cli/status.py index 53491a5b8..c56d3cdda 100644 --- a/hermes_cli/status.py +++ b/hermes_cli/status.py @@ -12,7 +12,7 @@ from pathlib import Path PROJECT_ROOT = Path(__file__).parent.parent.resolve() from hermes_cli.colors import Colors, color -from hermes_cli.config import get_env_path, get_env_value +from hermes_cli.config import get_env_path, get_env_value, get_hermes_home from hermes_constants import OPENROUTER_MODELS_URL def check_mark(ok: bool) -> str: @@ -267,7 +267,7 @@ def show_status(args): print() print(color("◆ Scheduled Jobs", Colors.CYAN, Colors.BOLD)) - jobs_file = Path.home() / ".hermes" / "cron" / "jobs.json" + jobs_file = get_hermes_home() / "cron" / "jobs.json" if jobs_file.exists(): import json try: @@ -287,7 +287,7 @@ def show_status(args): print() print(color("◆ Sessions", Colors.CYAN, Colors.BOLD)) - sessions_file = Path.home() / ".hermes" / "sessions" / "sessions.json" + sessions_file = get_hermes_home() / "sessions" / "sessions.json" if sessions_file.exists(): import json try: diff --git a/run_agent.py b/run_agent.py index 0d7037c42..b9bacf7d6 100644 --- a/run_agent.py +++ b/run_agent.py @@ -408,7 +408,7 @@ class AIAgent: # Persistent error log -- always writes WARNING+ to ~/.hermes/logs/errors.log # so tool failures, API errors, etc. are inspectable after the fact. from agent.redact import RedactingFormatter - _error_log_dir = Path.home() / ".hermes" / "logs" + _error_log_dir = _hermes_home / "logs" _error_log_dir.mkdir(parents=True, exist_ok=True) _error_log_path = _error_log_dir / "errors.log" from logging.handlers import RotatingFileHandler diff --git a/tests/gateway/test_channel_directory.py b/tests/gateway/test_channel_directory.py index 9ff8ac979..74c95213d 100644 --- a/tests/gateway/test_channel_directory.py +++ b/tests/gateway/test_channel_directory.py @@ -1,6 +1,7 @@ """Tests for gateway/channel_directory.py — channel resolution and display.""" import json +import os from pathlib import Path from unittest.mock import patch @@ -122,7 +123,7 @@ class TestResolveChannelName: class TestBuildFromSessions: def _write_sessions(self, tmp_path, sessions_data): """Write sessions.json at the path _build_from_sessions expects.""" - sessions_path = tmp_path / ".hermes" / "sessions" / "sessions.json" + sessions_path = tmp_path / "sessions" / "sessions.json" sessions_path.parent.mkdir(parents=True) sessions_path.write_text(json.dumps(sessions_data)) @@ -152,7 +153,7 @@ class TestBuildFromSessions: }, }) - with patch.object(Path, "home", return_value=tmp_path): + with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}): entries = _build_from_sessions("telegram") assert len(entries) == 2 @@ -161,7 +162,7 @@ class TestBuildFromSessions: assert "Bob" in names def test_missing_sessions_file(self, tmp_path): - with patch.object(Path, "home", return_value=tmp_path): + with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}): entries = _build_from_sessions("telegram") assert entries == [] @@ -171,7 +172,7 @@ class TestBuildFromSessions: "s2": {"origin": {"platform": "telegram", "chat_id": "123", "chat_name": "X"}}, }) - with patch.object(Path, "home", return_value=tmp_path): + with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}): entries = _build_from_sessions("telegram") assert len(entries) == 1 diff --git a/tests/tools/test_clipboard.py b/tests/tools/test_clipboard.py index 19be40125..6f1ecf8db 100644 --- a/tests/tools/test_clipboard.py +++ b/tests/tools/test_clipboard.py @@ -808,7 +808,7 @@ class TestTryAttachClipboardImage: with patch("hermes_cli.clipboard.save_clipboard_image", return_value=True): cli._try_attach_clipboard_image() path = cli._attached_images[0] - assert path.parent == Path.home() / ".hermes" / "images" + assert path.parent == Path(os.environ["HERMES_HOME"]) / "images" assert path.name.startswith("clip_") assert path.suffix == ".png" diff --git a/tools/environments/base.py b/tools/environments/base.py index 295c84daa..896937adf 100644 --- a/tools/environments/base.py +++ b/tools/environments/base.py @@ -5,18 +5,20 @@ import os import subprocess from pathlib import Path +from hermes_cli.config import get_hermes_home + def get_sandbox_dir() -> Path: """Return the host-side root for all sandbox storage (Docker workspaces, Singularity overlays/SIF cache, etc.). - Configurable via TERMINAL_SANDBOX_DIR. Defaults to ~/.hermes/sandboxes/. + Configurable via TERMINAL_SANDBOX_DIR. Defaults to {HERMES_HOME}/sandboxes/. """ custom = os.getenv("TERMINAL_SANDBOX_DIR") if custom: p = Path(custom) else: - p = Path.home() / ".hermes" / "sandboxes" + p = get_hermes_home() / "sandboxes" p.mkdir(parents=True, exist_ok=True) return p diff --git a/tools/environments/modal.py b/tools/environments/modal.py index 44ad51eba..56f08e9fe 100644 --- a/tools/environments/modal.py +++ b/tools/environments/modal.py @@ -13,12 +13,13 @@ import uuid from pathlib import Path from typing import Any, Dict, Optional +from hermes_cli.config import get_hermes_home from tools.environments.base import BaseEnvironment from tools.interrupt import is_interrupted logger = logging.getLogger(__name__) -_SNAPSHOT_STORE = Path.home() / ".hermes" / "modal_snapshots.json" +_SNAPSHOT_STORE = get_hermes_home() / "modal_snapshots.json" def _load_snapshots() -> Dict[str, str]: diff --git a/tools/environments/singularity.py b/tools/environments/singularity.py index 0be1c38f0..f462cd055 100644 --- a/tools/environments/singularity.py +++ b/tools/environments/singularity.py @@ -16,12 +16,13 @@ import uuid from pathlib import Path from typing import Any, Dict, Optional +from hermes_cli.config import get_hermes_home from tools.environments.base import BaseEnvironment from tools.interrupt import is_interrupted logger = logging.getLogger(__name__) -_SNAPSHOT_STORE = Path.home() / ".hermes" / "singularity_snapshots.json" +_SNAPSHOT_STORE = get_hermes_home() / "singularity_snapshots.json" def _load_snapshots() -> Dict[str, str]: diff --git a/tools/process_registry.py b/tools/process_registry.py index 2c044f9f9..d08510d90 100644 --- a/tools/process_registry.py +++ b/tools/process_registry.py @@ -47,11 +47,13 @@ from dataclasses import dataclass, field from pathlib import Path from typing import Any, Dict, List, Optional +from hermes_cli.config import get_hermes_home + logger = logging.getLogger(__name__) # Checkpoint file for crash recovery (gateway only) -CHECKPOINT_PATH = Path(os.path.expanduser("~/.hermes/processes.json")) +CHECKPOINT_PATH = get_hermes_home() / "processes.json" # Limits MAX_OUTPUT_CHARS = 200_000 # 200KB rolling output buffer diff --git a/tools/tts_tool.py b/tools/tts_tool.py index 7d39a9f73..3544b20fd 100644 --- a/tools/tts_tool.py +++ b/tools/tts_tool.py @@ -65,7 +65,7 @@ DEFAULT_ELEVENLABS_VOICE_ID = "pNInz6obpgDQGcFmaJgB" # Adam DEFAULT_ELEVENLABS_MODEL_ID = "eleven_multilingual_v2" DEFAULT_OPENAI_MODEL = "gpt-4o-mini-tts" DEFAULT_OPENAI_VOICE = "alloy" -DEFAULT_OUTPUT_DIR = os.path.expanduser("~/.hermes/audio_cache") +DEFAULT_OUTPUT_DIR = str(Path(os.getenv("HERMES_HOME", Path.home() / ".hermes")) / "audio_cache") MAX_TEXT_LENGTH = 4000