diff --git a/plugins/memory/honcho/session_peers.py b/plugins/memory/honcho/session_peers.py index e9b44af0a6..c507212b34 100644 --- a/plugins/memory/honcho/session_peers.py +++ b/plugins/memory/honcho/session_peers.py @@ -123,11 +123,15 @@ class SessionPeersMixin: def resolve_author_peer_id(self, key: str, author_id: str | None, author_name: str | None = None) -> str | None: """Peer ID for the turn's author, or None to keep the session's peer: no author named, the - author IS the session's peer, or ``pinPeerName`` collapsing identities by operator request. + author IS the session's peer, or ``pinPeerName`` collapsing the operator's accounts. Bot authors + are never collapsed: pinned or not, a bot's words go under the bot's peer. ``author_name`` is a display name (attacker-influenceable), so it never becomes a peer ID.""" runtime_id = str(author_id).strip() if author_id else "" if not runtime_id: return None + # The pin collapses the operator's own accounts onto one peer; a bot is never one of those. + if runtime_id.startswith(BOT_AUTHOR_PREFIX): + return self._peer_id_for_runtime_id(runtime_id) if self._config is not None and bool(getattr(self._config, "peer_name", None)) \ and getattr(self._config, "pin_peer_name", False) is True: return None diff --git a/tests/honcho_plugin/test_a2a_sessions.py b/tests/honcho_plugin/test_a2a_sessions.py index 619f07a50e..b3ff482eed 100644 --- a/tests/honcho_plugin/test_a2a_sessions.py +++ b/tests/honcho_plugin/test_a2a_sessions.py @@ -85,8 +85,8 @@ class TestA2aRouting: provider._manager.get_or_create.assert_not_called() - def test_collapsed_bot_peer_keeps_the_default_user_peer(self): - """pinUserPeer returns no author peer; the a2a session then falls back to the resolved peer.""" + def test_unresolvable_bot_peer_keeps_the_default_user_peer(self): + """When no author peer resolves, the a2a session still opens under the resolved peer.""" provider = _provider() provider._manager.resolve_author_peer_id.return_value = None diff --git a/tests/honcho_plugin/test_turn_author_peers.py b/tests/honcho_plugin/test_turn_author_peers.py index 2895356fc6..ddde59d353 100644 --- a/tests/honcho_plugin/test_turn_author_peers.py +++ b/tests/honcho_plugin/test_turn_author_peers.py @@ -99,9 +99,10 @@ class TestResolveAuthorPeerId: mgr = _manager(_config(), runtime_id="7654321") assert mgr.resolve_author_peer_id("telegram:dm1", "bot:") == "bot-" - def test_pin_peer_name_collapses_bot_authors_too(self): + def test_pin_peer_name_does_not_collapse_bot_authors(self): + """The pin unifies the operator's accounts; a bot's words never land under the human's peer.""" mgr = _manager(_config(pin_peer_name=True), runtime_id="7654321") - assert mgr.resolve_author_peer_id("telegram:dm1", "bot:coder") is None + assert mgr.resolve_author_peer_id("telegram:dm1", "bot:coder") == "coder" def test_display_name_never_becomes_a_peer_id(self): """Display names are attacker-influenceable on most platforms."""