mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-08-31 01:46:49 +00:00
Merge pull request #1846 from Jehu/fix/memory-float32-json-serialization
fix(memory): keep numpy scalars out of metadata and API JSON
This commit is contained in:
commit
fe70025dc0
5 changed files with 43 additions and 4 deletions
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
## Work Guidance
|
||||
|
||||
- Keep dashboard metadata JSON-safe without changing shared API serialization.
|
||||
- Coordinate tool, prompt, and consolidation changes so saved memories remain useful and bounded.
|
||||
|
||||
## Verification
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import numpy as np
|
||||
|
||||
from helpers.api import ApiHandler, Request, Response
|
||||
from helpers import files
|
||||
from helpers.localization import Localization
|
||||
|
|
@ -216,7 +218,10 @@ class MemoryDashboard(ApiHandler):
|
|||
|
||||
def _format_memory_for_dashboard(self, m: Document) -> dict:
|
||||
"""Format a memory document for the dashboard."""
|
||||
metadata = m.metadata
|
||||
metadata = dict(m.metadata)
|
||||
similarity = metadata.get("_consolidation_similarity")
|
||||
if isinstance(similarity, np.generic):
|
||||
metadata["_consolidation_similarity"] = float(similarity)
|
||||
timestamp = self._serialize_memory_timestamp(metadata.get("timestamp", "unknown"))
|
||||
return {
|
||||
"id": metadata.get("id", "unknown"),
|
||||
|
|
|
|||
|
|
@ -614,7 +614,7 @@ class Memory:
|
|||
res = max(
|
||||
0, min(1, res)
|
||||
) # float precision can cause values like 1.0000000596046448
|
||||
return res
|
||||
return float(res) # native float, not numpy scalar (JSON serializable)
|
||||
|
||||
@staticmethod
|
||||
def format_docs_plain(docs: list[Document]) -> list[str]:
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ class MemoryConsolidator:
|
|||
filter=f"area == '{area}'"
|
||||
)
|
||||
for doc, score in semantic_results:
|
||||
doc.metadata['_consolidation_similarity'] = score
|
||||
doc.metadata['_consolidation_similarity'] = float(score) if score is not None else 0.0
|
||||
all_similar.append(doc)
|
||||
|
||||
# Step 3: Keyword-based searches with real scores
|
||||
|
|
@ -358,7 +358,7 @@ class MemoryConsolidator:
|
|||
filter=f"area == '{area}'"
|
||||
)
|
||||
for doc, score in keyword_results:
|
||||
doc.metadata['_consolidation_similarity'] = score
|
||||
doc.metadata['_consolidation_similarity'] = float(score) if score is not None else 0.0
|
||||
all_similar.append(doc)
|
||||
|
||||
# Step 4: Deduplicate by document ID, keep highest score per memory ID
|
||||
|
|
|
|||
33
tests/test_memory_json_serialization.py
Normal file
33
tests/test_memory_json_serialization.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import json
|
||||
import threading
|
||||
|
||||
import numpy as np
|
||||
from langchain_core.documents import Document
|
||||
|
||||
from plugins._memory.api.memory_dashboard import MemoryDashboard
|
||||
from plugins._memory.helpers.memory import Memory
|
||||
|
||||
|
||||
def test_cosine_normalizer_returns_native_float():
|
||||
score = Memory._cosine_normalizer(np.float32(0.8))
|
||||
|
||||
assert type(score) is float
|
||||
|
||||
|
||||
def test_memory_dashboard_serializes_legacy_numpy_similarity():
|
||||
dashboard = MemoryDashboard(app=None, thread_lock=threading.RLock())
|
||||
document = Document(
|
||||
page_content="legacy memory",
|
||||
metadata={
|
||||
"id": "memory-1",
|
||||
"area": "main",
|
||||
"timestamp": "unknown",
|
||||
"_consolidation_similarity": np.float32(0.75),
|
||||
},
|
||||
)
|
||||
|
||||
formatted = dashboard._format_memory_for_dashboard(document)
|
||||
|
||||
assert type(formatted["metadata"]["_consolidation_similarity"]) is float
|
||||
assert isinstance(document.metadata["_consolidation_similarity"], np.float32)
|
||||
json.dumps(formatted)
|
||||
Loading…
Add table
Add a link
Reference in a new issue