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>fix/verification-admin-route-recovery
parent
8191f621c3
commit
f7d6f099db
|
|
@ -330,12 +330,33 @@ class GatewaySlashCommandsMixin:
|
||||||
return EphemeralReply(f"{header}{_tip_line}")
|
return EphemeralReply(f"{header}{_tip_line}")
|
||||||
|
|
||||||
async def _handle_profile_command(self, event: MessageEvent) -> str:
|
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_constants import display_hermes_home
|
||||||
from hermes_cli.profiles import get_active_profile_name
|
from hermes_cli.profiles import get_active_profile_name
|
||||||
|
|
||||||
display = display_hermes_home()
|
source = getattr(event, "source", None)
|
||||||
profile_name = get_active_profile_name()
|
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 = [
|
lines = [
|
||||||
t("gateway.profile.header", profile=profile_name),
|
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
|
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
|
@pytest.mark.asyncio
|
||||||
async def test_post_delivery_callback_generation_snapshot_happens_after_bind():
|
async def test_post_delivery_callback_generation_snapshot_happens_after_bind():
|
||||||
"""Regression: the callback_generation snapshot in _process_message_background
|
"""Regression: the callback_generation snapshot in _process_message_background
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue