#!/usr/bin/env python3 # -*- coding: utf-8 -*- """EchoCache - a semantic cache and cost-observability layer for LLM APIs. Design rules that this file never breaks: * No torch / transformers / sklearn / faiss. Only numpy, pandas, gradio, huggingface_hub and the standard library. * Similarity, normalization and safety screening are 100% local. The optional embedding API only *re-ranks*; if it is disabled, rate limited (429), out of credit (402) or slow, every core feature keeps working unchanged. * No public function may raise. Failures come back as {"ok": false, "error": {"code": ..., "message": ...}}. * Import time does no heavy work: no model download, no big allocation. * Memory is bounded by MAX_ENTRIES and MAX_TEXT_CHARS, with LRU eviction. """ from __future__ import annotations import csv import functools import hashlib import html as html_lib import io import json import math import os import re import tempfile import threading import time import unicodedata import zlib from collections import Counter, OrderedDict, deque from enum import Enum from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple import numpy as np import pandas as pd import gradio as gr APP_NAME = "EchoCache" APP_VERSION = "1.0.0" START_TIME = time.time() # ============================================================================= # (A) Configuration # ============================================================================= def _env_str(name: str, default: str = "") -> str: """Guarantees: returns a stripped string, never raises, never returns None.""" try: raw = os.environ.get(name) return default if raw is None else str(raw).strip() except Exception: return default def _env_int(name: str, default: int, lo: int = 0, hi: int = 10 ** 9) -> int: """Guarantees: returns an int clamped into [lo, hi]; bad values fall back to default.""" try: val = int(float(_env_str(name, "").replace(",", "") or default)) except Exception: val = default return max(lo, min(hi, val)) def _env_float(name: str, default: float, lo: float = -1e9, hi: float = 1e9) -> float: """Guarantees: returns a float clamped into [lo, hi]; bad values fall back to default.""" try: val = float(_env_str(name, "") or default) if math.isnan(val) or math.isinf(val): val = default except Exception: val = default return max(lo, min(hi, val)) def _safe_int(value: Any, default: int) -> int: """Guarantees: an int for ANY input - NaN, inf, None, "abc" and objects all fall back to default.""" try: if value is None or isinstance(value, bool): return default number = float(value) if math.isnan(number) or math.isinf(number): return default return int(number) except Exception: return default def _safe_float(value: Any, default: float) -> float: """Guarantees: a finite float for ANY input; NaN, inf and junk fall back to default.""" try: if value is None or isinstance(value, bool): return default number = float(value) if math.isnan(number) or math.isinf(number): return default return number except Exception: return default def _env_bool(name: str, default: bool = False) -> bool: """Guarantees: returns a bool for any input ('1/true/yes/on' are true).""" raw = _env_str(name, "").lower() if not raw: return default return raw in ("1", "true", "yes", "y", "on") # --- required by the spec ---------------------------------------------------- HF_TOKEN = _env_str("HF_TOKEN") or _env_str("HUGGINGFACE_HUB_TOKEN") or _env_str("HUGGINGFACEHUB_API_TOKEN") EMBED_MODEL = _env_str("EMBED_MODEL", "sentence-transformers/all-MiniLM-L6-v2") MAX_ENTRIES = _env_int("MAX_ENTRIES", 5000, lo=1, hi=200000) MAX_TEXT_CHARS = _env_int("MAX_TEXT_CHARS", 8000, lo=64, hi=200000) DEFAULT_THRESHOLD = _env_float("DEFAULT_THRESHOLD", 0.92, lo=0.0, hi=1.0) BORDERLINE_MARGIN = _env_float("BORDERLINE_MARGIN", 0.03, lo=0.0, hi=0.5) MAX_TTL_SEC = 365 * 24 * 3600 # hard ceiling for any TTL, including imported ones DEFAULT_TTL_SEC = _env_int("DEFAULT_TTL_SEC", 86400, lo=1, hi=MAX_TTL_SEC) PRICE_IN_PER_1K = _env_float("PRICE_IN_PER_1K", 0.0, lo=0.0, hi=1000.0) PRICE_OUT_PER_1K = _env_float("PRICE_OUT_PER_1K", 0.0, lo=0.0, hi=1000.0) # --- tunables (all optional, all have safe defaults) ------------------------- VECTOR_DIM = _env_int("VECTOR_DIM", 4096, lo=256, hi=65536) NGRAM_N = _env_int("NGRAM_N", 3, lo=2, hi=6) SIMHASH_BITS = 64 SIMHASH_MAX_DIST = _env_int("SIMHASH_MAX_DIST", 12, lo=0, hi=64) # Recall guard: when the SimHash band returns nothing and the partition is small, # fall back to a full scan. Cheap for small indexes, never used for big ones. FULL_SCAN_LIMIT = _env_int("FULL_SCAN_LIMIT", 512, lo=0, hi=20000) CANDIDATE_LIMIT = _env_int("CANDIDATE_LIMIT", 64, lo=1, hi=4096) GUARD_MAX_CHECK = _env_int("GUARD_MAX_CHECK", 5, lo=1, hi=64) EMBED_WEIGHT = _env_float("EMBED_WEIGHT", 0.35, lo=0.0, hi=1.0) # local-leaning by default EMBED_TIMEOUT = _env_float("EMBED_TIMEOUT", 6.0, lo=0.5, hi=60.0) EMBED_TOPK = _env_int("EMBED_TOPK", 5, lo=1, hi=32) EMBED_CACHE_SIZE = _env_int("EMBED_CACHE_SIZE", 2048, lo=16, hi=100000) EMBED_FAIL_THRESHOLD = _env_int("EMBED_FAIL_THRESHOLD", 3, lo=1, hi=100) EMBED_COOLDOWN_SEC = _env_int("EMBED_COOLDOWN_SEC", 600, lo=10, hi=86400) EVENT_BUFFER = _env_int("EVENT_BUFFER", 5000, lo=100, hi=200000) LOG_PROMPT_PREFIX = _env_int("LOG_PROMPT_PREFIX", 0, lo=0, hi=200) # 0 = never log prompt text SWEEP_MAX_ROWS = _env_int("SWEEP_MAX_ROWS", 2000, lo=10, hi=100000) SWEEP_TIME_BUDGET_SEC = _env_float("SWEEP_TIME_BUDGET_SEC", 90.0, lo=5.0, hi=900.0) EXPIRE_SWEEP_INTERVAL = _env_float("EXPIRE_SWEEP_INTERVAL", 30.0, lo=1.0, hi=3600.0) ENTROPY_THRESHOLD = _env_float("ENTROPY_THRESHOLD", 4.0, lo=0.0, hi=8.0) ENTROPY_MIN_LEN = _env_int("ENTROPY_MIN_LEN", 24, lo=8, hi=512) MAX_EMAILS = _env_int("MAX_EMAILS", 1, lo=0, hi=100) # reject when count > MAX_EMAILS MAX_PHONES = _env_int("MAX_PHONES", 1, lo=0, hi=100) # reject when count > MAX_PHONES MAX_TENANTS = _env_int("MAX_TENANTS", 256, lo=1, hi=10000) # MAX_ENTRIES is PER TENANT; this is the hard ceiling across every partition. # Memory is dominated by the vector matrix: entries x VECTOR_DIM x 4 bytes # (20000 x 4096 x 4B = 327 MB), which is what keeps a 16 GB free Space safe. MAX_TOTAL_ENTRIES = _env_int("MAX_TOTAL_ENTRIES", 20000, lo=1, hi=2000000) IMPORT_MAX_BYTES = _env_int("IMPORT_MAX_BYTES", 64 * 1024 * 1024, lo=1024, hi=512 * 1024 * 1024) # Comma separated guard checks to disable, e.g. GUARD_DISABLE="proper_noun,question_type" GUARD_DISABLE = {x.strip() for x in _env_str("GUARD_DISABLE", "").split(",") if x.strip()} EMBED_ENABLED = bool(HF_TOKEN) MODE = "local+embedding" if EMBED_ENABLED else "local-only" _TMP_DIR = os.path.join(tempfile.gettempdir(), "echocache") try: os.makedirs(_TMP_DIR, exist_ok=True) except Exception: _TMP_DIR = tempfile.gettempdir() def config_snapshot() -> Dict[str, Any]: """Guarantees: returns a JSON-serializable copy of the effective configuration, never secrets.""" return { "app": APP_NAME, "version": APP_VERSION, "mode": MODE, "hf_token_present": bool(HF_TOKEN), "embed_model": EMBED_MODEL if EMBED_ENABLED else None, "embed_weight": EMBED_WEIGHT if EMBED_ENABLED else 0.0, "max_entries": MAX_ENTRIES, "max_text_chars": MAX_TEXT_CHARS, "default_threshold": DEFAULT_THRESHOLD, "borderline_margin": BORDERLINE_MARGIN, "default_ttl_sec": DEFAULT_TTL_SEC, "price_in_per_1k": PRICE_IN_PER_1K, "price_out_per_1k": PRICE_OUT_PER_1K, "vector_dim": VECTOR_DIM, "ngram_n": NGRAM_N, "simhash_max_dist": SIMHASH_MAX_DIST, "candidate_limit": CANDIDATE_LIMIT, "guard_disabled_checks": sorted(GUARD_DISABLE), "log_prompt_prefix": LOG_PROMPT_PREFIX, "max_tenants": MAX_TENANTS, "max_total_entries": MAX_TOTAL_ENTRIES, "gradio_version": getattr(gr, "__version__", "unknown"), } # ============================================================================= # Result envelopes + the "nothing ever raises" decorator # ============================================================================= class ErrorCode(str, Enum): """Stable machine-readable error codes shared by the UI and the HTTP API.""" INTERNAL = "internal_error" BAD_INPUT = "bad_input" EMPTY_PROMPT = "empty_prompt" EMPTY_RESPONSE = "empty_response" EMPTY_PREFIX = "empty_prefix" TENANT_LIMIT = "tenant_limit_reached" NOT_FOUND = "not_found" PAYLOAD_TOO_LARGE = "payload_too_large" BAD_PAYLOAD = "bad_payload" NO_FILE = "no_file" def ok(**payload: Any) -> Dict[str, Any]: """Guarantees: returns a dict whose "ok" key is always True.""" out: Dict[str, Any] = {"ok": True} out.update(payload) return out def err(code: Any, message: str, **extra: Any) -> Dict[str, Any]: """Guarantees: returns {"ok": False, "error": {...}} with a string code, always JSON-safe.""" code_str = code.value if isinstance(code, Enum) else str(code) body: Dict[str, Any] = {"code": code_str, "message": str(message)[:800]} for key, value in extra.items(): try: json.dumps(value) body[key] = value except Exception: body[key] = repr(value)[:200] return {"ok": False, "error": body} def guarded(fn: Callable[..., Any]) -> Callable[..., Any]: """Guarantees: the wrapped callable never raises; any exception becomes an error envelope.""" @functools.wraps(fn) def wrapper(*args: Any, **kwargs: Any) -> Any: """Guarantees: calls the wrapped function and converts any exception into an error envelope.""" try: return fn(*args, **kwargs) except Exception as exc: # noqa: BLE001 - deliberate catch-all, see module docstring return err( ErrorCode.INTERNAL, "{0}: {1}".format(type(exc).__name__, exc), where=getattr(fn, "__name__", "unknown"), ) return wrapper def _jsonable(obj: Any) -> Any: """Guarantees: returns a structure json.dumps can serialize, degrading to repr() strings.""" try: json.dumps(obj) return obj except Exception: pass if isinstance(obj, dict): return {str(k): _jsonable(v) for k, v in obj.items()} if isinstance(obj, (list, tuple, set)): return [_jsonable(v) for v in obj] if isinstance(obj, (np.integer,)): return int(obj) if isinstance(obj, (np.floating,)): return float(obj) if isinstance(obj, np.ndarray): return obj.tolist() return repr(obj)[:500] # ============================================================================= # (B) Normalizer # ============================================================================= # CJK punctuation is NOT folded by NFKC, so it is mapped explicitly. Keeping the # table tiny and explicit matters: over-aggressive folding creates false merges. _PUNCT_MAP = { "。": ".", # 。 "、": ",", # 、 ",": ",", # , ".": ".", # . "・": " ", # ・ "「": '"', "」": '"', # 「 」 "『": '"', "』": '"', # 『 』 "「": '"', "」": '"', "‘": "'", "’": "'", "“": '"', "”": '"', "–": "-", "—": "-", "‐": "-", "‑": "-", "‒": "-", "―": "-", "ー": "ー", # keep the katakana prolonged mark as-is "…": "...", " ": " ", " ": " ", "": "", "": "", } _PUNCT_TABLE = {ord(k): v for k, v in _PUNCT_MAP.items()} # Boilerplate removal. Each pattern is deliberately anchored so that it can only # eat greetings / sign-offs / disclaimers - never the substance of a request. _BOILERPLATE_PATTERNS: List[re.Pattern] = [ # English greetings at the start of a line: "Hi team," / "Dear support:" re.compile(r"^[ \t]*(?:hi|hello|hey|dear|good\s+(?:morning|afternoon|evening))\b[^\n]{0,40}?[,:!.]\s*", re.I | re.M), # English sign-offs and everything that follows (signature blocks). # These MUST stay anchored to the start of a line: an unanchored # "cheers[\s\S]*$" would turn "Translate cheers into French" into # "translate", colliding with every other "Translate ... " prompt and # serving a wrong answer through the exact-match stage, which never # consults MismatchGuard. re.compile(r"^[ \t]*(?:best|kind|warm)\s+regards\b[\s\S]*$", re.I | re.M), re.compile(r"^[ \t]*(?:sincerely|cheers|thanks\s+again)\b[\s\S]*$", re.I | re.M), re.compile(r"^[ \t]*--[ \t]*$[\s\S]*", re.M), # Trailing politeness on its own line. re.compile(r"\b(?:thanks?|thank you)(?:\s+(?:so|very)\s+much)?(?:\s+in\s+advance)?[!.,]*[ \t]*$", re.I | re.M), re.compile(r"^[ \t]*(?:please\s+)?let\s+me\s+know\s+if[^\n]{0,80}$", re.I | re.M), # Leading polite-request frames. "Could you please tell me how do I reset my # password?" is the SAME request as "How do I reset my password?" - without # this the two score 0.73 and a legitimate reuse is lost. re.compile(r"^[ \t]*(?:could|can|would|will)\s+you\s+(?:kindly\s+|please\s+)?" r"(?:tell\s+me|let\s+me\s+know|explain|clarify|confirm|advise)\b[,:]?\s*", re.I | re.M), re.compile(r"^[ \t]*i(?:'m|\s+am)?\s*(?:was\s+)?wondering\b(?:\s+if|\s+whether)?[,:]?\s*", re.I | re.M), re.compile(r"^[ \t]*(?:just\s+a\s+)?quick\s+question[:,]?\s*", re.I | re.M), re.compile(r"^[ \t]*(?:please\s+)?let\s+me\s+know\s+(?=where|how|what|when|why|who|which)", re.I | re.M), re.compile(r"^[ \t]*(?:i\s+)?(?:have|had)\s+a\s+quick\s+question[:,.]?\s*", re.I | re.M), re.compile(r"お手数(?:ですが|ですけれども|をおかけしますが|をおかけしますけれども|ながら)[、,]?"), re.compile(r"(?:大変)?恐縮ですが[、,]?"), re.compile(r"(?:大変)?(?:申し訳(?:ありません|ございません)|すみません)が[、,]?"), # Confidentiality / AI disclaimers. re.compile(r"this\s+(?:e-?mail|message)\s+(?:and\s+any\s+attachments\s+)?(?:is|are)\s+confidential[\s\S]*$", re.I), re.compile(r"\bas\s+an\s+ai\s+(?:language\s+)?model\b[^.\n]*[.\n]?", re.I), re.compile(r"\bi'?m\s+sorry,?\s+but\s+as\s+an\s+ai\b[^.\n]*[.\n]?", re.I), # Japanese greetings / closings / hedges. re.compile(r"(?:いつも)?(?:大変)?お世話になって(?:おります|います)[。\.、,]?"), re.compile(r"(?:何卒|どうぞ)?よろしくお願い(?:いた|致)?します[。\.!!]?"), re.compile(r"よろしくお願いいたします[。\.!!]?"), re.compile(r"恐れ入りま(?:すが|す)[、,]?"), re.compile(r"お忙しいところ(?:恐縮ですが|失礼(?:いた)?します)[、,]?"), re.compile(r"ご確認のほど(?:よろしくお願いします)?[。\.]?"), re.compile(r"^[ \t]*(?:こんにちは|こんばんは|おはようございます|はじめまして)[、,。\.!!]?", re.M), re.compile(r"(?:どうも)?ありがとうございま(?:す|した)[。\.!!]?"), re.compile(r"^[ \t]*以上[、,。\.]?[ \t]*$", re.M), # A line that is nothing but an addressee ("山田様" / "サポート担当者様"). re.compile(r"^[ \t]*[^\n]{1,16}(?:様|御中)[、,]?[ \t]*$", re.M), ] _WS_RE = re.compile(r"[ \t ]+") _MULTINL_RE = re.compile(r"\n{2,}") _REPEAT_PUNCT_RE = re.compile(r"([?!.,])\1+") def _visible_len(text: str) -> int: """Guarantees: the number of non-whitespace characters, the unit the strip budget is measured in.""" return len("".join(text.split())) def strip_boilerplate(text: str) -> str: """Guarantees: removes only greeting/sign-off/disclaimer spans, never more than half the content per rule.""" out = text for pattern in _BOILERPLATE_PATTERNS: try: candidate = pattern.sub(" ", out) except Exception: continue if candidate == out: # no match: skip the (relatively costly) budget check continue before = _visible_len(out) after = _visible_len(candidate) # Fail-safe: a single boilerplate rule that swallows more than half of # what is left is almost certainly matching content, not a sign-off. # Skipping it can only cost a cache miss; applying it could collapse # two different prompts onto one key and serve a wrong answer. if before > 0 and after * 2 < before: continue out = candidate return out def normalize(text: Any) -> str: """Guarantees: deterministic, offline, idempotent canonical form; equal meaning-surface -> equal string.""" if text is None: return "" try: raw = text if isinstance(text, str) else str(text) except Exception: return "" if not raw: return "" raw = raw[: MAX_TEXT_CHARS * 2] try: out = unicodedata.normalize("NFKC", raw) except Exception: out = raw out = out.replace("\r\n", "\n").replace("\r", "\n") out = strip_boilerplate(out) out = out.translate(_PUNCT_TABLE) out = out.lower() # Collapse whitespace: per-line trim first, then fold blank lines away. lines = [_WS_RE.sub(" ", line).strip() for line in out.split("\n")] out = "\n".join(line for line in lines if line) out = _MULTINL_RE.sub("\n", out) out = _WS_RE.sub(" ", out) # Fold repeated and trailing sentence punctuation so "...ください。", "...ください" # and "password??" collapse onto one key. A single "?" is deliberately kept: # it distinguishes a question from a statement. out = _REPEAT_PUNCT_RE.sub(r"\1", out) out = out.strip().rstrip(" .!,;:") return out.strip()[:MAX_TEXT_CHARS] def light_normalize(text: Any) -> str: """Guarantees: NFKC + whitespace folding only - case, digits and negations are preserved for MismatchGuard.""" if text is None: return "" try: raw = text if isinstance(text, str) else str(text) except Exception: return "" try: out = unicodedata.normalize("NFKC", raw) except Exception: out = raw out = out.replace("\r\n", "\n").replace("\r", "\n") out = out.translate({ord(" "): " ", ord(" "): " ", ord(""): None}) out = _WS_RE.sub(" ", out) return out.strip()[:MAX_TEXT_CHARS] def exact_key(text: Any) -> str: """Guarantees: the sha256 of normalize(text) - the canonical exact-match key of stage 1.""" return hashlib.sha256(normalize(text).encode("utf-8", "replace")).hexdigest() # ============================================================================= # (C) Vectorizer - numpy only, no sklearn, no tokenizer, no word boundaries # ============================================================================= _POPCOUNT8 = np.array([bin(i).count("1") for i in range(256)], dtype=np.uint8) _MASK64 = 0xFFFFFFFFFFFFFFFF _M1 = 0x5555555555555555 _M2 = 0x3333333333333333 _M4 = 0x0F0F0F0F0F0F0F0F _H01 = 0x0101010101010101 def _ngram_counts(text: str, n: int = NGRAM_N) -> Counter: """Guarantees: character n-gram multiset that works for CJK and any unspaced script.""" if not text: return Counter() padded = " " + text + " " n = max(1, min(8, int(n))) if len(padded) <= n: return Counter([padded]) return Counter(padded[i : i + n] for i in range(len(padded) - n + 1)) def char_ngram_hash(text: str, n: int = 3, dim: int = 4096) -> np.ndarray: """Guarantees: a deterministic L2-normalized float32 vector of length dim, tokenizer-free and offline.""" dim = max(16, int(dim)) vec = np.zeros(dim, dtype=np.float32) counts = _ngram_counts(text or "", n) if not counts: return vec idxs = np.empty(len(counts), dtype=np.int64) vals = np.empty(len(counts), dtype=np.float32) for i, (gram, count) in enumerate(counts.items()): # crc32 is stable across processes and Python versions (unlike hash()), # which is what makes export/import of an index reproducible. h = zlib.crc32(gram.encode("utf-8", "replace")) & 0xFFFFFFFF idxs[i] = h % dim sign = 1.0 if (h >> 17) & 1 else -1.0 # sub-linear term weighting damps the effect of a repeated n-gram vals[i] = sign * (1.0 + math.log(count)) np.add.at(vec, idxs, vals) norm = float(np.linalg.norm(vec)) if norm > 0.0: vec /= np.float32(norm) return vec def simhash(text: str, bits: int = 64) -> int: """Guarantees: a stable b-bit fingerprint where near-duplicate texts differ in few bits.""" bits = 64 if bits not in (32, 64, 128) else int(bits) nbytes = bits // 8 counts = _ngram_counts(text or "", NGRAM_N) if not counts: return 0 digests = bytearray() weights = np.empty(len(counts), dtype=np.int32) for i, (gram, count) in enumerate(counts.items()): digests += hashlib.blake2b(gram.encode("utf-8", "replace"), digest_size=nbytes).digest() weights[i] = count arr = np.frombuffer(bytes(digests), dtype=np.uint8).reshape(-1, nbytes) bit_matrix = np.unpackbits(arr, axis=1).astype(np.int32) # (m, bits), MSB first acc = ((bit_matrix * 2 - 1) * weights[:, None]).sum(axis=0) packed = np.packbits((acc > 0).astype(np.uint8)) return int.from_bytes(packed.tobytes(), "big") def hamming(a: int, b: int) -> int: """Guarantees: exact Hamming distance of two 64-bit fingerprints using pure bit arithmetic.""" x = (int(a) ^ int(b)) & _MASK64 x = x - ((x >> 1) & _M1) x = (x & _M2) + ((x >> 2) & _M2) x = (x + (x >> 4)) & _M4 return int(((x * _H01) & _MASK64) >> 56) def hamming_array(fingerprints: np.ndarray, query: int) -> np.ndarray: """Guarantees: vectorized Hamming distances (uint8 popcount table) for a whole partition at once.""" if fingerprints.size == 0: return np.zeros(0, dtype=np.int32) xor = np.bitwise_xor(np.ascontiguousarray(fingerprints), np.uint64(int(query) & _MASK64)) return _POPCOUNT8[xor.view(np.uint8).reshape(-1, 8)].sum(axis=1).astype(np.int32) def cosine(a: np.ndarray, b: np.ndarray) -> float: """Guarantees: cosine similarity in [-1, 1]; returns 0.0 for degenerate vectors instead of NaN.""" try: na = float(np.linalg.norm(a)) nb = float(np.linalg.norm(b)) if na <= 0.0 or nb <= 0.0: return 0.0 return float(np.clip(float(np.dot(a, b)) / (na * nb), -1.0, 1.0)) except Exception: return 0.0 def featurize(text: str, dim: int = None, n: int = None) -> Dict[str, Any]: """Guarantees: every local feature (normalized text, key, vector, fingerprint) computed in one offline pass.""" norm = normalize(text) return { "norm": norm, "key": hashlib.sha256(norm.encode("utf-8", "replace")).hexdigest(), "vector": char_ngram_hash(norm, NGRAM_N if n is None else n, VECTOR_DIM if dim is None else dim), "simhash": simhash(norm, SIMHASH_BITS), } # ============================================================================= # (E) SafetyFilter - never cache a secret # ============================================================================= class ReasonCode(str, Enum): """Stable reason codes returned identically by the UI and by the JSON API.""" OK = "ok" EMPTY_PROMPT = "empty_prompt" EMPTY_RESPONSE = "empty_response" CREDIT_CARD = "credit_card_luhn" CREDENTIAL_PREFIX = "credential_prefix" JWT = "jwt_structure" HIGH_ENTROPY = "high_entropy_secret" CONTACT_PII = "contact_pii_excess" PRIVATE_KEY = "private_key_block" REASON_HELP: Dict[str, str] = { ReasonCode.OK.value: "Safe to cache.", ReasonCode.EMPTY_PROMPT.value: "Prompt was empty after normalization.", ReasonCode.EMPTY_RESPONSE.value: "Response was empty.", ReasonCode.CREDIT_CARD.value: "A digit run passed the Luhn checksum (probable card number).", ReasonCode.CREDENTIAL_PREFIX.value: "A known credential prefix was found (sk-, ghp_, AKIA, xoxb-, AIza, hf_...).", ReasonCode.JWT.value: "A three-part JWT structure was found.", ReasonCode.HIGH_ENTROPY.value: "A long alphanumeric run exceeded the Shannon-entropy threshold.", ReasonCode.CONTACT_PII.value: "Too many e-mail addresses or phone numbers.", ReasonCode.PRIVATE_KEY.value: "A PEM private-key block was found.", } _CARD_CANDIDATE_RE = re.compile(r"(? bool: """Guarantees: True only for a 13-19 digit string whose Luhn checksum is valid.""" digits = "".join(ch for ch in digits if ch.isdigit()) if not (13 <= len(digits) <= 19): return False total = 0 parity = len(digits) % 2 for i, ch in enumerate(digits): d = ord(ch) - 48 if i % 2 == parity: d *= 2 if d > 9: d -= 9 total += d return total % 10 == 0 def shannon_entropy(text: str) -> float: """Guarantees: Shannon entropy in bits/char computed locally, 0.0 for empty input.""" if not text: return 0.0 counts = Counter(text) n = float(len(text)) return float(-sum((c / n) * math.log2(c / n) for c in counts.values())) _SEGMENT_SPLIT_RE = re.compile(r"[-_/=.+:@]") _CAMEL_SPLIT_RE = re.compile(r"[A-Z]+(?![a-z])|[A-Z][a-z]+|[a-z]+|\d+") def _looks_like_identifier(token: str) -> bool: """Guarantees: True for URL slugs, snake_case names and CamelCase identifiers - never for a random key. Shannon entropy alone cannot separate the two populations: measured over 340 random 24-48 char keys the minimum was 3.97 bits/char, while ordinary identifiers such as "com/blog/how-to-reset-your-password-2024" (4.16) and "UserAuthenticationServiceImpl2024Handler" (4.36) sit in the same band. Structure is what separates them - a real key has no word-shaped segments. With this filter the screen catches 97.4% of random keys and stops refusing ordinary URLs and filenames. """ segments = [s for s in _SEGMENT_SPLIT_RE.split(token) if s] if len(segments) >= 2: words = sum(1 for s in segments if s.isalpha() and len(s) >= 3) if words >= max(2, int(0.6 * len(segments))): return True parts = _CAMEL_SPLIT_RE.findall(token) wordy = [p for p in parts if p.isalpha() and len(p) >= 3] return len(wordy) >= 3 and sum(len(p) for p in wordy) >= 0.7 * len(token) def _has_high_entropy_secret(text: str) -> bool: """Guarantees: True only for long mixed-class runs whose entropy exceeds the configured threshold.""" for match in _ENTROPY_TOKEN_RE.finditer(text): token = match.group(0) if len(token) > 512: token = token[:512] has_digit = any(ch.isdigit() for ch in token) has_alpha = any(ch.isalpha() for ch in token) if not (has_digit and has_alpha): continue if _looks_like_identifier(token): continue entropy = shannon_entropy(token) # Long hex strings (hashes, request ids) cap out near 4.0 bits/char, so a # slightly lower bar is used for them; base64-ish secrets go well above 4. limit = ENTROPY_THRESHOLD if not _HEXY_RE.match(token) else min(ENTROPY_THRESHOLD, 3.75) if entropy >= limit and len(set(token)) >= 12: return True return False def should_cache(prompt: str, response: str) -> Tuple[bool, str]: """Guarantees: never raises and returns (False, reason_code) whenever a secret-shaped pattern is present.""" try: prompt = prompt or "" response = response or "" blob = prompt + "\n" + response if not normalize(prompt): return False, ReasonCode.EMPTY_PROMPT.value if not response.strip(): return False, ReasonCode.EMPTY_RESPONSE.value if _PRIVATE_KEY_RE.search(blob): return False, ReasonCode.PRIVATE_KEY.value if _JWT_RE.search(blob): return False, ReasonCode.JWT.value for pattern in _CREDENTIAL_RES: if pattern.search(blob): return False, ReasonCode.CREDENTIAL_PREFIX.value for match in _CARD_CANDIDATE_RE.finditer(blob): if luhn_ok(match.group(0)): return False, ReasonCode.CREDIT_CARD.value if _has_high_entropy_secret(blob): return False, ReasonCode.HIGH_ENTROPY.value if len(_EMAIL_RE.findall(blob)) > MAX_EMAILS: return False, ReasonCode.CONTACT_PII.value if len(_PHONE_RE.findall(blob)) > MAX_PHONES: return False, ReasonCode.CONTACT_PII.value return True, ReasonCode.OK.value except Exception: # Fail closed: if the screen itself fails we refuse to cache. return False, ReasonCode.HIGH_ENTROPY.value # ============================================================================= # (F) MismatchGuard - the quality core # ============================================================================= # # WHY THIS EXISTS # --------------- # A character n-gram cosine of 0.95+ means "these two strings look alike", which # is NOT the same as "these two questions have the same answer". Serving a cached # answer for a different question is not a cache miss, it is a *wrong answer* - # a quality incident that is far more expensive than the tokens it saved. # Every check below exists because of a concrete near-duplicate pair that a pure # similarity score happily accepts. Each check is intentionally conservative: # when in doubt we return a miss (cheap) rather than a wrong hit (expensive). _NEG_EN_RE = re.compile( r"\b(?:not|n't|never|no|none|cannot|can't|cant|won't|wont|don't|dont|doesn't|doesnt|didn't|didnt|" r"isn't|isnt|aren't|arent|wasn't|wasnt|shouldn't|shouldnt|without|unable|fails?|failed|except|" r"exclude[sd]?|excluding|omit(?:s|ted)?|" r"disable[sd]?|deny|denied|forbidden|prohibited)\b", re.I, ) _NEG_JA_RE = re.compile( r"(?:ない|無い|ありません|ません|できない|出来ない|しない|不可|不能|禁止|以外|除く|除外|なし|無し|" r"いいえ|未対応|非対応|不要|不可能)" ) _NUM_RE = re.compile(r"(? str: """Guarantees: removes a leading polite-request wrapper so it cannot masquerade as a question type.""" return _REQUEST_FRAME_RE.sub("", text or "", count=1) def _negation_profile(text: str) -> bool: """Guarantees: True iff the text carries at least one explicit negation cue (EN or JA).""" return bool(_NEG_EN_RE.search(text) or _NEG_JA_RE.search(text)) def _numeric_profile(text: str) -> Tuple[frozenset, frozenset]: """Guarantees: (bare numbers, number+unit pairs) with thousands separators folded away.""" numbers = set() for raw in _NUM_RE.findall(text): cleaned = raw.replace(",", "") try: value = float(cleaned) numbers.add(str(int(value)) if value.is_integer() else str(value)) except Exception: numbers.add(cleaned) units = set() for value, unit in _UNIT_RE.findall(text): units.add(value.replace(",", "") + unit.lower().replace("%", "%")) return frozenset(numbers), frozenset(units) def _proper_noun_profile(text: str) -> frozenset: """Guarantees: proper nouns / model identifiers only, with sentence-initial capitalization ignored.""" found = set() for sentence in _SENT_SPLIT_RE.split(text): sentence = sentence.strip() if not sentence: continue tokens = _PROPER_RE.findall(sentence) if tokens and sentence.startswith(tokens[0]): tokens = tokens[1:] # sentence-initial capital carries no information for token in tokens: if token.lower() in _CAP_STOPWORDS: continue if len(token) < 2: continue found.add(token.lower()) for token in _MODEL_RE.findall(text): if any(ch.isdigit() for ch in token) and any(ch.isalpha() for ch in token): found.add(token.lower()) return frozenset(found) def _temporal_profile(text: str) -> frozenset: """Guarantees: the set of time anchors (years, relative-date words, month names) in the text.""" lowered = text.lower() found = set(_YEAR_RE.findall(text)) found.update(m.lower() for m in _TIME_RE_EN.findall(lowered)) # Japanese has no word boundaries, so a substring test is the correct test. for word in _TIME_WORDS_JA: if word in text: found.add(word) return frozenset(found) def _question_profile(text: str) -> frozenset: """Guarantees: the interrogative types present, with a polite request wrapper ignored. "Could you please tell me how do I reset my password?" asks the same KIND of question as "How do I reset my password?"; without stripping the wrapper the leading "Could" registers as a yes/no question and vetoes a valid reuse. """ stripped = _strip_request_frame(text) return frozenset(label for label, pattern in _QUESTION_PATTERNS if pattern.search(stripped)) def _fmt_set(values: Iterable[str], limit: int = 4) -> str: """Guarantees: a short, stable, human-readable rendering of a set for the audit screen.""" items = sorted(str(v) for v in values) if not items: return "{}" shown = items[:limit] suffix = ",+{0}".format(len(items) - limit) if len(items) > limit else "" return "{" + ",".join(shown) + suffix + "}" def is_semantically_safe(query: str, candidate: str) -> Tuple[bool, List[str]]: """Guarantees: never raises and returns (False, reasons) whenever a meaning-changing difference is detected.""" reasons: List[str] = [] try: q = light_normalize(query) c = light_normalize(candidate) if not q or not c: return False, ["empty_text"] # 1) NEGATION FLIP. # "Can I cancel my plan?" vs "Can I not cancel my plan?" -> cosine ~0.97, # opposite answers. Japanese: 「返品できます」 vs 「返品できません」. if "negation" not in GUARD_DISABLE: if _negation_profile(q) != _negation_profile(c): reasons.append("negation_mismatch:q={0},c={1}".format(_negation_profile(q), _negation_profile(c))) # 2) QUANTITY / UNIT DIFFERENCE. # "retry after 3 seconds" vs "retry after 30 seconds" differ by one # character; "a 100GB plan" vs "a 100MB plan" differ by one letter. # Any difference in the numeric token set invalidates reuse. if "numeric" not in GUARD_DISABLE: qn, qu = _numeric_profile(q) cn, cu = _numeric_profile(c) if qn != cn: reasons.append("numeric_mismatch:q={0},c={1}".format(_fmt_set(qn), _fmt_set(cn))) elif qu != cu: reasons.append("unit_mismatch:q={0},c={1}".format(_fmt_set(qu), _fmt_set(cu))) # 3) PROPER NOUN / MODEL NUMBER DIFFERENCE. # "Does the X1 Carbon support 32GB?" vs "Does the X1 Yoga support 32GB?" # or "migrate from Postgres" vs "migrate from Oracle": same shape, # different product, completely different answer. if "proper_noun" not in GUARD_DISABLE: # q/c come from light_normalize(), which folds full-width to ASCII but # KEEPS case - exactly what proper-noun detection needs ("ABC-100" and # "ABC-100" are the same product, "Carbon" and "Yoga" are not). qp = _proper_noun_profile(q) cp = _proper_noun_profile(c) if qp != cp: reasons.append("proper_noun_mismatch:q={0},c={1}".format(_fmt_set(qp), _fmt_set(cp))) # 4) TENSE / TIME ANCHOR DIFFERENCE. # "What is the 2024 tax rate?" vs "What is the 2025 tax rate?", or # "latest release" vs "last year's release". Time-anchored answers go # stale the moment the anchor moves. if "temporal" not in GUARD_DISABLE: qt = _temporal_profile(q) ct = _temporal_profile(c) if qt != ct: reasons.append("temporal_mismatch:q={0},c={1}".format(_fmt_set(qt), _fmt_set(ct))) # 5) QUESTION TYPE SWITCH. # "How do I reset my password?" vs "Why do I need to reset my password?" # share almost every n-gram but ask for a procedure vs a rationale. if "question_type" not in GUARD_DISABLE: qq = _question_profile(q) cq = _question_profile(c) if qq != cq: reasons.append("question_type_mismatch:q={0},c={1}".format(_fmt_set(qq), _fmt_set(cq))) return (len(reasons) == 0), reasons except Exception as exc: # fail closed - an unusable guard must not create wrong hits return False, ["guard_error:{0}".format(type(exc).__name__)] # ============================================================================= # (G) Accounting # ============================================================================= _CJK_RANGES = ( (0x3000, 0x303F), (0x3040, 0x30FF), (0x3400, 0x4DBF), (0x4E00, 0x9FFF), (0xF900, 0xFAFF), (0xFF00, 0xFFEF), (0xAC00, 0xD7AF), (0x1100, 0x11FF), ) def _is_cjk(ch: str) -> bool: """Guarantees: True for CJK/Kana/Hangul/full-width code points, decided offline by range.""" code = ord(ch) for lo, hi in _CJK_RANGES: if lo <= code <= hi: return True return False def estimate_tokens(text: Any) -> int: """Guarantees: a dependency-free token estimate (~4 ASCII chars = 1 token, ~1 CJK char = 1 token).""" if not text: return 0 try: s = text if isinstance(text, str) else str(text) except Exception: return 0 cjk = 0 for ch in s: if _is_cjk(ch): cjk += 1 other = len(s) - cjk return int(cjk + math.ceil(other / 4.0)) def savings(entry: Dict[str, Any], price_in: float = None, price_out: float = None) -> Dict[str, Any]: """Guarantees: the estimated tokens and USD avoided by one reuse of this entry; never raises.""" try: pin = PRICE_IN_PER_1K if price_in is None else float(price_in) pout = PRICE_OUT_PER_1K if price_out is None else float(price_out) tokens_in = int(entry.get("tokens_in", 0) or 0) tokens_out = int(entry.get("tokens_out", 0) or 0) cost = (tokens_in / 1000.0) * pin + (tokens_out / 1000.0) * pout return { "saved_tokens_in": tokens_in, "saved_tokens_out": tokens_out, "saved_tokens": tokens_in + tokens_out, "saved_cost_usd": round(float(cost), 6), } except Exception: return {"saved_tokens_in": 0, "saved_tokens_out": 0, "saved_tokens": 0, "saved_cost_usd": 0.0} class Accounting: """Guarantees: thread-safe cumulative savings counters keyed by tenant and by route.""" def __init__(self) -> None: """Guarantees: an empty, lock-protected counter table; no I/O and no allocation of size.""" self._lock = threading.RLock() self._rows: Dict[Tuple[str, str], Dict[str, float]] = {} def add(self, tenant_id: str, route: str, event: str, saved: Dict[str, Any]) -> None: """Guarantees: accumulates one event without ever raising into the caller.""" try: with self._lock: key = (str(tenant_id), str(route or "default")) row = self._rows.get(key) if row is None: row = {"hits": 0.0, "misses": 0.0, "stores": 0.0, "rejects": 0.0, "saved_tokens": 0.0, "saved_cost_usd": 0.0} if len(self._rows) < MAX_TENANTS * 64: self._rows[key] = row else: return if event in ("hit", "miss", "store", "reject"): row[{"hit": "hits", "miss": "misses", "store": "stores", "reject": "rejects"}[event]] += 1.0 row["saved_tokens"] += float(saved.get("saved_tokens", 0) or 0) row["saved_cost_usd"] += float(saved.get("saved_cost_usd", 0.0) or 0.0) except Exception: return def frame(self) -> pd.DataFrame: """Guarantees: a DataFrame snapshot (possibly empty but always with the documented columns).""" cols = ["tenant_id", "route", "hits", "misses", "stores", "rejects", "hit_rate", "saved_tokens", "saved_cost_usd"] try: with self._lock: rows = [dict(tenant_id=k[0], route=k[1], **v) for k, v in self._rows.items()] if not rows: return pd.DataFrame(columns=cols) df = pd.DataFrame(rows) total = df["hits"] + df["misses"] df["hit_rate"] = np.where(total > 0, (df["hits"] / total).round(4), 0.0) df["saved_cost_usd"] = df["saved_cost_usd"].round(6) for col in ("hits", "misses", "stores", "rejects", "saved_tokens"): df[col] = df[col].astype(int) return df[cols].sort_values(["tenant_id", "route"]).reset_index(drop=True) except Exception: return pd.DataFrame(columns=cols) def reset(self) -> None: """Guarantees: clears every counter; used by tests and by the reset control.""" with self._lock: self._rows.clear() # ============================================================================= # (J) Enrichment - optional remote embeddings, never on the critical path # ============================================================================= class Embedder: """Guarantees: an optional re-ranking signal that can fail in any way without affecting correctness.""" def __init__(self) -> None: """Guarantees: no client is built and no network is touched until the first embed() call.""" self._lock = threading.RLock() self._client = None self._cache: "OrderedDict[str, np.ndarray]" = OrderedDict() self._fails = 0 self._disabled_until = 0.0 self._calls = 0 self._errors = 0 self._last_error = "" self._dim: Optional[int] = None # -- internals --------------------------------------------------------- def _get_client(self): """Guarantees: lazily builds an InferenceClient (never at import time); returns None on any failure.""" if self._client is not None: return self._client if not EMBED_ENABLED: return None try: from huggingface_hub import InferenceClient # imported lazily on purpose except Exception as exc: self._last_error = "import: {0}".format(exc) return None for kwargs in ( {"model": EMBED_MODEL, "token": HF_TOKEN, "timeout": EMBED_TIMEOUT}, {"model": EMBED_MODEL, "api_key": HF_TOKEN, "timeout": EMBED_TIMEOUT}, {"model": EMBED_MODEL, "token": HF_TOKEN}, {"model": EMBED_MODEL}, ): try: self._client = InferenceClient(**kwargs) return self._client except TypeError: continue except Exception as exc: self._last_error = "client: {0}".format(exc) return None return None def _trip(self, exc: Exception) -> None: """Guarantees: opens the circuit breaker after repeated failures so we stop burning credits.""" self._errors += 1 self._fails += 1 self._last_error = "{0}: {1}".format(type(exc).__name__, str(exc)[:160]) if self._fails >= EMBED_FAIL_THRESHOLD: self._disabled_until = time.time() + EMBED_COOLDOWN_SEC @staticmethod def _to_matrix(raw: Any, n: int) -> Optional[np.ndarray]: """Guarantees: converts any feature-extraction payload shape into an (n, d) float32 matrix or None.""" arr = np.asarray(raw, dtype=np.float32) if arr.ndim == 3: # (batch, tokens, dim) -> mean pool arr = arr.mean(axis=1) if arr.ndim == 1: arr = arr.reshape(1, -1) if arr.ndim != 2 or arr.shape[0] != n or arr.shape[1] < 2: return None norms = np.linalg.norm(arr, axis=1, keepdims=True) norms[norms == 0.0] = 1.0 return (arr / norms).astype(np.float32) def _cache_get(self, key: str) -> Optional[np.ndarray]: """Guarantees: returns a cached embedding (marking it recently used) or None.""" with self._lock: vec = self._cache.get(key) if vec is not None: self._cache.move_to_end(key) return vec def _cache_put(self, key: str, vec: np.ndarray) -> None: """Guarantees: stores one embedding and evicts the oldest so the cache stays at EMBED_CACHE_SIZE.""" with self._lock: self._cache[key] = vec self._cache.move_to_end(key) while len(self._cache) > EMBED_CACHE_SIZE: self._cache.popitem(last=False) # -- public ------------------------------------------------------------ def available(self) -> bool: """Guarantees: True only when a token exists and the circuit breaker is closed.""" return bool(EMBED_ENABLED) and time.time() >= self._disabled_until def embed(self, texts: Sequence[str]) -> Optional[np.ndarray]: """Guarantees: returns an (n, d) L2-normalized matrix, or None on ANY problem - callers must handle None.""" try: if not texts: return None texts = [(t or "")[:1000] for t in texts] keys = [hashlib.sha1(t.encode("utf-8", "replace")).hexdigest() for t in texts] cached = [self._cache_get(k) for k in keys] missing = [i for i, v in enumerate(cached) if v is None] if missing: if not self.available(): return None client = self._get_client() if client is None: return None payload = [texts[i] for i in missing] self._calls += 1 try: raw = client.feature_extraction(payload if len(payload) > 1 else payload[0]) except TypeError: raw = client.feature_extraction(payload if len(payload) > 1 else payload[0], model=EMBED_MODEL) matrix = self._to_matrix(raw, len(payload)) if matrix is None: self._trip(ValueError("unexpected embedding shape")) return None self._fails = 0 self._dim = int(matrix.shape[1]) for pos, idx in enumerate(missing): vec = matrix[pos] cached[idx] = vec self._cache_put(keys[idx], vec) dims = {v.shape[0] for v in cached if v is not None} if len(dims) != 1 or any(v is None for v in cached): return None return np.vstack(cached).astype(np.float32) except Exception as exc: # 402 / 429 / timeout / DNS / anything at all try: self._trip(exc) except Exception: pass return None def status(self) -> Dict[str, Any]: """Guarantees: a JSON-safe snapshot of embedding health, with no token material in it.""" now = time.time() return { "enabled": bool(EMBED_ENABLED), "available_now": self.available(), "model": EMBED_MODEL if EMBED_ENABLED else None, "weight": EMBED_WEIGHT if EMBED_ENABLED else 0.0, "calls": self._calls, "errors": self._errors, "consecutive_failures": self._fails, "cooldown_remaining_sec": max(0, int(self._disabled_until - now)), "dim": self._dim, "cache_size": len(self._cache), "last_error": self._last_error[:160], } _EMBEDDER = Embedder() def embed_remote(texts: Sequence[str]) -> Optional[np.ndarray]: """Guarantees: optional remote embeddings, or None - the caller must remain fully functional without it.""" return _EMBEDDER.embed(texts) # ============================================================================= # (D) CacheIndex - strictly partitioned per tenant # ============================================================================= # # TENANT ISOLATION # ---------------- # Every read and write goes through _partition(tenant_id), which returns exactly # one dict. No method accepts more than one partition, no method iterates over # self._parts to answer a lookup, and vectors/fingerprints live inside the # partition. There is therefore no code path that can surface tenant A's entry # to tenant B - isolation is structural, not a filter applied after the fact. _TENANT_SAFE_RE = re.compile(r"[^A-Za-z0-9_.\-:@]+") def normalize_tenant(tenant_id: Any) -> str: """Guarantees: a non-empty, bounded, filesystem/JSON-safe partition id ("default" when unset).""" try: raw = "" if tenant_id is None else str(tenant_id) except Exception: raw = "" raw = _TENANT_SAFE_RE.sub("_", raw.strip())[:64] return raw or "default" class CacheIndex: """Guarantees: bounded memory, per-tenant isolation, and a three-stage lookup that never raises.""" def __init__( self, max_entries: int = MAX_ENTRIES, max_text_chars: int = MAX_TEXT_CHARS, dim: int = VECTOR_DIM, name: str = "live", record_events: bool = True, max_total_entries: int = None, ) -> None: """Guarantees: an empty index with bounded limits; allocates nothing per tenant until first use.""" self.max_entries = max(1, int(max_entries)) self.max_total_entries = max(self.max_entries, int(max_total_entries or MAX_TOTAL_ENTRIES)) self.max_text_chars = max(16, int(max_text_chars)) self.dim = max(16, int(dim)) self.name = name self.record_events = record_events self._lock = threading.RLock() self._parts: "OrderedDict[str, Dict[str, Any]]" = OrderedDict() self._last_expire_sweep = 0.0 self._counter = 0 # -- partition plumbing ------------------------------------------------ def _new_partition(self, tenant_id: str) -> Dict[str, Any]: """Guarantees: a fresh, empty partition with the documented structure and no shared buffers.""" cap = max(1, min(64, self.max_entries)) return { "tenant_id": tenant_id, "exact": {}, # norm-key -> slot "entries": [], # slot -> entry dict | None "matrix": np.zeros((cap, self.dim), dtype=np.float32), # slot -> unit vector "simhashes": np.zeros(cap, dtype=np.uint64), # slot -> fingerprint "alive": np.zeros(cap, dtype=bool), "lru": OrderedDict(), # slot -> True (oldest first) "free": [], "stats": {"stored": 0, "evicted": 0, "expired": 0, "invalidated": 0, "rejected": 0, "hits": 0, "misses": 0, "updates": 0}, } def _partition(self, tenant_id: str, create: bool = True) -> Optional[Dict[str, Any]]: """Guarantees: returns exactly one tenant's partition - the single access point for all data.""" tid = normalize_tenant(tenant_id) part = self._parts.get(tid) if part is None and create: if len(self._parts) >= MAX_TENANTS: # Evict the least-recently-used *tenant* so an unbounded tenant id # space cannot exhaust memory. self._parts.popitem(last=False) part = self._new_partition(tid) self._parts[tid] = part if part is not None: self._parts.move_to_end(tid) return part def _grow(self, part: Dict[str, Any], needed: int) -> None: """Guarantees: capacity grows geometrically and never beyond max_entries.""" cap = int(part["matrix"].shape[0]) if needed < cap: return new_cap = min(self.max_entries, max(64, cap * 2)) while new_cap <= needed and new_cap < self.max_entries: new_cap = min(self.max_entries, new_cap * 2) if new_cap <= cap: return matrix = np.zeros((new_cap, self.dim), dtype=np.float32) matrix[:cap] = part["matrix"] part["matrix"] = matrix sims = np.zeros(new_cap, dtype=np.uint64) sims[:cap] = part["simhashes"] part["simhashes"] = sims alive = np.zeros(new_cap, dtype=bool) alive[:cap] = part["alive"] part["alive"] = alive def _drop_slot(self, part: Dict[str, Any], slot: int, stat_key: str) -> None: """Guarantees: fully removes one entry (exact key, vector, fingerprint, LRU) and frees its slot.""" entries = part["entries"] if slot < 0 or slot >= len(entries): return entry = entries[slot] if entry is None: return part["exact"].pop(entry.get("key", ""), None) part["lru"].pop(slot, None) part["alive"][slot] = False part["matrix"][slot] = 0.0 part["simhashes"][slot] = np.uint64(0) entries[slot] = None part["free"].append(slot) part["stats"][stat_key] = part["stats"].get(stat_key, 0) + 1 def _live_total(self) -> int: """Guarantees: the number of live entries across every partition (memory accounting).""" return sum(len(p["lru"]) for p in self._parts.values()) def _enforce_global_budget(self) -> None: """Guarantees: total entries stay under max_total_entries by evicting the LRU entry of the largest partition. This is an eviction-only cross-partition operation: it deletes, it never reads or moves data between tenants, so tenant isolation is preserved. """ total = self._live_total() while total >= self.max_total_entries and self._parts: victim = max(self._parts.values(), key=lambda p: len(p["lru"])) if not victim["lru"]: break slot, _ = next(iter(victim["lru"].items())) self._drop_slot(victim, int(slot), "evicted") total -= 1 def _alloc_slot(self, part: Dict[str, Any]) -> int: """Guarantees: returns a usable slot index, evicting the LRU entry when the partition or budget is full.""" self._enforce_global_budget() while (len(part["lru"]) >= self.max_entries) and part["lru"]: old_slot, _ = next(iter(part["lru"].items())) self._drop_slot(part, int(old_slot), "evicted") if part["free"]: return int(part["free"].pop()) slot = len(part["entries"]) self._grow(part, slot) if slot >= int(part["matrix"].shape[0]): # Capacity is capped at max_entries: force an eviction and reuse a slot. if part["lru"]: old_slot, _ = next(iter(part["lru"].items())) self._drop_slot(part, int(old_slot), "evicted") if part["free"]: return int(part["free"].pop()) raise MemoryError("index capacity exhausted") part["entries"].append(None) return slot def _next_id(self) -> int: """Guarantees: a monotonically increasing per-index counter (lock is held by the caller).""" self._counter += 1 return self._counter def _features(self, text: str, provided: Any = None) -> Dict[str, Any]: """Guarantees: features that always match THIS index's vector dimension, recomputing if they do not.""" if isinstance(provided, dict): vector = provided.get("vector") if isinstance(vector, np.ndarray) and vector.shape == (self.dim,) and provided.get("key"): return provided return featurize(text, self.dim) # -- (D-1) put --------------------------------------------------------- def put(self, tenant_id: str, prompt: str, response: str, meta: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """Guarantees: stores only screened content, bounded in size and count, inside one tenant partition.""" try: meta = dict(meta or {}) tid = normalize_tenant(tenant_id) route = str(meta.get("route") or "default")[:64] prompt = "" if prompt is None else str(prompt) response = "" if response is None else str(response) allow_empty = bool(meta.get("allow_empty_response", False)) skip_safety = bool(meta.get("skip_safety", False)) if not prompt.strip(): return err(ErrorCode.EMPTY_PROMPT, "prompt is empty", stored=False, reason=ReasonCode.EMPTY_PROMPT.value) if not response.strip() and not allow_empty: return err(ErrorCode.EMPTY_RESPONSE, "response is empty", stored=False, reason=ReasonCode.EMPTY_RESPONSE.value) truncated = len(prompt) > self.max_text_chars or len(response) > self.max_text_chars prompt = prompt[: self.max_text_chars] response = response[: self.max_text_chars] if not skip_safety: safe, reason = should_cache(prompt, response if response.strip() else "x") if not safe: with self._lock: part = self._partition(tid) part["stats"]["rejected"] += 1 return ok(stored=False, tenant_id=tid, reason=reason, reason_help=REASON_HELP.get(reason, ""), truncated=truncated) features = self._features(prompt, meta.get("features")) norm = features["norm"] key = features["key"] if not norm: return err(ErrorCode.EMPTY_PROMPT, "prompt is empty after normalization", stored=False, reason=ReasonCode.EMPTY_PROMPT.value) now = _safe_float(meta.get("now"), 0.0) or time.time() ttl = max(1, min(MAX_TTL_SEC, _safe_int(meta.get("ttl_sec"), DEFAULT_TTL_SEC) or DEFAULT_TTL_SEC)) # An imported snapshot is untrusted input: a bogus created_at would # report a negative age, and a bogus expires_at (1e18, inf, NaN) # would create an entry that sweep_expired can never remove. created_at = min(_safe_float(meta.get("created_at"), 0.0) or now, now) expires_at = _safe_float(meta.get("expires_at"), 0.0) or (created_at + ttl) expires_at = min(max(expires_at, now - 1.0), now + MAX_TTL_SEC) tokens_in = estimate_tokens(prompt) tokens_out = estimate_tokens(response) with self._lock: part = self._partition(tid) updated = False slot = part["exact"].get(key) if slot is None or slot >= len(part["entries"]) or part["entries"][slot] is None: slot = self._alloc_slot(part) else: updated = True entry = { "id": key, "key": key, "tenant_id": tid, "slot": int(slot), "prompt": prompt, "norm": norm, "response": response, "route": route, "meta": {k: v for k, v in meta.items() if k not in ("features", "skip_safety", "allow_empty_response", "now")}, "created_at": created_at, "expires_at": expires_at, "ttl_sec": ttl, "hits": max(0, _safe_int(meta.get("hits"), 0)), "last_hit_at": _safe_float(meta.get("last_hit_at"), 0.0), "tokens_in": tokens_in, "tokens_out": tokens_out, "chars": len(prompt) + len(response), } part["entries"][slot] = entry part["matrix"][slot] = features["vector"] part["simhashes"][slot] = np.uint64(int(features["simhash"]) & _MASK64) part["alive"][slot] = True part["exact"][key] = slot part["lru"][slot] = True part["lru"].move_to_end(slot) part["stats"]["updates" if updated else "stored"] += 1 live = len(part["lru"]) if self.record_events: OBS.record(tenant_id=tid, route=route, event="store", stage="store", similarity=1.0 if updated else 0.0, latency_ms=0.0, saved_tokens=0, saved_cost=0.0, guard_reasons=[], entry_id=key, prompt=prompt) ACC.add(tid, route, "store", {"saved_tokens": 0, "saved_cost_usd": 0.0}) return ok(stored=True, updated=updated, tenant_id=tid, entry_id=key, route=route, reason=ReasonCode.OK.value, ttl_sec=ttl, expires_at=expires_at, tokens_in=tokens_in, tokens_out=tokens_out, truncated=truncated, entries_in_tenant=live) except Exception as exc: return err(ErrorCode.INTERNAL, "{0}: {1}".format(type(exc).__name__, exc), stored=False, where="put") # -- (D-2) lookup ------------------------------------------------------ def lookup(self, tenant_id: str, prompt: str, threshold: float = None, **options: Any) -> Dict[str, Any]: """Guarantees: a three-stage (exact -> SimHash band -> cosine+guard) match inside one tenant partition only.""" t0 = time.perf_counter() try: tid = normalize_tenant(tenant_id) route = str(options.get("route") or "default")[:64] use_guard = bool(options.get("use_guard", True)) use_embed = bool(options.get("use_embed", True)) record = bool(options.get("record", self.record_events)) now = float(options.get("now") or time.time()) try: thr = DEFAULT_THRESHOLD if threshold is None else float(threshold) except Exception: thr = DEFAULT_THRESHOLD thr = max(0.0, min(1.0, thr)) prompt = "" if prompt is None else str(prompt)[: self.max_text_chars] if not prompt.strip(): return self._miss(tid, route, "empty_prompt", thr, t0, record, extra={"candidates": 0}) if not options.get("skip_expire_sweep"): self._maybe_sweep_expired(now) features = self._features(prompt, options.get("features")) qnorm, qkey, qvec, qsim = features["norm"], features["key"], features["vector"], features["simhash"] with self._lock: part = self._partition(tid) entries = part["entries"] n = len(entries) # ---- STAGE 1: exact match on the normalized key ---------- slot = part["exact"].get(qkey) if slot is not None and 0 <= slot < n and entries[slot] is not None: entry = entries[slot] if entry["expires_at"] <= now: self._drop_slot(part, slot, "expired") else: self._touch(part, slot, now) payload = self._hit_payload(entry, 1.0, "exact", now, []) part["stats"]["hits"] += 1 return self._finish_hit(tid, route, payload, t0, record, prompt) if n == 0 or not bool(part["alive"][:n].any()): return self._miss(tid, route, "empty_index", thr, t0, record, extra={"candidates": 0}) # ---- STAGE 2: SimHash band to shrink the candidate set ---- alive = part["alive"][:n] dists = hamming_array(part["simhashes"][:n], qsim) band = alive & (dists <= SIMHASH_MAX_DIST) cand = np.nonzero(band)[0] scan_mode = "simhash_band" if cand.size == 0: live_count = int(alive.sum()) if 0 < live_count <= FULL_SCAN_LIMIT: # Recall safety net for small partitions only: a wide # fingerprint band would otherwise hide valid paraphrases. cand = np.nonzero(alive)[0] scan_mode = "full_scan" else: return self._miss(tid, route, "no_candidates", thr, t0, record, extra={"candidates": 0, "scan_mode": scan_mode}) if cand.size > CANDIDATE_LIMIT: order = np.argsort(dists[cand], kind="stable")[:CANDIDATE_LIMIT] cand = cand[order] # ---- STAGE 3: cosine on candidates only ------------------ sims_local = part["matrix"][cand] @ qvec sims_local = np.clip(sims_local.astype(np.float64), -1.0, 1.0) cand_prompts = [entries[int(i)]["prompt"] for i in cand] cand_ids = [entries[int(i)]["id"] for i in cand] cand_expiry = [float(entries[int(i)]["expires_at"]) for i in cand] # --- optional embedding re-rank (outside the lock: it does I/O) --- sims_final = sims_local embed_used = False if use_embed and EMBED_WEIGHT > 0.0 and _EMBEDDER.available() and cand.size: top = np.argsort(-sims_local, kind="stable")[: min(EMBED_TOPK, cand.size)] matrix = embed_remote([prompt] + [cand_prompts[int(i)] for i in top]) if matrix is not None and matrix.shape[0] == len(top) + 1: qemb = matrix[0] blended = sims_local.copy() for pos, idx in enumerate(top): esim = float(np.clip(float(np.dot(qemb, matrix[pos + 1])), -1.0, 1.0)) blended[int(idx)] = (1.0 - EMBED_WEIGHT) * sims_local[int(idx)] + EMBED_WEIGHT * esim sims_final = blended embed_used = True order = np.argsort(-sims_final, kind="stable") best_sim = float(sims_final[order[0]]) if order.size else 0.0 guard_reasons: List[str] = [] rejected_by_guard: List[Dict[str, Any]] = [] for rank, pos in enumerate(order[:GUARD_MAX_CHECK]): pos = int(pos) sim = float(sims_final[pos]) if sim < thr: break if cand_expiry[pos] <= now: continue if use_guard: safe, reasons = is_semantically_safe(prompt, cand_prompts[pos]) if not safe: rejected_by_guard.append({"entry_id": cand_ids[pos], "similarity": round(sim, 4), "reasons": reasons}) guard_reasons = reasons continue slot = int(cand[pos]) with self._lock: part = self._partition(tid) if slot >= len(part["entries"]) or part["entries"][slot] is None: continue entry = part["entries"][slot] if entry["id"] != cand_ids[pos]: continue # slot was recycled while we were re-ranking self._touch(part, slot, now) payload = self._hit_payload(entry, sim, "embedding" if embed_used else "cosine", now, []) part["stats"]["hits"] += 1 payload["scan_mode"] = scan_mode payload["candidates"] = int(cand.size) payload["embed_used"] = embed_used payload["rank"] = rank payload["guard_rejected"] = rejected_by_guard payload["borderline"] = bool(abs(sim - thr) <= BORDERLINE_MARGIN) return self._finish_hit(tid, route, payload, t0, record, prompt) reason = "guard_rejected" if rejected_by_guard else "below_threshold" return self._miss( tid, route, reason, thr, t0, record, extra={ "candidates": int(cand.size), "best_similarity": round(best_sim, 4), "scan_mode": scan_mode, "embed_used": embed_used, "guard_reasons": guard_reasons, "guard_rejected": rejected_by_guard, "borderline": bool(abs(best_sim - thr) <= BORDERLINE_MARGIN), }, ) except Exception as exc: return err(ErrorCode.INTERNAL, "{0}: {1}".format(type(exc).__name__, exc), hit=False, where="lookup") # -- lookup helpers ---------------------------------------------------- def _touch(self, part: Dict[str, Any], slot: int, now: float) -> None: """Guarantees: marks an entry as most-recently-used and counts the reuse.""" entry = part["entries"][slot] if entry is None: return entry["hits"] = int(entry.get("hits", 0)) + 1 entry["last_hit_at"] = now part["lru"][slot] = True part["lru"].move_to_end(slot) def _hit_payload(self, entry: Dict[str, Any], sim: float, stage: str, now: float, guard_reasons: List[str]) -> Dict[str, Any]: """Guarantees: a uniform hit payload carrying stage, similarity, entry_id and age_sec.""" return { "hit": True, "stage": stage, "similarity": round(float(sim), 6), "entry_id": entry["id"], "age_sec": round(max(0.0, now - float(entry["created_at"])), 3), "ttl_remaining_sec": round(max(0.0, float(entry["expires_at"]) - now), 3), "response": entry["response"], "route": entry["route"], "hits": entry["hits"], "tokens_in": entry["tokens_in"], "tokens_out": entry["tokens_out"], "guard_reasons": list(guard_reasons), "cached_prompt_preview": entry["prompt"][:200], } def _finish_hit(self, tid: str, route: str, payload: Dict[str, Any], t0: float, record: bool, prompt: str) -> Dict[str, Any]: """Guarantees: attaches savings + latency to a hit and records exactly one observability event.""" latency_ms = round((time.perf_counter() - t0) * 1000.0, 3) saved = savings({"tokens_in": payload.get("tokens_in", 0), "tokens_out": payload.get("tokens_out", 0)}) payload.setdefault("candidates", 0) payload.setdefault("scan_mode", "exact") payload.setdefault("embed_used", False) payload.setdefault("borderline", False) payload.setdefault("guard_rejected", []) payload["latency_ms"] = latency_ms payload["savings"] = saved payload["tenant_id"] = tid if record: OBS.record(tenant_id=tid, route=route, event="hit", stage=payload["stage"], similarity=payload["similarity"], latency_ms=latency_ms, saved_tokens=saved["saved_tokens"], saved_cost=saved["saved_cost_usd"], guard_reasons=payload.get("guard_reasons", []), entry_id=payload["entry_id"], borderline=payload["borderline"], prompt=prompt) ACC.add(tid, route, "hit", saved) return ok(**payload) def _miss(self, tid: str, route: str, reason: str, thr: float, t0: float, record: bool, extra: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """Guarantees: a uniform miss payload that always states WHY nothing was reused.""" latency_ms = round((time.perf_counter() - t0) * 1000.0, 3) payload: Dict[str, Any] = { "hit": False, "stage": "miss", "similarity": 0.0, "entry_id": None, "age_sec": None, "reason": reason, "threshold": round(thr, 4), "latency_ms": latency_ms, "tenant_id": tid, "savings": {"saved_tokens_in": 0, "saved_tokens_out": 0, "saved_tokens": 0, "saved_cost_usd": 0.0}, } if extra: payload.update(extra) payload["similarity"] = float(payload.get("best_similarity", 0.0) or 0.0) if record: with self._lock: self._partition(tid)["stats"]["misses"] += 1 OBS.record(tenant_id=tid, route=route, event="miss", stage=reason, similarity=payload["similarity"], latency_ms=latency_ms, saved_tokens=0, saved_cost=0.0, guard_reasons=payload.get("guard_reasons", []), entry_id=None, borderline=bool(payload.get("borderline", False)), prompt=None) ACC.add(tid, route, "miss", {"saved_tokens": 0, "saved_cost_usd": 0.0}) return ok(**payload) # -- (D-3) invalidate -------------------------------------------------- def invalidate(self, tenant_id: str, key_prefix: str) -> Dict[str, Any]: """Guarantees: removes only entries of this tenant whose key starts with the prefix; returns the count.""" try: tid = normalize_tenant(tenant_id) prefix = "" if key_prefix is None else str(key_prefix).strip() if not prefix: return err(ErrorCode.EMPTY_PREFIX, 'key_prefix is required; pass "*" to invalidate the whole tenant', removed=0) with self._lock: part = self._partition(tid, create=False) if part is None: return ok(removed=0, tenant_id=tid, key_prefix=prefix) targets = [] for slot, entry in enumerate(part["entries"]): if entry is None: continue if prefix == "*" or entry["id"].startswith(prefix) or entry["route"] == prefix: targets.append(slot) for slot in targets: self._drop_slot(part, slot, "invalidated") remaining = len(part["lru"]) return ok(removed=len(targets), tenant_id=tid, key_prefix=prefix, remaining=remaining) except Exception as exc: return err(ErrorCode.INTERNAL, "{0}: {1}".format(type(exc).__name__, exc), removed=0, where="invalidate") # -- (D-4) TTL sweep --------------------------------------------------- def sweep_expired(self, now: Optional[float] = None) -> int: """Guarantees: drops every entry whose TTL has passed, in every partition, and returns how many.""" removed = 0 try: now = float(now or time.time()) with self._lock: for part in list(self._parts.values()): for slot, entry in enumerate(part["entries"]): if entry is not None and float(entry["expires_at"]) <= now: self._drop_slot(part, slot, "expired") removed += 1 self._last_expire_sweep = now except Exception: return removed return removed def _maybe_sweep_expired(self, now: float) -> None: """Guarantees: the per-lookup TTL sweep stays cheap by running at most once per interval.""" if now - self._last_expire_sweep >= EXPIRE_SWEEP_INTERVAL: self.sweep_expired(now) # -- (D-5) export / import -------------------------------------------- def export_json(self, include_responses: bool = True, tenant_id: Optional[str] = None) -> Dict[str, Any]: """Guarantees: a portable JSON snapshot (vectors recomputed on import) with responses optional.""" try: now = time.time() with self._lock: tenants = {} items = self._parts.items() if not tenant_id else [ (normalize_tenant(tenant_id), self._parts.get(normalize_tenant(tenant_id))) ] for tid, part in items: if part is None: continue rows = [] for entry in part["entries"]: if entry is None or float(entry["expires_at"]) <= now: continue rows.append({ "id": entry["id"], "prompt": entry["prompt"], "response": entry["response"] if include_responses else None, "route": entry["route"], "created_at": entry["created_at"], "expires_at": entry["expires_at"], "ttl_sec": entry["ttl_sec"], "hits": entry["hits"], "tokens_in": entry["tokens_in"], "tokens_out": entry["tokens_out"], }) tenants[tid] = {"entries": rows, "stats": dict(part["stats"])} return { "format": "echocache-index", "version": 1, "exported_at": now, "include_responses": bool(include_responses), "config": {"vector_dim": self.dim, "ngram_n": NGRAM_N, "max_text_chars": self.max_text_chars}, "tenants": tenants, } except Exception as exc: return {"format": "echocache-index", "version": 1, "error": str(exc), "tenants": {}} def import_json(self, payload: Any, skip_safety: bool = False) -> Dict[str, Any]: """Guarantees: merges a snapshot without ever crossing tenant boundaries; re-screens and re-vectorizes.""" try: if isinstance(payload, (bytes, bytearray)): payload = payload.decode("utf-8", "replace") if isinstance(payload, str): if len(payload) > IMPORT_MAX_BYTES: return err(ErrorCode.PAYLOAD_TOO_LARGE, "payload exceeds IMPORT_MAX_BYTES", imported=0) payload = json.loads(payload) if not isinstance(payload, dict) or not isinstance(payload.get("tenants"), dict): return err(ErrorCode.BAD_PAYLOAD, "expected an echocache-index JSON object", imported=0) now = time.time() imported = skipped_no_response = expired = rejected = failed = 0 for tid, blob in payload["tenants"].items(): if not isinstance(blob, dict): continue for row in blob.get("entries", []) or []: try: response = row.get("response") if not response: skipped_no_response += 1 continue expires_at = _safe_float(row.get("expires_at"), 0.0) or (now + DEFAULT_TTL_SEC) expires_at = min(expires_at, now + MAX_TTL_SEC) if expires_at <= now: expired += 1 continue res = self.put(tid, row.get("prompt") or "", response, { "route": row.get("route") or "default", "created_at": min(_safe_float(row.get("created_at"), 0.0) or now, now), "expires_at": expires_at, "ttl_sec": _safe_int(row.get("ttl_sec"), DEFAULT_TTL_SEC), "hits": max(0, _safe_int(row.get("hits"), 0)), "skip_safety": bool(skip_safety), "now": now, }) if res.get("ok") and res.get("stored"): imported += 1 elif res.get("ok"): rejected += 1 else: failed += 1 except Exception: failed += 1 return ok(imported=imported, skipped_no_response=skipped_no_response, expired=expired, rejected_by_safety=rejected, failed=failed, tenants=len(payload["tenants"])) except Exception as exc: return err(ErrorCode.BAD_PAYLOAD, "{0}: {1}".format(type(exc).__name__, exc), imported=0) # -- introspection ----------------------------------------------------- def health(self) -> Dict[str, Any]: """Guarantees: a JSON-safe snapshot of size, eviction counters and approximate memory use.""" try: with self._lock: tenants = [] total_entries = total_chars = 0 matrix_bytes = 0 agg = {"stored": 0, "evicted": 0, "expired": 0, "invalidated": 0, "rejected": 0, "hits": 0, "misses": 0, "updates": 0} for tid, part in self._parts.items(): live = len(part["lru"]) chars = sum(e["chars"] for e in part["entries"] if e is not None) matrix_bytes += int(part["matrix"].nbytes) + int(part["simhashes"].nbytes) total_entries += live total_chars += chars for k in agg: agg[k] += int(part["stats"].get(k, 0)) tenants.append({"tenant_id": tid, "entries": live, "chars": chars, "capacity": int(part["matrix"].shape[0]), **part["stats"]}) approx_mb = round((matrix_bytes + total_chars * 2) / (1024.0 * 1024.0), 2) return { "entries": total_entries, "tenants": len(tenants), "capacity_per_tenant": self.max_entries, "capacity_total": self.max_total_entries, "vector_matrix_mb_per_full_tenant": round(self.max_entries * self.dim * 4 / (1024.0 * 1024.0), 1), "approx_memory_mb": approx_mb, "vector_bytes_per_entry": self.dim * 4, "totals": agg, "per_tenant": tenants, } except Exception as exc: return {"entries": 0, "tenants": 0, "error": str(exc), "per_tenant": []} def top_entries(self, limit: int = 20, tenant_id: Optional[str] = None) -> pd.DataFrame: """Guarantees: the most-reused live entries as a DataFrame, never containing response bodies.""" cols = ["tenant_id", "entry_id", "route", "hits", "age_sec", "ttl_remaining_sec", "tokens_in", "tokens_out", "prompt_preview"] try: now = time.time() rows = [] with self._lock: for tid, part in self._parts.items(): if tenant_id and tid != normalize_tenant(tenant_id): continue for entry in part["entries"]: if entry is None: continue rows.append({ "tenant_id": tid, "entry_id": entry["id"][:16], "route": entry["route"], "hits": entry["hits"], "age_sec": round(now - entry["created_at"], 1), "ttl_remaining_sec": round(max(0.0, entry["expires_at"] - now), 1), "tokens_in": entry["tokens_in"], "tokens_out": entry["tokens_out"], "prompt_preview": entry["prompt"][:80].replace("\n", " "), }) if not rows: return pd.DataFrame(columns=cols) df = pd.DataFrame(rows).sort_values(["hits", "age_sec"], ascending=[False, True]) return df.head(max(1, int(limit)))[cols].reset_index(drop=True) except Exception: return pd.DataFrame(columns=cols) # ============================================================================= # (I) Observability - ring buffer + pandas aggregation, prompt-free by default # ============================================================================= EVENT_COLUMNS = ["ts", "datetime", "tenant_id", "route", "event", "stage", "similarity", "latency_ms", "saved_tokens", "saved_cost", "guard_reasons", "entry_id", "borderline", "prompt_prefix"] class EventLog: """Guarantees: a bounded, thread-safe event ring buffer that never stores prompt text unless opted in.""" def __init__(self, maxlen: int = EVENT_BUFFER) -> None: """Guarantees: a fixed-size ring buffer; memory cannot grow past maxlen events.""" self._lock = threading.RLock() self._buf: deque = deque(maxlen=max(100, int(maxlen))) self._dropped = 0 self._total = 0 def record(self, **kw: Any) -> None: """Guarantees: records one event, truncating prompt text per LOG_PROMPT_PREFIX (0 = never).""" try: now = time.time() prompt = kw.get("prompt") prefix = "" if LOG_PROMPT_PREFIX > 0 and isinstance(prompt, str): prefix = prompt[:LOG_PROMPT_PREFIX].replace("\n", " ") reasons = kw.get("guard_reasons") or [] if not isinstance(reasons, (list, tuple)): reasons = [str(reasons)] row = { "ts": now, "tenant_id": str(kw.get("tenant_id") or "default"), "route": str(kw.get("route") or "default"), "event": str(kw.get("event") or "unknown"), "stage": str(kw.get("stage") or ""), "similarity": float(kw.get("similarity") or 0.0), "latency_ms": float(kw.get("latency_ms") or 0.0), "saved_tokens": int(kw.get("saved_tokens") or 0), "saved_cost": float(kw.get("saved_cost") or 0.0), "guard_reasons": [str(r)[:160] for r in reasons][:8], "entry_id": (str(kw.get("entry_id"))[:16] if kw.get("entry_id") else ""), "borderline": bool(kw.get("borderline", False)), "prompt_prefix": prefix, } with self._lock: if len(self._buf) == self._buf.maxlen: self._dropped += 1 self._buf.append(row) self._total += 1 except Exception: return def frame(self) -> pd.DataFrame: """Guarantees: a DataFrame with EVENT_COLUMNS, even when the buffer is empty.""" try: with self._lock: rows = list(self._buf) if not rows: return pd.DataFrame(columns=EVENT_COLUMNS) df = pd.DataFrame(rows) df["datetime"] = pd.to_datetime(df["ts"], unit="s", utc=True) df["guard_reasons"] = df["guard_reasons"].apply(lambda r: " | ".join(r) if isinstance(r, list) else str(r)) return df[EVENT_COLUMNS] except Exception: return pd.DataFrame(columns=EVENT_COLUMNS) def stats(self) -> Dict[str, Any]: """Guarantees: buffer occupancy figures so operators know when events are being dropped.""" with self._lock: return {"buffered": len(self._buf), "capacity": self._buf.maxlen, "total_recorded": self._total, "dropped": self._dropped} def reset(self) -> None: """Guarantees: empties the ring buffer without disturbing the cache index.""" with self._lock: self._buf.clear() self._dropped = 0 self._total = 0 OBS = EventLog() ACC = Accounting() INDEX = CacheIndex() def _filter_events(df: pd.DataFrame, tenant_id: str = "", route: str = "") -> pd.DataFrame: """Guarantees: applies optional tenant/route filters without mutating the source frame.""" out = df if tenant_id: out = out[out["tenant_id"] == normalize_tenant(tenant_id)] if route: out = out[out["route"] == str(route)] return out def hit_rate_timeseries(df: pd.DataFrame, freq: str = "1min", window: int = 5) -> pd.DataFrame: """Guarantees: a per-bucket hit-rate series plus its moving average, empty-safe.""" cols = ["bucket", "hits", "misses", "requests", "hit_rate", "hit_rate_ma"] try: served = df[df["event"].isin(["hit", "miss"])].copy() if served.empty: return pd.DataFrame(columns=cols) served = served.set_index("datetime") grouped = served.groupby([pd.Grouper(freq=freq), "event"]).size().unstack(fill_value=0) for col in ("hit", "miss"): if col not in grouped.columns: grouped[col] = 0 out = grouped.reset_index().rename(columns={"datetime": "bucket", "hit": "hits", "miss": "misses"}) out["requests"] = out["hits"] + out["misses"] out["hit_rate"] = np.where(out["requests"] > 0, out["hits"] / out["requests"], 0.0).round(4) out["hit_rate_ma"] = out["hit_rate"].rolling(max(1, int(window)), min_periods=1).mean().round(4) out["bucket"] = out["bucket"].dt.strftime("%Y-%m-%d %H:%M") return out[cols] except Exception: return pd.DataFrame(columns=cols) def savings_cumulative(df: pd.DataFrame, by: str = "tenant_id") -> pd.DataFrame: """Guarantees: cumulative saved tokens/cost grouped by tenant or route, empty-safe.""" cols = [by, "bucket", "saved_tokens", "saved_cost", "cum_saved_tokens", "cum_saved_cost"] try: hits = df[df["event"] == "hit"].copy() if hits.empty: return pd.DataFrame(columns=cols) hits = hits.set_index("datetime") grouped = (hits.groupby([by, pd.Grouper(freq="1min")])[["saved_tokens", "saved_cost"]] .sum().reset_index().rename(columns={"datetime": "bucket"})) grouped = grouped.sort_values([by, "bucket"]) grouped["cum_saved_tokens"] = grouped.groupby(by)["saved_tokens"].cumsum() grouped["cum_saved_cost"] = grouped.groupby(by)["saved_cost"].cumsum().round(6) grouped["bucket"] = grouped["bucket"].dt.strftime("%Y-%m-%d %H:%M") return grouped[cols] except Exception: return pd.DataFrame(columns=cols) def latency_distribution(df: pd.DataFrame) -> pd.DataFrame: """Guarantees: p50/p90/p99 latency split by hit vs miss, empty-safe.""" cols = ["event", "count", "mean_ms", "p50_ms", "p90_ms", "p99_ms", "max_ms"] try: served = df[df["event"].isin(["hit", "miss"])] if served.empty: return pd.DataFrame(columns=cols) rows = [] for event, group in served.groupby("event"): values = group["latency_ms"].astype(float) rows.append({ "event": event, "count": int(values.size), "mean_ms": round(float(values.mean()), 3), "p50_ms": round(float(values.quantile(0.50)), 3), "p90_ms": round(float(values.quantile(0.90)), 3), "p99_ms": round(float(values.quantile(0.99)), 3), "max_ms": round(float(values.max()), 3), }) return pd.DataFrame(rows)[cols] except Exception: return pd.DataFrame(columns=cols) def borderline_events(df: pd.DataFrame, limit: int = 200) -> pd.DataFrame: """Guarantees: every decision whose similarity fell within +/- BORDERLINE_MARGIN of the threshold.""" cols = ["datetime", "tenant_id", "route", "event", "stage", "similarity", "entry_id", "guard_reasons"] try: sub = df[df["borderline"] == True] # noqa: E712 - explicit for pandas masks if sub.empty: return pd.DataFrame(columns=cols) sub = sub.sort_values("ts", ascending=False).head(max(1, int(limit))).copy() sub["datetime"] = sub["datetime"].dt.strftime("%Y-%m-%d %H:%M:%S") return sub[cols].reset_index(drop=True) except Exception: return pd.DataFrame(columns=cols) def guard_rejection_events(df: pd.DataFrame, limit: int = 200) -> pd.DataFrame: """Guarantees: every case where MismatchGuard refused a similar-enough candidate, with its reasons.""" cols = ["datetime", "tenant_id", "route", "stage", "similarity", "guard_reasons", "prompt_prefix"] try: sub = df[(df["guard_reasons"].astype(str).str.len() > 0)] if sub.empty: return pd.DataFrame(columns=cols) sub = sub.sort_values("ts", ascending=False).head(max(1, int(limit))).copy() sub["datetime"] = sub["datetime"].dt.strftime("%Y-%m-%d %H:%M:%S") return sub[cols].reset_index(drop=True) except Exception: return pd.DataFrame(columns=cols) def _prune_temp_files(max_age_sec: float = 3600.0, keep: int = 200) -> None: """Guarantees: old generated files are removed so a long-lived Space cannot fill its temp dir.""" try: now = time.time() names = os.listdir(_TMP_DIR) if len(names) <= keep: names = [n for n in names if n.startswith("echocache-")] for name in names: if not name.startswith("echocache-"): continue path = os.path.join(_TMP_DIR, name) try: if now - os.path.getmtime(path) > max_age_sec: os.remove(path) except Exception: continue except Exception: return def write_temp_file(content: str, prefix: str, suffix: str) -> Optional[str]: """Guarantees: a UNIQUE file per call - two concurrent exports can never overwrite each other.""" try: _prune_temp_files() stamp = time.strftime("%Y%m%d-%H%M%S") # mkstemp gives an atomically unique name: a plain timestamp collides for # two downloads in the same second, and one tenant would then receive the # other tenant's file. fd, path = tempfile.mkstemp(prefix="{0}-{1}-".format(prefix, stamp), suffix=suffix, dir=_TMP_DIR) with os.fdopen(fd, "w", encoding="utf-8", newline="") as handle: handle.write(content) return path except Exception: return None # ============================================================================= # Tiny dependency-free SVG charts (no matplotlib, no gradio plot API drift) # ============================================================================= _PALETTE = ["#2f81f7", "#e36209", "#2da44e", "#a371f7", "#cf222e", "#0969da"] def _svg_frame(body: str, title: str, width: int, height: int) -> str: """Guarantees: a themed SVG wrapper that renders correctly in both light and dark Gradio themes.""" return ( '