avoigt1121
Claude Opus 5.5
feat: governed ToolUniverse core for the knowledge specialist (s1)
377417d Download src/cache.py from anne-voigt/pdac-knowledge-agent-dev: direct link, hf CLI and curl.
- Browser
- Download file 3.15 kB
-
https://huggingface.co/spaces/anne-voigt/pdac-knowledge-agent-dev/resolve/main/src/cache.py
- Command line
-
hf download hf://spaces/anne-voigt/pdac-knowledge-agent-dev/src/cache.py
-
curl -L -o cache.py https://huggingface.co/spaces/anne-voigt/pdac-knowledge-agent-dev/resolve/main/src/cache.py
3.15 kB
| """Response cache — SQLite inside the container, ephemeral, TTL per source (ADR-0001 §8). | |
| ToolUniverse's own result cache is switched off (``src.tu_client``) so this is the only one, and | |
| it keeps the one fact a cache usually hides: ``retrieved_at`` is when the SOURCE answered, and a | |
| hit returns that original time, never the time the cache served it. Only responses that passed | |
| their schema check are stored, so a drifted response is never replayed. | |
| The file lives in the temp dir by default (``KNOWLEDGE_CACHE_PATH`` overrides; ``:memory:`` for | |
| tests). Nothing here is persistent on a Space, by design: a rebuild empties it. | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import json | |
| import os | |
| import sqlite3 | |
| import tempfile | |
| import threading | |
| import time | |
| from collections.abc import Callable | |
| from pathlib import Path | |
| from typing import Any | |
| from src import config | |
| DEFAULT_PATH = str(Path(tempfile.gettempdir()) / "pdac-knowledge-cache.sqlite3") | |
| def cache_key(tool: str, args: dict[str, Any]) -> str: | |
| canonical = json.dumps({"tool": tool, "args": args}, sort_keys=True, separators=(",", ":")) | |
| return hashlib.sha256(canonical.encode("utf-8")).hexdigest() | |
| class ResponseCache: | |
| def __init__(self, path: str | None = None, *, clock: Callable[[], float] = time.time): | |
| self.path = path or os.environ.get("KNOWLEDGE_CACHE_PATH") or DEFAULT_PATH | |
| self._clock = clock | |
| self._lock = threading.Lock() | |
| self._db = sqlite3.connect(self.path, check_same_thread=False) | |
| self._db.execute( | |
| "CREATE TABLE IF NOT EXISTS responses (" | |
| " key TEXT PRIMARY KEY, source TEXT NOT NULL, tool TEXT NOT NULL," | |
| " data TEXT NOT NULL, retrieved_at REAL NOT NULL)" | |
| ) | |
| self._db.commit() | |
| def get(self, source: str, tool: str, args: dict[str, Any]) -> tuple[Any, float] | None: | |
| """``(data, retrieved_at)`` for a live entry, else None. Expired entries are dropped.""" | |
| key = cache_key(tool, args) | |
| ttl = config.source(source)["ttl_seconds"] | |
| with self._lock: | |
| row = self._db.execute( | |
| "SELECT data, retrieved_at FROM responses WHERE key = ?", (key,) | |
| ).fetchone() | |
| if row is None: | |
| return None | |
| data, retrieved_at = row | |
| if self._clock() - retrieved_at >= ttl: | |
| self._db.execute("DELETE FROM responses WHERE key = ?", (key,)) | |
| self._db.commit() | |
| return None | |
| return json.loads(data), retrieved_at | |
| def put( | |
| self, source: str, tool: str, args: dict[str, Any], data: Any, retrieved_at: float | |
| ) -> None: | |
| key = cache_key(tool, args) | |
| with self._lock: | |
| self._db.execute( | |
| "INSERT OR REPLACE INTO responses (key, source, tool, data, retrieved_at)" | |
| " VALUES (?, ?, ?, ?, ?)", | |
| (key, source, tool, json.dumps(data), retrieved_at), | |
| ) | |
| self._db.commit() | |
| def clear(self) -> None: | |
| with self._lock: | |
| self._db.execute("DELETE FROM responses") | |
| self._db.commit() | |