Buckets:
Agent Q3
| """ | |
| Agent-Q3 — Redis-backed shared memory layer. | |
| Used by all services (multimodal, coder, research, monitor) to: | |
| - Cache MCP tool call results (TTL'd) | |
| - Store conversation history per session | |
| - Persist monitor metrics across restarts | |
| - Track skill activation log | |
| - Coordinate cross-service rate limits | |
| Falls back to a no-op in-memory store if REDIS_URL is unset. | |
| """ | |
| import json | |
| import time | |
| from typing import Any | |
| import structlog | |
| from .config import settings | |
| log = structlog.get_logger(__name__) | |
| class _InMemoryFallback: | |
| """Drop-in async stub used when REDIS_URL is unset.""" | |
| def __init__(self): | |
| self._store: dict[str, tuple[float, str]] = {} | |
| self._lists: dict[str, list] = {} | |
| async def get(self, key: str) -> str | None: | |
| item = self._store.get(key) | |
| if not item: | |
| return None | |
| expires_at, value = item | |
| if expires_at and time.time() > expires_at: | |
| self._store.pop(key, None) | |
| return None | |
| return value | |
| async def set(self, key: str, value: str, ex: int | None = None) -> None: | |
| exp = (time.time() + ex) if ex else 0 | |
| self._store[key] = (exp, value) | |
| async def delete(self, *keys: str) -> None: | |
| for k in keys: | |
| self._store.pop(k, None) | |
| async def lpush(self, key: str, *values: str) -> int: | |
| self._lists.setdefault(key, []) | |
| for v in values: | |
| self._lists[key].insert(0, v) | |
| return len(self._lists[key]) | |
| async def lrange(self, key: str, start: int, stop: int) -> list: | |
| lst = self._lists.get(key, []) | |
| if stop == -1: | |
| return lst[start:] | |
| return lst[start : stop + 1] | |
| async def ltrim(self, key: str, start: int, stop: int) -> None: | |
| lst = self._lists.get(key, []) | |
| if stop == -1: | |
| self._lists[key] = lst[start:] | |
| else: | |
| self._lists[key] = lst[start : stop + 1] | |
| async def ping(self) -> bool: | |
| return True | |
| async def close(self) -> None: | |
| pass | |
| class Memory: | |
| """Async memory facade. Uses redis.asyncio when REDIS_URL set, else in-memory.""" | |
| def __init__(self): | |
| self._client = None | |
| self._backend: str = "uninitialized" | |
| async def connect(self) -> None: | |
| if settings.redis_url: | |
| try: | |
| from redis.asyncio import from_url | |
| self._client = from_url(settings.redis_url, decode_responses=True) | |
| await self._client.ping() | |
| self._backend = "redis" | |
| log.info("memory connected", backend="redis", url=settings.redis_url.split("@")[-1]) | |
| return | |
| except Exception as e: | |
| log.warning("redis unavailable, falling back to in-memory", error=str(e)) | |
| self._client = _InMemoryFallback() | |
| self._backend = "in-memory" | |
| log.info("memory connected", backend="in-memory") | |
| def backend(self) -> str: | |
| return self._backend | |
| def client(self): | |
| return self._client | |
| # ── Typed helpers ──────────────────────────────────────────────────────── | |
| async def cache_get(self, key: str) -> Any | None: | |
| raw = await self._client.get(f"cache:{key}") | |
| return json.loads(raw) if raw else None | |
| async def cache_set(self, key: str, value: Any, ttl_secs: int = 300) -> None: | |
| await self._client.set(f"cache:{key}", json.dumps(value), ex=ttl_secs) | |
| async def log_event(self, channel: str, event: dict, max_history: int = 500) -> None: | |
| key = f"events:{channel}" | |
| await self._client.lpush(key, json.dumps({"ts": time.time(), **event})) | |
| await self._client.ltrim(key, 0, max_history - 1) | |
| async def get_events(self, channel: str, limit: int = 50) -> list[dict]: | |
| raw_items = await self._client.lrange(f"events:{channel}", 0, limit - 1) | |
| return [json.loads(x) for x in raw_items] | |
| async def session_append(self, session_id: str, message: dict, max_turns: int = 50) -> None: | |
| key = f"session:{session_id}" | |
| await self._client.lpush(key, json.dumps(message)) | |
| await self._client.ltrim(key, 0, max_turns - 1) | |
| async def session_history(self, session_id: str, limit: int = 50) -> list[dict]: | |
| raw_items = await self._client.lrange(f"session:{session_id}", 0, limit - 1) | |
| return [json.loads(x) for x in reversed(raw_items)] | |
| async def ping(self) -> bool: | |
| try: | |
| return await self._client.ping() | |
| except Exception: | |
| return False | |
| async def close(self) -> None: | |
| try: | |
| await self._client.close() | |
| except Exception: | |
| pass | |
| memory = Memory() | |
Xet Storage Details
- Size:
- 4.98 kB
- Xet hash:
- 599436c4cc6611d16a613a18888a3a1ec374b7d0270e2aab9a3b5eb88f0027d2
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.