Add memory system session context API

This commit is contained in:
2026-05-26 12:24:56 +08:00
parent d73f59f38d
commit a89807b174
10 changed files with 358 additions and 2 deletions

View File

@ -255,6 +255,49 @@ def test_openviking_search_uses_session_target_uri():
]
def test_openviking_get_session_context_uses_user_key_auth():
client = OpenVikingMemorySystemClient(store=FakeStore())
calls = []
responses = [
FakeResponse(
200,
{
"status": "ok",
"result": {
"latest_archive_overview": "# Working Memory",
"messages": [],
},
},
)
]
client._client = lambda api_key, extra_headers=None: FakeAsyncClient( # type: ignore[method-assign]
calls,
responses,
api_key,
extra_headers or {},
)
credential = client.user_credential("tom-key", "tom", agent_id="sess-1")
result = asyncio.run(client.get_session_context(credential, "sess-1"))
assert result == {
"status": "ok",
"result": {
"latest_archive_overview": "# Working Memory",
"messages": [],
},
}
assert calls == [
(
"get",
"tom-key",
{},
"/api/v1/sessions/sess-1/context",
None,
)
]
def test_openviking_commit_keeps_no_recent_live_messages():
client = OpenVikingMemorySystemClient(store=FakeStore())
calls = []

View File

@ -4,6 +4,14 @@ def test_memory_system_server_exposes_routes():
paths = {route.path for route in app.routes}
assert "/memory-system/users" in paths
assert "/memory-system/messages" in paths
assert "/memory-system/sessions/{session_id}/context" in paths
context_methods = {
method
for route in app.routes
if getattr(route, "path", "") == "/memory-system/sessions/{session_id}/context"
for method in getattr(route, "methods", set())
}
assert {"GET", "POST"} <= context_methods
assert "/memory-system/search" in paths
assert "/memory-system/users/{user_id}/profile" in paths

View File

@ -1,6 +1,6 @@
import asyncio
from memory_system_api.schemas import MessageIngestRequest, SearchRequest
from memory_system_api.schemas import MessageIngestRequest, SearchRequest, SessionContextRequest
from memory_system_api.service import MemorySystemService
@ -44,6 +44,19 @@ class FakeOpenViking:
await asyncio.sleep(0.01)
return {"items": [{"source": "openviking-search"}]}
async def get_session_context(self, user_key: str, session_id: str) -> dict:
self.calls.append(("get_session_context", user_key, session_id))
return {
"status": "ok",
"result": {
"latest_archive_overview": "# Working Memory\nUser likes coffee.",
"pre_archive_abstracts": [],
"messages": [],
"estimatedTokens": 42,
"stats": {"totalArchives": 1},
},
}
async def commit_session(self, user_key: str, session_id: str) -> dict:
self.calls.append(("commit_session", user_key, session_id))
return {"status": "ok", "result": {"task_id": "task-1", "archive_uri": "archive-1"}}
@ -203,6 +216,43 @@ def test_search_returns_compact_items_and_backend_diagnostics_without_duplicate_
assert not _has_key(response.backends["everos"].result, "original_data")
def test_session_context_combines_openviking_context_and_everos_search_items():
openviking = FakeOpenViking()
everos = FakeEverOSVerbose()
service = MemorySystemService(openviking=openviking, everos=everos)
response = asyncio.run(
service.get_session_context(
"sess-1",
SessionContextRequest(user_id="tom", user_key="tom-key", query="我喜欢喝什么?", limit=5),
)
)
assert response.status == "success"
assert response.context == {
"latest_archive_overview": "# Working Memory\nUser likes coffee.",
"pre_archive_abstracts": [],
"messages": [],
"estimatedTokens": 42,
"stats": {"totalArchives": 1},
}
assert response.items == [
{
"source_backend": "everos",
"memory_type": "episode",
"id": "episode-1",
"user_id": "tom",
"session_id": "sess-1",
"timestamp": "2026-05-22T07:50:51.750000Z",
"summary": "userB 在对话中表示自己喜欢拿铁。",
"score": 0.72,
}
]
assert ("credential_for_user", "tom", "tom-key", "sess-1") in openviking.calls
assert ("get_session_context", "key-tom", "sess-1") in openviking.calls
assert ("search", "tom", "sess-1", "我喜欢喝什么?", "hybrid", 5) in everos.calls
def _has_key(value, key: str) -> bool:
if isinstance(value, dict):
return key in value or any(_has_key(item, key) for item in value.values())