fix(honcho): runtime peer mapping — correctness follow-ups + setup wizard + docs#30077
Merged
kshitijk4poor merged 15 commits intoMay 27, 2026
Merged
Conversation
(cherry picked from commit 864cdb3)
(cherry picked from commit d89a57e)
(cherry picked from commit 4ae3c1a)
PR NousResearch#27371 added host-scoped userPeerAliases, runtimePeerPrefix, and pinPeerName, but the cloned-profile allowlist in plugins/memory/honcho/cli.py::clone_honcho_for_profile() omitted them. A new profile created via 'hermes honcho setup' or similar would silently drop the operator's identity-mapping config, causing gateway users to resolve to raw runtime IDs and fragmenting Honcho memory across an unintended set of peers. Add the three keys to the allowlist and a regression test class covering all three plus the unset case.
…ed-thread peer contamination PR NousResearch#27371 introduced a per-user-peer resolver in HonchoSessionManager, but the resolved runtime identity is frozen into the manager at first- message init. When the gateway session_key intentionally omits the participant ID (the default for threads via thread_sessions_per_user= False), a cached AIAgent created by user A is reused for user B's messages, attributing B's writes to A's resolved Honcho peer and breaking NousResearch#27371's per-user-peer contract. Fix by including user_id and user_id_alt in _agent_config_signature so the cache key distinguishes participants in shared threads. Each user in a shared thread now triggers a fresh AIAgent build (trading prompt- cache warmth for memory-attribution correctness — the right tradeoff for an external-memory backend where misattribution is unrecoverable). The default-None case keeps the signature byte-identical to pre-fix behavior so this change doesn't invalidate in-flight caches on deploy.
The PR NousResearch#27371 resolver introduced three identity-mapping config keys (pinPeerName, userPeerAliases, runtimePeerPrefix), but operators had no guided way to set them — they had to read the README, understand the resolver ladder, and hand-edit honcho.json. This commit adds an interactive step to 'hermes honcho setup' that asks one question ('what's your deployment shape?') and writes the right combination of keys. Three shapes cover the realistic deployments: * single -- pinPeerName=true. All gateway users collapse to your peerName. Recommended for personal/single-operator use. * multi -- pinPeerName=false, no aliases. Each runtime user gets their own peer. Optional runtimePeerPrefix for cross- platform namespace isolation. * hybrid -- pinPeerName=false, with userPeerAliases mapping YOUR runtime IDs (Telegram UID, Discord snowflake, Slack user, Matrix MXID) to peerName. Multi-user gateway where you are a privileged operator. A 'skip' option leaves existing identity-mapping config untouched — critical because re-running setup must not silently wipe operator- curated aliases. The wizard detects the current shape from existing config so the prompt's default matches what the operator already has.
…r pinPeerName The original key 'pinPeerName' from NousResearch#14984 is ambiguous: a fresh reader can't tell whether it pins the user peer or the AI peer from the name alone. The resolver only ever pins the user-side (_resolve_user_peer_id short-circuits when pin_peer_name is true; the AI peer is already pinned by construction via aiPeer). Add 'pinUserPeer' as the canonical alias. Both keys land on the same internal pin_peer_name field; precedence is host pinUserPeer → host pinPeerName → root pinUserPeer → root pinPeerName → default. Host-level always beats root-level regardless of alias, so a host block can still explicitly disable a root-level pin even via the new key. Make _resolve_bool variadic so it can express the four-value precedence chain. All existing callers pass two positional args + default keyword, which the new signature accepts unchanged. Internal var name (pin_peer_name) stays the same to keep the cherry-picked NousResearch#27371 commits clean and avoid a noisy rename diff.
…ployment shapes PR NousResearch#27371 introduced three new identity-mapping config keys (pinPeerName, userPeerAliases, runtimePeerPrefix), but the README's 'Full Configuration Reference' didn't mention them. Operators had to read the source to understand the resolver, leading to predictable support questions ("why is my user split across two peers?", "what does pinPeerName actually pin?"). Add a new 'Identity Mapping' subsection that covers: * The four config keys (pinUserPeer + alias, userPeerAliases, runtimePeerPrefix) with concrete examples. * The 7-step resolver ladder so operators can predict which peer a given runtime ID will land on. * Why there's no symmetric pinAiPeer (the AI peer is already pinned by construction; the asymmetry is intentional). * Host vs root semantics (host-level replaces root for maps, wipes with empty value). * The three deployment shapes ('hermes honcho setup' uses these same shape names) with one-line guidance per shape.
Three correctness gaps when honcho.json's identity-mapping config changes mid-flight: 1. The gateway's agent cache signature ignored honcho identity keys, so editing peerName / pinPeerName / userPeerAliases / runtimePeerPrefix was silently dropped until an unrelated cache eviction. Extend _extract_cache_busting_config to fingerprint the resolved honcho config so the AIAgent rebuilds on the next message. 2. cmd_setup let single → multi flips orphan the pinned-pool history under peerName without warning. Detect the transition, warn that runtime users will resolve to fresh empty peers, and auto-steer to hybrid (alias the operator's runtime IDs back to peerName) so the operator's own continuity survives. yes / no overrides available. 3. README didn't document the orphaning behaviour. Add a "Migrating single → multi" callout under Deployment shapes. Tests: - TestPinTransition (test_pin_peer_name.py): fresh-manager flip resolves to runtime, in-process flip is gated by the per-key session cache (documents the gateway-cache-must-bust contract), 3 cache-bust signature tests for pin / aliases / prefix. - TestProfilePeerUniqueness: two profiles pinned to distinct peerNames resolve to distinct peers; host-level peerName overrides root when pinned. - test_single_to_multi_steers_to_hybrid_by_default and test_single_to_multi_yes_override_keeps_multi (test_cli.py): wizard guard end-to-end coverage.
Remove "PR NousResearch#14984 / NousResearch#27371 / NousResearch#1969" references and "the original key / legacy / backwards-compatible / Port #N" narration from the honcho plugin README, tests, and one stale code comment. These artefacts age poorly: they describe how a change happened rather than what the code does today, and they tax readers who weren't around for the original work. Also drop a dangling reference to scratch/memory-plugin-ux-specs.md in __init__.py — the file isn't in the repo or git history. No behaviour change.
…nd gateway cache
Three related regressions stemming from the pinUserPeer alias landing:
- Setup wizard read host-only fields when detecting current shape but the
parser supports root-level config and gives host pinUserPeer higher
precedence than pinPeerName. Re-running setup could mis-detect shape
and silently flip routing. Detection now uses the same resolver order
as HonchoClientConfig, and each shape branch scrubs every peer-mapping
key before writing so a stale pinUserPeer=false can't outrank a freshly
written pinPeerName=true. Multi no longer auto-writes
userPeerAliases={} (was silently masking root-level baselines).
- clone_honcho_for_profile inherited pinPeerName but not pinUserPeer, so
a default profile configured with the newer key produced cloned
profiles without the pin.
- Gateway cache-busting signature fingerprinted Honcho user-peer fields
but not ai_peer. Since HonchoSessionManager freezes cfg.ai_peer at
init, mid-flight aiPeer edits kept assistant writes on the old peer
until an unrelated cache eviction. ai_peer is now part of the
signature.
3 tasks
honcho_profile(peer="user") returned an empty card even when Honcho
held a populated peer card for the user. Two independent bugs combined
to produce the symptom:
1. Read path: get_peer_card() called _fetch_peer_card(observer, target=user),
which hits GET /peers/{observer}/card?target={user} — the observer's local
card of the user. On self-hosted Honcho v3 this slot is empty unless writes
also use it. The peer card lives on the user peer itself
(GET /peers/{user}/card). Add a fallback: when the observer-target slot is
empty and a target exists, retry against the target peer's own card.
2. Write path: set_peer_card() resolved only the target peer and called
user_peer.set_card(card). The read path uses the assistant peer as
observer, so writes and reads addressed different Honcho card scopes.
Align set_peer_card() with _resolve_observer_target() so writes go to
assistant_peer.set_card(card, target=user_peer_id), matching the read.
Both paths now use the same observer/target resolution, and the read
path additionally falls back to the target's own card for compatibility
with deployments where cards were written directly to the peer.
Closes: related to NousResearch#13375, NousResearch#17124, NousResearch#20729
Use the shared observer/target resolver for session context so peer='user' and explicit configured peer IDs query Honcho from the same assistant-observed perspective when allowed. Add regression coverage for user alias, explicit peer, and self-observer fallback.
Contributor
Author
|
Local smoke checks for the #30077 surfaces passed. Covered:
Command: python /tmp/honcho_smoke_30077.pyResult: all local smoke checks passed. |
1 task
7 tasks
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Carries forward @mavrickdeveloper's work in #27371 (Honcho runtime peer alias / prefix mapping for multi-user gateways) with original authorship preserved, then adds follow-ups that close correctness gaps and ship the operator-facing UX for the resolver.
This also adopts the peer-card/session-context perspective fixes from #27979 and #23485 with original authorship preserved.
Closes #27314.
Closes #28283.
Closes #31219.
Closes #33382.
Supersedes #27371, #28572, #27979, #23485, #17124, #31240, #23022, #20729, #21539, and #15598.
Cherry-picks / adopted commits (preserved authorship)
From #27371:
1fea2b3@mavrickdeveloper — Add Honcho runtime peer mappingbcbed03@mavrickdeveloper — Cover Honcho runtime peer edge casesf7d8f29@mavrickdeveloper — Avoid Honcho runtime peer collisionsFrom #27979:
43141a2David Doan — Align peer-card read/write pathsFrom #23485:
107a22bDora / kyra-nest — Alignhoncho_contextuser peer perspectiveWhat this covers
userPeerAliasesfor known runtime IDs.runtimePeerPrefixfor unknown runtime IDs.pinUserPeeras the clearer alias forpinPeerName, with backwards compatibility.user_idso shared threads do not reuse the wrong Honcho provider state.honcho.jsonmtime when Honcho is active.honcho_context(peer="user")perspective alignment with explicit user peer lookup.Superseded PRs
userPeerAliases+runtimePeerPrefixresolver model; no separate config surface needed.Kept separate
X-Hermes-User-*/X-Hermes-Chat-*identity headers. Useful companion work, but broader gateway/API-server scope.Test plan
Targeted local test suite:
scripts/run_tests.sh tests/honcho_plugin/test_session.py tests/test_honcho_session_context.py tests/honcho_plugin/test_pin_peer_name.py tests/honcho_plugin/test_cli.py tests/run_agent/test_memory_provider_init.py tests/gateway/test_agent_cache.pyResult: 251 passed, 0 failed.
Cache-busting follow-up:
scripts/run_tests.sh tests/gateway/test_agent_cache.pyResult: 62 passed, 0 failed.
Full local test suite was also run. It currently has unrelated failures in Anthropic adapter, macOS
systemctlguard tests, browser dependency installation, TUI browser launch hint, and gateway approval E2E tests; none are in the Honcho/runtime identity touched surface. GitHub CI for this PR is green except attribution.