repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources15d ago| #1 | """[issue #45 followup] Tests for hermes_plugin.tools.mnemosyne_recall. |
| #2 | |
| #3 | Adversarial review of issue #45's PR caught that the Hermes plugin's recall |
| #4 | handler ALSO drops vec_weight / fts_weight / importance_weight. The |
| #5 | RECALL_SCHEMA at hermes_plugin/tools.py:66-110 doesn't advertise the |
| #6 | scoring weights, and the handler at lines 375-393 doesn't forward them |
| #7 | to mem.recall. |
| #8 | |
| #9 | Same bug class as the MCP-side fix in PR #46 and the |
| #10 | hermes_memory_provider fix on the C12.b branch — schema/handler mismatch |
| #11 | with what BeamMemory.recall actually accepts. |
| #12 | """ |
| #13 | |
| #14 | from __future__ import annotations |
| #15 | |
| #16 | import json |
| #17 | from unittest.mock import MagicMock, patch |
| #18 | |
| #19 | import pytest |
| #20 | |
| #21 | |
| #22 | def test_recall_schema_advertises_scoring_weights(): |
| #23 | """Hermes plugin's RECALL_SCHEMA must advertise vec_weight / fts_weight / |
| #24 | importance_weight as type=number properties so Hermes' tool-arg validator |
| #25 | accepts them instead of stripping as unknown fields.""" |
| #26 | from hermes_plugin.tools import RECALL_SCHEMA |
| #27 | |
| #28 | props = RECALL_SCHEMA["parameters"]["properties"] |
| #29 | for key in ("vec_weight", "fts_weight", "importance_weight"): |
| #30 | assert key in props, ( |
| #31 | f"hermes_plugin RECALL_SCHEMA missing {key!r} — schema " |
| #32 | f"advertises 'hybrid vector + full-text search' but doesn't " |
| #33 | f"let clients tune the weights" |
| #34 | ) |
| #35 | assert props[key]["type"] == "number", ( |
| #36 | f"{key} should be type=number, got {props[key].get('type')!r}" |
| #37 | ) |
| #38 | |
| #39 | |
| #40 | def test_mnemosyne_recall_forwards_scoring_weights_to_mem(monkeypatch): |
| #41 | """hermes_plugin.tools.mnemosyne_recall handler must forward vec_weight / |
| #42 | fts_weight / importance_weight to mem.recall when caller supplies them.""" |
| #43 | from hermes_plugin import tools as plugin_tools |
| #44 | |
| #45 | captured = {} |
| #46 | |
| #47 | class _StubMem: |
| #48 | def recall(self, query, **kwargs): |
| #49 | captured["query"] = query |
| #50 | captured.update(kwargs) |
| #51 | return [] |
| #52 | |
| #53 | monkeypatch.setattr(plugin_tools, "_get_memory", lambda: _StubMem()) |
| #54 | |
| #55 | response = plugin_tools.mnemosyne_recall({ |
| #56 | "query": "anything", |
| #57 | "top_k": 3, |
| #58 | "vec_weight": 0.55, |
| #59 | "fts_weight": 0.25, |
| #60 | "importance_weight": 0.20, |
| #61 | }) |
| #62 | |
| #63 | parsed = json.loads(response) |
| #64 | assert "error" not in parsed, parsed |
| #65 | assert captured.get("vec_weight") == 0.55, ( |
| #66 | f"mnemosyne_recall did not forward vec_weight; captured={captured!r}" |
| #67 | ) |
| #68 | assert captured.get("fts_weight") == 0.25 |
| #69 | assert captured.get("importance_weight") == 0.20 |
| #70 | |
| #71 | |
| #72 | def test_mnemosyne_recall_omits_weights_when_caller_does_not_supply(monkeypatch): |
| #73 | """When caller omits the scoring weights, the handler must NOT pass |
| #74 | spurious values to mem.recall — beam treats None as 'fall back to env |
| #75 | var or default' via _normalize_weights, and forcing 0.0 / 0.5 / etc. |
| #76 | would override that resolution and break MNEMOSYNE_*_WEIGHT env-var |
| #77 | deployments.""" |
| #78 | from hermes_plugin import tools as plugin_tools |
| #79 | |
| #80 | captured = {} |
| #81 | |
| #82 | class _StubMem: |
| #83 | def recall(self, query, **kwargs): |
| #84 | captured["query"] = query |
| #85 | captured.update(kwargs) |
| #86 | return [] |
| #87 | |
| #88 | monkeypatch.setattr(plugin_tools, "_get_memory", lambda: _StubMem()) |
| #89 | |
| #90 | plugin_tools.mnemosyne_recall({"query": "anything", "top_k": 3}) |
| #91 | |
| #92 | # Acceptable: kwarg not in mem.recall's call OR explicitly None. |
| #93 | # Failing path: a numeric default (0.5 / 0.0) leaked through. |
| #94 | for key in ("vec_weight", "fts_weight", "importance_weight"): |
| #95 | val = captured.get(key, "OMITTED") |
| #96 | assert val in (None, "OMITTED"), ( |
| #97 | f"mnemosyne_recall forwarded {key}={val!r} when caller " |
| #98 | f"omitted it; this overrides beam's env/default resolution. " |
| #99 | f"Either pass None or omit the kwarg entirely." |
| #100 | ) |
| #101 |