mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-20 07:01:03 +00:00
feat: add memory management actions and local filters in memory settings (#1467)
* Add MVP memory management actions * Fix memory settings locale coverage * Polish memory management interactions * Add memory search and type filters * Refine memory settings review feedback * docs: simplify memory settings review setup * fix: restore memory updater compatibility helpers * fix: address memory settings review feedback * docs: soften memory sample review wording --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com> Co-authored-by: JeffJiang <for-eleven@hotmail.com>
This commit is contained in:
@@ -674,6 +674,19 @@ class TestMemoryManagement:
|
||||
result = client.reload_memory()
|
||||
assert result == data
|
||||
|
||||
def test_clear_memory(self, client):
|
||||
data = {"version": "1.0", "facts": []}
|
||||
with patch("deerflow.agents.memory.updater.clear_memory_data", return_value=data):
|
||||
result = client.clear_memory()
|
||||
assert result == data
|
||||
|
||||
def test_delete_memory_fact(self, client):
|
||||
data = {"version": "1.0", "facts": []}
|
||||
with patch("deerflow.agents.memory.updater.delete_memory_fact", return_value=data) as delete_fact:
|
||||
result = client.delete_memory_fact("fact_123")
|
||||
delete_fact.assert_called_once_with("fact_123")
|
||||
assert result == data
|
||||
|
||||
def test_get_memory_config(self, client):
|
||||
config = MagicMock()
|
||||
config.enabled = True
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.gateway.routers import memory
|
||||
|
||||
|
||||
def _sample_memory(facts: list[dict] | None = None) -> dict:
|
||||
return {
|
||||
"version": "1.0",
|
||||
"lastUpdated": "2026-03-26T12:00:00Z",
|
||||
"user": {
|
||||
"workContext": {"summary": "", "updatedAt": ""},
|
||||
"personalContext": {"summary": "", "updatedAt": ""},
|
||||
"topOfMind": {"summary": "", "updatedAt": ""},
|
||||
},
|
||||
"history": {
|
||||
"recentMonths": {"summary": "", "updatedAt": ""},
|
||||
"earlierContext": {"summary": "", "updatedAt": ""},
|
||||
"longTermBackground": {"summary": "", "updatedAt": ""},
|
||||
},
|
||||
"facts": facts or [],
|
||||
}
|
||||
|
||||
|
||||
def test_clear_memory_route_returns_cleared_memory() -> None:
|
||||
app = FastAPI()
|
||||
app.include_router(memory.router)
|
||||
|
||||
with patch("app.gateway.routers.memory.clear_memory_data", return_value=_sample_memory()):
|
||||
with TestClient(app) as client:
|
||||
response = client.delete("/api/memory")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["facts"] == []
|
||||
|
||||
|
||||
def test_delete_memory_fact_route_returns_updated_memory() -> None:
|
||||
app = FastAPI()
|
||||
app.include_router(memory.router)
|
||||
updated_memory = _sample_memory(
|
||||
facts=[
|
||||
{
|
||||
"id": "fact_keep",
|
||||
"content": "User likes Python",
|
||||
"category": "preference",
|
||||
"confidence": 0.9,
|
||||
"createdAt": "2026-03-20T00:00:00Z",
|
||||
"source": "thread-1",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
with patch("app.gateway.routers.memory.delete_memory_fact", return_value=updated_memory):
|
||||
with TestClient(app) as client:
|
||||
response = client.delete("/api/memory/facts/fact_delete")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["facts"] == updated_memory["facts"]
|
||||
|
||||
|
||||
def test_delete_memory_fact_route_returns_404_for_missing_fact() -> None:
|
||||
app = FastAPI()
|
||||
app.include_router(memory.router)
|
||||
|
||||
with patch("app.gateway.routers.memory.delete_memory_fact", side_effect=KeyError("fact_missing")):
|
||||
with TestClient(app) as client:
|
||||
response = client.delete("/api/memory/facts/fact_missing")
|
||||
|
||||
assert response.status_code == 404
|
||||
assert response.json()["detail"] == "Memory fact 'fact_missing' not found."
|
||||
@@ -1,7 +1,12 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from deerflow.agents.memory.prompt import format_conversation_for_update
|
||||
from deerflow.agents.memory.updater import MemoryUpdater, _extract_text
|
||||
from deerflow.agents.memory.updater import (
|
||||
MemoryUpdater,
|
||||
_extract_text,
|
||||
clear_memory_data,
|
||||
delete_memory_fact,
|
||||
)
|
||||
from deerflow.config.memory_config import MemoryConfig
|
||||
|
||||
|
||||
@@ -138,6 +143,57 @@ def test_apply_updates_preserves_threshold_and_max_facts_trimming() -> None:
|
||||
assert result["facts"][1]["source"] == "thread-9"
|
||||
|
||||
|
||||
def test_clear_memory_data_resets_all_sections() -> None:
|
||||
with patch("deerflow.agents.memory.updater._save_memory_to_file", return_value=True):
|
||||
result = clear_memory_data()
|
||||
|
||||
assert result["version"] == "1.0"
|
||||
assert result["facts"] == []
|
||||
assert result["user"]["workContext"]["summary"] == ""
|
||||
assert result["history"]["recentMonths"]["summary"] == ""
|
||||
|
||||
|
||||
def test_delete_memory_fact_removes_only_matching_fact() -> None:
|
||||
current_memory = _make_memory(
|
||||
facts=[
|
||||
{
|
||||
"id": "fact_keep",
|
||||
"content": "User likes Python",
|
||||
"category": "preference",
|
||||
"confidence": 0.9,
|
||||
"createdAt": "2026-03-18T00:00:00Z",
|
||||
"source": "thread-a",
|
||||
},
|
||||
{
|
||||
"id": "fact_delete",
|
||||
"content": "User prefers tabs",
|
||||
"category": "preference",
|
||||
"confidence": 0.8,
|
||||
"createdAt": "2026-03-18T00:00:00Z",
|
||||
"source": "thread-b",
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
with (
|
||||
patch("deerflow.agents.memory.updater.get_memory_data", return_value=current_memory),
|
||||
patch("deerflow.agents.memory.updater._save_memory_to_file", return_value=True),
|
||||
):
|
||||
result = delete_memory_fact("fact_delete")
|
||||
|
||||
assert [fact["id"] for fact in result["facts"]] == ["fact_keep"]
|
||||
|
||||
|
||||
def test_delete_memory_fact_raises_for_unknown_id() -> None:
|
||||
with patch("deerflow.agents.memory.updater.get_memory_data", return_value=_make_memory()):
|
||||
try:
|
||||
delete_memory_fact("fact_missing")
|
||||
except KeyError as exc:
|
||||
assert exc.args == ("fact_missing",)
|
||||
else:
|
||||
raise AssertionError("Expected KeyError for missing fact id")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _extract_text — LLM response content normalization
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user