Replace EverMemOS with EverOS backend

This commit is contained in:
2026-05-13 17:56:50 +08:00
parent 0acee1ec6c
commit b226749c61
37 changed files with 1327 additions and 1986 deletions

View File

@ -7,7 +7,7 @@ from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
import memory_gateway.api_v2 as api_v2
from memory_gateway.evermemos_client import EverMemOSClient
from memory_gateway.everos_client import EverOSClient
from memory_gateway.openviking_client import OpenVikingClient
from memory_gateway.repositories import InMemoryRepository
from memory_gateway.schemas_v2 import BackendRefStatus, BackendType, IngestRequest, IngestResponse, OperationStatus
@ -28,13 +28,13 @@ def _env(name: str) -> str:
return value
def test_real_openviking_and_evermemos_ingest_writes_memory_refs():
def test_real_openviking_and_everos_ingest_writes_memory_refs():
openviking_base_url = _env("OPENVIKING_BASE_URL")
evermemos_base_url = _env("EVERMEMOS_BASE_URL")
everos_base_url = _env("EVEROS_BASE_URL")
openviking_api_key = os.environ.get("OPENVIKING_API_KEY", "")
evermemos_api_key = os.environ.get("EVERMEMOS_API_KEY", "")
everos_api_key = os.environ.get("EVEROS_API_KEY", "")
openviking_ingest_path = os.environ.get("OPENVIKING_INGEST_PATH")
evermemos_ingest_path = os.environ.get("EVERMEMOS_INGEST_PATH")
everos_ingest_path = os.environ.get("EVEROS_INGEST_PATH")
async def openviking_factory():
return OpenVikingClient(
@ -48,11 +48,11 @@ def test_real_openviking_and_evermemos_ingest_writes_memory_refs():
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=openviking_factory,
evermemos_client=EverMemOSClient(
everos_client=EverOSClient(
mode="real",
base_url=evermemos_base_url,
api_key=evermemos_api_key,
ingest_path=evermemos_ingest_path,
base_url=everos_base_url,
api_key=everos_api_key,
ingest_path=everos_ingest_path,
),
)
run_id = uuid4().hex[:12]
@ -60,20 +60,20 @@ def test_real_openviking_and_evermemos_ingest_writes_memory_refs():
response = asyncio.run(post_ingest(service, run_id))
refs = repo.list_memory_refs(session_id=f"real_ingest_sess_{run_id}", limit=10)
assert {ref.backend_type for ref in refs} == {BackendType.OPENVIKING, BackendType.EVERMEMOS}
assert {ref.backend_type for ref in refs} == {BackendType.OPENVIKING, BackendType.EVEROS}
assert all(ref.content_hash for ref in refs)
openviking_ref = next(ref for ref in refs if ref.backend_type == BackendType.OPENVIKING)
evermemos_ref = next(ref for ref in refs if ref.backend_type == BackendType.EVERMEMOS)
everos_ref = next(ref for ref in refs if ref.backend_type == BackendType.EVEROS)
assert openviking_ref.status == BackendRefStatus.SUCCESS
if evermemos_ref.status == BackendRefStatus.SUCCESS:
if everos_ref.status == BackendRefStatus.SUCCESS:
assert response.status == OperationStatus.SUCCESS
assert evermemos_ref.native_id
assert evermemos_ref.native_uri
assert everos_ref.native_id
assert everos_ref.native_uri
else:
assert evermemos_ref.status == BackendRefStatus.FAILED
assert everos_ref.status == BackendRefStatus.FAILED
assert response.status == OperationStatus.PARTIAL_SUCCESS
assert evermemos_ref.error_message
assert everos_ref.error_message
async def post_ingest(service: MemoryGatewayV2Service, run_id: str):

View File

@ -1,53 +0,0 @@
import asyncio
from memory_gateway.evermemos_service import ConsolidateRequest, consolidate_session
def test_evermemos_service_consolidates_session(monkeypatch, tmp_path):
monkeypatch.setattr(
"memory_gateway.obsidian_review.get_config",
lambda: type(
"Config",
(),
{
"obsidian": type(
"Obsidian",
(),
{"vault_path": str(tmp_path / "vault"), "review_dir": "Reviews/Queue"},
)()
},
)(),
)
payload = {
"session_id": "sess_service",
"context": {"user_id": "user_a", "agent_id": "agent_a", "workspace_id": "ws_a", "session_id": "sess_service"},
"episodes": [
{
"user_id": "user_a",
"agent_id": "agent_a",
"workspace_id": "ws_a",
"session_id": "sess_service",
"namespace": "session/sess_service/episodic",
"content": "结论EverMemOS 本地服务负责整理稳定长期记忆。",
"tags": ["decision"],
},
{
"user_id": "user_a",
"agent_id": "agent_a",
"workspace_id": "ws_a",
"session_id": "sess_service",
"namespace": "session/sess_service/episodic",
"content": "重要:高价值记忆应该进入 Obsidian review queue。",
"tags": ["review", "high-value"],
},
],
}
response = asyncio.run(consolidate_session(ConsolidateRequest.model_validate(payload)))
assert response["status"] == "ok"
result = response["result"]
assert result["episodes"] == 2
assert len(result["candidates"]) == 2
assert len(result["promoted"]) == 1
assert len(result["review_drafts"]) == 1

View File

@ -137,7 +137,7 @@ def test_health_requires_api_key(monkeypatch):
fake_get_openviking_client,
)
monkeypatch.setattr("memory_gateway.server.summarize_with_llm", fake_summarize_with_llm)
monkeypatch.setattr("memory_gateway.server.v1_service.evermemos_health", lambda: {"status": "disabled"})
monkeypatch.setattr("memory_gateway.server.v1_service.everos_health", lambda: {"status": "disabled"})
with pytest.raises(HTTPException) as exc_info:
server.verify_api_key()

View File

@ -11,7 +11,7 @@ from memory_gateway.schemas import (
Visibility,
)
from memory_gateway.services import MemoryGatewayService
from memory_gateway.types import Config, EverMemOSConfig, ObsidianConfig
from memory_gateway.types import Config, EverOSConfig, ObsidianConfig
def test_private_memory_is_isolated_by_user():
@ -67,10 +67,10 @@ def test_sqlite_repository_persists_memory(tmp_path):
assert reloaded.content == "持久化 SQLite memory"
def test_commit_session_promotes_dedupes_and_creates_review_draft(monkeypatch, tmp_path):
def test_commit_session_disabled_does_not_use_local_fallback(monkeypatch, tmp_path):
monkeypatch.setattr(
"memory_gateway.services.get_config",
lambda: Config(evermemos=EverMemOSConfig(enabled=False)),
lambda: Config(everos=EverOSConfig(enabled=False)),
)
monkeypatch.setattr(
"memory_gateway.obsidian_review.get_config",
@ -103,29 +103,27 @@ def test_commit_session_promotes_dedupes_and_creates_review_draft(monkeypatch, t
),
)
assert len(result["promoted"]) == 1
assert result["evermemos_backend"] == "local-disabled"
assert len(result["review_drafts"]) == 1
assert (tmp_path / "vault" / "Reviews" / "Queue").exists()
assert result["promoted"] == []
assert result["everos_backend"] == "disabled"
def test_commit_session_uses_external_evermemos(monkeypatch):
def test_commit_session_uses_external_everos(monkeypatch):
monkeypatch.setattr(
"memory_gateway.services.get_config",
lambda: Config(evermemos=EverMemOSConfig(enabled=True, fallback_to_local=False)),
lambda: Config(everos=EverOSConfig(enabled=True)),
)
class FakeEverMemOSClient:
class FakeEverOSClient:
def consolidate_session(self, **kwargs):
return {
"episodes": 1,
"candidates": [],
"promoted": [
{
"content": "外部 EverMemOS 总结出的长期记忆",
"summary": "外部 EverMemOS 长期记忆",
"content": "外部 EverOS 总结出的长期记忆",
"summary": "外部 EverOS 长期记忆",
"memory_type": "summary",
"tags": ["external-evermemos"],
"tags": ["external-everos"],
}
],
"duplicates": [],
@ -136,12 +134,12 @@ def test_commit_session_uses_external_evermemos(monkeypatch):
def health(self):
return {"status": "ok"}
service = MemoryGatewayService(InMemoryRepository(), evermemos_client=FakeEverMemOSClient())
service = MemoryGatewayService(InMemoryRepository(), everos_client=FakeEverOSClient())
service.append_episode(
EpisodeAppendRequest(
user_id="user_a",
session_id="sess_external",
content="这条 episode 应该交给外部 EverMemOS。",
content="这条 episode 应该交给外部 EverOS。",
)
)
result = service.commit_session(
@ -149,9 +147,9 @@ def test_commit_session_uses_external_evermemos(monkeypatch):
CommitSessionRequest(user_id="user_a", session_id="sess_external"),
)
assert result["evermemos_backend"] == "external"
assert result["everos_backend"] == "external"
assert len(result["promoted"]) == 1
search = service.search_memory(MemorySearchRequest(user_id="user_a", query="外部 EverMemOS"))
search = service.search_memory(MemorySearchRequest(user_id="user_a", query="外部 EverOS"))
assert search["total"] == 1

View File

@ -16,9 +16,9 @@ from memory_gateway.backend_adapter_mapping import (
)
from memory_gateway.backend_normalization import (
map_backend_error_to_retryable,
normalize_evermemos_commit_response,
normalize_evermemos_ingest_response,
normalize_evermemos_retrieve_response,
normalize_everos_commit_response,
normalize_everos_ingest_response,
normalize_everos_retrieve_response,
normalize_openviking_commit_response,
normalize_openviking_ingest_response,
normalize_openviking_retrieve_response,
@ -27,13 +27,14 @@ from memory_gateway.backend_contracts import (
BackendCommitResult,
BackendOperation,
BackendProducedRef,
BackendRetrieveItem,
BackendResultStatus,
BackendRetrieveResult,
BackendWriteResult,
OutboxEventStatus,
)
from memory_gateway.backend_ref_mapping import map_backend_ref_type
from memory_gateway.evermemos_client import EverMemOSClient
from memory_gateway.everos_client import EverOSClient
from memory_gateway.obsidian_review_client import ObsidianReviewClient
from memory_gateway.openviking_client import OpenVikingClient
from memory_gateway.repositories import InMemoryRepository, SQLiteRepository
@ -51,12 +52,75 @@ from memory_gateway.server_auth import verify_api_key_compat
from memory_gateway.services_v2 import MemoryGatewayV2Service
FIXTURE_DIR = Path(__file__).parent / "fixtures" / "backend_responses"
DOCS_DIR = Path(__file__).parent.parent / "docs"
def load_backend_fixture(name: str):
return json.loads((FIXTURE_DIR / name).read_text())
def backend_response(name: str):
responses = {
"openviking_ingest_success.json": {
"status": "created",
"id": "ov_turn_fixture_1",
"uri": "viking://sessions/sess_fixture/turns/ov_turn_fixture_1",
"metadata": {"schema_version": "openviking.fixture.ingest.v2", "conversation": "SECRET"},
},
"openviking_ingest_real_success.json": {
"status": "created",
"id": "ov_real_turn_fixture_1",
"uri": "viking://sessions/ov_real_sess_fixture_1/turns/ov_real_turn_fixture_1",
"metadata": {"backend_request_id": "ov_req_real_1", "content": "SECRET"},
},
"openviking_ingest_real_error_401.json": {"status": "failed", "error": "unauthorized", "error_code": "unauthorized"},
"openviking_ingest_real_error_422.json": {"status": "failed", "error": "validation failed", "error_code": "validation_error"},
"openviking_ingest_real_error_500.json": {"status": "failed", "error": "server error", "error_code": "server_error"},
"openviking_commit_success.json": {
"status": "ok",
"session_id": "sess_fixture",
"result": {
"refs": [
{"type": "session_archive", "id": "ov_archive_fixture_1"},
{"type": "context_resource", "id": "ov_resource_fixture_1"},
]
},
"metadata": {"schema_version": "openviking.fixture.commit.v2", "messages": ["SECRET"]},
},
"openviking_retrieve_success.json": {
"status": "ok",
"result": {
"items": [
{"text": "Relevant session summary", "id": "ov_archive_fixture_1", "score": 0.91, "type": "session_archive"},
{"text": "Relevant resource", "id": "ov_resource_fixture_1", "score": 0.84, "type": "context_resource"},
]
},
"metadata": {"schema_version": "openviking.fixture.retrieve.v2", "transcript": "SECRET"},
},
"everos_ingest_success.json": {
"status": "success",
"memory_id": "em_memory_fixture_1",
"metadata": {"schema_version": "everos.fixture.ingest.v2", "transcript": "SECRET"},
},
"everos_commit_success_multiple_refs.json": {
"status": "success",
"data": {
"produced_refs": [
{"ref_type": "episodic_memory", "memory_id": "em_episode_fixture_1"},
{"ref_type": "profile", "profile_id": "em_profile_fixture_1"},
{"ref_type": "unknown_kind", "id": "em_long_fixture_1"},
]
},
"metadata": {"schema_version": "everos.fixture.commit.v2", "messages": ["SECRET"]},
},
"everos_retrieve_success.json": {
"status": "success",
"data": {
"items": [
{"text": "Relevant episodic memory", "memory_id": "em_episode_fixture_1", "score": 0.88, "memory_type": "episodic_memory"},
{"text": "Relevant profile", "profile_id": "em_profile_fixture_1", "score": 0.73, "memory_type": "profile"},
]
},
"metadata": {"schema_version": "everos.fixture.retrieve.v2", "conversation": "SECRET"},
},
}
return responses[name]
def build_ingest_payload(**overrides):
@ -86,23 +150,53 @@ class FakeOpenVikingClient:
"native_uri": f"viking://sessions/{payload['session_id']}/{payload['turn_id']}",
}
async def retrieve_context_v2(self, payload):
return BackendRetrieveResult(
backend_type=BackendType.OPENVIKING,
status=BackendResultStatus.SUCCESS,
items=[
BackendRetrieveItem(
text="OpenViking context for remember",
source_backend=BackendType.OPENVIKING,
ref_id="ov_ctx_1",
score=0.82,
memory_type="context_resource",
)
],
)
async def fake_openviking_factory():
return FakeOpenVikingClient()
class FakeEverMemOSClient:
class FakeEverOSClient:
def ingest_message(self, payload):
return {
"status": "success",
"native_id": f"em_{payload['turn_id']}",
"native_uri": f"evermemos://memories/{payload['turn_id']}",
"native_uri": f"everos://memories/{payload['turn_id']}",
}
def retrieve_context_v2(self, payload):
return BackendRetrieveResult(
backend_type=BackendType.EVEROS,
status=BackendResultStatus.SUCCESS,
items=[
BackendRetrieveItem(
text="EverOS memory for remember",
source_backend=BackendType.EVEROS,
ref_id="em_ctx_1",
score=0.91,
memory_type="episodic_memory",
)
],
)
class FailingEverMemOSClient:
class FailingEverOSClient:
def ingest_message(self, payload):
raise RuntimeError("evermemos unavailable")
raise RuntimeError("everos unavailable")
class FakeCommitOpenVikingClient:
@ -120,7 +214,7 @@ def fake_commit_openviking_factory(result: BackendCommitResult):
return factory
class FakeCommitEverMemOSClient:
class FakeCommitEverOSClient:
def __init__(self, result: BackendCommitResult) -> None:
self.result = result
@ -149,7 +243,7 @@ def commit_result(
def test_v2_adapters_return_backend_write_result_contract():
ov_result = asyncio.run(
OpenVikingClient().ingest_conversation_turn(
OpenVikingClient(mode="offline").ingest_conversation_turn(
{
"workspace_id": "ws_1",
"session_id": "sess_1",
@ -157,7 +251,7 @@ def test_v2_adapters_return_backend_write_result_contract():
}
)
)
em_result = EverMemOSClient().ingest_message(
em_result = EverOSClient(mode="offline").ingest_message(
{
"workspace_id": "ws_1",
"session_id": "sess_1",
@ -168,7 +262,7 @@ def test_v2_adapters_return_backend_write_result_contract():
assert isinstance(ov_result, BackendWriteResult)
assert isinstance(em_result, BackendWriteResult)
assert ov_result.backend_type == BackendType.OPENVIKING
assert em_result.backend_type == BackendType.EVERMEMOS
assert em_result.backend_type == BackendType.EVEROS
assert ov_result.operation == BackendOperation.INGEST_TURN
assert em_result.operation == BackendOperation.INGEST_TURN
assert ov_result.status == BackendResultStatus.SKIPPED
@ -180,10 +274,10 @@ def test_backend_env_overrides_enable_real_modes(monkeypatch, tmp_path):
monkeypatch.setenv("OPENVIKING_BASE_URL", "http://openviking.env.test")
monkeypatch.setenv("OPENVIKING_API_KEY", "ov-env-token")
monkeypatch.setenv("OPENVIKING_TIMEOUT_SECONDS", "17")
monkeypatch.setenv("EVERMEMOS_MODE", "real")
monkeypatch.setenv("EVERMEMOS_BASE_URL", "http://evermemos.env.test")
monkeypatch.setenv("EVERMEMOS_API_KEY", "em-env-token")
monkeypatch.setenv("EVERMEMOS_INGEST_PATH", "/api/v1/memories")
monkeypatch.setenv("EVEROS_MODE", "real")
monkeypatch.setenv("EVEROS_BASE_URL", "http://everos.env.test")
monkeypatch.setenv("EVEROS_API_KEY", "em-env-token")
monkeypatch.setenv("EVEROS_INGEST_PATH", "/api/v1/memories")
config = load_config(str(tmp_path / "missing.yaml"))
@ -191,10 +285,10 @@ def test_backend_env_overrides_enable_real_modes(monkeypatch, tmp_path):
assert config.openviking.url == "http://openviking.env.test"
assert config.openviking.api_key == "ov-env-token"
assert config.openviking.timeout == 17
assert config.evermemos.mode == "real"
assert config.evermemos.url == "http://evermemos.env.test"
assert config.evermemos.api_key == "em-env-token"
assert config.evermemos.ingest_path == "/api/v1/memories"
assert config.everos.mode == "real"
assert config.everos.url == "http://everos.env.test"
assert config.everos.api_key == "em-env-token"
assert config.everos.ingest_path == "/api/v1/memories"
def test_openviking_default_ingest_does_not_touch_network():
@ -202,6 +296,7 @@ def test_openviking_default_ingest_does_not_touch_network():
raise AssertionError("offline OpenViking ingest should not perform HTTP")
client = OpenVikingClient(
mode="offline",
base_url="http://openviking.test",
transport=httpx.MockTransport(handler),
)
@ -263,7 +358,7 @@ def test_openviking_mode_real_with_base_url_uses_mock_http():
def handler(request):
calls["count"] += 1
return httpx.Response(200, json=load_backend_fixture("openviking_ingest_real_success.json"))
return httpx.Response(200, json=backend_response("openviking_ingest_real_success.json"))
client = OpenVikingClient(
mode="real",
@ -312,7 +407,7 @@ def test_openviking_real_ingest_mode_real_without_base_url_returns_config_error(
def test_openviking_real_ingest_success_uses_mock_http_and_normalization():
seen_payload = {}
seen_headers = {}
fixture = load_backend_fixture("openviking_ingest_real_success.json")
fixture = backend_response("openviking_ingest_real_success.json")
def handler(request):
seen_payload.update(json.loads(request.content.decode()))
@ -375,7 +470,7 @@ def test_openviking_real_ingest_http_retryable_and_nonretryable_statuses():
mode="real",
base_url="http://openviking.test",
api_key="super-secret-token",
transport=httpx.MockTransport(lambda request: httpx.Response(status_code, json=load_backend_fixture(name))),
transport=httpx.MockTransport(lambda request: httpx.Response(status_code, json=backend_response(name))),
)
result_429 = asyncio.run(client_for_fixture("openviking_ingest_real_error_500.json", 429).ingest_conversation_turn({"session_id": "sess_http"}))
@ -415,14 +510,14 @@ def test_openviking_real_ingest_invalid_json_returns_failed_retryable():
assert "SECRET_JSON" not in json.dumps(result.model_dump(mode="json"), ensure_ascii=False)
def test_evermemos_default_ingest_does_not_touch_network_even_if_enabled():
def test_everos_default_ingest_does_not_touch_network_even_if_enabled():
def handler(request):
raise AssertionError("EverMemOS ingest should not perform HTTP unless mode=real")
raise AssertionError("EverOS ingest should not perform HTTP unless mode=real")
client = EverMemOSClient(
client = EverOSClient(
enabled=True,
mode="offline",
base_url="http://evermemos.test",
base_url="http://everos.test",
transport=httpx.MockTransport(handler),
)
@ -431,8 +526,8 @@ def test_evermemos_default_ingest_does_not_touch_network_even_if_enabled():
assert result.status == BackendResultStatus.SKIPPED
def test_evermemos_real_ingest_mode_real_without_base_url_returns_config_error():
client = EverMemOSClient(mode="real", base_url="")
def test_everos_real_ingest_mode_real_without_base_url_returns_config_error():
client = EverOSClient(mode="real", base_url="")
result = client.ingest_message({"session_id": "sess_missing_url", "content": "SECRET"})
@ -442,19 +537,19 @@ def test_evermemos_real_ingest_mode_real_without_base_url_returns_config_error()
assert "SECRET" not in json.dumps(result.model_dump(mode="json"), ensure_ascii=False)
def test_evermemos_real_ingest_success_uses_mock_http_and_normalization():
def test_everos_real_ingest_success_uses_mock_http_and_normalization():
seen_payload = {}
seen_headers = {}
fixture = load_backend_fixture("evermemos_ingest_success.json")
fixture = backend_response("everos_ingest_success.json")
def handler(request):
seen_payload.update(json.loads(request.content.decode()))
seen_headers.update(dict(request.headers))
return httpx.Response(200, json=fixture)
client = EverMemOSClient(
client = EverOSClient(
mode="real",
base_url="http://evermemos.test",
base_url="http://everos.test",
api_key="em-token",
transport=httpx.MockTransport(handler),
)
@ -472,9 +567,9 @@ def test_evermemos_real_ingest_success_uses_mock_http_and_normalization():
"metadata": {"channel": "test"},
}
)
expected = normalize_evermemos_ingest_response(fixture)
expected = normalize_everos_ingest_response(fixture)
assert seen_payload["content"] == "SECRET_EM_CONTENT"
assert seen_payload["messages"][0]["content"] == "SECRET_EM_CONTENT"
assert seen_headers["x-api-key"] == "em-token"
assert seen_headers["authorization"] == "Bearer em-token"
assert result == expected
@ -484,11 +579,11 @@ def test_evermemos_real_ingest_success_uses_mock_http_and_normalization():
assert "em-token" not in serialized
def test_evermemos_real_ingest_errors_are_backend_write_results_and_safe():
def test_everos_real_ingest_errors_are_backend_write_results_and_safe():
def client_for_response(status_code, body=None, content=None):
return EverMemOSClient(
return EverOSClient(
mode="real",
base_url="http://evermemos.test",
base_url="http://everos.test",
api_key="em-super-secret-token",
transport=httpx.MockTransport(lambda request: httpx.Response(status_code, json=body, content=content)),
)
@ -517,13 +612,13 @@ def test_evermemos_real_ingest_errors_are_backend_write_results_and_safe():
assert "em-super-secret-token" not in serialized
def test_evermemos_real_ingest_timeout_is_retryable_and_safe():
def test_everos_real_ingest_timeout_is_retryable_and_safe():
def handler(request):
raise httpx.ReadTimeout("timeout while sending SECRET_TIMEOUT_CONTENT")
client = EverMemOSClient(
client = EverOSClient(
mode="real",
base_url="http://evermemos.test",
base_url="http://everos.test",
transport=httpx.MockTransport(handler),
)
@ -540,9 +635,9 @@ def test_backend_adapter_mapping_spec_is_contract_first_and_control_plane_only()
(BackendType.OPENVIKING, BackendOperation.INGEST_TURN),
(BackendType.OPENVIKING, BackendOperation.COMMIT_SESSION),
(BackendType.OPENVIKING, BackendOperation.RETRIEVE_CONTEXT),
(BackendType.EVERMEMOS, BackendOperation.INGEST_TURN),
(BackendType.EVERMEMOS, BackendOperation.COMMIT_SESSION),
(BackendType.EVERMEMOS, BackendOperation.RETRIEVE_CONTEXT),
(BackendType.EVEROS, BackendOperation.INGEST_TURN),
(BackendType.EVEROS, BackendOperation.COMMIT_SESSION),
(BackendType.EVEROS, BackendOperation.RETRIEVE_CONTEXT),
(BackendType.OBSIDIAN, BackendOperation.CREATE_REVIEW_DRAFT),
}
@ -551,12 +646,12 @@ def test_backend_adapter_mapping_spec_is_contract_first_and_control_plane_only()
assert not DISALLOWED_PAYLOAD_FIELDS.intersection(spec.allowed_payload_fields)
openviking_commit = get_adapter_mapping_spec(BackendType.OPENVIKING, BackendOperation.COMMIT_SESSION)
evermemos_ingest = get_adapter_mapping_spec(BackendType.EVERMEMOS, BackendOperation.INGEST_TURN)
everos_ingest = get_adapter_mapping_spec(BackendType.EVEROS, BackendOperation.INGEST_TURN)
assert openviking_commit.adapter_method == "commit_session_v2"
assert openviking_commit.result_model is BackendCommitResult
assert evermemos_ingest.adapter_method == "ingest_message"
assert evermemos_ingest.result_model is BackendWriteResult
assert everos_ingest.adapter_method == "ingest_message"
assert everos_ingest.result_model is BackendWriteResult
def test_control_plane_persisted_payload_validator_rejects_content_and_raw_request():
@ -590,26 +685,18 @@ def test_runtime_adapter_request_may_be_transient_but_outbox_payload_is_control_
validate_control_plane_persisted_payload(outbox_payload)
def test_commit_and_retrieve_adapter_skeletons_return_unified_contracts():
def test_commit_adapter_skeletons_return_unified_contracts():
payload = {"workspace_id": "ws_1", "session_id": "sess_1", "gateway_id": "gw_1"}
ov_commit = asyncio.run(OpenVikingClient().commit_session_v2(payload))
ov_retrieve = asyncio.run(OpenVikingClient().retrieve_context_v2(payload))
em_commit = EverMemOSClient().extract_profile_long_term_v2(payload)
em_retrieve = EverMemOSClient().retrieve_context_v2(payload)
ov_commit = asyncio.run(OpenVikingClient(mode="skeleton").commit_session_v2(payload))
em_commit = EverOSClient(mode="skeleton").extract_profile_long_term_v2(payload)
assert isinstance(ov_commit, BackendCommitResult)
assert isinstance(em_commit, BackendCommitResult)
assert isinstance(ov_retrieve, BackendRetrieveResult)
assert isinstance(em_retrieve, BackendRetrieveResult)
assert ov_commit.status == BackendResultStatus.SUCCESS
assert em_commit.status == BackendResultStatus.SUCCESS
assert ov_retrieve.status == BackendResultStatus.SUCCESS
assert em_retrieve.status == BackendResultStatus.SUCCESS
assert ov_commit.refs[0].ref_type == MemoryRefType.SESSION_ARCHIVE
assert {ref.ref_type for ref in em_commit.refs} == {MemoryRefType.PROFILE, MemoryRefType.LONG_TERM_MEMORY}
assert len(ov_retrieve.items) == 1
assert len(em_retrieve.items) == 2
def test_client_skeletons_use_normalization_contracts_and_safe_metadata():
@ -621,8 +708,8 @@ def test_client_skeletons_use_normalization_contracts_and_safe_metadata():
"content": "TRANSIENT_CONTENT_ONLY",
"raw_request": {"content": "TRANSIENT_CONTENT_ONLY"},
}
ov_client = OpenVikingClient()
em_client = EverMemOSClient()
ov_client = OpenVikingClient(mode="skeleton")
em_client = EverOSClient(mode="skeleton")
ov_ingest = asyncio.run(ov_client.ingest_conversation_turn(payload))
ov_commit = asyncio.run(ov_client.commit_session_v2(payload))
@ -649,8 +736,8 @@ def test_client_skeletons_use_normalization_contracts_and_safe_metadata():
"status": "skipped",
"memory_id": "turn_contract",
"metadata": {
"reason": "evermemos_v2_ingest_adapter_not_configured",
"schema_version": "evermemos.fixture.ingest.v2",
"reason": "everos_v2_ingest_adapter_not_configured",
"schema_version": "everos.fixture.ingest.v2",
},
}
)
@ -667,57 +754,30 @@ def test_client_skeletons_use_normalization_contracts_and_safe_metadata():
assert blocked not in serialized
def test_retrieve_skeletons_use_retrieve_normalization_and_safe_metadata():
payload = {
"workspace_id": "ws_1",
"user_id": "user_a",
"session_id": "sess_retrieve_contract",
"query": "fixture query",
"content": "TRANSIENT_RETRIEVE_CONTENT",
}
ov_result = asyncio.run(OpenVikingClient().retrieve_context_v2(payload))
em_result = EverMemOSClient().retrieve_context_v2(payload)
assert isinstance(ov_result, BackendRetrieveResult)
assert isinstance(em_result, BackendRetrieveResult)
assert ov_result.status == BackendResultStatus.SUCCESS
assert em_result.status == BackendResultStatus.SUCCESS
assert ov_result.items[0].source_backend == BackendType.OPENVIKING
assert em_result.items[0].source_backend == BackendType.EVERMEMOS
assert ov_result.items[0].text
assert em_result.items[0].ref_id
serialized = json.dumps(
{"ov": ov_result.model_dump(mode="json"), "em": em_result.model_dump(mode="json")},
ensure_ascii=False,
)
for blocked in ("TRANSIENT_RETRIEVE_CONTENT", "content", "raw_request", "messages", "conversation", "transcript"):
assert blocked not in serialized
def test_openviking_commit_skeleton_ref_type_is_mapped_from_fixture():
result = asyncio.run(OpenVikingClient().commit_session_v2({"session_id": "sess_ov_map"}))
result = asyncio.run(OpenVikingClient(mode="skeleton").commit_session_v2({"session_id": "sess_ov_map"}))
assert result.refs
assert result.refs[0].ref_type == MemoryRefType.SESSION_ARCHIVE
assert result.refs[0].native_id == "ov_session_summary:sess_ov_map"
def test_evermemos_skeleton_multiple_refs_are_written_by_process_outbox_event():
def test_everos_skeleton_multiple_refs_are_written_by_process_outbox_event():
repo = InMemoryRepository()
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SKIPPED)
),
evermemos_client=EverMemOSClient(),
everos_client=EverOSClient(),
)
response = asyncio.run(
service.commit_session("sess_em_skeleton", CommitRequest(workspace_id="ws_1", user_id="user_a", agent_id="agent_cli"))
)
event = next(event for event in repo.list_outbox_events_by_job(response.job_id) if event.backend_type == BackendType.EVERMEMOS)
event = next(event for event in repo.list_outbox_events_by_job(response.job_id) if event.backend_type == BackendType.EVEROS)
updated = asyncio.run(service.process_outbox_event(event.id))
refs = repo.list_memory_refs(session_id="sess_em_skeleton", backend_type=BackendType.EVERMEMOS, status=BackendRefStatus.SUCCESS)
refs = repo.list_memory_refs(session_id="sess_em_skeleton", backend_type=BackendType.EVEROS, status=BackendRefStatus.SUCCESS)
assert updated.status == OutboxEventStatus.SUCCESS
assert len(refs) == 2
@ -735,18 +795,18 @@ def test_obsidian_review_adapter_skeleton_returns_skipped_write_result():
def test_backend_commit_result_supports_multiple_produced_refs():
result = BackendCommitResult(
backend_type=BackendType.EVERMEMOS,
backend_type=BackendType.EVEROS,
status=BackendResultStatus.SUCCESS,
refs=[
BackendProducedRef(ref_type=MemoryRefType.PROFILE, native_id="profile_1"),
BackendProducedRef(ref_type=MemoryRefType.LONG_TERM_MEMORY, native_uri="evermemos://memories/long_1"),
BackendProducedRef(ref_type=MemoryRefType.LONG_TERM_MEMORY, native_uri="everos://memories/long_1"),
],
)
dumped = result.model_dump(mode="json")
assert len(result.refs) == 2
assert dumped["refs"][0]["ref_type"] == "profile"
assert dumped["refs"][1]["native_uri"] == "evermemos://memories/long_1"
assert dumped["refs"][1]["native_uri"] == "everos://memories/long_1"
def test_backend_ref_type_mapping_and_unknown_fallback_preserves_original_type():
@ -758,11 +818,11 @@ def test_backend_ref_type_mapping_and_unknown_fallback_preserves_original_type()
assert mapped == MemoryRefType.SESSION_ARCHIVE
assert metadata == {}
mapped, metadata = map_backend_ref_type(BackendType.EVERMEMOS, "preference")
mapped, metadata = map_backend_ref_type(BackendType.EVEROS, "preference")
assert mapped == MemoryRefType.PROFILE
assert metadata == {}
mapped, metadata = map_backend_ref_type(BackendType.EVERMEMOS, "unknown_signal")
mapped, metadata = map_backend_ref_type(BackendType.EVEROS, "unknown_signal")
assert mapped == MemoryRefType.LONG_TERM_MEMORY
assert metadata["original_ref_type"] == "unknown_signal"
@ -798,29 +858,10 @@ def test_openviking_commit_fixture_normalizes_to_backend_commit_result_without_u
assert "messages" not in serialized
def test_backend_response_fixture_files_exist_and_load():
names = {
"openviking_ingest_success.json",
"openviking_ingest_real_success.json",
"openviking_ingest_real_error_401.json",
"openviking_ingest_real_error_422.json",
"openviking_ingest_real_error_500.json",
"openviking_commit_success.json",
"openviking_retrieve_success.json",
"evermemos_ingest_success.json",
"evermemos_commit_success_multiple_refs.json",
"evermemos_retrieve_success.json",
}
for name in names:
payload = load_backend_fixture(name)
assert payload["status"]
def test_openviking_success_fixtures_normalize_without_unsafe_metadata():
ingest = normalize_openviking_ingest_response(load_backend_fixture("openviking_ingest_success.json"))
commit = normalize_openviking_commit_response(load_backend_fixture("openviking_commit_success.json"))
retrieve = normalize_openviking_retrieve_response(load_backend_fixture("openviking_retrieve_success.json"))
ingest = normalize_openviking_ingest_response(backend_response("openviking_ingest_success.json"))
commit = normalize_openviking_commit_response(backend_response("openviking_commit_success.json"))
retrieve = normalize_openviking_retrieve_response(backend_response("openviking_retrieve_success.json"))
assert ingest.status == BackendResultStatus.SUCCESS
assert ingest.native_id == "ov_turn_fixture_1"
@ -841,7 +882,7 @@ def test_openviking_success_fixtures_normalize_without_unsafe_metadata():
assert blocked not in serialized
def test_evermemos_commit_fixture_normalizes_multiple_produced_refs_and_unknown_type():
def test_everos_commit_fixture_normalizes_multiple_produced_refs_and_unknown_type():
raw = {
"status": "success",
"data": {
@ -853,7 +894,7 @@ def test_evermemos_commit_fixture_normalizes_multiple_produced_refs_and_unknown_
},
}
result = normalize_evermemos_commit_response(raw)
result = normalize_everos_commit_response(raw)
assert result.status == BackendResultStatus.SUCCESS
assert len(result.refs) == 3
@ -866,10 +907,10 @@ def test_evermemos_commit_fixture_normalizes_multiple_produced_refs_and_unknown_
assert "SECRET_PROFILE" not in json.dumps(result.model_dump(mode="json"), ensure_ascii=False)
def test_evermemos_success_fixtures_normalize_without_unsafe_metadata():
ingest = normalize_evermemos_ingest_response(load_backend_fixture("evermemos_ingest_success.json"))
commit = normalize_evermemos_commit_response(load_backend_fixture("evermemos_commit_success_multiple_refs.json"))
retrieve = normalize_evermemos_retrieve_response(load_backend_fixture("evermemos_retrieve_success.json"))
def test_everos_success_fixtures_normalize_without_unsafe_metadata():
ingest = normalize_everos_ingest_response(backend_response("everos_ingest_success.json"))
commit = normalize_everos_commit_response(backend_response("everos_commit_success_multiple_refs.json"))
retrieve = normalize_everos_retrieve_response(backend_response("everos_retrieve_success.json"))
assert ingest.status == BackendResultStatus.SUCCESS
assert ingest.native_id == "em_memory_fixture_1"
@ -881,7 +922,7 @@ def test_evermemos_success_fixtures_normalize_without_unsafe_metadata():
}
assert retrieve.status == BackendResultStatus.SUCCESS
assert len(retrieve.items) == 2
assert retrieve.items[0].source_backend == BackendType.EVERMEMOS
assert retrieve.items[0].source_backend == BackendType.EVEROS
assert retrieve.items[0].memory_type == "episodic_memory"
serialized = json.dumps(
{
@ -897,7 +938,7 @@ def test_evermemos_success_fixtures_normalize_without_unsafe_metadata():
def test_malformed_retrieve_response_returns_skipped_empty_result():
ov = normalize_openviking_retrieve_response({})
em = normalize_evermemos_retrieve_response({"data": {"unexpected": "shape"}})
em = normalize_everos_retrieve_response({"data": {"unexpected": "shape"}})
assert ov.status == BackendResultStatus.SKIPPED
assert ov.items == []
@ -914,7 +955,7 @@ def test_ingest_response_normalizers_return_write_results_and_sanitize_metadata(
"metadata": {"backend_request_id": "ov_req", "conversation": "SECRET"},
}
)
em = normalize_evermemos_ingest_response(
em = normalize_everos_ingest_response(
{
"status": "success",
"memory_id": "em_turn_1",
@ -935,12 +976,12 @@ def test_ingest_response_normalizers_return_write_results_and_sanitize_metadata(
def test_backend_error_retryable_mapping():
for status_code in (429, 500, 502, 503, 504):
assert map_backend_error_to_retryable(BackendType.OPENVIKING, status_code=status_code) is True
assert map_backend_error_to_retryable(BackendType.EVERMEMOS, error_code="timeout") is True
assert map_backend_error_to_retryable(BackendType.EVERMEMOS, error_message="network_error: reset") is True
assert map_backend_error_to_retryable(BackendType.EVEROS, error_code="timeout") is True
assert map_backend_error_to_retryable(BackendType.EVEROS, error_message="network_error: reset") is True
assert map_backend_error_to_retryable(BackendType.OPENVIKING, error_code="mystery") is True
for status_code in (400, 401, 403, 404, 422):
assert map_backend_error_to_retryable(BackendType.EVERMEMOS, status_code=status_code) is False
assert map_backend_error_to_retryable(BackendType.EVEROS, status_code=status_code) is False
def test_client_map_error_contracts_for_future_http_integration():
@ -951,8 +992,8 @@ def test_client_map_error_contracts_for_future_http_integration():
def __str__(self):
return f"response {self.status_code}"
ov_client = OpenVikingClient()
em_client = EverMemOSClient()
ov_client = OpenVikingClient(mode="skeleton")
em_client = EverOSClient(mode="skeleton")
for status_code in (429, 500, 502, 503, 504):
assert ov_client._map_error(ResponseLike(status_code)) is True
@ -979,20 +1020,20 @@ def test_ingest_service_records_two_success_refs():
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
response = asyncio.run(service.ingest_conversation_turn(IngestRequest(**build_ingest_payload())))
assert response.status == "success"
assert len(response.refs) == 2
assert {ref.backend_type.value for ref in response.refs} == {"openviking", "evermemos"}
assert {ref.backend_type.value for ref in response.refs} == {"openviking", "everos"}
assert {ref.status for ref in repo.list_memory_refs()} == {BackendRefStatus.SUCCESS}
assert len(repo.list_memory_refs(backend_type="openviking", status=BackendRefStatus.SUCCESS)) == 1
def test_v2_ingest_service_openviking_real_mock_success_writes_safe_memory_ref():
fixture = load_backend_fixture("openviking_ingest_real_success.json")
fixture = backend_response("openviking_ingest_real_success.json")
def handler(request):
payload = json.loads(request.content.decode())
@ -1012,7 +1053,7 @@ def test_v2_ingest_service_openviking_real_mock_success_writes_safe_memory_ref()
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=real_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
response = asyncio.run(
@ -1034,10 +1075,10 @@ def test_v2_ingest_service_openviking_real_mock_success_writes_safe_memory_ref()
assert "ov-super-secret-token" not in audit_json
def test_v2_ingest_service_real_mock_success_writes_openviking_and_evermemos_refs_safely():
ov_fixture = load_backend_fixture("openviking_ingest_real_success.json")
em_fixture = load_backend_fixture("evermemos_ingest_success.json")
seen = {"openviking": 0, "evermemos": 0}
def test_v2_ingest_service_real_mock_success_writes_openviking_and_everos_refs_safely():
ov_fixture = backend_response("openviking_ingest_real_success.json")
em_fixture = backend_response("everos_ingest_success.json")
seen = {"openviking": 0, "everos": 0}
def openviking_handler(request):
payload = json.loads(request.content.decode())
@ -1046,12 +1087,12 @@ def test_v2_ingest_service_real_mock_success_writes_openviking_and_evermemos_ref
seen["openviking"] += 1
return httpx.Response(200, json=ov_fixture)
def evermemos_handler(request):
def everos_handler(request):
payload = json.loads(request.content.decode())
assert payload["content"] == "SECRET_DUAL_REAL_CONTENT"
assert payload["messages"][0]["content"] == "SECRET_DUAL_REAL_CONTENT"
assert request.headers["x-api-key"] == "em-dual-token"
assert request.headers["authorization"] == "Bearer em-dual-token"
seen["evermemos"] += 1
seen["everos"] += 1
return httpx.Response(200, json=em_fixture)
async def real_openviking_factory():
@ -1066,11 +1107,11 @@ def test_v2_ingest_service_real_mock_success_writes_openviking_and_evermemos_ref
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=real_openviking_factory,
evermemos_client=EverMemOSClient(
everos_client=EverOSClient(
mode="real",
base_url="http://evermemos.test",
base_url="http://everos.test",
api_key="em-dual-token",
transport=httpx.MockTransport(evermemos_handler),
transport=httpx.MockTransport(everos_handler),
),
)
@ -1092,8 +1133,8 @@ def test_v2_ingest_service_real_mock_success_writes_openviking_and_evermemos_ref
audit_json = json.dumps([entry.model_dump(mode="json") for entry in repo.list_audit()], ensure_ascii=False)
assert response.status == OperationStatus.SUCCESS
assert seen == {"openviking": 1, "evermemos": 1}
assert {ref.backend_type for ref in refs} == {BackendType.OPENVIKING, BackendType.EVERMEMOS}
assert seen == {"openviking": 1, "everos": 1}
assert {ref.backend_type for ref in refs} == {BackendType.OPENVIKING, BackendType.EVEROS}
assert {ref.status for ref in refs} == {BackendRefStatus.SUCCESS}
assert {ref.content_hash for ref in refs}
assert "trace_dual_real" in serialized_refs
@ -1108,7 +1149,7 @@ def test_ingest_service_backend_failure_is_partial_success():
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FailingEverMemOSClient(),
everos_client=FailingEverOSClient(),
)
response = asyncio.run(service.ingest_conversation_turn(IngestRequest(**build_ingest_payload())))
@ -1117,8 +1158,8 @@ def test_ingest_service_backend_failure_is_partial_success():
assert len(response.refs) == 2
failed = [ref for ref in response.refs if ref.status == BackendRefStatus.FAILED]
assert len(failed) == 1
assert failed[0].backend_type.value == "evermemos"
assert "evermemos unavailable" in failed[0].error_message
assert failed[0].backend_type.value == "everos"
assert "everos unavailable" in failed[0].error_message
def test_ingest_service_records_two_skipped_refs_when_policy_disables_backends():
@ -1126,7 +1167,7 @@ def test_ingest_service_records_two_skipped_refs_when_policy_disables_backends()
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
response = asyncio.run(
@ -1135,7 +1176,7 @@ def test_ingest_service_records_two_skipped_refs_when_policy_disables_backends()
**build_ingest_payload(
policy={
"allow_openviking": False,
"allow_evermemos": False,
"allow_everos": False,
}
)
)
@ -1153,7 +1194,7 @@ def test_duplicate_idempotency_key_upserts_memory_refs_without_duplicates():
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
first = asyncio.run(
@ -1185,7 +1226,7 @@ def test_memory_ref_metadata_does_not_store_conversation_content_or_raw_request(
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
sensitive_content = "SECRET_CONVERSATION_CONTENT_SHOULD_NOT_BE_STORED"
@ -1213,7 +1254,7 @@ def test_sqlite_repository_persists_v2_memory_refs(tmp_path):
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
asyncio.run(service.ingest_conversation_turn(IngestRequest(**build_ingest_payload(turn_id="turn_sqlite"))))
@ -1253,7 +1294,7 @@ def test_commit_session_creates_commit_job_and_outbox_events():
assert job.session_id == "sess_commit"
assert job.status.value == "accepted"
assert len(events) == 2
assert {event.backend_type for event in events} == {BackendType.OPENVIKING, BackendType.EVERMEMOS}
assert {event.backend_type for event in events} == {BackendType.OPENVIKING, BackendType.EVEROS}
assert {event.operation for event in events} == {BackendOperation.COMMIT_SESSION}
assert {event.status for event in events} == {OutboxEventStatus.PENDING}
@ -1336,7 +1377,7 @@ def test_retrieve_response_contract_contains_items_refs_conflicts_trace_id_statu
service = MemoryGatewayV2Service(
repo=repo,
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
asyncio.run(service.ingest_conversation_turn(IngestRequest(**build_ingest_payload())))
@ -1357,8 +1398,14 @@ def test_retrieve_response_contract_contains_items_refs_conflicts_trace_id_statu
assert set(["items", "refs", "conflicts", "trace_id", "status"]).issubset(dumped)
assert response.trace_id == "trace_1"
assert response.status.value == "success"
assert len(response.items) == len(response.refs)
assert [item.source_backend for item in response.items] == [BackendType.EVEROS, BackendType.OPENVIKING]
assert [item.score for item in response.items] == [0.91, 0.82]
assert len(response.refs) == 2
assert response.conflicts == []
assert response.metadata["backend_results"] == [
{"backend_type": "openviking", "status": "success", "items": 1, "error_code": None, "error_message": None},
{"backend_type": "everos", "status": "success", "items": 1, "error_code": None, "error_message": None},
]
def test_process_commit_job_success_updates_job_and_writes_memory_refs():
@ -1368,8 +1415,8 @@ def test_process_commit_job_success_updates_job_and_writes_memory_refs():
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_commit_1", native_uri="viking://sessions/sess_commit")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.SUCCESS, native_id="em_commit_1", native_uri="evermemos://memories/em_commit_1")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.SUCCESS, native_id="em_commit_1", native_uri="everos://memories/em_commit_1")
),
)
response = asyncio.run(
@ -1389,7 +1436,7 @@ def test_process_commit_job_success_updates_job_and_writes_memory_refs():
assert job.created_refs_count == 2
assert {event.status for event in events} == {OutboxEventStatus.SUCCESS}
assert len(refs) == 2
assert {ref.backend_type for ref in refs} == {BackendType.OPENVIKING, BackendType.EVERMEMOS}
assert {ref.backend_type for ref in refs} == {BackendType.OPENVIKING, BackendType.EVEROS}
def test_process_outbox_event_writes_multiple_produced_memory_refs():
@ -1529,8 +1576,8 @@ def test_process_commit_job_one_success_one_failed_is_partial_success():
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_commit_1")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.FAILED, retryable=False, error_message="evermemos failed")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.FAILED, retryable=False, error_message="everos failed")
),
)
response = asyncio.run(
@ -1542,7 +1589,7 @@ def test_process_commit_job_one_success_one_failed_is_partial_success():
assert job.status.value == "partial_success"
assert job.created_refs_count == 1
assert "evermemos failed" in job.error_message
assert "everos failed" in job.error_message
assert {event.status for event in events} == {OutboxEventStatus.SUCCESS, OutboxEventStatus.DEAD_LETTER}
@ -1553,8 +1600,8 @@ def test_process_commit_job_two_failed_is_failed():
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.FAILED, retryable=False, error_message="openviking failed")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.FAILED, retryable=False, error_message="evermemos failed")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.FAILED, retryable=False, error_message="everos failed")
),
)
response = asyncio.run(
@ -1566,7 +1613,7 @@ def test_process_commit_job_two_failed_is_failed():
assert job.status.value == "failed"
assert job.created_refs_count == 0
assert "openviking failed" in job.error_message
assert "evermemos failed" in job.error_message
assert "everos failed" in job.error_message
def test_retryable_failed_outbox_event_requeues_with_next_retry():
@ -1597,8 +1644,8 @@ def test_process_pending_outbox_events_processes_pending_batch():
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_commit_1")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.SUCCESS, native_id="em_commit_1")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.SUCCESS, native_id="em_commit_1")
),
)
asyncio.run(
@ -1641,8 +1688,8 @@ def test_commit_pipeline_metadata_does_not_store_content_or_raw_request():
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_commit_1")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.SUCCESS, native_id="em_commit_1")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.SUCCESS, native_id="em_commit_1")
),
)
sensitive_content = "SECRET_COMMIT_PIPELINE_CONTENT_SHOULD_NOT_BE_STORED"
@ -1728,8 +1775,8 @@ def test_process_pending_outbox_events_uses_claim_and_does_not_process_existing_
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_claimed")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.SUCCESS, native_id="em_claimed")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.SUCCESS, native_id="em_claimed")
),
)
response = asyncio.run(
@ -1754,8 +1801,8 @@ def test_terminal_outbox_statuses_clear_lock_fields():
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_lock_clear")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.SKIPPED)
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.SKIPPED)
),
)
response = asyncio.run(
@ -1848,8 +1895,8 @@ def test_admin_process_outbox_endpoint_triggers_pending_processing(monkeypatch):
openviking_client_factory=fake_commit_openviking_factory(
commit_result(BackendType.OPENVIKING, BackendResultStatus.SUCCESS, native_id="ov_admin")
),
evermemos_client=FakeCommitEverMemOSClient(
commit_result(BackendType.EVERMEMOS, BackendResultStatus.SUCCESS, native_id="em_admin")
everos_client=FakeCommitEverOSClient(
commit_result(BackendType.EVEROS, BackendResultStatus.SUCCESS, native_id="em_admin")
),
)
asyncio.run(
@ -1907,7 +1954,7 @@ def test_v2_ingest_router_accepts_legal_request(monkeypatch):
api_v2.v2_service = MemoryGatewayV2Service(
repo=InMemoryRepository(),
openviking_client_factory=fake_openviking_factory,
evermemos_client=FakeEverMemOSClient(),
everos_client=FakeEverOSClient(),
)
app = FastAPI()
app.dependency_overrides[verify_api_key_compat] = lambda: None