Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions mnemon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ def get_config_schema(self) -> list[dict[str, Any]]:
"description": "Mnemon memory store name (defaults to profile name)",
"required": False,
"default": ""
},
{
"key": "max_compress_chars",
"description": "Cap (in chars) applied to each message stored by the on_pre_compress hook. Set to 0 for no cap (default: 600).",
"required": False,
"default": 600
},
{
"key": "max_mirror_chars",
"description": "Cap (in chars) applied when mirroring file-memory writes into mnemon. Set to 0 for no limit (default: 8000, matching the mnemon binary's own ceiling).",
"required": False,
"default": 8000
}
]

Expand Down Expand Up @@ -156,6 +168,21 @@ def initialize(self, session_id: str, **kwargs) -> None:
except Exception as e:
logger.warning("Failed to load mnemon.json: %s", e)

# Load plugin-specific config (max_compress_chars, max_mirror_chars)
max_compress_chars = 600
max_mirror_chars = 8000
if hermes_home:
config_file = Path(hermes_home) / "mnemon.json"
if config_file.exists():
try:
plugin_data = json.loads(config_file.read_text())
max_compress_chars = int(plugin_data.get("max_compress_chars", 600))
max_mirror_chars = int(plugin_data.get("max_mirror_chars", 8000))
except Exception as e:
logger.warning("Failed to load mnemon plugin config: %s", e)
self._max_compress_chars: int = max_compress_chars
self._max_mirror_chars: int = max_mirror_chars

profile = kwargs.get("agent_identity", "default")
# Precedence: config value -> environment variable -> fallback to profile
self._store = store_config or os.environ.get("MNEMON_STORE") or profile
Expand Down Expand Up @@ -212,6 +239,7 @@ def _auto_remember(self, user_text: str, asst_text: str) -> None:
if _FORGET_RE.search(combined):
return
for text in (user_text.strip(), asst_text.strip()):
# Skip noise: sub-30-char utterances rarely carry decision/preference signal
if not text or len(text) < 30:
continue
cat = self._auto_cat(text)
Expand Down Expand Up @@ -289,7 +317,7 @@ def on_pre_compress(self, messages: list[dict]) -> str:
key_msgs = [m for m in messages if m.get("role") in ("assistant","user")
and len(m.get("content","")) > 80][-10:]
for msg in key_msgs:
self._remember_and_index(msg["content"][: 600],
self._remember_and_index(msg["content"][: self._max_compress_chars],
category="context", importance=2)
return ""

Expand All @@ -303,11 +331,18 @@ def on_memory_write(self, action: str, target: str,
cat = "preference" if target == "user" else "general"
imp = 4 if cat == "preference" else 3
src = (metadata or {}).get("write_origin", "agent")
# Warn if mirroring would truncate
if self._max_mirror_chars > 0 and len(content) > self._max_mirror_chars:
logger.warning(
"mnemon mirror: entry is %d chars; truncating to max_mirror_chars=%d. "
"Set max_mirror_chars: 0 in the mnemon provider config to store full content.",
len(content), self._max_mirror_chars,
)
threading.Thread(
target=lambda: self._remember_and_index(content[:2500],
category=cat,
importance=imp,
source=src),
target=lambda: self._remember_and_index(
content[: self._max_mirror_chars] if self._max_mirror_chars > 0 else content,
category=cat, importance=imp, source=src,
),
daemon=True,
).start()

Expand Down
4 changes: 3 additions & 1 deletion tests/test_mnemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,10 @@ def test_get_config_schema(self):
p = MnemonMemoryProvider()
schema = p.get_config_schema()
self.assertIsInstance(schema, list)
self.assertEqual(len(schema), 1)
self.assertEqual(len(schema), 3)
self.assertEqual(schema[0]["key"], "store")
self.assertEqual(schema[1]["key"], "max_compress_chars")
self.assertEqual(schema[2]["key"], "max_mirror_chars")

@patch("mnemon._run_mnemon")
def test_save_config_and_initialize_with_hermes_home(self, mock_run):
Expand Down