123 lines
3.7 KiB
Common Lisp
Raw Normal View History

;; 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