Coerce memory load numeric args
Normalize memory_load threshold and limit values from model calls before vector search so numeric strings from Responses tool arguments do not reach FAISS unchanged. Add a focused regression covering string threshold/limit values and document the memory plugin contract.
Alessandro committed
Jun 30, 2026 at 16:35 UTC
b07d142938420e5e658a97556dd841bdd2713e60
3 files changed
+56
plugins/_memory/AGENTS.md
+1
@@ -16,6 +16,7 @@
16
17
- Keep memory scoped by configured subdirectory/context.
18
- Preserve embedding metadata needed to rebuild indexes safely.
19
+- `memory_load` accepts numeric `threshold` and `limit` values as native numbers or numeric strings and coerces them before vector search.
20
- Avoid storing transient action-history noise as durable memory.
21
22
## Work Guidance
plugins/_memory/tools/memory_load.py
+7
@@ -8,6 +8,13 @@ DEFAULT_LIMIT = 10
8
class MemoryLoad(Tool):
9
10
async def execute(self, query="", threshold=DEFAULT_THRESHOLD, limit=DEFAULT_LIMIT, filter="", **kwargs):
11
+ if threshold is None or threshold == "":
12
+ threshold = DEFAULT_THRESHOLD
13
+ if limit is None or limit == "":
14
+ limit = DEFAULT_LIMIT
15
+ threshold = float(threshold)
16
+ limit = int(limit)
17
+
18
db = await Memory.get(self.agent)
19
docs = await db.search_similarity_threshold(query=query, limit=limit, threshold=threshold, filter=filter)
20
tests/test_tool_action_contracts.py
+48
@@ -548,6 +548,54 @@ def test_memory_forget_tool_imports_plugin_memory_load(monkeypatch):
548
]
549
550
551
+def test_memory_load_coerces_numeric_string_args(monkeypatch):
552
+ _install_tool_stub(monkeypatch)
553
+ monkeypatch.syspath_prepend(str(Path.cwd()))
554
+
555
+ class FakeDb:
556
+ def __init__(self) -> None:
557
+ self.calls = []
558
+
559
+ async def search_similarity_threshold(self, **kwargs):
560
+ self.calls.append(kwargs)
561
+ return []
562
+
563
+ fake_db = FakeDb()
564
+
565
+ async def get_memory(_agent):
566
+ return fake_db
567
+
568
+ memory_stub = types.ModuleType("plugins._memory.helpers.memory")
569
+ memory_stub.Memory = types.SimpleNamespace(get=get_memory)
570
+ monkeypatch.setitem(sys.modules, "plugins._memory.helpers.memory", memory_stub)
571
+
572
+ sys.modules.pop("plugins._memory.tools.memory_load", None)
573
+ module = importlib.import_module("plugins._memory.tools.memory_load")
574
+ tool = module.MemoryLoad(
575
+ _FakeAgent(),
576
+ "memory_load",
577
+ None,
578
+ {
579
+ "query": "smoke test project context",
580
+ "threshold": "0.7",
581
+ "limit": "3",
582
+ },
583
+ "",
584
+ None,
585
+ )
586
+
587
+ asyncio.run(tool.execute(**tool.args))
588
+
589
+ assert fake_db.calls == [
590
+ {
591
+ "query": "smoke test project context",
592
+ "threshold": 0.7,
593
+ "limit": 3,
594
+ "filter": "",
595
+ }
596
+ ]
597
+
598
+
599
def test_behaviour_adjustment_normalizes_duplicate_rules(monkeypatch):
600
_install_tool_stub(monkeypatch)
601
monkeypatch.syspath_prepend(str(Path.cwd()))