fix(plugins): canonical activation keys + remove/toggle bookkeeping across CLI, dashboard and RPC
Symptoms fixed (all live-reproduced on origin/main in a fake HERMES_HOME): - `hermes plugins disable photon-platform` wrote `platforms/photon` while the loader keyed the bundled adapter `photon-platform`, so the disable never applied (#27548). The loader now keys bundled platforms `platforms/<dir>` like every other category (one call site in plugins_discovery.py); the manifest name stays an accepted alias through gate_manifest. - `plugins.manage toggle` / dashboard toggle wrote the raw identifier: enabling by bare leaf or manifest name returned ok while a stale canonical key in plugins.disabled kept the plugin off. dashboard_set_agent_plugin_enabled resolves the canonical key and purges every alias from the opposing list (shared _activate_key, also used by cmd_enable/cmd_disable); the RPC reports the key. - remove/uninstall (CLI, dashboard, RPC) left the plugin in plugins.enabled/disabled and plugins.entries (#54336), left memory.provider dangling so the next agent init re-cloned the provider from the catalog (uninstall silently reverted), and, for a symlink inside the plugins dir, deleted the TARGET plugin and its metadata while the link stayed dangling. _remove_user_plugin is the shared tail: unlink a link only, then forget config under every alias and reset memory.provider (reported as cleared_memory_provider). - `hermes plugins list` / dashboard hub / TUI hub called bundled backends, bundled platforms and the live memory.provider "not enabled" (#73131, #82898): _plugin_status mirrors gate_manifest. - A user-installed memory provider parked in plugins.disabled kept loading: load_memory_provider honours the deny-list (name, dir name or manifest name) and says so once.
This commit is contained in:
@@ -202,6 +202,12 @@ def load_memory_provider(name: str, *, register_skills: Optional[bool] = None) -
|
||||
if not provider_dir and entry_point is None:
|
||||
logger.debug("Memory provider '%s' not found in bundled, user plugins, or entry points", name)
|
||||
return None
|
||||
if provider_dir is not None and _explicitly_disabled(name, provider_dir):
|
||||
# The Plugins hub / `hermes plugins disable` park a user-installed provider in
|
||||
# ``plugins.disabled``; the loader must honour it or "disabled" is a lie in the UI.
|
||||
logger.warning("Memory provider '%s' is disabled via plugins.disabled; run `hermes plugins enable %s` "
|
||||
"or change memory.provider.", name, name)
|
||||
return None
|
||||
|
||||
def _load(_dir):
|
||||
if provider_dir:
|
||||
@@ -421,6 +427,28 @@ def _get_active_memory_provider() -> Optional[str]:
|
||||
return None
|
||||
|
||||
|
||||
def _explicitly_disabled(name: str, provider_dir: Path) -> bool:
|
||||
"""True when a NON-bundled provider is parked in ``plugins.disabled`` under any spelling the
|
||||
plugin commands write: the provider name, its directory name or its manifest ``name:``."""
|
||||
if _MEMORY_PLUGINS_DIR in provider_dir.parents:
|
||||
return False
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
disabled = cfg_get(load_config(), "plugins", "disabled")
|
||||
except Exception:
|
||||
return False
|
||||
if not isinstance(disabled, list):
|
||||
return False
|
||||
names = {name, provider_dir.name}
|
||||
try:
|
||||
import yaml
|
||||
with open(provider_dir / "plugin.yaml", encoding="utf-8-sig") as f:
|
||||
names.add(str((yaml.safe_load(f) or {}).get("name") or ""))
|
||||
except Exception:
|
||||
pass
|
||||
return bool(names & {v for v in disabled if isinstance(v, str)})
|
||||
|
||||
|
||||
def _prune_inactive_memory_provider_skills(active_provider: Optional[str] = None) -> None:
|
||||
"""Remove tracked skills that no longer belong to the active provider."""
|
||||
if active_provider is None:
|
||||
|
||||
Reference in New Issue
Block a user