Skip to content

fix(agent): gate memory tool injection on platform_toolsets containing 'memory'#5788

Closed
Lempkey wants to merge 1 commit into
NousResearch:mainfrom
Lempkey:fix/memory-tools-respect-platform-toolsets-5544
Closed

fix(agent): gate memory tool injection on platform_toolsets containing 'memory'#5788
Lempkey wants to merge 1 commit into
NousResearch:mainfrom
Lempkey:fix/memory-tools-respect-platform-toolsets-5544

Conversation

@Lempkey

@Lempkey Lempkey commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #5544.

Root cause

Memory provider tool schemas (fact_store and friends) were injected into the agent's tool surface unconditionally in AIAgent.__init__ (run_agent.py ~line 1115), regardless of the platform's enabled_toolsets configuration:

# before — always runs if a memory manager is present
if self._memory_manager and self.tools is not None:
    for _schema in self._memory_manager.get_all_tool_schemas():
        ...

Setting platform_toolsets: telegram: [] had no effect on memory tools — they were still appended to self.tools, bypassing the platform toolset filter that correctly gates every other tool category.

Impact

On local model deployments the overhead is severe. Tool-formatted prompts process at ~134 tok/s vs ~1,230 tok/s for plain text (Qwen3-30B-A3B Q4_K_M on an RTX 3090). With 8 memory tool schemas injected, a simple "hello" on Telegram takes ~42 s instead of ~1.7 s. Smaller models also enter tool-call loops when memory tools are the only tools present.

What changed

A single guard before the injection loop (run_agent.py ~line 1115):

if self._memory_manager and self.tools is not None:
    if self.enabled_toolsets is None or "memory" in self.enabled_toolsets:
        for _schema in self._memory_manager.get_all_tool_schemas():
            ...
  • enabled_toolsets is None → no filter active, inject as before (full backward compatibility)
  • "memory" in enabled_toolsets → memory explicitly listed, inject
  • enabled_toolsets = [] or a list without "memory" → skip injection

No changes to any other file. The AIAgent constructor already stores enabled_toolsets at line 682; the fix only reads it.

Tests

python -m pytest tests/test_memory_toolset_gate.py -v
7 passed

Covers: no filter (None), explicit ["memory"] in list, empty list [], list without memory, no memory manager, multiple schemas all injected, multiple schemas all blocked.

…g 'memory'

Memory provider tool schemas (fact_store etc.) were injected into the
agent's tool surface unconditionally in AIAgent.__init__, regardless of
the platform's enabled_toolsets configuration. This meant that setting

    platform_toolsets:
      telegram: []

had no effect on memory tools — they were still appended to self.tools,
bypassing the toolset filter entirely.

The impact is severe for local model deployments: tool-formatted prompts
process at ~134 tok/s vs ~1230 tok/s for plain text on typical consumer
hardware (Qwen3-30B-A3B Q4_K_M / RTX 3090). With 8 memory tool schemas,
a simple "hello" on Telegram takes ~42 s instead of ~1.7 s.

Fix: add a guard before the injection loop so memory tools are only
injected when enabled_toolsets is None (no filter active — backward-
compatible default) or "memory" is explicitly listed in enabled_toolsets.

Fixes NousResearch#5544
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder tool/memory Memory tool and memory providers labels Apr 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #5552 — both fix #5544 (memory tools injected regardless of platform_toolsets). This PR has a cleaner single-guard approach.

SelfParody added a commit to SelfParody/hermes-agent that referenced this pull request May 2, 2026
…han subprocess leak

v5 — addresses GPT-5.5 fusion-judge SHIP_WITH_FIXES on v4.
One-line cosmetic fix: SIGTERM handler now uses cleanup-scope local
alias `_os_local.kill(_os_local.getpid(), signum)` instead of bare
`os.kill(os.getpid(), signum)`, completing the self-containment intent.
Behavior unchanged (verified: SIGTERM still exits 143, SIGINT still 130).

═══ Code review history ═══

- v1: qwen3-max single review → SHIP_WITH_FIXES
- v2: Fusion (Codex+Sonnet+Gemini, GPT-5.5 judge) → NEEDS_REWORK (7 fixes)
- v3: Fusion → SHIP_WITH_FIXES (3 required + 4 hardening fixes)
- v4: Fusion → SHIP_WITH_FIXES (1 cosmetic — use _os_local in SIGTERM)
- v5 (this commit): cosmetic fix applied; behavior verified unchanged

═══ Final fix tracking ═══

| v2 required fix                       | Final |
|---------------------------------------|-------|
| 1. Fail-open import behavior          | FIXED |
| 2. SIGTERM exit code 143              | FIXED |
| 3. Unmatched -t warning logic         | FIXED |
| 4. _stdio_pids robustness             | FIXED |
| 5. time/os imports verified           | FIXED |
| 6. Poll-loop logger.debug             | FIXED |
| 7. Idempotency guard                  | FIXED |
| 8. SIGTERM uses self-contained _os    | FIXED (v5) |

═══ Verified locally (final) ═══

  hermes -z "ACK" -t web        : 4.8s wall (was 65s — 93% reduction)
  hermes -z "ACK" -t slack      : 5.5s wall (was 67s — 92% reduction)
  hermes -z "ACK"  (no -t)      : 75s     (unchanged — backwards-compat)
  SIGINT mid-flight             : exit 130 ✓
  SIGTERM mid-flight            : exit 143 ✓
  Orphan accumulation           : 0 new PPID=1 across 10+ runs

Related issues:
- Fixes the MCP subprocess component of NousResearch#18438 (gateway memory leak)
- Supersedes the startup-drag portion of NousResearch#18523 (closed unmerged)
- Extends toolset-gating pattern from NousResearch#18166 and NousResearch#5788 (memory) to MCPs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@teknium1

Copy link
Copy Markdown
Contributor

Salvaged into PR #30177 (merged) — #30177

Your one-line gate is now on main as commit 4c61fb6cf with your authorship preserved via rebase-merge. The file moved from run_agent.py to agent/agent_init.py since this PR was opened, so a clean cherry-pick wasn't possible — your fix was re-applied surgically onto current main, then the same gate was widened to the sibling context-engine injection site.

Thanks @Lempkey — this was a clean, correct, well-reasoned fix. Added you to scripts/release.py AUTHOR_MAP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug + feature request: Memory provider tools auto-injected regardless of platform_toolsets config — 10x latency penalty on local models

3 participants