diff --git a/plugins/memory/hindsight/README.md b/plugins/memory/hindsight/README.md index 34f5088f36..3a1df59e4d 100644 --- a/plugins/memory/hindsight/README.md +++ b/plugins/memory/hindsight/README.md @@ -73,6 +73,7 @@ Config file: `~/.hermes/hindsight/config.json` |-----|---------|-------------| | `llm_provider` | `openai` | LLM provider: `openai`, `anthropic`, `gemini`, `groq`, `minimax`, `ollama` | | `llm_model` | per-provider | Model name (e.g. `gpt-4o-mini`, `openai/gpt-oss-120b`) | +| `llm_base_url` | — | LLM Base URL override (e.g. `https://openrouter.ai/api/v1`) | The LLM API key is stored in `~/.hermes/.env` as `HINDSIGHT_LLM_API_KEY`. @@ -92,6 +93,7 @@ Available in `hybrid` and `tools` memory modes: |----------|-------------| | `HINDSIGHT_API_KEY` | API key for Hindsight Cloud | | `HINDSIGHT_LLM_API_KEY` | LLM API key for local mode | +| `HINDSIGHT_API_LLM_BASE_URL` | LLM Base URL for local mode (e.g. OpenRouter) | | `HINDSIGHT_API_URL` | Override API endpoint | | `HINDSIGHT_BANK_ID` | Override bank name | | `HINDSIGHT_BUDGET` | Override recall budget | diff --git a/plugins/memory/hindsight/__init__.py b/plugins/memory/hindsight/__init__.py index 199a7dd5cd..c87497745e 100644 --- a/plugins/memory/hindsight/__init__.py +++ b/plugins/memory/hindsight/__init__.py @@ -235,6 +235,7 @@ class HindsightMemoryProvider(MemoryProvider): {"key": "api_key", "description": "Hindsight Cloud API key", "secret": True, "env_var": "HINDSIGHT_API_KEY", "url": "https://ui.hindsight.vectorize.io", "when": {"mode": "cloud"}}, {"key": "llm_provider", "description": "LLM provider for local mode", "default": "openai", "choices": ["openai", "anthropic", "gemini", "groq", "minimax", "ollama"], "when": {"mode": "local"}}, {"key": "llm_api_key", "description": "LLM API key for local Hindsight", "secret": True, "env_var": "HINDSIGHT_LLM_API_KEY", "when": {"mode": "local"}}, + {"key": "llm_base_url", "description": "LLM Base URL (e.g. for OpenRouter)", "default": "", "env_var": "HINDSIGHT_API_LLM_BASE_URL", "when": {"mode": "local"}}, {"key": "llm_model", "description": "LLM model for local mode", "default": "gpt-4o-mini", "default_from": {"field": "llm_provider", "map": _PROVIDER_DEFAULT_MODELS}, "when": {"mode": "local"}}, {"key": "bank_id", "description": "Memory bank name", "default": "hermes"}, {"key": "budget", "description": "Recall thoroughness", "default": "mid", "choices": ["low", "mid", "high"]}, @@ -251,12 +252,16 @@ class HindsightMemoryProvider(MemoryProvider): # different loop" errors during GC — we handle cleanup in # shutdown() instead. HindsightEmbedded.__del__ = lambda self: None - self._client = HindsightEmbedded( + kwargs = dict( profile=self._config.get("profile", "hermes"), llm_provider=self._config.get("llm_provider", ""), - llm_api_key=self._config.get("llmApiKey") or os.environ.get("HINDSIGHT_LLM_API_KEY", ""), + llm_api_key=self._config.get("llm_api_key") or os.environ.get("HINDSIGHT_LLM_API_KEY", ""), llm_model=self._config.get("llm_model", ""), ) + base_url = self._config.get("llm_base_url") or os.environ.get("HINDSIGHT_API_LLM_BASE_URL", "") + if base_url: + kwargs["llm_base_url"] = base_url + self._client = HindsightEmbedded(**kwargs) else: from hindsight_client import Hindsight kwargs = {"base_url": self._api_url, "timeout": 30.0} @@ -311,9 +316,10 @@ class HindsightMemoryProvider(MemoryProvider): # If the config changed and the daemon is running, stop it. from pathlib import Path as _Path profile_env = _Path.home() / ".hindsight" / "profiles" / f"{profile}.env" - current_key = self._config.get("llmApiKey") or os.environ.get("HINDSIGHT_LLM_API_KEY", "") + current_key = self._config.get("llm_api_key") or os.environ.get("HINDSIGHT_LLM_API_KEY", "") current_provider = self._config.get("llm_provider", "") current_model = self._config.get("llm_model", "") + current_base_url = self._config.get("llm_base_url") or os.environ.get("HINDSIGHT_API_LLM_BASE_URL", "") # Read saved profile config saved = {} @@ -326,18 +332,22 @@ class HindsightMemoryProvider(MemoryProvider): config_changed = ( saved.get("HINDSIGHT_API_LLM_PROVIDER") != current_provider or saved.get("HINDSIGHT_API_LLM_MODEL") != current_model or - saved.get("HINDSIGHT_API_LLM_API_KEY") != current_key + saved.get("HINDSIGHT_API_LLM_API_KEY") != current_key or + saved.get("HINDSIGHT_API_LLM_BASE_URL", "") != current_base_url ) if config_changed: # Write updated profile .env profile_env.parent.mkdir(parents=True, exist_ok=True) - profile_env.write_text( + env_lines = ( f"HINDSIGHT_API_LLM_PROVIDER={current_provider}\n" f"HINDSIGHT_API_LLM_API_KEY={current_key}\n" f"HINDSIGHT_API_LLM_MODEL={current_model}\n" f"HINDSIGHT_API_LOG_LEVEL=info\n" ) + if current_base_url: + env_lines += f"HINDSIGHT_API_LLM_BASE_URL={current_base_url}\n" + profile_env.write_text(env_lines) if client._manager.is_running(profile): with open(log_path, "a") as f: f.write("\n=== Config changed, restarting daemon ===\n")