feat(honcho): scope host and peer resolution to active Hermes profile
Derives the Honcho host key from the active Hermes profile so that each profile gets its own Honcho host block, workspace, and AI peer identity. Profile "coder" resolves to host "hermes.coder", reads from hosts["hermes.coder"] in honcho.json, and defaults workspace + aiPeer to the derived host name. Resolution order: HERMES_HONCHO_HOST env var > active profile name > "hermes" (default). Complements #3681 (profiles) with the Honcho identity layer that was part of #2845 (named instances), adapted to the merged profiles system.
This commit is contained in:
@@ -11,9 +11,12 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
from honcho_integration.client import resolve_config_path, GLOBAL_CONFIG_PATH
|
||||
from honcho_integration.client import resolve_active_host, resolve_config_path, GLOBAL_CONFIG_PATH, HOST
|
||||
|
||||
HOST = "hermes"
|
||||
|
||||
def _host_key() -> str:
|
||||
"""Return the active Honcho host key, derived from the current Hermes profile."""
|
||||
return resolve_active_host()
|
||||
|
||||
|
||||
def _config_path() -> Path:
|
||||
@@ -52,7 +55,7 @@ def _write_config(cfg: dict, path: Path | None = None) -> None:
|
||||
|
||||
def _resolve_api_key(cfg: dict) -> str:
|
||||
"""Resolve API key with host -> root -> env fallback."""
|
||||
host_key = ((cfg.get("hosts") or {}).get(HOST) or {}).get("apiKey")
|
||||
host_key = ((cfg.get("hosts") or {}).get(_host_key()) or {}).get("apiKey")
|
||||
return host_key or cfg.get("apiKey", "") or os.environ.get("HONCHO_API_KEY", "")
|
||||
|
||||
|
||||
@@ -118,10 +121,10 @@ def cmd_setup(args) -> None:
|
||||
if not _ensure_sdk_installed():
|
||||
return
|
||||
|
||||
# All writes go to hosts.hermes — root keys are managed by the user
|
||||
# or the honcho CLI only.
|
||||
# All writes go to the active host block — root keys are managed by
|
||||
# the user or the honcho CLI only.
|
||||
hosts = cfg.setdefault("hosts", {})
|
||||
hermes_host = hosts.setdefault(HOST, {})
|
||||
hermes_host = hosts.setdefault(_host_key(), {})
|
||||
|
||||
# API key — shared credential, lives at root so all hosts can read it
|
||||
current_key = cfg.get("apiKey", "")
|
||||
@@ -148,7 +151,7 @@ def cmd_setup(args) -> None:
|
||||
if new_workspace:
|
||||
hermes_host["workspace"] = new_workspace
|
||||
|
||||
hermes_host.setdefault("aiPeer", HOST)
|
||||
hermes_host.setdefault("aiPeer", _host_key())
|
||||
|
||||
# Memory mode
|
||||
current_mode = hermes_host.get("memoryMode") or cfg.get("memoryMode", "hybrid")
|
||||
@@ -354,9 +357,9 @@ def cmd_peer(args) -> None:
|
||||
if user_name is None and ai_name is None and reasoning is None:
|
||||
# Show current values
|
||||
hosts = cfg.get("hosts", {})
|
||||
hermes = hosts.get(HOST, {})
|
||||
hermes = hosts.get(_host_key(), {})
|
||||
user = hermes.get('peerName') or cfg.get('peerName') or '(not set)'
|
||||
ai = hermes.get('aiPeer') or cfg.get('aiPeer') or HOST
|
||||
ai = hermes.get('aiPeer') or cfg.get('aiPeer') or _host_key()
|
||||
lvl = hermes.get("dialecticReasoningLevel") or cfg.get("dialecticReasoningLevel") or "low"
|
||||
max_chars = hermes.get("dialecticMaxChars") or cfg.get("dialecticMaxChars") or 600
|
||||
print("\nHoncho peers\n" + "─" * 40)
|
||||
@@ -371,12 +374,12 @@ def cmd_peer(args) -> None:
|
||||
return
|
||||
|
||||
if user_name is not None:
|
||||
cfg.setdefault("hosts", {}).setdefault(HOST, {})["peerName"] = user_name.strip()
|
||||
cfg.setdefault("hosts", {}).setdefault(_host_key(), {})["peerName"] = user_name.strip()
|
||||
changed = True
|
||||
print(f" User peer → {user_name.strip()}")
|
||||
|
||||
if ai_name is not None:
|
||||
cfg.setdefault("hosts", {}).setdefault(HOST, {})["aiPeer"] = ai_name.strip()
|
||||
cfg.setdefault("hosts", {}).setdefault(_host_key(), {})["aiPeer"] = ai_name.strip()
|
||||
changed = True
|
||||
print(f" AI peer → {ai_name.strip()}")
|
||||
|
||||
@@ -384,7 +387,7 @@ def cmd_peer(args) -> None:
|
||||
if reasoning not in REASONING_LEVELS:
|
||||
print(f" Invalid reasoning level '{reasoning}'. Options: {', '.join(REASONING_LEVELS)}")
|
||||
return
|
||||
cfg.setdefault("hosts", {}).setdefault(HOST, {})["dialecticReasoningLevel"] = reasoning
|
||||
cfg.setdefault("hosts", {}).setdefault(_host_key(), {})["dialecticReasoningLevel"] = reasoning
|
||||
changed = True
|
||||
print(f" Dialectic reasoning level → {reasoning}")
|
||||
|
||||
@@ -404,7 +407,7 @@ def cmd_mode(args) -> None:
|
||||
|
||||
if mode_arg is None:
|
||||
current = (
|
||||
(cfg.get("hosts") or {}).get(HOST, {}).get("memoryMode")
|
||||
(cfg.get("hosts") or {}).get(_host_key(), {}).get("memoryMode")
|
||||
or cfg.get("memoryMode")
|
||||
or "hybrid"
|
||||
)
|
||||
@@ -419,7 +422,7 @@ def cmd_mode(args) -> None:
|
||||
print(f" Invalid mode '{mode_arg}'. Options: {', '.join(MODES)}\n")
|
||||
return
|
||||
|
||||
cfg.setdefault("hosts", {}).setdefault(HOST, {})["memoryMode"] = mode_arg
|
||||
cfg.setdefault("hosts", {}).setdefault(_host_key(), {})["memoryMode"] = mode_arg
|
||||
_write_config(cfg)
|
||||
print(f" Memory mode → {mode_arg} ({MODES[mode_arg]})\n")
|
||||
|
||||
@@ -428,7 +431,7 @@ def cmd_tokens(args) -> None:
|
||||
"""Show or set token budget settings."""
|
||||
cfg = _read_config()
|
||||
hosts = cfg.get("hosts", {})
|
||||
hermes = hosts.get(HOST, {})
|
||||
hermes = hosts.get(_host_key(), {})
|
||||
|
||||
context = getattr(args, "context", None)
|
||||
dialectic = getattr(args, "dialectic", None)
|
||||
@@ -453,11 +456,11 @@ def cmd_tokens(args) -> None:
|
||||
|
||||
changed = False
|
||||
if context is not None:
|
||||
cfg.setdefault("hosts", {}).setdefault(HOST, {})["contextTokens"] = context
|
||||
cfg.setdefault("hosts", {}).setdefault(_host_key(), {})["contextTokens"] = context
|
||||
print(f" context tokens → {context}")
|
||||
changed = True
|
||||
if dialectic is not None:
|
||||
cfg.setdefault("hosts", {}).setdefault(HOST, {})["dialecticMaxChars"] = dialectic
|
||||
cfg.setdefault("hosts", {}).setdefault(_host_key(), {})["dialecticMaxChars"] = dialectic
|
||||
print(f" dialectic cap → {dialectic} chars")
|
||||
changed = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user