fix(memhub): home memory count matches the memory page
The home card counted chat memories only (list_memories without a scene), so it showed 55 while the memory page showed 94. It now reads memory_stats total (chat + working + coding experiences, facts not counted) and takes the newest memory from list_memories(scene="all"). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
dd3809a34b
commit
423cb00dbf
2 files changed
+62
-1
No files matched your search
@@ -2824,11 +2824,24 @@ def create_app(
|
||||
dependencies=protected,
|
||||
)
|
||||
async def sdk_home_summary() -> SdkHomeSummary:
|
||||
"""The home card: the memory page's count and its newest memory.
|
||||
|
||||
The count is `memory_stats` total (chat + working + coding
|
||||
experiences, facts not counted), the same set the memory page lists
|
||||
with scene="all". Without a scene `list_memories` counts chat only,
|
||||
which showed 55 on the home card against 94 on the memory page.
|
||||
"""
|
||||
try:
|
||||
client = await _sdk_client_handle(app).client()
|
||||
stats = await asyncio.to_thread(
|
||||
client.memory_stats,
|
||||
user_id="local",
|
||||
statuses=["active"],
|
||||
)
|
||||
raw = await asyncio.to_thread(
|
||||
client.list_memories,
|
||||
user_id="local",
|
||||
scene="all",
|
||||
statuses=["active"],
|
||||
limit=1,
|
||||
offset=0,
|
||||
@@ -2838,8 +2851,9 @@ def create_app(
|
||||
_log_skipped_sdk_memories(skipped)
|
||||
except Exception as error:
|
||||
raise _sdk_http_error(error, "hy_memory_list_failed") from None
|
||||
total = stats.get("total") if isinstance(stats, dict) else None
|
||||
return SdkHomeSummary(
|
||||
memory_count=page.total,
|
||||
memory_count=total if isinstance(total, int) and total >= 0 else page.total,
|
||||
latest=page.memories[0] if page.memories else None,
|
||||
observed_at=datetime.now(UTC),
|
||||
)
|
||||
|
||||
@@ -90,6 +90,7 @@ class FakeSdk:
|
||||
self.productivity = {}
|
||||
self.search_calls = []
|
||||
self.list_calls = []
|
||||
self.stats_calls = []
|
||||
self.get_calls = []
|
||||
self.update_calls = []
|
||||
self.delete_calls = []
|
||||
@@ -227,6 +228,22 @@ class FakeSdk:
|
||||
"elapsed_ms": 1.0,
|
||||
}
|
||||
|
||||
def memory_stats(self, *, user_id, statuses=None):
|
||||
self.stats_calls.append({"user_id": user_id, "statuses": statuses})
|
||||
experiences = [
|
||||
variant for (kind, variant, _id) in self.productivity if kind == "experience"
|
||||
]
|
||||
facts = [variant for (kind, variant, _id) in self.productivity if kind == "fact"]
|
||||
scenes = {"chat": {"count": len(self.chat)}}
|
||||
for variant in ("coding", "working"):
|
||||
scenes[variant] = {"count": experiences.count(variant), "facts": facts.count(variant)}
|
||||
return {
|
||||
"total": len(self.chat) + len(experiences),
|
||||
"scenes": scenes,
|
||||
"request_id": "stats",
|
||||
"elapsed_ms": 1.0,
|
||||
}
|
||||
|
||||
def get(self, memory_id, kind=None, variant=None):
|
||||
self.get_calls.append((memory_id, kind, variant))
|
||||
match = self._matches(memory_id, kind, variant)
|
||||
@@ -647,3 +664,33 @@ def test_scene_filter_narrows_search_and_binds_the_window(tmp_path, monkeypatch)
|
||||
assert len(sdk.search_calls) == 2
|
||||
|
||||
run_with_sdk(tmp_path, monkeypatch, scenario)
|
||||
|
||||
|
||||
@pytest.mark.fresh_sdk
|
||||
def test_home_summary_counts_what_the_memory_page_lists(tmp_path, monkeypatch):
|
||||
"""Home showed 55 (chat only) while the memory page showed 94."""
|
||||
|
||||
async def scenario(app, sdk, client):
|
||||
sdk.add_chat(chat_row("chat-1", "cursor chat"))
|
||||
sdk.add_chat(chat_row("chat-2", "codebuddy chat", source="codebuddy"))
|
||||
sdk.add_productivity("experience", experience_row("exp-w", "task w", "solution w"))
|
||||
sdk.add_productivity(
|
||||
"experience", experience_row("exp-c", "task c", "solution c", variant="coding")
|
||||
)
|
||||
# Facts are not listed on the memory page, so they are not counted.
|
||||
sdk.add_productivity("fact", fact_row("fact-1", "The pytest suite runs in CI"))
|
||||
|
||||
response = await client.get("/api/v2/home-summary")
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
library = (await client.get("/api/v2/memory-library")).json()
|
||||
assert body["memory_count"] == library["total"] == 4
|
||||
assert sdk.stats_calls == [{"user_id": "local", "statuses": ["active"]}]
|
||||
# The newest memory across scenes, not the newest chat memory.
|
||||
home_list = sdk.list_calls[0]
|
||||
assert home_list["scene"] == "all"
|
||||
assert (home_list["offset"], home_list["limit"], home_list["order"]) == (0, 1, "desc")
|
||||
assert body["latest"]["memory_id"] == "exp-w"
|
||||
assert body["latest"]["scene"] == "working"
|
||||
|
||||
run_with_sdk(tmp_path, monkeypatch, scenario)
|
||||
Reference in new issue
Block a user