Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions s16code/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
16 changes: 15 additions & 1 deletion tests/test_capability_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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):
Expand All @@ -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()
2 changes: 1 addition & 1 deletion tests/test_channel_connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down