;; Canonical package declaration. (define-package "oracle/cached-infer" :description "Cached LLM inference with golden receipt matching" :exports '(cached-infer) :effects '(infer.op) :requires '(oracle/core) :version "0.1.0" ) ;;; lib/cache/cached-infer.lisp ;;; Semantic Cache Library - Job 029 ;;; ;;; Provides cached versions of LLM inference to avoid redundant API calls. ;;; Responses are cached by prompt hash and returned instantly on subsequent calls. ;;; ;;; Usage: ;;; (cached-infer "What is 2+2?") ; First call: LLM ;;; (cached-infer "What is 2+2?") ; Second call: Instant from cache! ;;; ;;; (cache-stats) ; Get hit/miss statistics ;;; (cache-clear) ; Clear all cached entries ;; ============================================================ ;; Core Cached Inference ;; ============================================================ (define (cached-infer prompt) "Call LLM with caching. Identical prompts return cached responses. First call to a prompt: LLM is called, response is cached. Subsequent calls with same prompt: Cached response returned instantly. Returns: LLM response string Example: (cached-infer \"Summarize this document\") " ;; Check cache first (let ((cached (effect cache.get.op prompt))) (if (string? cached) ;; Cache hit - return cached response (begin ;; (display \"[cache] HIT\\n\") cached) ;; Cache miss - call LLM and cache result (begin ;; (display \"[cache] MISS\\n\") (let ((response (effect infer.op prompt))) (effect cache.set.op prompt response "unknown") response))))) (define (cached-infer-with-model prompt model) "Cached inference with explicit model tracking. model: String identifying the model (e.g., \"gpt-4o\", \"claude-sonnet\") Example: (cached-infer-with-model \"Analyze code\" \"gpt-4o\") " (let ((cached (effect cache.get.op prompt))) (if (string? cached) cached (let ((response (effect infer.op prompt))) (effect cache.set.op prompt response model) response)))) ;; ============================================================ ;; Cache Management ;; ============================================================ (define (cache-stats) "Get cache statistics as a record. Returns a record with: - hits: Number of cache hits - misses: Number of cache misses - entries: Number of cached entries - savedCalls: Number of LLM calls saved (same as hits) - hitRate: Ratio of hits to total lookups (0.0-1.0) Example: (define stats (cache-stats)) (record-ref stats 'hitRate) ; => 0.75 " (effect cache.stats.op)) (define (cache-has? prompt) "Check if a prompt is in the cache (without counting as hit/miss). Returns: #t if cached, #f otherwise " (effect cache.has.op prompt)) (define (cache-clear) "Clear all cached entries and reset statistics. Use when you want fresh LLM responses or to free memory. " (effect cache.clear.op) (display "[cache] Cleared\n")) ;; ============================================================ ;; Helper: record-ref for cache stats ;; ============================================================ ;; Note: record-ref may already be defined if loading other libs ;; This is a local fallback definition (define (cache-record-ref m key) "Access field in a Map value returned by cache-stats." (if (eq? m #f) #f (let ((found (cache-assoc key m))) (if (pair? found) (cdr found) #f)))) (define (cache-assoc key alist) (cond ((null? alist) #f) ((equal? key (car (car alist))) (car alist)) (else (cache-assoc key (cdr alist))))) 'cache/cached-infer-loaded