88 lines
3.1 KiB
Python
88 lines
3.1 KiB
Python
|
|
"""Deterministic local adapters used by tests and first integrations."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
from .models import MemoryEdge, MemoryEvent, MemoryNode, PolicyDecision, ProfileIntent
|
||
|
|
|
||
|
|
|
||
|
|
class InMemoryMemoryGraphStore:
|
||
|
|
def __init__(self) -> None:
|
||
|
|
self._profiles: dict[str, ProfileIntent] = {}
|
||
|
|
self._nodes: dict[str, MemoryNode] = {}
|
||
|
|
self._edges: dict[str, MemoryEdge] = {}
|
||
|
|
|
||
|
|
def save_profile(self, profile: ProfileIntent) -> ProfileIntent:
|
||
|
|
self._profiles[profile.profile_id] = profile
|
||
|
|
return profile
|
||
|
|
|
||
|
|
def get_profile(self, profile_id: str) -> ProfileIntent:
|
||
|
|
return self._profiles[profile_id]
|
||
|
|
|
||
|
|
def save_node(self, node: MemoryNode) -> MemoryNode:
|
||
|
|
self._nodes[node.node_id] = node
|
||
|
|
return node
|
||
|
|
|
||
|
|
def get_node(self, node_id: str) -> MemoryNode:
|
||
|
|
return self._nodes[node_id]
|
||
|
|
|
||
|
|
def list_nodes(self, *, kind: str | None = None) -> list[MemoryNode]:
|
||
|
|
nodes = list(self._nodes.values())
|
||
|
|
if kind:
|
||
|
|
nodes = [node for node in nodes if node.kind == kind]
|
||
|
|
return sorted(nodes, key=lambda node: node.node_id)
|
||
|
|
|
||
|
|
def save_edge(self, edge: MemoryEdge) -> MemoryEdge:
|
||
|
|
self._edges[edge.edge_id] = edge
|
||
|
|
return edge
|
||
|
|
|
||
|
|
def list_edges(self, *, source: str | None = None, target: str | None = None) -> list[MemoryEdge]:
|
||
|
|
edges = list(self._edges.values())
|
||
|
|
if source:
|
||
|
|
edges = [edge for edge in edges if edge.source == source]
|
||
|
|
if target:
|
||
|
|
edges = [edge for edge in edges if edge.target == target]
|
||
|
|
return sorted(edges, key=lambda edge: edge.edge_id)
|
||
|
|
|
||
|
|
|
||
|
|
class InMemoryMemoryEventLog:
|
||
|
|
def __init__(self) -> None:
|
||
|
|
self._events: list[MemoryEvent] = []
|
||
|
|
|
||
|
|
def append(self, event: MemoryEvent) -> MemoryEvent:
|
||
|
|
if any(existing.event_id == event.event_id for existing in self._events):
|
||
|
|
raise ValueError(f"Duplicate memory event id: {event.event_id}")
|
||
|
|
self._events.append(event)
|
||
|
|
return event
|
||
|
|
|
||
|
|
def list_events(self, *, kind: str | None = None) -> list[MemoryEvent]:
|
||
|
|
events = list(self._events)
|
||
|
|
if kind:
|
||
|
|
events = [event for event in events if event.kind == kind]
|
||
|
|
return events
|
||
|
|
|
||
|
|
|
||
|
|
class NoopContextPackageCompiler:
|
||
|
|
def compile_selection(self, selection: dict[str, Any]) -> dict[str, Any]:
|
||
|
|
return {
|
||
|
|
"package_id": f"package:{selection.get('id', 'anonymous')}",
|
||
|
|
"selection": dict(selection),
|
||
|
|
"item_count": len(selection.get("nodes", ())) + len(selection.get("events", ())),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
class AllowAllPolicyGateway:
|
||
|
|
def authorize(self, *, action: str, resource: str, context: dict[str, Any] | None = None) -> PolicyDecision:
|
||
|
|
return PolicyDecision(True, reason="local allow-all policy", metadata={"action": action, "resource": resource, "context": context or {}})
|
||
|
|
|
||
|
|
|
||
|
|
class RecordingAuditSink:
|
||
|
|
def __init__(self) -> None:
|
||
|
|
self.events: list[dict[str, Any]] = []
|
||
|
|
|
||
|
|
def record(self, event: dict[str, Any]) -> dict[str, Any]:
|
||
|
|
stored = dict(event)
|
||
|
|
self.events.append(stored)
|
||
|
|
return {"recorded": True, "index": len(self.events) - 1, "event": stored}
|