Add memory management APIs for OpenViking: list, read, write, and delete memories
This commit is contained in:
@ -68,8 +68,8 @@ class FakeAsyncClient:
|
||||
self.calls.append(("post", self.api_key, self.headers, path, json, files))
|
||||
return self.responses.pop(0)
|
||||
|
||||
async def get(self, path: str) -> FakeResponse:
|
||||
self.calls.append(("get", self.api_key, self.headers, path, None))
|
||||
async def get(self, path: str, params: dict | None = None) -> FakeResponse:
|
||||
self.calls.append(("get", self.api_key, self.headers, path, params))
|
||||
return self.responses.pop(0)
|
||||
|
||||
async def delete(self, path: str, params: dict | None = None) -> FakeResponse:
|
||||
@ -573,6 +573,135 @@ def test_openviking_delete_resource_sends_uri_and_recursive_flag():
|
||||
]
|
||||
|
||||
|
||||
def test_openviking_list_memories_calls_fs_ls_with_recursive_flag():
|
||||
client = OpenVikingMemorySystemClient(store=FakeStore())
|
||||
calls = []
|
||||
responses = [FakeResponse(200, {"status": "ok", "result": {"children": []}})]
|
||||
client._client = lambda api_key, extra_headers=None, json_content_type=True: FakeAsyncClient( # type: ignore[method-assign]
|
||||
calls,
|
||||
responses,
|
||||
api_key,
|
||||
extra_headers or {},
|
||||
)
|
||||
credential = client.user_credential("tom-key", "tom")
|
||||
|
||||
result = asyncio.run(
|
||||
client.list_memories(
|
||||
credential,
|
||||
uri="viking://user/memories",
|
||||
recursive=True,
|
||||
)
|
||||
)
|
||||
|
||||
assert result == {"status": "ok", "result": {"children": []}}
|
||||
assert calls == [
|
||||
(
|
||||
"get",
|
||||
"tom-key",
|
||||
{},
|
||||
"/api/v1/fs/ls",
|
||||
{"uri": "viking://user/memories", "recursive": "true"},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_openviking_read_memory_calls_content_read():
|
||||
client = OpenVikingMemorySystemClient(store=FakeStore())
|
||||
calls = []
|
||||
responses = [FakeResponse(200, {"status": "ok", "result": {"content": "# Python"}})]
|
||||
client._client = lambda api_key, extra_headers=None, json_content_type=True: FakeAsyncClient( # type: ignore[method-assign]
|
||||
calls,
|
||||
responses,
|
||||
api_key,
|
||||
extra_headers or {},
|
||||
)
|
||||
credential = client.user_credential("tom-key", "tom")
|
||||
|
||||
result = asyncio.run(client.read_memory(credential, "viking://user/memories/preferences/python.md"))
|
||||
|
||||
assert result == {"status": "ok", "result": {"content": "# Python"}}
|
||||
assert calls == [
|
||||
(
|
||||
"get",
|
||||
"tom-key",
|
||||
{},
|
||||
"/api/v1/content/read",
|
||||
{"uri": "viking://user/memories/preferences/python.md"},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_openviking_write_memory_posts_content_write_mode_and_wait():
|
||||
client = OpenVikingMemorySystemClient(store=FakeStore())
|
||||
calls = []
|
||||
responses = [FakeResponse(200, {"status": "ok", "result": {"uri": "viking://user/memories/profile.md"}})]
|
||||
client._client = lambda api_key, extra_headers=None, json_content_type=True: FakeAsyncClient( # type: ignore[method-assign]
|
||||
calls,
|
||||
responses,
|
||||
api_key,
|
||||
extra_headers or {},
|
||||
)
|
||||
credential = client.user_credential("tom-key", "tom")
|
||||
|
||||
result = asyncio.run(
|
||||
client.write_memory(
|
||||
credential,
|
||||
uri="viking://user/memories/profile.md",
|
||||
content="# Profile\n\nLikes Python.",
|
||||
mode="replace",
|
||||
wait=True,
|
||||
)
|
||||
)
|
||||
|
||||
assert result == {"status": "ok", "result": {"uri": "viking://user/memories/profile.md"}}
|
||||
assert calls == [
|
||||
(
|
||||
"post",
|
||||
"tom-key",
|
||||
{},
|
||||
"/api/v1/content/write",
|
||||
{
|
||||
"uri": "viking://user/memories/profile.md",
|
||||
"content": "# Profile\n\nLikes Python.",
|
||||
"mode": "replace",
|
||||
"wait": True,
|
||||
},
|
||||
None,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_openviking_delete_memory_defaults_non_recursive():
|
||||
client = OpenVikingMemorySystemClient(store=FakeStore())
|
||||
calls = []
|
||||
responses = [FakeResponse(200, {"status": "ok", "result": {"estimated_deleted_count": 1}})]
|
||||
client._client = lambda api_key, extra_headers=None, json_content_type=True: FakeAsyncClient( # type: ignore[method-assign]
|
||||
calls,
|
||||
responses,
|
||||
api_key,
|
||||
extra_headers or {},
|
||||
)
|
||||
credential = client.user_credential("tom-key", "tom")
|
||||
|
||||
result = asyncio.run(
|
||||
client.delete_memory(
|
||||
credential,
|
||||
uri="viking://user/memories/preferences/python.md",
|
||||
)
|
||||
)
|
||||
|
||||
assert result == {"status": "ok", "result": {"estimated_deleted_count": 1}}
|
||||
assert calls == [
|
||||
(
|
||||
"delete",
|
||||
"tom-key",
|
||||
{},
|
||||
"/api/v1/fs",
|
||||
{"uri": "viking://user/memories/preferences/python.md", "recursive": "false"},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_everos_assistant_payload_does_not_use_user_id_as_sender():
|
||||
client = EverOSMemorySystemClient()
|
||||
|
||||
|
||||
@ -14,6 +14,8 @@ def test_memory_system_server_exposes_routes():
|
||||
assert {"GET", "POST"} <= context_methods
|
||||
assert "/memory-system/search" in paths
|
||||
assert "/memory-system/resources" in paths
|
||||
assert "/memory-system/memories" in paths
|
||||
assert "/memory-system/memories/content" in paths
|
||||
assert "/memory-system/users/{user_id}/profile" in paths
|
||||
task_methods = {
|
||||
method
|
||||
@ -36,6 +38,20 @@ def test_memory_system_server_exposes_routes():
|
||||
for method in getattr(route, "methods", set())
|
||||
}
|
||||
assert {"DELETE", "POST"} <= resource_methods
|
||||
memory_methods = {
|
||||
method
|
||||
for route in app.routes
|
||||
if getattr(route, "path", "") == "/memory-system/memories"
|
||||
for method in getattr(route, "methods", set())
|
||||
}
|
||||
memory_content_methods = {
|
||||
method
|
||||
for route in app.routes
|
||||
if getattr(route, "path", "") == "/memory-system/memories/content"
|
||||
for method in getattr(route, "methods", set())
|
||||
}
|
||||
assert {"DELETE", "GET", "POST"} <= memory_methods
|
||||
assert {"GET"} <= memory_content_methods
|
||||
|
||||
|
||||
def test_memory_system_messages_does_not_require_account_key_header():
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
import asyncio
|
||||
|
||||
from memory_system_api.schemas import MessageIngestRequest, ResourceUploadRequest, SearchRequest, SessionContextRequest
|
||||
from memory_system_api.schemas import (
|
||||
MemoryWriteRequest,
|
||||
MessageIngestRequest,
|
||||
ResourceUploadRequest,
|
||||
SearchRequest,
|
||||
SessionContextRequest,
|
||||
)
|
||||
from memory_system_api.service import MemorySystemService
|
||||
|
||||
|
||||
@ -120,6 +126,22 @@ class FakeOpenViking:
|
||||
self.calls.append(("delete_resource", user_key, uri, recursive))
|
||||
return {"status": "ok", "result": {"uri": uri, "estimated_deleted_count": 4}}
|
||||
|
||||
async def list_memories(self, user_key: str, uri: str, recursive: bool = True) -> dict:
|
||||
self.calls.append(("list_memories", user_key, uri, recursive))
|
||||
return {"status": "ok", "result": {"children": [{"uri": "viking://user/memories/profile.md"}]}}
|
||||
|
||||
async def read_memory(self, user_key: str, uri: str) -> dict:
|
||||
self.calls.append(("read_memory", user_key, uri))
|
||||
return {"status": "ok", "result": {"uri": uri, "content": "# Profile"}}
|
||||
|
||||
async def write_memory(self, user_key: str, uri: str, content: str, mode: str, wait: bool = True) -> dict:
|
||||
self.calls.append(("write_memory", user_key, uri, content, mode, wait))
|
||||
return {"status": "ok", "result": {"uri": uri, "mode": mode}}
|
||||
|
||||
async def delete_memory(self, user_key: str, uri: str, recursive: bool = False) -> dict:
|
||||
self.calls.append(("delete_memory", user_key, uri, recursive))
|
||||
return {"status": "ok", "result": {"uri": uri, "estimated_deleted_count": 1}}
|
||||
|
||||
|
||||
class FakeEverOS:
|
||||
def __init__(self, fail_on_append: bool = False):
|
||||
@ -334,6 +356,93 @@ def test_delete_resource_delegates_to_openviking_only():
|
||||
assert everos.calls == []
|
||||
|
||||
|
||||
def test_list_memories_delegates_to_openviking_only():
|
||||
openviking = FakeOpenViking()
|
||||
everos = FakeEverOS()
|
||||
service = MemorySystemService(openviking=openviking, everos=everos)
|
||||
|
||||
response = asyncio.run(service.list_memories(
|
||||
user_id="tom",
|
||||
user_key="tom-key",
|
||||
uri="viking://user/memories",
|
||||
recursive=True,
|
||||
))
|
||||
|
||||
assert response.status == "success"
|
||||
assert response.memory == {"status": "ok", "result": {"children": [{"uri": "viking://user/memories/profile.md"}]}}
|
||||
assert openviking.calls == [
|
||||
("credential_for_user", "tom", "tom-key", None),
|
||||
("list_memories", "key-tom", "viking://user/memories", True),
|
||||
]
|
||||
assert everos.calls == []
|
||||
|
||||
|
||||
def test_read_memory_delegates_to_openviking_only():
|
||||
openviking = FakeOpenViking()
|
||||
everos = FakeEverOS()
|
||||
service = MemorySystemService(openviking=openviking, everos=everos)
|
||||
|
||||
response = asyncio.run(service.read_memory(
|
||||
user_id="tom",
|
||||
user_key="tom-key",
|
||||
uri="viking://user/memories/profile.md",
|
||||
))
|
||||
|
||||
assert response.status == "success"
|
||||
assert response.memory == {"status": "ok", "result": {"uri": "viking://user/memories/profile.md", "content": "# Profile"}}
|
||||
assert openviking.calls == [
|
||||
("credential_for_user", "tom", "tom-key", None),
|
||||
("read_memory", "key-tom", "viking://user/memories/profile.md"),
|
||||
]
|
||||
assert everos.calls == []
|
||||
|
||||
|
||||
def test_write_memory_delegates_to_openviking_content_write_only():
|
||||
openviking = FakeOpenViking()
|
||||
everos = FakeEverOS()
|
||||
service = MemorySystemService(openviking=openviking, everos=everos)
|
||||
|
||||
response = asyncio.run(service.write_memory(MemoryWriteRequest(
|
||||
user_id="tom",
|
||||
user_key="tom-key",
|
||||
uri="viking://user/memories/profile.md",
|
||||
content="# Profile\n\nLikes Python.",
|
||||
mode="replace",
|
||||
wait=True,
|
||||
)))
|
||||
|
||||
assert response.status == "success"
|
||||
assert response.memory == {"status": "ok", "result": {"uri": "viking://user/memories/profile.md", "mode": "replace"}}
|
||||
assert openviking.calls == [
|
||||
("credential_for_user", "tom", "tom-key", None),
|
||||
("write_memory", "key-tom", "viking://user/memories/profile.md", "# Profile\n\nLikes Python.", "replace", True),
|
||||
]
|
||||
assert everos.calls == []
|
||||
|
||||
|
||||
def test_delete_memory_delegates_to_openviking_only_and_defaults_non_recursive():
|
||||
openviking = FakeOpenViking()
|
||||
everos = FakeEverOS()
|
||||
service = MemorySystemService(openviking=openviking, everos=everos)
|
||||
|
||||
response = asyncio.run(service.delete_memory(
|
||||
user_id="tom",
|
||||
user_key="tom-key",
|
||||
uri="viking://user/memories/preferences/python.md",
|
||||
))
|
||||
|
||||
assert response.status == "success"
|
||||
assert response.memory == {
|
||||
"status": "ok",
|
||||
"result": {"uri": "viking://user/memories/preferences/python.md", "estimated_deleted_count": 1},
|
||||
}
|
||||
assert openviking.calls == [
|
||||
("credential_for_user", "tom", "tom-key", None),
|
||||
("delete_memory", "key-tom", "viking://user/memories/preferences/python.md", False),
|
||||
]
|
||||
assert everos.calls == []
|
||||
|
||||
|
||||
def test_search_removes_vectors_from_items_and_backend_results():
|
||||
service = MemorySystemService(openviking=FakeOpenViking(), everos=FakeEverOSWithVector())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user