NousResearch/hermes-agent

Reconciling agent.disabled_toolsets when enabling a toolset

Cluster 49995 · apps/desktop. Data as of

Nothing open on GitHub. Fix merged in #54334 on 28 Jun 2026. Check it covers your case.

The short answer

0open issues
0open PRs
3items grouped
Known?
Yes. 3 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #54334. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this resolved, deciding PR #54334. That is separate from the fix event.
Still open
Nothing open on GitHub.

Members appear to concern one theme: enabling a toolset while it is listed in agent.disabled_toolsets. Two share the same title for a tools fix, and one bug report describes the Desktop Toolsets UI not re-enabling such a toolset and showing it as OFF on reopen.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #54334 fix(tools): reconcile agent.disabled_toolsets when a toolset is enabled

    merged to main

    files: hermes_cli/tools_config.py, tests/hermes_cli/test_tools_config.py

    Show the diff
    • hermes_cli/tools_config.py
      @@ -1736,6 +1736,32 @@ def _save_platform_tools(config: dict, platform: str, enabled_toolset_keys: Set[
               config.setdefault("known_plugin_toolsets", {})
               config["known_plugin_toolsets"][platform] = sorted(plugin_keys)
       
      +    # Reconcile with agent.disabled_toolsets. _get_platform_tools() applies
      +    # that list as a final override AFTER reading platform_toolsets.<platform>,
      +    # so a toolset listed there stays permanently OFF no matter what this
      +    # function writes — the toggle "saves" but silently can't ever take
      +    # effect. Blank Slate installs pre-populate this list with ~27 toolsets,
      +    # making most of the desktop Toolsets UI unusable for re-enabling
      +    # anything (issue #49995).
      +    #
      +    # Only toolsets the user just explicitly enabled FOR THIS PLATFORM are
      +    # cleared from the global disabled list — toolsets the user did not
      +    # touch (still unchecked) or that remain disabled on other platforms
      +    # are left alone, so agent.disabled_toolsets keeps working as a
      +    # cross-platform suppression list for anything not actively re-enabled.
      +    agent_cfg = config.get("agent")
      +    if isinstance(agent_cfg, dict):
      +        disabled_toolsets = agent_cfg.get("disabled_toolsets")
      +        if isinstance(disabled_toolsets, list) and disabled_toolsets:
      +            newly_enabled = enabled_toolset_keys - preserved_entries
      +            if newly_enabled:
      +                remaining = [
      +                    ts for ts in disabled_toolsets
      +                    if str(ts) not in newly_enabled
      +                ]
      +                if remaining != disabled_toolsets:
      +                    agent_cfg["disabled_toolsets"] = remaining
      +
           save_config(config)
       
       
    • tests/hermes_cli/test_tools_config.py
      @@ -1676,3 +1676,83 @@ def test_vision_picker_custom_endpoint(tmp_path, monkeypatch):
           save_env.assert_called_once_with("OPENAI_API_KEY", "sk-secret")
       
       
      +def test_save_platform_tools_clears_newly_enabled_from_disabled_toolsets():
      +    """Enabling a toolset via the picker must remove it from
      +    agent.disabled_toolsets, or _get_platform_tools() permanently masks it
      +    back to OFF on the next read no matter what platform_toolsets says.
      +
      +    Blank Slate installs pre-populate disabled_toolsets with ~27 toolsets,
      +    making the desktop Toolsets UI's enable toggle effectively a no-op for
      +    any of them (issue #49995).
      +    """
      +    config = {
      +        "platform_toolsets": {"cli": ["file", "terminal"]},
      +        "agent": {"disabled_toolsets": ["todo", "memory", "browser"]},
      +    }
      +
      +    with patch("hermes_cli.tools_config.save_config"):
      +        _save_platform_tools(config, "cli", {"file", "terminal", "todo"})
      +
      +    # The toolset the user just enabled is cleared from the block-list...
      +    assert "todo" not in config["agent"]["disabled_toolsets"]
      +    # ...but toolsets the user did NOT touch stay disabled (no over-reach).
      +    assert "memory" in config["agent"]["disabled_toolsets"]
      +    assert "browser" in config["agent"]["disabled_toolsets"]
      +    assert "todo" in config["platform_toolsets"]["cli"]
      +
      +
      +def test_save_platform_tools_resolves_to_enabled_after_disabled_toolsets_reconcile():
      +    """End-to-end: after _save_platform_tools() reconciles disabled_toolsets,
      +    _get_platform_tools() must actually resolve the toolset as enabled --
      +    this is the exact symptom from issue #49995 (toggle saves but the UI/agent
      +    still reads it as OFF after reopen).
      +    """
      +    config = {
      +        "platform_toolsets": {"cli": ["file", "terminal"]},
      +        "agent": {"disabled_toolsets": ["todo", "memory"]},
      +    }
      +
      +    # Before: todo is masked off despite not being in platform_toolsets yet.
      +    assert "todo" not in _get_platform_tools(config, "cli")
      +
      +    with patch("hermes_cli.tools_config.save_config"):
      +        _save_platform_tools(config, "cli", {"file", "terminal", "todo"})
      +
      +    # After: todo must resolve as enabled, and untouched 'memory' must
      +    # remain masked off.
      +    resolved = _get_platform_tools(config, "cli")
      +    assert "todo" in resolved
      +    assert "memory" not in resolved
      +
      +
      +def test_save_platform_tools_no_disabled_toolsets_is_noop():
      +    """When agent.disabled_toolsets is absent or empty, the reconcile step
      +    must be a complete no-op (no KeyError, no spurious 'agent' key creation).
      +    """
      +    config = {"platform_toolsets": {"cli": ["file", "terminal"]}}
      +
      +    with patch("hermes_cli.tools_config.save_config"):
      +        _save_platform_tools(config, "cli", {"file", "terminal", "todo"})
      +
      +    assert "todo" in config["platform_toolsets"]["cli"]
      +    # No 'agent' key should be fabricated when none existed.
      +    assert "agent" not in config
      +
      +
      +def test_save_platform_tools_disabling_a_toolset_does_not_touch_disabled_toolsets():
      +    """Turning a toolset OFF (not present in enabled_toolset_keys) must not
      +    remove anything from agent.disabled_toolsets -- only toolsets the user
      +    just explicitly enabled are reconciled.
      +    """
      +    config = {
      +        "platform_toolsets": {"cli": ["file", "terminal", "todo"]},
      +        "agent": {"disabled_toolsets": ["memory"]},
      +    }
      +
      +    with patch("hermes_cli.tools_config.save_config"):
      +        # User unchecks 'todo' -- it's no longer in enabled_toolset_keys.
      +        _save_platform_tools(config, "cli", {"file", "terminal"})
      +
      +    assert "todo" not in config["platform_toolsets"]["cli"]
      +    # disabled_toolsets is untouched by a disable action.
      +    assert config["agent"]["disabled_toolsets"] == ["memory"]

1 PR closed without merging

From the close comments: merged via another change 1

  • #50012 fix(tools): reconcile agent.disabled_toolsets when a toolset is enabled · merged via another change → 3e16176, #54334, #49995
Closed issues · 1
  • Closed#49995[Bug]: Desktop Toolsets UI can't re-enable a toolset that's in agent.disabled_toolsets (Blank Slate); enabled toolsets revert to OFF on reopen
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
apps/desktop
Merged PRs
#54334
Closed issues
1
Attempts
1 PR closed without merging
Fix link checked
28 Jun 2026

For your agent

The same facts, typed.