module LLM::Cache

Defined in:

llm/cache.cr

Constant Summary

CACHE_FILE_SUFFIX = ".json"

All cache entries are stored as <sha256>.json flat in .cache_dir. The bulk operations below (.clear, .purge_older_than, .stats) filter on this suffix so a stray .lock or user-dropped file in the directory is left alone.

CACHE_TMP_MARKER = ".tmp-"

Infix .store stamps onto its in-flight temp file (see .store). Kept as a constant so the writer and the sweepers below can't drift apart: a stranded temp file whose name the sweepers don't recognize is a file nothing can ever delete.

Class Method Summary

Class Method Detail

def self.cache_dir : String #

[View source]
def self.clear : DeleteOutcome #

[View source]
def self.delete(key : String) : Bool #

[View source]
def self.disable : Nil #

[View source]
def self.disabled_by_env? : Bool #

[View source]
def self.enable : Nil #

[View source]
def self.enabled? : Bool #

[View source]
def self.ensure_dir : Nil #

[View source]
def self.fetch(key : String) : String | Nil #

[View source]
def self.key(provider : String, model : String, kind : String, format : String, payload : String) : String #

Build a deterministic cache key from inputs

  • provider: "openai", "ollama", url, etc.
  • model: "gpt-4o", "llama3", etc.
  • kind: logical operation e.g. "FILTER", "ANALYZE", "BUNDLE_ANALYZE"
  • format: response_format string (e.g., "json" or JSON schema string)
  • payload: variable content (file list, source code, bundle, etc.)

Returns a hex-encoded SHA256 digest.


[View source]
def self.path_for(key : String) : String #

[View source]
def self.purge_older_than(days : Int32) : DeleteOutcome #

[View source]
def self.stats : Stats #

[View source]
def self.store(key : String, content : String) : Bool #

Write atomically: a partially-written file from a crash mid-write would parse as broken JSON on the next .fetch, forcing a spurious fresh API call. By writing to a tmp sibling and renaming we either leave the previous (valid) entry in place or atomically publish the new one.


[View source]
def self.tmp_entry?(name : String) : Bool #

True for a temp file stranded by a crash between File.write and File.rename. These do not end in .json, so the bulk operations used to skip them entirely — .clear could not remove them and .stats did not count their bytes, leaving files that grew the cache directory with no way to reclaim them from the CLI.


[View source]