Files
hermes-agent/tests/agent/test_memory_recall_indicator.py
T
kshitij 8b243dff62 fix: security + efficiency review fixes for salvaged PR #74379
1. Use open_credentialed_url() instead of bare urlopen() in
   templates.py apply_template() and probe_existing_customization().
   Both send Authorization: Bearer headers; bare urlopen forwards
   credentials on cross-origin redirects. The codebase has
   open_credentialed_url() in hermes_cli/urllib_security.py that
   strips credentials on cross-origin redirects — used by 4 other
   modules.

2. Guard unavailable_reason() with the dedup set check before
   calling it. The gateway builds a fresh AIAgent per message, so
   without this guard unavailable_reason() (which calls _load_config()
   → stat + file read + JSON parse, and _check_local_runtime() →
   importlib probes) runs on every gateway turn for an unavailable
   provider, even though the warning is deduped after the first.

3. Move INDICATOR_GLYPH from Hindsight's eye emoji to a generic
   brain (🧠) in core (agent/memory_provider.py). Hindsight overrides
   with its own _HINDSIGHT_GLYPH (👁️) in recall_status() and
   _emit_saving_indicator(). Other memory providers no longer inherit
   Hindsight's brand mark as the default glyph.
2026-08-13 23:15:25 +05:30

91 lines
3.2 KiB
Python

"""MemoryManager.describe_recall — the deterministic recall indicator.
When auto-recall injects memory, Hermes surfaces a model-independent
"🧠 <provider> — recalled N memories" status line so the user SEES memory
working regardless of whether the model chooses to mention it. These tests
lock the formatting (singular/plural/generic) and the aggregation across
providers, all deterministically (no LLM, no network).
"""
from typing import Optional
from agent.memory_manager import MemoryManager
from agent.memory_provider import MemoryProvider, RecallStatus
class _FakeProvider(MemoryProvider):
"""Provider with a settable recall_status for indicator tests."""
def __init__(self, name: str, status: Optional[RecallStatus], *, raises: bool = False):
self._name = name
self._status = status
self._raises = raises
@property
def name(self) -> str:
return self._name
def is_available(self) -> bool:
return True
def initialize(self, session_id: str = "", **kwargs) -> None:
pass
def get_tool_schemas(self):
return []
def handle_tool_call(self, tool_name, args, **kwargs) -> str:
return ""
def recall_status(self) -> Optional[RecallStatus]:
if self._raises:
raise RuntimeError("boom")
return self._status
def test_no_status_returns_empty_string():
mgr = MemoryManager()
mgr.add_provider(_FakeProvider("hindsight", None))
assert mgr.describe_recall() == ""
def test_no_providers_returns_empty_string():
assert MemoryManager().describe_recall() == ""
def test_single_memory_is_singular():
mgr = MemoryManager()
mgr.add_provider(_FakeProvider("hindsight", RecallStatus("Hindsight", 1)))
assert mgr.describe_recall() == "🧠 Hindsight — recalled 1 memory"
def test_multiple_memories_are_plural():
mgr = MemoryManager()
mgr.add_provider(_FakeProvider("hindsight", RecallStatus("Hindsight", 3)))
assert mgr.describe_recall() == "🧠 Hindsight — recalled 3 memories"
def test_zero_count_renders_generic():
# count 0 = content injected but no discrete count (e.g. reflect synthesis).
mgr = MemoryManager()
mgr.add_provider(_FakeProvider("hindsight", RecallStatus("Hindsight", 0)))
assert mgr.describe_recall() == "🧠 Hindsight — recalled relevant memory"
def test_aggregates_multiple_providers():
# builtin is always accepted first; a second external is rejected, so use
# builtin + one external to exercise the join path.
mgr = MemoryManager()
mgr.add_provider(_FakeProvider("builtin", RecallStatus("Notes", 2)))
mgr.add_provider(_FakeProvider("hindsight", RecallStatus("Hindsight", 5)))
result = mgr.describe_recall()
assert "🧠 Notes — recalled 2 memories" in result
assert "🧠 Hindsight — recalled 5 memories" in result
def test_failing_provider_is_skipped_not_fatal():
mgr = MemoryManager()
mgr.add_provider(_FakeProvider("builtin", None, raises=True))
mgr.add_provider(_FakeProvider("hindsight", RecallStatus("Hindsight", 1)))
# The raising provider is swallowed; the healthy one still surfaces.
assert mgr.describe_recall() == "🧠 Hindsight — recalled 1 memory"