fix(tui_gateway): honor prefill_messages_file on the Desktop agent path
Desktop and TUI agents are built by tui_gateway.server._make_agent, which never runs the classic CLI bootstrap and passed no prefill_messages to AIAgent, so a configured prefill_messages_file was silently ignored there. Resolve it with the CLI's own resolver/loader (env > prefill_messages_file > legacy agent.prefill_messages_file). The loader takes an optional base_dir so relative paths resolve against the profile building the agent, not the launch home. Co-authored-by: leakedd <66937184+leakedd@users.noreply.github.com>
This commit is contained in:
@@ -24,14 +24,16 @@ def _cli():
|
||||
return cli
|
||||
|
||||
|
||||
def _load_prefill_messages(file_path: str) -> List[Dict[str, Any]]:
|
||||
"""Load prefill messages (JSON array) from *file_path*; relative to ~/.hermes/; missing/empty -> []."""
|
||||
from cli import _hermes_home
|
||||
def _load_prefill_messages(file_path: str, base_dir: Path | None = None) -> List[Dict[str, Any]]:
|
||||
"""Load prefill messages (JSON array) from *file_path*; missing/empty -> [].
|
||||
|
||||
Relative paths resolve against *base_dir*, defaulting to the CLI's hermes home.
|
||||
"""
|
||||
if not file_path:
|
||||
return []
|
||||
path = Path(file_path).expanduser()
|
||||
if not path.is_absolute():
|
||||
path = _hermes_home / path
|
||||
path = (base_dir or _cli()._hermes_home) / path
|
||||
if not path.exists():
|
||||
logger.warning("Prefill messages file not found: %s", path)
|
||||
return []
|
||||
|
||||
55
tests/tui_gateway/test_make_agent_prefill.py
Normal file
55
tests/tui_gateway/test_make_agent_prefill.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Desktop/TUI agents honor ``prefill_messages_file`` from the active profile.
|
||||
|
||||
Regression for #60456: ``tui_gateway.server._make_agent`` (the Desktop / ``hermes serve`` agent
|
||||
factory) never passed ``prefill_messages``, so a configured prefill file only worked in the
|
||||
classic CLI and the messaging gateway.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import types
|
||||
|
||||
import yaml
|
||||
|
||||
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
|
||||
from tui_gateway import server
|
||||
|
||||
|
||||
def _write_home(root, name: str, content: str):
|
||||
home = root / name
|
||||
home.mkdir()
|
||||
(home / "config.yaml").write_text(yaml.safe_dump({"prefill_messages_file": "prefill.json"}), encoding="utf-8")
|
||||
(home / "prefill.json").write_text(json.dumps([{"role": "user", "content": content}]), encoding="utf-8")
|
||||
return home
|
||||
|
||||
|
||||
def _built_prefill(monkeypatch, home):
|
||||
captured = {}
|
||||
|
||||
def fake_agent(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return types.SimpleNamespace(model=kwargs.get("model"))
|
||||
|
||||
monkeypatch.setattr("run_agent.AIAgent", fake_agent)
|
||||
token = set_hermes_home_override(home)
|
||||
try:
|
||||
server._make_agent("sid", "session-key")
|
||||
finally:
|
||||
reset_hermes_home_override(token)
|
||||
return captured["prefill_messages"]
|
||||
|
||||
|
||||
def test_make_agent_injects_the_active_profiles_prefill(monkeypatch, tmp_path):
|
||||
monkeypatch.delenv("HERMES_PREFILL_MESSAGES_FILE", raising=False)
|
||||
monkeypatch.setattr(server, "_resolve_agent_model_runtime", lambda *_a: ("test-model", {}))
|
||||
monkeypatch.setattr(server, "_load_enabled_toolsets", lambda *_a, **_kw: None)
|
||||
monkeypatch.setattr(server, "_get_db", lambda: None)
|
||||
monkeypatch.setattr(server, "_agent_cbs", lambda sid: {})
|
||||
home_a = _write_home(tmp_path, "a", "prefill from A")
|
||||
home_b = _write_home(tmp_path, "b", "prefill from B")
|
||||
|
||||
# A -> B -> A: the relative path resolves against whichever profile builds the agent.
|
||||
assert _built_prefill(monkeypatch, home_a) == [{"role": "user", "content": "prefill from A"}]
|
||||
assert _built_prefill(monkeypatch, home_b) == [{"role": "user", "content": "prefill from B"}]
|
||||
assert _built_prefill(monkeypatch, home_a) == [{"role": "user", "content": "prefill from A"}]
|
||||
@@ -330,6 +330,15 @@ def _load_fallback_model():
|
||||
return get_fallback_chain(_load_cfg())
|
||||
|
||||
|
||||
def _load_prefill_messages() -> list:
|
||||
"""Configured prefill messages, resolved like the CLI (env > ``prefill_messages_file`` > legacy
|
||||
``agent.*``). Desktop/TUI agents never run the CLI bootstrap, so without this the setting was
|
||||
ignored there (#60456). Relative paths resolve against the active profile home, per call."""
|
||||
from hermes_cli.cli_config_load import _load_prefill_messages as _load, _resolve_prefill_messages_file
|
||||
from hermes_constants import get_hermes_home
|
||||
return _load(_resolve_prefill_messages_file(_load_cfg()), get_hermes_home())
|
||||
|
||||
|
||||
def _sync_agent_fallback_with_config(sid: str, session: dict) -> None:
|
||||
"""Adopt ``fallback_providers`` edits into the cached agent at turn start.
|
||||
|
||||
|
||||
@@ -2548,7 +2548,7 @@ def _make_agent(
|
||||
checkpoints_enabled=is_truthy_value(os.environ.get("HERMES_TUI_CHECKPOINTS")),
|
||||
pass_session_id=is_truthy_value(os.environ.get("HERMES_TUI_PASS_SESSION_ID")),
|
||||
skip_context_files=ignore_rules, skip_memory=ignore_rules, fallback_model=_load_fallback_model(),
|
||||
**_agent_cbs(sid))
|
||||
prefill_messages=_load_prefill_messages() or None, **_agent_cbs(sid))
|
||||
if context_cwd_is_launch_artifact is None:
|
||||
context_cwd_is_launch_artifact = _context_cwd_is_launch_artifact(session)
|
||||
agent._context_cwd_is_launch_artifact = bool(context_cwd_is_launch_artifact)
|
||||
|
||||
Reference in New Issue
Block a user