mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
fix(gateway): /profile reports the profile serving the source, not the multiplexer's
On a multiplexed gateway the process-level active profile is always the multiplexer's own (usually "default"), so /profile answered "default" in every chat regardless of which profile actually served it — making per-chat persona routing look broken when it was working. Report source.profile (stamped by the /p/<profile>/ URL prefix, a per-credential adapter, or a room->profile map) and resolve the displayed home under that profile's runtime scope, mirroring the scoped /reset banner (#59003). Unstamped sources fall back to the active profile and default home, so single-profile gateways are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8191f621c3
commit
f7d6f099db
2 changed files with 78 additions and 3 deletions
|
|
@ -330,12 +330,33 @@ class GatewaySlashCommandsMixin:
|
|||
return EphemeralReply(f"{header}{_tip_line}")
|
||||
|
||||
async def _handle_profile_command(self, event: MessageEvent) -> str:
|
||||
"""Handle /profile — show active profile name and home directory."""
|
||||
"""Handle /profile — show the profile serving this source and its home.
|
||||
|
||||
On a multiplexed gateway the process-level active profile is always
|
||||
the multiplexer's own (usually ``default``), so reporting it would
|
||||
answer "default" in every chat regardless of which profile actually
|
||||
serves the room/channel (``source.profile`` — stamped by the
|
||||
``/p/<profile>/`` URL prefix, a per-credential adapter, or a room→
|
||||
profile map). Report the stamped profile and, like the scoped /reset
|
||||
banner (#59003), resolve the displayed home under that profile's
|
||||
runtime scope. Single-profile gateways are unchanged: an unstamped
|
||||
source falls back to the active profile and the default home.
|
||||
"""
|
||||
from hermes_constants import display_hermes_home
|
||||
from hermes_cli.profiles import get_active_profile_name
|
||||
|
||||
display = display_hermes_home()
|
||||
profile_name = get_active_profile_name()
|
||||
source = getattr(event, "source", None)
|
||||
profile_name = (
|
||||
getattr(source, "profile", "") or ""
|
||||
).strip() or get_active_profile_name()
|
||||
try:
|
||||
from gateway.run import _profile_runtime_scope
|
||||
|
||||
profile_home = self._resolve_profile_home_for_source(source)
|
||||
with _profile_runtime_scope(profile_home):
|
||||
display = display_hermes_home()
|
||||
except Exception:
|
||||
display = display_hermes_home()
|
||||
|
||||
lines = [
|
||||
t("gateway.profile.header", profile=profile_name),
|
||||
|
|
|
|||
|
|
@ -672,6 +672,60 @@ async def test_profile_command_reports_custom_root_profile(monkeypatch, tmp_path
|
|||
assert f"**Home:** `{profile_home}`" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_profile_command_reports_source_stamped_profile(monkeypatch, tmp_path):
|
||||
"""On a multiplexed gateway, /profile reports the profile SERVING the
|
||||
source (source.profile — URL prefix / per-credential adapter / room map),
|
||||
not the multiplexer's active profile, which is always the default and
|
||||
made /profile answer "default" in every persona chat."""
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
profile_home = hermes_home / "profiles" / "milo"
|
||||
profile_home.mkdir(parents=True)
|
||||
|
||||
session_entry = SessionEntry(
|
||||
session_key=build_session_key(_make_source()),
|
||||
session_id="sess-1",
|
||||
created_at=datetime.now(),
|
||||
updated_at=datetime.now(),
|
||||
platform=Platform.TELEGRAM,
|
||||
chat_type="dm",
|
||||
)
|
||||
runner = _make_runner(session_entry)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
event = _make_event("/profile")
|
||||
event.source.profile = "milo"
|
||||
|
||||
result = await runner._handle_profile_command(event)
|
||||
|
||||
assert "**Profile:** `milo`" in result
|
||||
assert f"**Home:** `{profile_home}`" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_profile_command_unstamped_source_unchanged(monkeypatch, tmp_path):
|
||||
"""Single-profile behavior is untouched: an unstamped source reports the
|
||||
active profile and the default home."""
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
|
||||
session_entry = SessionEntry(
|
||||
session_key=build_session_key(_make_source()),
|
||||
session_id="sess-1",
|
||||
created_at=datetime.now(),
|
||||
updated_at=datetime.now(),
|
||||
platform=Platform.TELEGRAM,
|
||||
chat_type="dm",
|
||||
)
|
||||
runner = _make_runner(session_entry)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
result = await runner._handle_profile_command(_make_event("/profile"))
|
||||
|
||||
assert "**Profile:** `default`" in result
|
||||
assert f"**Home:** `{hermes_home}`" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_post_delivery_callback_generation_snapshot_happens_after_bind():
|
||||
"""Regression: the callback_generation snapshot in _process_message_background
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue