windlass.core.cache¶
cache
¶
Caching for expensive, repeatable calls.
Embedding the same corpus twice, or re-asking the same question at temperature 0, should not cost twice. Windlass ships two backends behind one interface:
- :class:
MemoryCache— a thread-safe TTL + LRU dict. No dependencies. - :class:
DiskCache— persistent, process-shared, backed bydiskcache(pip install "windlass[cache]").
Caching is opt-in::
configure(cache={"enabled": True, "ttl": 3600})
Keys are content hashes of the call arguments, so nothing collides across providers or models.
Cache
¶
Bases: ABC
Key/value cache interface used across Windlass.
Implementations must be safe to call from multiple threads. Async methods default to running the sync ones, which is right for in-process backends; a network-backed cache should override them.
NullCache
¶
MemoryCache
¶
Bases: Cache
Thread-safe in-process cache with TTL expiry and LRU eviction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_size
|
int
|
Maximum number of live entries. The least recently used entry is evicted when the cache is full. |
1024
|
ttl
|
float | None
|
Default lifetime in seconds; |
3600.0
|
Attributes:
| Name | Type | Description |
|---|---|---|
hits |
Number of successful lookups since construction. |
|
misses |
Number of failed lookups since construction. |
Example
cache = MemoryCache(max_size=2) cache.set("a", 1) cache.get("a") 1 cache.set("b", 2); cache.set("c", 3) # evicts "a" cache.get("a") is None True
Source code in src\windlass\core\cache.py
get
¶
Return the value for key, or None when missing or expired.
Source code in src\windlass\core\cache.py
set
¶
Store value, evicting the least recently used entry if needed.
Source code in src\windlass\core\cache.py
delete
¶
clear
¶
stats
¶
Return hit/miss counters and the current size.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A dict with |
dict[str, Any]
|
|
Source code in src\windlass\core\cache.py
DiskCache
¶
DiskCache(
directory: str | Path | None = None,
ttl: float | None = 3600.0,
size_limit: int = 1000000000,
)
Bases: Cache
Persistent cache backed by the diskcache package.
Survives process restarts and is safe to share between processes on one machine, which makes it the right choice for ingestion pipelines that are re-run during development.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
str | Path | None
|
Where to store the cache files. Created if absent. |
None
|
ttl
|
float | None
|
Default lifetime in seconds. |
3600.0
|
size_limit
|
int
|
Approximate maximum on-disk size in bytes. |
1000000000
|
Raises:
| Type | Description |
|---|---|
MissingDependencyError
|
When |
Source code in src\windlass\core\cache.py
make_key
¶
Build a deterministic cache key from arbitrary arguments.
Arguments are JSON-encoded with sorted keys, so dict ordering never changes
the key. Values that are not JSON-serialisable fall back to repr.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*parts
|
Any
|
Anything identifying the call — provider, model, prompt, params. |
()
|
namespace
|
str
|
Optional prefix to keep different caches from colliding. |
''
|
Returns:
| Type | Description |
|---|---|
str
|
A |
Example
make_key("openai", {"b": 1, "a": 2}) == make_key("openai", {"a": 2, "b": 1}) True
Source code in src\windlass\core\cache.py
build_cache
¶
Construct the cache described by config.
Falls back to :class:MemoryCache (with a warning) if the disk backend is
requested but diskcache is missing — a broken cache should never take
down the application.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
CacheConfig | None
|
Cache policy. Defaults to the global configuration. |
None
|
Returns:
| Type | Description |
|---|---|
Cache
|
A ready-to-use cache. :class: |
Example
isinstance(build_cache(CacheConfig(enabled=False)), NullCache) True
Source code in src\windlass\core\cache.py
cached_call
async
¶
cached_call(
cache: Cache,
key: str,
factory: Callable[[], Awaitable[_T]],
*,
ttl: float | None = None
) -> _T
Return a cached value or compute, store and return it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache
|
Cache
|
The cache to consult. |
required |
key
|
str
|
Precomputed key, usually from :func: |
required |
factory
|
Callable[[], Awaitable[_T]]
|
Zero-argument async callable producing the value on a miss. |
required |
ttl
|
float | None
|
Override for this entry's lifetime. |
None
|
Returns:
| Type | Description |
|---|---|
_T
|
The cached or freshly computed value. |
Example
import asyncio cache = MemoryCache() async def compute(): return 42 asyncio.run(cached_call(cache, "k", compute)) 42 asyncio.run(cached_call(cache, "k", compute)) # served from cache 42