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:
alvinfeiandClaude Opus 5.5 committed 2026-10-27 23:33:19 +08:00
1 parent dd3809a34b
commit 423cb00dbf
2 files changed
+62 -1

No files matched your search

+15 -1
View File
@@ -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)