hermes-agent/tests/hermes_cli/test_assistant_presets.py

111 lines
4.2 KiB
Python

"""Tests for hermes_cli.assistant_presets (Energy-inspired role presets)."""
import sys
from pathlib import Path
from unittest.mock import patch
import pytest
from hermes_cli.assistant_presets import (
PRESETS,
apply_preset_files,
format_preset_catalog,
get_preset,
preset_keys,
suggested_automation_commands,
)
from hermes_cli.profiles import create_profile, read_profile_meta
@pytest.fixture()
def profile_env(tmp_path, monkeypatch):
"""Isolated profile root (mirrors tests/hermes_cli/test_profiles.py)."""
monkeypatch.setattr(Path, "home", lambda: tmp_path)
default_home = tmp_path / ".hermes"
default_home.mkdir(parents=True, exist_ok=True)
monkeypatch.setenv("HERMES_HOME", str(default_home))
return tmp_path
class TestCatalog:
def test_catalog_is_nonempty_with_unique_keys(self):
keys = preset_keys()
assert keys
assert len(keys) == len(set(keys))
def test_every_preset_is_complete(self):
for p in PRESETS:
assert p.title and p.tagline and p.description and p.soul, p.key
def test_automation_keys_resolve_against_blueprint_catalog(self):
"""Preset automations must reference real blueprints AND fill cleanly
with their declared slot values + blueprint defaults (contract, not
snapshot: catalog edits that break a preset fail here)."""
from cron.blueprint_catalog import fill_blueprint, get_blueprint
for p in PRESETS:
for key, values in p.automations:
bp = get_blueprint(key)
assert bp is not None, f"preset {p.key} references unknown blueprint {key}"
spec = fill_blueprint(bp, values)
assert spec["prompt"] and spec["schedule"]
def test_get_preset_is_case_insensitive_and_none_on_unknown(self):
first = PRESETS[0]
assert get_preset(first.key.upper()) is first
assert get_preset("no-such-preset") is None
assert get_preset("") is None
def test_format_catalog_mentions_every_key(self):
text = format_preset_catalog()
for p in PRESETS:
assert p.key in text
class TestApplyPresetFiles:
def test_writes_soul_and_description(self, tmp_path):
preset = PRESETS[0]
apply_preset_files(tmp_path, preset)
soul = (tmp_path / "SOUL.md").read_text(encoding="utf-8")
assert preset.soul in soul
meta = read_profile_meta(tmp_path)
assert meta.get("description") == preset.description
assert meta.get("description_auto") is False
class TestCreateProfileWithPreset:
def test_unknown_preset_fails_before_creating_directory(self, profile_env):
with pytest.raises(ValueError, match="Unknown preset"):
create_profile("scout", preset="not-a-preset")
assert not (profile_env / ".hermes" / "profiles" / "scout").exists()
def test_preset_overrides_default_soul_and_sets_description(self, profile_env):
preset = get_preset("research-scout")
profile_dir = create_profile("scout", no_alias=True, preset="research-scout")
soul = (profile_dir / "SOUL.md").read_text(encoding="utf-8")
assert preset.soul in soul
assert read_profile_meta(profile_dir).get("description") == preset.description
def test_explicit_description_wins_over_preset(self, profile_env):
profile_dir = create_profile(
"scout2", no_alias=True, preset="research-scout",
description="My custom router text",
)
assert read_profile_meta(profile_dir).get("description") == "My custom router text"
def test_no_preset_keeps_default_soul(self, profile_env):
from hermes_cli.default_soul import DEFAULT_SOUL_MD
profile_dir = create_profile("plain", no_alias=True)
assert (profile_dir / "SOUL.md").read_text(encoding="utf-8") == DEFAULT_SOUL_MD
class TestSuggestedCommands:
def test_commands_render_for_presets_with_automations(self):
for p in PRESETS:
cmds = suggested_automation_commands(p, "myrole")
assert len(cmds) == len(p.automations)
for cmd in cmds:
assert "hermes -p myrole" in cmd
assert "/blueprint " in cmd