Skip to content

fix(memory): honor config.yaml limits in registry-dispatched memory calls (#11665) - #11693

Closed
briandevans wants to merge 2 commits into
NousResearch:mainfrom
briandevans:fix/memory-char-limit-dispatch-path
Closed

fix(memory): honor config.yaml limits in registry-dispatched memory calls (#11665)#11693
briandevans wants to merge 2 commits into
NousResearch:mainfrom
briandevans:fix/memory-char-limit-dispatch-path

Conversation

@briandevans

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #11665.

The memory tool is reachable through two code paths, and until now only one of them respected config.yaml:

  • Path AAIAgent._invoke_tool / the main agent loop passes store=self._memory_store, which AIAgent.__init__ (run_agent.py:1219) builds with the user's configured memory.memory_char_limit / memory.user_char_limit. ✅
  • Path B — anything that routes through model_tools.handle_function_calltools.registry.registry.dispatch("memory", ...). The registry handler lambda reads store=kw.get("store"), and nothing passes store= through that path. ❌

Code paths affected by Path B:

  • tools/code_execution_tool.py (execute_code sandboxes that call tools back via JSON-RPC)
  • environments/agent_loop.py (RL training loop)
  • environments/tool_context.py (reward / verifier helpers)
  • hermes_cli/plugins.py (plugin dispatch — already plumbs parent_agent but the handler wasn't using it)

On pre-fix code, dispatches via Path B silently errored with "Memory is not available" (the reporter's description of "hardcoded defaults" maps to the same underlying symptom — config.yaml values were invisible to that path). Any memory_char_limit: 3000 or user_char_limit: … override a user set in config.yaml was ignored in every dispatch site that wasn't the main AIAgent loop.

Root cause

tools/memory_tool.py:572 — the registry handler:

handler=lambda args, **kw: memory_tool(
    ...
    store=kw.get("store")),

store is never populated by handle_function_call or registry.dispatch, so the tool always received None and short-circuited at the if store is None guard (tools/memory_tool.py:475).

Smallest safe fix

Extend the registry handler with _resolve_memory_store_from_kwargs — a fallback chain:

  1. Explicit store= kwarg — main agent loop + tests, unchanged.
  2. kw[\"parent_agent\"]._memory_storehermes_cli/plugins.py already plumbs parent_agent into dispatch kwargs, so plugin-initiated memory calls now reuse the live agent's store.
  3. A process-wide config-driven MemoryStore singleton built lazily from hermes_cli.config.load_config(). Cached so repeated dispatches don't re-read config.yaml or the on-disk MEMORY.md / USER.md files.
  4. If both memory_enabled and user_profile_enabled are false in config, returns None — preserves the "Memory is not available" error for users who opted out.

Also exports _reset_default_store_for_tests so tests that mutate HERMES_HOME can force the next dispatch to rebuild the singleton. No public API change.

Precedence / compat truth table

caller / state store used
explicit store= kwarg passed that store (unchanged — main agent loop path)
plugin dispatch with parent_agent, parent has store parent's store (new)
plugin dispatch with parent_agent, parent store is None (subagent) falls through to config default (new)
no store, no parent_agent, memory_enabled: true in config config-driven singleton (new)
no store, no parent_agent, memory_enabled: false AND user_profile_enabled: false None → "not available" error (unchanged)

The main agent loop still uses self._memory_store directly in all three special-case sites (_invoke_tool, main tool-calling loop, flush_memories), so there is no behavior change for users on the normal CLI path. The fallback chain only activates when the registry handler lambda fires.

Narrow scope — why only the registry handler

I intentionally did not touch handle_function_call, registry.dispatch, or any of the caller sites that invoke them. Adding store= to those signatures would ripple through RL training, sandbox RPC, plugin context, and the public plugin API. The fallback-chain approach scoped inside memory_tool.py is local, is reversible, and keeps the single source of truth on config.yaml.

How to test

  1. Run the focused suite:

    source venv/bin/activate
    python -m pytest tests/tools/test_memory_tool.py -q
    

    41 passed (33 existing + 8 new).

  2. Confirm the new behavioral test catches the bug on origin/main:

    git stash push tools/memory_tool.py
    python -m pytest tests/tools/test_memory_tool.py::TestRegistryDispatchStoreResolution::test_registry_dispatch_uses_config_memory_limit -v
    

    → fails with

    AssertionError: dispatch returned: {'error': 'Memory is not available...', 'success': False}
    

    Restore with git stash pop.

  3. CI-aligned broad suite:

    python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short -n auto
    

    → 12389 passed, 39 skipped, 7 pre-existing baseline failures (tests/gateway/test_matrix.py, tests/gateway/test_approve_deny_commands.py ×2, tests/hermes_cli/test_gateway_wsl.py ×2, tests/tools/test_file_staleness.py ×2). Each reproduces on clean origin/main with identical assertions — none are in the touched code path.

Tested on: macOS 15 (Darwin 25.5.0), Python 3.11.15.

Related Issue

Fixes #11665

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • tools/memory_tool.py: add _resolve_memory_store_from_kwargs + _reset_default_store_for_tests + module-level lazy singleton; swap the registry handler to use the resolver.
  • tests/tools/test_memory_tool.py: add TestRegistryDispatchStoreResolution — 8 tests covering the full truth table (explicit store wins, parent_agent fallback, subagent-with-None falls through, config-driven default, user_profile-only activation, memory-disabled returns None, singleton identity, end-to-end registry dispatch).

Adjacent surfaces checked

  • run_agent.py special-case branches at lines 7411 and 7894 — unchanged; they still pass store=self._memory_store.
  • run_agent.py:1219 AIAgent.__init__ MemoryStore construction — unchanged.
  • tools/delegate_tool.py:366 (subagent skip_memory=True) — the new behavior is safe: subagents still don't get a store (parent_agent._memory_store is None on them); the resolver falls through to the config-driven default, but the subagent's own skip_memory=True keeps it from dispatching memory in the first place.
  • hermes_cli/plugins.py:291 plugin dispatch with parent_agent — now transparently uses parent's store.
  • tools/code_execution_tool.py sandbox dispatch — now works with config-driven defaults.
  • environments/agent_loop.py and environments/tool_context.py — now work with config-driven defaults.

Checklist

Code

  • I've read the Contributing Guide
  • Commit messages follow Conventional Commits (fix(scope):)
  • Searched for existing PRs — none on Memory char limits ignored by CLI/MCP tool dispatch path #11665
  • Only changes related to this fix
  • Ran the CI-aligned test command and classified failures baseline-vs-change
  • Added tests for my changes (8 new; 1 fails behaviorally on origin/main without the fix, the rest pin the fallback chain)
  • Tested on macOS 15 (Darwin 25.5.0), Python 3.11.15

Documentation & Housekeeping

  • No docs changes needed — internal dispatch detail, no public API surface
  • No config-key changes — existing memory.memory_char_limit / memory.user_char_limit keys are unchanged
  • No architecture/workflow changes
  • Cross-platform impact: none — pure Python, no filesystem/process/encoding changes
  • No tool descriptions/schemas touched

Notes for reviewers

  • No standalone lint command is defined; CI runs python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short -n auto (matches .github/workflows/tests.yml).
  • No hermes_cli/** changes — the Nix workflow should not trigger.

Copilot AI review requested due to automatic review settings April 17, 2026 16:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes inconsistent memory tool behavior across dispatch paths by ensuring registry-dispatched memory calls also honor config.yaml memory limits and enablement flags, aligning behavior with the main AIAgent loop (Fixes #11665).

Changes:

  • Add a registry-dispatch store resolver in tools/memory_tool.py that selects store via: explicit kwarg → parent_agent._memory_store → lazily-built config-driven singleton.
  • Add a test reset hook for the module-level singleton cache to support tests that mutate HERMES_HOME.
  • Add a focused regression test suite covering the full store-resolution truth table and an end-to-end registry.dispatch("memory", ...) path.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
tools/memory_tool.py Adds fallback store-resolution logic for registry-dispatched memory calls and updates registry handler to use it.
tests/tools/test_memory_tool.py Adds regression tests validating store-resolution precedence and end-to-end registry dispatch behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/memory_tool.py Outdated
Comment on lines +618 to +624
from hermes_cli.config import load_config
cfg = load_config() or {}
mem_cfg = cfg.get("memory", {}) or {}
if not (
mem_cfg.get("memory_enabled", False)
or mem_cfg.get("user_profile_enabled", False)
):

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling hermes_cli.config.load_config() here will run ensure_hermes_home(), which creates ~/.hermes subdirs and seeds SOUL.md (and may print warnings on YAML parse errors). That means a registry-dispatched memory call can have filesystem side effects even when config ultimately disables memory/user profile and the resolver returns None. Consider reading just the memory section without ensure_hermes_home (e.g., read_raw_config() merged with DEFAULT_CONFIG["memory"]) and only creating directories/loading from disk once you’ve confirmed memory_enabled/user_profile_enabled is true.

Copilot uses AI. Check for mistakes.
Comment on lines +449 to +465
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
monkeypatch.setattr("tools.memory_tool.get_memory_dir", lambda: hermes_home)

# Dispatch via the registry with NO store kwarg and NO parent_agent
# — mirrors handle_function_call's path.
raw = registry.dispatch(
"memory",
{"action": "add", "target": "memory", "content": "routed via registry dispatch"},
)
result = json.loads(raw)
# On unpatched code this fails with "Memory is not available".
assert result.get("success") is True, f"dispatch returned: {result}"

# The entry should have been persisted under the tmp HERMES_HOME.
memory_md = hermes_home / "MEMORY.md"
assert memory_md.exists(), "dispatch did not persist to config-driven hermes_home"
assert "routed via registry dispatch" in memory_md.read_text(encoding="utf-8")

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests monkeypatch get_memory_dir to return hermes_home directly, so they assert persistence to HERMES_HOME/MEMORY.md. In production, get_memory_dir() resolves to HERMES_HOME/memories, so the persisted file path is HERMES_HOME/memories/MEMORY.md. To keep the end-to-end registry dispatch test representative, consider patching get_memory_dir to hermes_home / "memories" and updating the assertion accordingly.

Copilot uses AI. Check for mistakes.
@briandevans

Copy link
Copy Markdown
Contributor Author

Addressed both Copilot review points in 5c2f58c7:

  1. Filesystem side effects (tools/memory_tool.py): swapped load_config() for read_raw_config() in the default-store builder. load_config() calls ensure_hermes_home(), which creates ~/.hermes subdirs and seeds SOUL.md — that's a visible side effect for every registry-dispatched call, even when memory is ultimately disabled and the resolver returns None. read_raw_config() is a plain YAML read, and the memory section is merged with DEFAULT_CONFIG["memory"] so defaults still resolve. Disk (MemoryStore construction + load_from_disk) is now only touched after we've confirmed memory_enabled / user_profile_enabled.

  2. Production layout in tests (tests/tools/test_memory_tool.py): every new test in TestRegistryDispatchStoreResolution now patches get_memory_dir to HERMES_HOME/memories (matching the production get_memory_dir() -> get_hermes_home() / "memories" at tools/memory_tool.py:55). The end-to-end behavioral test's persistence assertion now checks HERMES_HOME/memories/MEMORY.md — what a real dispatch actually produces.

  3. Side-effect regression guard: test_default_store_returns_none_when_memory_disabled now additionally asserts the memories/ subdir was NOT created — if the resolver ever regains ensure_hermes_home()-style eager side effects, this test catches it.

Validation: python -m pytest tests/tools/test_memory_tool.py -q -> 41 passed. Both behavioral tests still fail on origin/main (dispatch returns "Memory is not available" / ImportError on the helper) and pass with the full fix.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tools Tool registry, model_tools, toolsets tool/memory Memory tool and memory providers labels Apr 24, 2026
@iamvinay5555

Copy link
Copy Markdown

Hey! 👋

Just wanted to gently check in on this one — it's blocking a memory limit increase that would help a lot. Currently running at 95% capacity (2,991/3,000 chars) and really looking forward to the bump to 8K once this merges.

No rush at all — just wanted to make sure it hasn't fallen through the cracks. Happy to help test if needed!

Thanks for all the amazing work on Hermes 🙏

@briandevans
briandevans force-pushed the fix/memory-char-limit-dispatch-path branch from 5c2f58c to 91d3c37 Compare April 29, 2026 11:09
@briandevans

Copy link
Copy Markdown
Contributor Author

Rebased onto current origin/main (58a6171) — clean rebase (only intervening changes to tools/memory_tool.py were the symlink-safe atomic-write refactor in #16743 and follow-up b61d9b2, both orthogonal to the registry-dispatch resolver path). Re-ran tests/tools/test_memory_tool.py locally (41 passed). Ready when you are.

@briandevans
briandevans force-pushed the fix/memory-char-limit-dispatch-path branch from 91d3c37 to 455b97f Compare April 29, 2026 11:24
@briandevans

Copy link
Copy Markdown
Contributor Author

Re-rebased onto current origin/main (ed170f433). The earlier rebase to 58a6171bf was correct at the time, but main moved forward (5 commits) before the supply-chain CI run, so git diff base.sha..head.sha ended up including the inverse of the intervening commits — which incidentally touched hermes_cli/setup.py and tripped the supply-chain scanner's (^|/)setup\.py$ regex (a regex that doesn't distinguish between a packaging setup.py and a regular module named setup.py). Not a real finding, but the way to clear it is a clean re-rebase.

Diff is now strictly limited to tools/memory_tool.py (+96/-1) and tests/tools/test_memory_tool.py (+232/-0). tests/tools/test_memory_tool.py re-ran locally — 41/41 pass, including the 7 TestRegistryDispatchStoreResolution cases that exercise the registry-dispatch path. Ready when you are.

@briandevans

Copy link
Copy Markdown
Contributor Author

CI audit — all 33 test job failures + 1 collection error on commit 455b97fc1 are pre-existing baselines on clean origin/main (ed170f433). Zero failures intersect with touched code (tools/memory_tool.py::_resolve_memory_store_from_kwargs or tests/tools/test_memory_tool.py::TestRegistryDispatchStoreResolution). The 41-test focused suite (tests/tools/test_memory_tool.py) passes locally on this branch.

Failures grouped by category — all reproduce on clean origin/main with identical traceback:

Test file Failures Root cause on main
tests/gateway/test_session.py collection error: ImportError: cannot import name 'normalize_whatsapp_identifier' Test imports a symbol the production module no longer exports. Already being fixed by #17166 (re-export).
tests/hermes_cli/test_config_env_expansion.py 2 cfg_get-migration regression (TypeError: string indices must be integers, not 'str'); recently-merged refactor(config): migrate remaining 33 cfg_get call sites (#17311) is the suspect commit.
tests/hermes_cli/test_provider_config_validation.py 2 Same cfg_get migration — warnings/log assertions broke.
tests/hermes_cli/test_web_server.py (TestReloadEnv, TestBuildSchemaFromConfig) 3 Same cfg_get migration plus a prompt_caching schema split.
tests/hermes_cli/test_update_autostash.py 2 AttributeError: 'types.SimpleNamespace' object has no attribute 'stdout' — known fixture gap; already being fixed by my own #17149.
tests/hermes_cli/test_pty_bridge.py 1 CI sandbox lacks $TERM (tput: No value for $TERM).
tests/hermes_cli/test_container_aware_cli.py 1 assert None is not None — env-detection assumption broke on CI.
tests/hermes_cli/test_gemini_provider.py 1 TypeError: isinstance() arg 2 must be a type — provider-resolution regression.
tests/hermes_cli/test_plugin_scanner_recursion.py 1 Plugin-kind fallback assertion.
tests/agent/test_copilot_acp_client.py 1 Redaction assertion ('abc123def456' unexpectedly found).
tests/gateway/test_run_progress_topics.py 1 TypeError: 'NoneType' object is not callable in Slack DM path.
tests/gateway/test_gateway_shutdown.py, tests/gateway/test_session_split_brain_11016.py 4 30 s timeouts on session-cancel tests — concurrency/teardown flake on origin/main.
tests/test_tui_gateway_server.py, tests/tools/test_browser_orphan_reaper.py, tests/tools/test_mcp_dynamic_discovery.py, tests/tools/test_mcp_structured_content.py 6 MCP / orphan-worker / _rpc_lock SimpleNamespace regressions.
tests/tools/test_clipboard.py::TestIsWsl 3 WSL detection on Linux CI runner.
tests/tui_gateway/test_protocol.py::test_session_resume_returns_hydrated_messages 1 include_ancestors kwarg missing on the test's _DB.get_messages_as_conversation mock — already being addressed by my own #16683.
tests/run_agent/test_background_review_toolset_restriction.py, tests/hermes_cli/test_web_server.py::TestPtyWebSocket::test_resize_escape_is_forwarded 2 Toolset/WS regressions, unrelated to memory.

None of these tests import from tools.memory_tool, register on tools.registry.registry.dispatch("memory", ...), or touch ~/.hermes/memories/. The two-commit branch (b3dec33f1, 455b97fc1) only modifies the registry-dispatch resolver and adds tests for that path.

@iamvinay5555

Copy link
Copy Markdown

Hey team! 👋 Just checking in on this one — all Copilot feedback was addressed back in April, and the branch has been rebased on latest main.

This is a nice bugfix that ensures the memory tool respects config.yaml limits consistently across all call paths. Would love to get it merged when someone has a spare moment! 🙏

No rush — just making sure it hasn't fallen through the cracks.

@iamvinay5555

Copy link
Copy Markdown

👋 Bump — PR Needs Review + Merge

Hey team! Just checking in again. This PR has been open for ~23 days and the fix is solid.

Status Recap

  • ✅ All Copilot review feedback addressed (last rebase: Apr 29)
  • ✅ 41/41 test_memory_tool.py tests pass
  • ⚠️ CI test job fails — but this is a pre-existing CI environment issue, not a PR regression:
    • test_timeout_enforcement, test_kill_detached_session_uses_host_pid, test_concurrent_calls_share_one_token_fetch[trio] — all fail with ModuleNotFoundError: No module named 'psutil'
    • Same 3 tests fail identically on clean main
    • Fix needed: add psutil to CI environment dependencies

What's Needed to Merge

  1. Review + Approve from a maintainer
  2. Fix the CI env (psutil missing) — or skip those 3 tests as pre-existing baseline failures

This is blocking a memory_char_limit increase for several users. Would be great to get this in! 🙏

@briandevans
briandevans force-pushed the fix/memory-char-limit-dispatch-path branch from 455b97f to d2b0d8f Compare May 19, 2026 23:12
@iamvinay5555

Copy link
Copy Markdown

Hey folks! 👋 Just checking in on this one — it's been over a month and the fix looks good. The test failure is a pre-existing baseline issue (not from this PR), so all the blocking checks are actually green. Is there anything else needed to move this forward? Happy to help where needed! 🚀

@briandevans
briandevans force-pushed the fix/memory-char-limit-dispatch-path branch from d260a24 to 69c9f4b Compare May 29, 2026 17:11
@iamvinay5555

Copy link
Copy Markdown

Hey team! 👋

Just a gentle nudge on this PR whenever someone has a moment. Latest checks are green and it looks review-ready from our side.

No rush at all — just making sure it hasn't slipped through the cracks 🙏

@briandevans
briandevans force-pushed the fix/memory-char-limit-dispatch-path branch from 69c9f4b to 27a0445 Compare May 30, 2026 22:12
briandevans and others added 2 commits June 1, 2026 07:13
…alls (NousResearch#11665)

The memory tool is reachable through two code paths:

* ``AIAgent._invoke_tool`` / the main agent loop — explicitly passes
  ``store=self._memory_store``, which ``AIAgent.__init__`` built from
  ``config.yaml`` (``memory.memory_char_limit`` / ``memory.user_char_limit``).
* Any dispatch through ``model_tools.handle_function_call`` →
  ``tools.registry.registry.dispatch("memory", ...)`` — the registry
  handler lambda read ``store=kw.get("store")``, and nothing else in
  the codebase passed ``store=`` through that path.

The result was that code_execution sandboxes, RL training environments,
reward/verifier helpers (``environments/tool_context.py``), plugin
dispatches, and any future entry point that routes through the registry
silently errored with ``"Memory is not available"`` or (with a locally
built store) enforced the hardcoded 2200/1375 defaults instead of the
user's ``config.yaml`` values.

Smallest safe fix
-----------------
Extend the registry handler with a ``_resolve_memory_store_from_kwargs``
fallback chain:

1. Explicit ``store=`` kwarg (main agent loop + unit tests — unchanged).
2. ``kw["parent_agent"]._memory_store`` — ``hermes_cli/plugins.py``
   plumbs ``parent_agent`` into dispatch kwargs, so plugin-initiated
   memory calls now reuse the live agent's store.
3. A process-wide config-driven ``MemoryStore`` singleton, built lazily
   from ``hermes_cli.config.load_config()``.  Cached so repeated
   dispatches don't re-read ``config.yaml`` or reload on-disk files.
   Returns ``None`` when both ``memory_enabled`` and
   ``user_profile_enabled`` are false, preserving the ``"Memory is not
   available"`` error for users who opted out.

Also exposes ``_reset_default_store_for_tests`` so tests that mutate
``HERMES_HOME`` can force the next dispatch to rebuild the singleton.

Precedence truth table
----------------------
| caller / state | store used |
| --- | --- |
| explicit ``store=`` kwarg passed | that store (unchanged) |
| plugin dispatch with parent_agent, parent has store | parent's store |
| plugin dispatch with parent_agent, parent store is None (subagent) | falls through to config default |
| no store, no parent_agent, memory enabled in config | config-driven singleton (new) |
| no store, no parent_agent, memory disabled in config | ``None`` → "not available" error (unchanged) |

Internal state isolation
------------------------
The main agent loop continues to use ``self._memory_store`` directly in
all three special-case sites (``_invoke_tool``, main tool-calling loop,
flush_memories) — the fallback chain only activates when the registry
handler lambda fires, so no behavior change for users on the normal CLI
path.  The ``memory_char_limit``/``user_char_limit`` in ``config.yaml``
is now the single source of truth for every dispatch path.

Validation
----------
``source venv/bin/activate && python -m pytest tests/tools/test_memory_tool.py
-q`` -> 41 passed (33 existing + 8 new).  The behavioral dispatch test
(``test_registry_dispatch_uses_config_memory_limit``) fails on
``origin/main`` with ``AssertionError: dispatch returned: {'error':
'Memory is not available...'}``, and passes with the fix, confirming
the regression is covered.

CI-aligned broad suite: ``python -m pytest tests/ -q
--ignore=tests/integration --ignore=tests/e2e --tb=line -n auto`` ->
12389 passed, 39 skipped, 7 baseline failures (``test_matrix``,
``test_approve_deny_commands`` ×2, ``test_gateway_wsl`` ×2,
``test_file_staleness`` ×2).  All 7 reproduce on clean ``origin/main``
with identical assertions — none are in the touched code path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ies/ layout

Addresses the Copilot review on PR NousResearch#11693:

1. ``_resolve_memory_store_from_kwargs`` now calls ``read_raw_config()``
   instead of ``load_config()``.  ``load_config()`` runs
   ``ensure_hermes_home()``, which creates ``~/.hermes`` subdirs and
   seeds ``SOUL.md`` — that's a visible filesystem side effect for every
   registry-dispatched memory call, even when memory is ultimately
   disabled and the resolver returns ``None``.  ``read_raw_config()`` is
   a plain YAML read, and the memory section is merged with
   ``DEFAULT_CONFIG["memory"]`` so default flags/limits still resolve.

2. Updated the new regression tests in ``TestRegistryDispatchStoreResolution``
   to patch ``get_memory_dir`` to ``HERMES_HOME/memories`` — matching
   the production layout (``tools/memory_tool.py:55``: ``get_memory_dir()
   -> get_hermes_home() / "memories"``) rather than ``HERMES_HOME`` directly.
   The end-to-end behavioral test's assertion now checks
   ``HERMES_HOME/memories/MEMORY.md``, which is what a real dispatch
   produces.

3. Strengthened ``test_default_store_returns_none_when_memory_disabled``
   with an explicit assertion that the ``memories/`` subdir was NOT
   created — if the resolver regains ``ensure_hermes_home()``-style
   side effects in the future, this test will fail.

Validation: ``source venv/bin/activate && python -m pytest
tests/tools/test_memory_tool.py -q`` -> 41 passed.  The two behavioral
tests still fail on ``origin/main`` (dispatch returns ``"Memory is not
available"`` / ImportError on the helper) and pass with the full fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@briandevans
briandevans force-pushed the fix/memory-char-limit-dispatch-path branch from 27a0445 to 4c98db8 Compare June 1, 2026 14:13
@briandevans

Copy link
Copy Markdown
Contributor Author

Housekeeping: closing to keep my open-PR set focused on actively-reviewed work. This has been open ~45d without maintainer review and the surrounding code has continued to move, so it's unlikely to land as-is. The underlying fix still stands — happy to reopen and rebase if it would be useful. Thanks!

@iamvinay5555

Copy link
Copy Markdown

Superseded by #37102 — same fix, fresh rebase on latest main. Closing reference preserved for commit history.

Full context: config.yaml memory_char_limit / user_char_limit now honored in registry-dispatch paths.

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

Labels

comp/tools Tool registry, model_tools, toolsets 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.

Memory char limits ignored by CLI/MCP tool dispatch path

4 participants