Files
hermes-agent/tests/gateway/test_personality_routed_profile.py
T
Teknium d45bc39667 fix(gateway): resolve the ephemeral personality prompt per turn from the scoped profile
GatewayRunner.__init__ snapshotted _ephemeral_system_prompt once from the
launch profile's config and _get_system_prompt_for_channel returned that
string for every source, so under multiplex a routed profile's
display.personality / agent.system_prompt never injected (#89161), and
/personality from any chat rewrote the one process-global attribute for
everyone.

Drop the snapshot: _get_system_prompt_for_channel now calls
_load_ephemeral_system_prompt() (env var, then
resolve_ephemeral_system_prompt_from_config(_load_gateway_runtime_config()))
on each call. Its caller run_sync already runs inside
_profile_runtime_scope, so the routed profile's config.yaml is what gets
read; single-profile hot-edits of the personality also take effect on the
next turn instead of requiring a restart. /personality only persists via
persist_personality() (get_hermes_home()/config.yaml = the routed profile)
and no longer touches in-memory state.

Fixes #89161

Co-authored-by: worlldz <101180447+worlldz@users.noreply.github.com>
2026-09-02 06:36:16 -07:00

46 lines
2.0 KiB
Python

"""#89161: a routed multiplex profile's personality must reach its turns.
``GatewayRunner`` used to snapshot ``_ephemeral_system_prompt`` once at boot
from the launch profile's config and hand that string to every routed turn,
so a secondary profile's ``display.personality`` / ``agent.system_prompt`` never
injected. ``_get_system_prompt_for_channel`` now resolves from the config of
the profile currently in scope (``run_sync`` runs inside
``_profile_runtime_scope``).
"""
from __future__ import annotations
import gateway.run as gateway_run
from gateway.config import Platform
from gateway.run import GatewayRunner, _profile_runtime_scope
def test_routed_profile_prompt_resolves_from_its_own_config(tmp_path, monkeypatch):
default_home = tmp_path / "default"
routed_home = tmp_path / "profiles" / "beta"
default_home.mkdir()
routed_home.mkdir(parents=True)
(default_home / "config.yaml").write_text("agent:\n system_prompt: DEFAULT-PERSONA\n")
(routed_home / "config.yaml").write_text(
"agent:\n system_prompt: BETA-PERSONA\n personalities:\n pirate: ARR\n"
)
monkeypatch.setattr(gateway_run, "_hermes_home", default_home)
monkeypatch.setenv("HERMES_HOME", str(default_home))
monkeypatch.delenv("HERMES_EPHEMERAL_SYSTEM_PROMPT", raising=False)
runner = object.__new__(GatewayRunner)
runner.config = None
with _profile_runtime_scope(routed_home):
assert runner._get_system_prompt_for_channel(Platform.TELEGRAM, "c") == "BETA-PERSONA"
assert runner._get_system_prompt_for_channel(Platform.TELEGRAM, "c") == "DEFAULT-PERSONA"
# /personality from the routed chat writes the routed profile and only it.
from hermes_cli.personality import persist_personality
with _profile_runtime_scope(routed_home):
assert persist_personality("pirate")
assert runner._get_system_prompt_for_channel(Platform.TELEGRAM, "c") == "ARR"
assert "pirate" not in (default_home / "config.yaml").read_text()
assert runner._get_system_prompt_for_channel(Platform.TELEGRAM, "c") == "DEFAULT-PERSONA"