mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-23 10:42:00 +00:00
Merge pull request #46236 from kshitijk4poor/salvage/disabled-skills-union
fix(skills): platform-disabled skills still appear in <available_skills> + unify all resolution sites (#46201)
This commit is contained in:
commit
fc2b8b3d31
5 changed files with 53 additions and 15 deletions
|
|
@ -1164,7 +1164,7 @@ def build_skills_system_prompt(
|
|||
or get_session_env("HERMES_SESSION_PLATFORM")
|
||||
or ""
|
||||
)
|
||||
disabled = get_disabled_skill_names()
|
||||
disabled = get_disabled_skill_names(_platform_hint or None)
|
||||
cache_key = (
|
||||
str(skills_dir.resolve()),
|
||||
tuple(str(d) for d in external_dirs),
|
||||
|
|
|
|||
|
|
@ -278,8 +278,10 @@ def get_disabled_skill_names(platform: str | None = None) -> Set[str]:
|
|||
Args:
|
||||
platform: Explicit platform name (e.g. ``"telegram"``). When
|
||||
*None*, resolves from ``HERMES_PLATFORM`` or
|
||||
``HERMES_SESSION_PLATFORM`` env vars. Falls back to the
|
||||
global disabled list when no platform is determined.
|
||||
``HERMES_SESSION_PLATFORM`` env vars. Returns the global
|
||||
disabled list, unioned with the platform-specific list when a
|
||||
platform is resolved (a globally-disabled skill stays disabled
|
||||
on every platform).
|
||||
|
||||
Reads the config file directly (no CLI config imports) to stay
|
||||
lightweight.
|
||||
|
|
@ -305,13 +307,14 @@ def get_disabled_skill_names(platform: str | None = None) -> Set[str]:
|
|||
or os.getenv("HERMES_PLATFORM")
|
||||
or get_session_env("HERMES_SESSION_PLATFORM")
|
||||
)
|
||||
global_disabled = _normalize_string_set(skills_cfg.get("disabled"))
|
||||
if resolved_platform:
|
||||
platform_disabled = (skills_cfg.get("platform_disabled") or {}).get(
|
||||
resolved_platform
|
||||
)
|
||||
if platform_disabled is not None:
|
||||
return _normalize_string_set(platform_disabled)
|
||||
return _normalize_string_set(skills_cfg.get("disabled"))
|
||||
return global_disabled | _normalize_string_set(platform_disabled)
|
||||
return global_disabled
|
||||
|
||||
|
||||
def _normalize_string_set(values) -> Set[str]:
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@ PLATFORMS = {k: info.label for k, info in _PLATFORMS.items() if k != "api_server
|
|||
# ─── Config Helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
def get_disabled_skills(config: dict, platform: Optional[str] = None) -> Set[str]:
|
||||
"""Return disabled skill names. Platform-specific list falls back to global."""
|
||||
"""Return disabled skill names: the global list unioned with the
|
||||
platform-specific list when a platform is given.
|
||||
|
||||
A globally-disabled skill stays disabled on every platform, so the
|
||||
platform list adds to the global list rather than replacing it. This
|
||||
mirrors ``agent.skill_utils.get_disabled_skill_names``.
|
||||
"""
|
||||
skills_cfg = config.get("skills", {})
|
||||
global_disabled = set(skills_cfg.get("disabled", []))
|
||||
if platform is None:
|
||||
|
|
@ -33,7 +39,7 @@ def get_disabled_skills(config: dict, platform: Optional[str] = None) -> Set[str
|
|||
platform_disabled = cfg_get(skills_cfg, "platform_disabled", platform)
|
||||
if platform_disabled is None:
|
||||
return global_disabled
|
||||
return set(platform_disabled)
|
||||
return global_disabled | set(platform_disabled)
|
||||
|
||||
|
||||
def save_disabled_skills(config: dict, disabled: Set[str], platform: Optional[str] = None):
|
||||
|
|
|
|||
|
|
@ -22,7 +22,19 @@ class TestGetDisabledSkills:
|
|||
"disabled": ["skill-a"],
|
||||
"platform_disabled": {"telegram": ["skill-b"]}
|
||||
}}
|
||||
assert get_disabled_skills(config, platform="telegram") == {"skill-b"}
|
||||
# Union of global + platform: a globally-disabled skill stays disabled
|
||||
# on every platform, and the platform list adds to it.
|
||||
assert get_disabled_skills(config, platform="telegram") == {"skill-a", "skill-b"}
|
||||
|
||||
def test_platform_list_unions_with_global(self):
|
||||
from hermes_cli.skills_config import get_disabled_skills
|
||||
config = {"skills": {
|
||||
"disabled": ["global-skill"],
|
||||
"platform_disabled": {"telegram": []}
|
||||
}}
|
||||
# An explicit empty platform list does NOT re-enable a globally-disabled
|
||||
# skill (matches issue #46201 — global disables hold everywhere).
|
||||
assert get_disabled_skills(config, platform="telegram") == {"global-skill"}
|
||||
|
||||
def test_platform_falls_back_to_global(self):
|
||||
from hermes_cli.skills_config import get_disabled_skills
|
||||
|
|
@ -102,14 +114,27 @@ class TestIsSkillDisabled:
|
|||
assert _is_skill_disabled("tg-skill", platform="telegram") is True
|
||||
|
||||
@patch("hermes_cli.config.load_config")
|
||||
def test_platform_enabled_overrides_global(self, mock_load):
|
||||
def test_globally_disabled_stays_disabled_on_platform(self, mock_load):
|
||||
mock_load.return_value = {"skills": {
|
||||
"disabled": ["skill-a"],
|
||||
"platform_disabled": {"telegram": ["tg-skill"]}
|
||||
}}
|
||||
from tools.skills_tool import _is_skill_disabled
|
||||
# Union: a globally-disabled skill stays disabled on a platform that
|
||||
# has its own platform_disabled list (matches issue #46201).
|
||||
assert _is_skill_disabled("skill-a", platform="telegram") is True
|
||||
assert _is_skill_disabled("tg-skill", platform="telegram") is True
|
||||
|
||||
@patch("hermes_cli.config.load_config")
|
||||
def test_empty_platform_list_keeps_global_disabled(self, mock_load):
|
||||
mock_load.return_value = {"skills": {
|
||||
"disabled": ["skill-a"],
|
||||
"platform_disabled": {"telegram": []}
|
||||
}}
|
||||
from tools.skills_tool import _is_skill_disabled
|
||||
# telegram has explicit empty list -> skill-a is NOT disabled for telegram
|
||||
assert _is_skill_disabled("skill-a", platform="telegram") is False
|
||||
# An explicit empty platform list does NOT re-enable a globally-disabled
|
||||
# skill — global disables hold on every platform.
|
||||
assert _is_skill_disabled("skill-a", platform="telegram") is True
|
||||
|
||||
@patch("hermes_cli.config.load_config")
|
||||
def test_platform_falls_back_to_global(self, mock_load):
|
||||
|
|
@ -164,7 +189,7 @@ class TestGetDisabledSkillNames:
|
|||
|
||||
from agent.skill_utils import get_disabled_skill_names
|
||||
result = get_disabled_skill_names(platform="telegram")
|
||||
assert result == {"tg-only-skill"}
|
||||
assert result == {"tg-only-skill", "global-skill"}
|
||||
|
||||
def test_session_platform_env_var(self, tmp_path, monkeypatch):
|
||||
"""HERMES_SESSION_PLATFORM should be used when HERMES_PLATFORM is unset."""
|
||||
|
|
@ -183,7 +208,7 @@ class TestGetDisabledSkillNames:
|
|||
|
||||
from agent.skill_utils import get_disabled_skill_names
|
||||
result = get_disabled_skill_names()
|
||||
assert result == {"discord-skill"}
|
||||
assert result == {"discord-skill", "global-skill"}
|
||||
|
||||
def test_hermes_platform_takes_precedence(self, tmp_path, monkeypatch):
|
||||
"""HERMES_PLATFORM should win over HERMES_SESSION_PLATFORM."""
|
||||
|
|
|
|||
|
|
@ -583,11 +583,15 @@ def _is_skill_disabled(name: str, platform: str = None) -> bool:
|
|||
config = load_config()
|
||||
skills_cfg = config.get("skills", {})
|
||||
resolved_platform = platform or os.getenv("HERMES_PLATFORM") or _get_session_platform()
|
||||
global_disabled = skills_cfg.get("disabled", [])
|
||||
if resolved_platform:
|
||||
platform_disabled = cfg_get(skills_cfg, "platform_disabled", resolved_platform)
|
||||
if platform_disabled is not None:
|
||||
return name in platform_disabled
|
||||
return name in skills_cfg.get("disabled", [])
|
||||
# A globally-disabled skill stays disabled on every platform;
|
||||
# the platform list adds to it rather than replacing it. Keep
|
||||
# in sync with agent.skill_utils.get_disabled_skill_names.
|
||||
return name in platform_disabled or name in global_disabled
|
||||
return name in global_disabled
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue