hermes-agent/tests/gateway/test_shared_group_sender_prefix.py
Junass1 04f9ffb792 fix(gateway): preserve sender attribution in shared group sessions
Generalize shared multi-user session handling so non-thread group sessions
(group_sessions_per_user=False) get the same treatment as shared threads:
inbound messages are prefixed with [sender name], and the session prompt
shows a multi-user note instead of pinning a single **User:** line into
the cached system prompt.

Before: build_session_key already treated these as shared sessions, but
_prepare_inbound_message_text and build_session_context_prompt only
recognized shared threads — creating cross-user attribution drift and
prompt-cache contamination in shared groups.

- Add is_shared_multi_user_session() helper alongside build_session_key()
  so both the session key and the multi-user branches are driven by the
  same rules (DMs never shared, threads shared unless
  thread_sessions_per_user, groups shared unless group_sessions_per_user).
- Add shared_multi_user_session field to SessionContext, populated by
  build_session_context() from config.
- Use context.shared_multi_user_session in the prompt builder (label is
  'Multi-user thread' when a thread is present, 'Multi-user session'
  otherwise).
- Use the helper in _prepare_inbound_message_text so non-thread shared
  groups also get [sender] prefixes.

Default behavior unchanged: DMs stay single-user, groups with
group_sessions_per_user=True still show the user normally, shared threads
keep their existing multi-user behavior.

Tests (65 passed):
- tests/gateway/test_session.py: new shared non-thread group prompt case.
- tests/gateway/test_shared_group_sender_prefix.py: inbound preprocessing
  for shared non-thread groups and default groups.
2026-04-21 00:54:46 -07:00

70 lines
1.8 KiB
Python

import pytest
from gateway.config import GatewayConfig, Platform, PlatformConfig
from gateway.platforms.base import MessageEvent
from gateway.run import GatewayRunner
from gateway.session import SessionSource
def _make_runner(config: GatewayConfig) -> GatewayRunner:
runner = object.__new__(GatewayRunner)
runner.config = config
runner.adapters = {}
runner._model = "openai/gpt-4.1-mini"
runner._base_url = None
return runner
@pytest.mark.asyncio
async def test_preprocess_prefixes_sender_for_shared_non_thread_group_session():
runner = _make_runner(
GatewayConfig(
platforms={
Platform.TELEGRAM: PlatformConfig(enabled=True, token="fake"),
},
group_sessions_per_user=False,
)
)
source = SessionSource(
platform=Platform.TELEGRAM,
chat_id="-1002285219667",
chat_name="Test Group",
chat_type="group",
user_name="Alice",
)
event = MessageEvent(text="hello", source=source)
result = await runner._prepare_inbound_message_text(
event=event,
source=source,
history=[],
)
assert result == "[Alice] hello"
@pytest.mark.asyncio
async def test_preprocess_keeps_plain_text_for_default_group_sessions():
runner = _make_runner(
GatewayConfig(
platforms={
Platform.TELEGRAM: PlatformConfig(enabled=True, token="fake"),
},
)
)
source = SessionSource(
platform=Platform.TELEGRAM,
chat_id="-1002285219667",
chat_name="Test Group",
chat_type="group",
user_name="Alice",
)
event = MessageEvent(text="hello", source=source)
result = await runner._prepare_inbound_message_text(
event=event,
source=source,
history=[],
)
assert result == "hello"