docs+skills: add main UI/UX visual-truth PRD and skill links
This commit is contained in:
parent
1c36223e7f
commit
14a50ad4ae
289 changed files with 54463 additions and 0 deletions
241
.agents/skills/rlm-mem/brain/scripts/cache_system.py
Normal file
241
.agents/skills/rlm-mem/brain/scripts/cache_system.py
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
"""
|
||||
RLM-MEM - Cache System (D5.1)
|
||||
Simple in-memory caching for frequently accessed data.
|
||||
"""
|
||||
|
||||
import time
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
from threading import Lock
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CacheEntry:
|
||||
"""Single cache entry."""
|
||||
value: Any
|
||||
timestamp: float
|
||||
ttl: int # Time to live in seconds
|
||||
|
||||
|
||||
class MemoryCache:
|
||||
"""Thread-safe in-memory cache with TTL support."""
|
||||
|
||||
def __init__(self, default_ttl: int = 300):
|
||||
"""
|
||||
Initialize memory cache.
|
||||
|
||||
Args:
|
||||
default_ttl: Default time-to-live in seconds (5 minutes)
|
||||
"""
|
||||
self._cache: Dict[str, CacheEntry] = {}
|
||||
self._default_ttl = default_ttl
|
||||
self._lock = Lock()
|
||||
self._hits = 0
|
||||
self._misses = 0
|
||||
self._evictions = 0
|
||||
self._lookups = 0
|
||||
|
||||
def get(self, key: str) -> Optional[Any]:
|
||||
"""
|
||||
Get value from cache if not expired.
|
||||
|
||||
Args:
|
||||
key: Cache key
|
||||
|
||||
Returns:
|
||||
Cached value or None if not found/expired
|
||||
"""
|
||||
with self._lock:
|
||||
self._lookups += 1
|
||||
entry = self._cache.get(key)
|
||||
if entry is None:
|
||||
self._misses += 1
|
||||
logger.debug("Memory cache miss for %s", key)
|
||||
return None
|
||||
|
||||
# Check if expired
|
||||
if time.time() - entry.timestamp > entry.ttl:
|
||||
del self._cache[key]
|
||||
self._misses += 1
|
||||
self._evictions += 1
|
||||
logger.debug("Memory cache evicted expired entry for %s", key)
|
||||
return None
|
||||
|
||||
self._hits += 1
|
||||
logger.debug("Memory cache hit for %s", key)
|
||||
return entry.value
|
||||
|
||||
def set(self, key: str, value: Any, ttl: int = None):
|
||||
"""
|
||||
Store value in cache.
|
||||
|
||||
Args:
|
||||
key: Cache key
|
||||
value: Value to cache
|
||||
ttl: Time-to-live in seconds (uses default if None)
|
||||
"""
|
||||
if ttl is None:
|
||||
ttl = self._default_ttl
|
||||
|
||||
with self._lock:
|
||||
self._cache[key] = CacheEntry(
|
||||
value=value,
|
||||
timestamp=time.time(),
|
||||
ttl=ttl
|
||||
)
|
||||
|
||||
def delete(self, key: str) -> bool:
|
||||
"""
|
||||
Delete key from cache.
|
||||
|
||||
Args:
|
||||
key: Cache key
|
||||
|
||||
Returns:
|
||||
True if key was present and deleted
|
||||
"""
|
||||
with self._lock:
|
||||
if key in self._cache:
|
||||
del self._cache[key]
|
||||
return True
|
||||
return False
|
||||
|
||||
def clear(self):
|
||||
"""Clear all cache entries."""
|
||||
with self._lock:
|
||||
self._cache.clear()
|
||||
|
||||
def cleanup(self):
|
||||
"""Remove all expired entries."""
|
||||
with self._lock:
|
||||
now = time.time()
|
||||
expired = [
|
||||
key for key, entry in self._cache.items()
|
||||
if now - entry.timestamp > entry.ttl
|
||||
]
|
||||
for key in expired:
|
||||
del self._cache[key]
|
||||
self._evictions += len(expired)
|
||||
if expired:
|
||||
logger.debug("Memory cache cleanup evicted %d entries", len(expired))
|
||||
return len(expired)
|
||||
|
||||
def stats(self) -> Dict[str, Any]:
|
||||
"""Get cache statistics."""
|
||||
with self._lock:
|
||||
hit_rate = (self._hits / self._lookups) if self._lookups else 0.0
|
||||
return {
|
||||
"size": len(self._cache),
|
||||
"default_ttl": self._default_ttl,
|
||||
"lookups": self._lookups,
|
||||
"hits": self._hits,
|
||||
"misses": self._misses,
|
||||
"evictions": self._evictions,
|
||||
"hit_rate": round(hit_rate, 4)
|
||||
}
|
||||
|
||||
|
||||
class CacheManager:
|
||||
"""
|
||||
Manages in-memory cache.
|
||||
(Disk cache tier removed per ADR 0002)
|
||||
"""
|
||||
|
||||
def __init__(self, cache_dir: str = None, default_ttl: int = 300):
|
||||
"""
|
||||
Initialize cache manager.
|
||||
|
||||
Args:
|
||||
cache_dir: Ignored (legacy compatibility)
|
||||
default_ttl: Default time-to-live in seconds
|
||||
"""
|
||||
self.memory = MemoryCache(default_ttl)
|
||||
self._lock = Lock()
|
||||
self._metrics: Dict[str, int] = {
|
||||
"get_calls": 0,
|
||||
"memory_hits": 0,
|
||||
"misses": 0,
|
||||
"set_calls": 0,
|
||||
"delete_calls": 0,
|
||||
"clear_calls": 0,
|
||||
}
|
||||
|
||||
def get(self, key: str, use_disk: bool = False) -> Optional[Any]:
|
||||
"""
|
||||
Get from memory cache.
|
||||
|
||||
Args:
|
||||
key: Cache key
|
||||
use_disk: Ignored (legacy compatibility)
|
||||
|
||||
Returns:
|
||||
Cached value or None
|
||||
"""
|
||||
with self._lock:
|
||||
self._metrics["get_calls"] += 1
|
||||
|
||||
value = self.memory.get(key)
|
||||
if value is not None:
|
||||
with self._lock:
|
||||
self._metrics["memory_hits"] += 1
|
||||
return value
|
||||
|
||||
with self._lock:
|
||||
self._metrics["misses"] += 1
|
||||
return None
|
||||
|
||||
def set(self, key: str, value: Any, ttl: int = None, use_disk: bool = False):
|
||||
"""
|
||||
Store in cache.
|
||||
|
||||
Args:
|
||||
key: Cache key
|
||||
value: Value to cache
|
||||
ttl: Time-to-live
|
||||
use_disk: Ignored
|
||||
"""
|
||||
with self._lock:
|
||||
self._metrics["set_calls"] += 1
|
||||
self.memory.set(key, value, ttl)
|
||||
|
||||
def delete(self, key: str) -> bool:
|
||||
"""Delete from cache."""
|
||||
with self._lock:
|
||||
self._metrics["delete_calls"] += 1
|
||||
return self.memory.delete(key)
|
||||
|
||||
def clear(self):
|
||||
"""Clear all caches."""
|
||||
with self._lock:
|
||||
self._metrics["clear_calls"] += 1
|
||||
self.memory.clear()
|
||||
|
||||
def telemetry(self) -> Dict[str, Any]:
|
||||
"""Return manager-level telemetry with derived rates."""
|
||||
with self._lock:
|
||||
metrics = dict(self._metrics)
|
||||
total_gets = metrics["get_calls"]
|
||||
metrics["memory_hit_rate"] = round(
|
||||
(metrics["memory_hits"] / total_gets), 4
|
||||
) if total_gets else 0.0
|
||||
metrics["miss_rate"] = round(
|
||||
(metrics["misses"] / total_gets), 4
|
||||
) if total_gets else 0.0
|
||||
return metrics
|
||||
|
||||
def cleanup(self) -> Dict[str, int]:
|
||||
"""Cleanup expired entries from cache."""
|
||||
mem_removed = self.memory.cleanup()
|
||||
return {"memory": mem_removed}
|
||||
|
||||
def stats(self) -> Dict[str, Any]:
|
||||
"""Get combined cache statistics."""
|
||||
return {
|
||||
"memory": self.memory.stats(),
|
||||
"manager": self.telemetry()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue