diff --git a/plugins/memory/honcho/cli.py b/plugins/memory/honcho/cli.py index 672c7f23e3..d18e4d95a1 100644 --- a/plugins/memory/honcho/cli.py +++ b/plugins/memory/honcho/cli.py @@ -482,7 +482,7 @@ def _configure_raw_identity_mapping(hermes_host, current_pin, current_aliases, c "runtimePeerPrefix — namespace for unknown IDs (blank for none)") -def _setup_identity_mapping(cfg: dict, hermes_host: dict, current_peer: str) -> None: +def _setup_identity_mapping(cfg: dict, hermes_host: dict, current_peer: str, new_host: bool) -> None: """Gateway identity mapping step. Only the gateway supplies a runtime user ID (CLI/TUI/ desktop fall through to peerName), so the step is gated on gateway detection.""" current_pin, current_aliases, current_prefix, aliases_from_root, prefix_from_root = ( @@ -505,7 +505,7 @@ def _setup_identity_mapping(cfg: dict, hermes_host: dict, current_peer: str) -> peer_target = hermes_host.get("peerName") or current_peer or "user" ai_peer_label = hermes_host.get("aiPeer") or cfg.get("aiPeer") or "hermes" # Fresh configs default to the personal shape; configured ones keep their detected shape. - identity_configured = any(k in hermes_host or k in cfg for k in _IDENTITY_MAPPING_KEYS) + identity_configured = not new_host or any(k in cfg for k in _IDENTITY_MAPPING_KEYS) default_choice = {"single": "1", "hybrid": "2", "multi": "3"}[current_shape] if identity_configured else "1" print("\n This step covers the HUMAN mapping only. Each account using the\n" " gateway resolves to a peer — the entity Honcho reasons about over\n" @@ -836,6 +836,8 @@ def _setup_wizard(args) -> None: hermes_host = cfg.setdefault("hosts", {}).setdefault(_host_key(), {}) _migrate_pin_key(cfg) # canonicalize legacy pinPeerName before detection/writes _migrate_pin_key(hermes_host) + # Taken before the prompts populate the block: an existing install must not default to pinning every account. + new_host = not any(k in hermes_host for k in (*_IDENTITY_MAPPING_KEYS, "peerName", "workspace", "enabled")) # --- 1. Cloud or local? --- print(" Deployment:\n cloud -- Honcho cloud (api.honcho.dev)\n local -- self-hosted Honcho server") @@ -858,7 +860,7 @@ def _setup_wizard(args) -> None: if new := _prompt(label, default=default): hermes_host[key] = new - _setup_identity_mapping(cfg, hermes_host, current_peer) + _setup_identity_mapping(cfg, hermes_host, current_peer, new_host) print("\n For a gateway with many users and agents, run\n" " 'hermes honcho peers map' to map accounts interactively.") diff --git a/tests/honcho_plugin/test_cli.py b/tests/honcho_plugin/test_cli.py index a66a157491..e979e32069 100644 --- a/tests/honcho_plugin/test_cli.py +++ b/tests/honcho_plugin/test_cli.py @@ -561,10 +561,14 @@ class TestSetupWizardDeploymentShape: @pytest.mark.parametrize("initial_cfg, expected_pin", [ (None, True), + ({"apiKey": "***", "hosts": {"hermes": {}}}, True), ({"apiKey": "***", "hosts": {"hermes": {"pinUserPeer": False, "peerName": "eri"}}}, False), - ], ids=["fresh-config-defaults-to-single", "configured-multi-keeps-multi"]) + ({"apiKey": "***", "hosts": {"hermes": {"enabled": True, "workspace": "hermes", "peerName": "eri"}}}, False), + ], ids=["fresh-config-defaults-to-single", "empty-host-block-defaults-to-single", + "configured-multi-keeps-multi", "existing-install-without-mapping-keys-keeps-multi"]) def test_choice_default_follows_config(self, monkeypatch, tmp_path, initial_cfg, expected_pin): - """Enter on a fresh config picks the pinned personal shape; a chosen shape stays the default.""" + """Enter on a fresh config picks the pinned personal shape. An existing install, with or + without mapping keys, keeps its detected shape so Enter never merges every account onto one peer.""" answers = ["cloud", "", "eri", "hermetika", "hermes"] host = self._run_setup(monkeypatch, tmp_path, answers=answers, initial_cfg=initial_cfg) assert host["pinUserPeer"] is expected_pin