From 6367562dfc15bd159fffea9312653225b6e5a255 Mon Sep 17 00:00:00 2001 From: aditya Date: Mon, 31 Aug 2026 14:16:03 +0530 Subject: [PATCH] Fix runtime embedder injection for offline tests --- s16code/runtime.py | 6 +++--- tests/test_capability_contracts.py | 16 +++++++++++++++- tests/test_channel_connections.py | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/s16code/runtime.py b/s16code/runtime.py index b8fcef7..2b1cf69 100644 --- a/s16code/runtime.py +++ b/s16code/runtime.py @@ -27,7 +27,7 @@ from s16code.core.a2a.trust import AgentCardTrustPolicy from s16code.core.live_graph import Deferred, GraphStore, LiveGraphExecutor, TaskSpec from s16code.core.memory import MemoryKind, MemoryRecord, MemoryScope, MemoryStore, Principal, SourceRef -from s16code.core.memory.embeddings import OllamaNomicEmbedder +from s16code.core.memory.embeddings import Embedder, OllamaNomicEmbedder from s16code.economics import ( TIER_KEY, BudgetAwarePlanner, @@ -120,14 +120,14 @@ def _parse_json_object(text: str) -> dict[str, Any] | None: class AgentRuntime: """Owns the persistent stores and runs one user request through the graph.""" - def __init__(self, root: Path | None = None) -> None: + def __init__(self, root: Path | None = None, *, memory_embedder: Embedder | None = None) -> None: # Resolve the config directory at construction time. Tests and # embedders can deliberately use a different local profile in the # same Python process; importing CONFIG_DIR by value would leak memory # between those profiles. self.root = root or Path(os.getenv("S16_DATA_DIR", str(Path.home() / ".s16code"))) self.root.mkdir(parents=True, exist_ok=True) - self.memory = MemoryStore(self.root / "memory.sqlite", embedder=OllamaNomicEmbedder()) + self.memory = MemoryStore(self.root / "memory.sqlite", embedder=memory_embedder or OllamaNomicEmbedder()) self.graph = GraphStore(self.root / "graphs") self.outbox = ActionOutbox(self.root / "outbox") # One registry per runtime: the single source of truth for what a diff --git a/tests/test_capability_contracts.py b/tests/test_capability_contracts.py index 2bbb107..9c58c9a 100644 --- a/tests/test_capability_contracts.py +++ b/tests/test_capability_contracts.py @@ -116,6 +116,7 @@ def test_every_registered_capability_has_a_worker_and_every_worker_is_registered import s16code.runtime as runtime_module from s16code.core.memory import MemoryScope + from s16code.core.memory.embeddings import DeterministicEmbedder captured: set[str] = set() @@ -134,7 +135,7 @@ def __init__(self, *args, **kwargs): # noqa: ANN002, ANN003 async def never(prompt: str, system: str): # noqa: ANN202, ARG001 raise AssertionError("the probe must not reach a model") - runtime = runtime_module.AgentRuntime() + runtime = runtime_module.AgentRuntime(memory_embedder=DeterministicEmbedder(128)) runtime_module.LiveGraphExecutor = _Probe try: with pytest.raises(_Stop): @@ -147,3 +148,16 @@ async def never(prompt: str, system: str): # noqa: ANN202, ARG001 finally: runtime_module.LiveGraphExecutor = original_executor runtime.close() + + +def test_agent_runtime_accepts_an_injected_memory_embedder(tmp_path) -> None: + """Runtime-level tests must be able to stay offline without mutating internals.""" + from s16code.core.memory.embeddings import DeterministicEmbedder + from s16code.runtime import AgentRuntime + + embedder = DeterministicEmbedder(32) + runtime = AgentRuntime(root=tmp_path / "state", memory_embedder=embedder) + try: + assert runtime.memory.embedder is embedder + finally: + runtime.close() diff --git a/tests/test_channel_connections.py b/tests/test_channel_connections.py index 4cb238b..799994b 100644 --- a/tests/test_channel_connections.py +++ b/tests/test_channel_connections.py @@ -4,9 +4,9 @@ from datetime import UTC, datetime from unittest.mock import AsyncMock +import conftest import httpx -import conftest import s16code.routes as agent_route from s16code.core.live_graph import Deferred, GraphPatch, TaskSpec from s16code.core.memory.embeddings import DeterministicEmbedder