Skip to content

fix(honcho): runtime peer mapping — correctness follow-ups + setup wizard + docs#30077

Merged
kshitijk4poor merged 15 commits into
NousResearch:mainfrom
erosika:fix/honcho-runtime-peer-mapping-followups
May 27, 2026
Merged

fix(honcho): runtime peer mapping — correctness follow-ups + setup wizard + docs#30077
kshitijk4poor merged 15 commits into
NousResearch:mainfrom
erosika:fix/honcho-runtime-peer-mapping-followups

Conversation

@erosika

@erosika erosika commented May 21, 2026

Copy link
Copy Markdown
Contributor

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:

From #27979:

  • 43141a2 David Doan — Align peer-card read/write paths

From #23485:

  • 107a22b Dora / kyra-nest — Align honcho_context user peer perspective

What this covers

  • Runtime Honcho user-peer resolution for multi-user gateway sessions.
  • userPeerAliases for known runtime IDs.
  • runtimePeerPrefix for unknown runtime IDs.
  • Collision protection for generated runtime peer IDs.
  • pinUserPeer as the clearer alias for pinPeerName, with backwards compatibility.
  • Setup/status/docs coverage for single-user, multi-user, and known-alias deployment shapes.
  • Agent cache separation by user_id so shared threads do not reuse the wrong Honcho provider state.
  • Honcho cache-busting config is skipped for non-Honcho providers and memoized by honcho.json mtime when Honcho is active.
  • Peer-card fallback/read/write alignment for self-hosted Honcho v3-style direct peer-card lookups.
  • honcho_context(peer="user") perspective alignment with explicit user peer lookup.

Superseded PRs

Kept separate

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.py

Result: 251 passed, 0 failed.

Cache-busting follow-up:

  • scripts/run_tests.sh tests/gateway/test_agent_cache.py

Result: 62 passed, 0 failed.

Full local test suite was also run. It currently has unrelated failures in Anthropic adapter, macOS systemctl guard 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.

mavrickdeveloper and others added 8 commits May 21, 2026 19:19
(cherry picked from commit 864cdb3)
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.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins tool/memory Memory tool and memory providers labels May 21, 2026
erosika added 3 commits May 26, 2026 11:03
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.
David Doan and others added 4 commits May 27, 2026 11:00
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.
@erosika erosika changed the title fix(honcho): runtime peer mapping — correctness follow-ups + setup wizard + docs (supersedes #27371) fix(honcho): runtime peer mapping — correctness follow-ups + setup wizard + docs May 27, 2026
@erosika

erosika commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

Local smoke checks for the #30077 surfaces passed.

Covered:

  • pinUserPeer pins runtime user_id to peerName
  • userPeerAliases maps a known runtime ID to the configured peer
  • runtimePeerPrefix isolates unknown runtime IDs
  • generated runtime peer collision protection
  • host/root config parsing for pinUserPeer, userPeerAliases, runtimePeerPrefix
  • honcho_profile(peer="user") observer-target lookup falling back to target self-card
  • peer-card write path using the same observer-target path as reads
  • honcho_context(peer="user") using assistant-observed user perspective
  • provider tool wrapper returning formatted honcho_context

Command:

python /tmp/honcho_smoke_30077.py

Result: all local smoke checks passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

4 participants