Scope memory JSON compatibility to the dashboard
Keep shared API serialization strict while converting legacy NumPy consolidation scores in the memory dashboard response. Add regressions for native relevance scores and legacy dashboard metadata without mutating stored documents.
Alessandro committed
Aug 23, 2026 at 16:47 UTC
454d45c434e6f02f786c0054e907a015ea476f0a
4 files changed
+41
-2
helpers/api.py
+1
-1
@@ -83,7 +83,7 @@ class ApiHandler:
83
if isinstance(output, Response):
84
return output
85
else:
86
- response_json = json.dumps(output, default=float)
86
+ response_json = json.dumps(output)
87
return Response(
88
response=response_json, status=200, mimetype="application/json"
89
)
plugins/_memory/AGENTS.md
+1
@@ -21,6 +21,7 @@
21
22
## Work Guidance
23
24
+- Keep dashboard metadata JSON-safe without changing shared API serialization.
25
- Coordinate tool, prompt, and consolidation changes so saved memories remain useful and bounded.
26
27
## Verification
plugins/_memory/api/memory_dashboard.py
+6
-1
@@ -1,3 +1,5 @@
1
+import numpy as np
2
+
3
from helpers.api import ApiHandler, Request, Response
4
from helpers import files
5
from helpers.localization import Localization
@@ -216,7 +218,10 @@ class MemoryDashboard(ApiHandler):
218
219
def _format_memory_for_dashboard(self, m: Document) -> dict:
220
"""Format a memory document for the dashboard."""
219
- metadata = m.metadata
221
+ metadata = dict(m.metadata)
222
+ similarity = metadata.get("_consolidation_similarity")
223
+ if isinstance(similarity, np.generic):
224
+ metadata["_consolidation_similarity"] = float(similarity)
225
timestamp = self._serialize_memory_timestamp(metadata.get("timestamp", "unknown"))
226
return {
227
"id": metadata.get("id", "unknown"),
tests/test_memory_json_serialization.py
new
+33
@@ -0,0 +1,33 @@
1
+import json
2
+import threading
3
+
4
+import numpy as np
5
+from langchain_core.documents import Document
6
+
7
+from plugins._memory.api.memory_dashboard import MemoryDashboard
8
+from plugins._memory.helpers.memory import Memory
9
+
10
+
11
+def test_cosine_normalizer_returns_native_float():
12
+ score = Memory._cosine_normalizer(np.float32(0.8))
13
+
14
+ assert type(score) is float
15
+
16
+
17
+def test_memory_dashboard_serializes_legacy_numpy_similarity():
18
+ dashboard = MemoryDashboard(app=None, thread_lock=threading.RLock())
19
+ document = Document(
20
+ page_content="legacy memory",
21
+ metadata={
22
+ "id": "memory-1",
23
+ "area": "main",
24
+ "timestamp": "unknown",
25
+ "_consolidation_similarity": np.float32(0.75),
26
+ },
27
+ )
28
+
29
+ formatted = dashboard._format_memory_for_dashboard(document)
30
+
31
+ assert type(formatted["metadata"]["_consolidation_similarity"]) is float
32
+ assert isinstance(document.metadata["_consolidation_similarity"], np.float32)
33
+ json.dumps(formatted)