Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
pull_request:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
lint:
runs-on: ubuntu-latest
Expand All @@ -14,9 +18,11 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install ruff==0.17.3
- run: pip install ruff==0.17.3 "mypy>=1.9.0" "numpy>=1.24.0,<2.0.0" "click>=8.1.0"
- name: Check lint and formatting
run: make lint
- name: Type check (strict)
run: make typecheck

test:
timeout-minutes: 20
Expand Down Expand Up @@ -89,6 +95,9 @@ jobs:
- name: Run offline reliability example
run: uv run --no-sync python examples/reliability.py

- name: Typecheck consumer against wheel
run: uv run --no-sync python scripts/wheel_typecheck_v5.py

- name: Validate documentation
if: matrix.python-version == '3.12'
run: uv run --no-sync mkdocs build --strict
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

All notable changes are recorded here using [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [0.5.0] - 2026-11-04

### Added

- **PEP 561 Public Typing:** Added `py.typed` marker package data. All modules across core, backends, integrations, middleware, and CLI pass strict typing under `mypy --strict`.
- **Public API Stability Classification:** Exported `PUBLIC_API_STABILITY` dictionary classifying every exported symbol into `stable-candidate`, `experimental`, or `pass-through` tiers.
- **Support Matrix Documentation:** Authored comprehensive runtime, OS, backend, and integration matrix in `docs/support-matrix.md` with migration guide in `docs/migration-v0.5.md`.
- **Type-Check Gate Runner:** Authored `scripts/wheel_typecheck_v5.py` and `tests/test_public_api_v5.py` to enforce that wheels ship `py.typed` and external consumers pass strict typing.

### Changed

- **Liskov Substitution Principle (LSP) Compliance:** Resolved backend signature incompatibility in `SharedRedisCacheBackend.store` by adding standard `store(entry: CacheEntry) -> int` and extracting distributed coordination into `store_shared(...)`.
- **Public Method Cleanliness:** Removed all leaked private `_`-prefixed keyword arguments from public method signatures across `LongCache` (`lookup`, `alookup`, `set`, `aset`, `get`, `aget`, `get_or_compute`, `aget_or_compute`, `cached`). Internal control flags are cleanly captured via `**kwargs`.
- **Retired Legacy Parameters:** Removed dead configuration and call-site parameters (`track_miss`, `model`, `system_prompt`, `temperature`) from `CacheConfig` and public cache methods. Identity must be declared explicitly via `RequestContext`.

## [0.4.0] - 2026-11-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ format:
ruff check --fix .

typecheck:
mypy src/longcache/ --ignore-missing-imports
mypy src/longcache/ --strict

test:
pytest -v --tb=short
Expand Down
78 changes: 36 additions & 42 deletions README.md

Large diffs are not rendered by default.

49 changes: 0 additions & 49 deletions ROADMAP.md

This file was deleted.

4 changes: 2 additions & 2 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@
| `shared_max_tag_chars` | `256` |
| `distributed_lease_seconds`, `distributed_renew_interval_seconds` | `15.0`, `5.0` |

Legacy model/prompt/temperature fields are insufficient to establish trusted request identity. Explicit-context calls reject conflicting legacy keywords. Calls with a fixed cache context may map compatible legacy per-call keywords into that context; use `RequestContext` for new code.
Legacy `model`, `system_prompt`, `temperature`, and `track_miss` parameters were removed in v0.5.0; supply execution identity explicitly via `RequestContext`. See [Upgrading to v0.5](migration-v0.5.md) and the [Support Matrix](support-matrix.md) for public API stability classifications (`PUBLIC_API_STABILITY`).

## Policy and embedding interfaces

`PolicyDecision(action, reason)` has action `accept`, `reject`, or `abstain`. Admission receives `(context, normalized_response)`; verification receives `(query, candidate_query, normalized_response, similarity, context)`. Hook exceptions/invalid return values reject reuse or storage. Mandatory checks cannot be overridden.

`BaseEmbedder` requires `dimension`, `embed(text)`, and a stable `EmbeddingDescriptor(model, revision, dimension, preprocessing, normalization)`. Single vectors and batches must be contiguous float32 arrays with finite, L2-normalized rows and the declared dimension. Empty batches must have shape `(0, dimension)` and float32 dtype; they do not bypass dtype validation. The default batch implementation supports empty batches. Calls are serialized per embedder; malformed or incompatible vectors are rejected.

See [architecture](how-it-works/architecture.md), [v0.3 migration](migration-v0.3.md), and the [support matrix](index.md#supported-integrations) for limits.
See [architecture](how-it-works/architecture.md), [v0.5 migration](migration-v0.5.md), [v0.3 migration](migration-v0.3.md), and the [support matrix](support-matrix.md) for limits.

For a decorated function, `answer.cache_context_for(base_context)` returns its immutable derived operation context. Use it for inspection, exports, or invalidation of that function's entries. Fixed contexts and per-call resolver contexts use the same derivation.

Expand Down
15 changes: 15 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

All notable changes are recorded here using [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [0.5.0] - 2026-11-04

### Added

- **PEP 561 Public Typing:** Added `py.typed` marker package data. All modules across core, backends, integrations, middleware, and CLI pass strict typing under `mypy --strict`.
- **Public API Stability Classification:** Exported `PUBLIC_API_STABILITY` dictionary classifying every exported symbol into `stable-candidate`, `experimental`, or `pass-through` tiers.
- **Support Matrix Documentation:** Authored comprehensive runtime, OS, backend, and integration matrix in `docs/support-matrix.md` with migration guide in `docs/migration-v0.5.md`.
- **Type-Check Gate Runner:** Authored `scripts/wheel_typecheck_v5.py` and `tests/test_public_api_v5.py` to enforce that wheels ship `py.typed` and external consumers pass strict typing.

### Changed

- **Liskov Substitution Principle (LSP) Compliance:** Resolved backend signature incompatibility in `SharedRedisCacheBackend.store` by adding standard `store(entry: CacheEntry) -> int` and extracting distributed coordination into `store_shared(...)`.
- **Public Method Cleanliness:** Removed all leaked private `_`-prefixed keyword arguments from public method signatures across `LongCache` (`lookup`, `alookup`, `set`, `aset`, `get`, `aget`, `get_or_compute`, `aget_or_compute`, `cached`). Internal control flags are cleanly captured via `**kwargs`.
- **Retired Legacy Parameters:** Removed dead configuration and call-site parameters (`track_miss`, `model`, `system_prompt`, `temperature`) from `CacheConfig` and public cache methods. Identity must be declared explicitly via `RequestContext`.

## [0.4.0] - 2026-11-02

- Opt-in shared Redis keyspace, revision-aware local indexes, authoritative replay guards, scoped invalidation fences, and distributed exact-request leases.
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Installation

LongCache v0.4 requires Python 3.11 or newer; Python 3.11 and 3.12 are the tested interpreters. v0.1.1 remains the Python 3.10-compatible line.
LongCache v0.5 requires Python 3.11 or newer; Python 3.11 and 3.12 are the tested interpreters. v0.1.1 remains the Python 3.10-compatible line.

v0.4.0 has not been published by this implementation task. The package-index commands install the available published release; they do not select this development checkout. To install this branch from the repository root:
v0.5.0 is the current development line. The package-index commands install the available published release; they do not select this development checkout. To install this branch from the repository root:

```bash
uv sync --locked --extra all --extra dev --extra docs
Expand All @@ -15,6 +15,6 @@ uv pip install longcache
uv pip install 'longcache[openai,server,redis]'
```

The local model downloads weights on first use. Pin `embedder_revision` for a deployment, then cache the weights for offline operation. Custom embedders still use the current core package dependencies. See [upgrading from v0.2](../migration-v0.3.md) before reusing a format-2 store. For v0.1.1 stores, follow the separate [legacy migration](../migration-v0.2.md); those stores require a fresh path/generation.
The local model downloads weights on first use. Pin `embedder_revision` for a deployment, then cache the weights for offline operation. Custom embedders still use the current core package dependencies. See [upgrading to v0.5](../migration-v0.5.md) and the [support matrix](../support-matrix.md) before upgrading. Compatible format-2 stores from v0.2–v0.4 require no reset. For v0.1.1 stores, follow the separate [legacy migration](../migration-v0.2.md); those stores require a fresh path/generation.

For the tested CPU runtime, install `torch==2.14.0+cpu` from `https://download.pytorch.org/whl/cpu` before installing the wheel. Installer index settings in the project's lockfile do not become wheel dependency metadata.
2 changes: 1 addition & 1 deletion docs/getting-started/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ Release resources with `with` / `close()` in sync code or `async with` / `aclose
async code. `examples/safe_reuse.py` and `examples/reliability.py` are executable offline
examples with deterministic injected embedders and no external service/model download.
For changing documents, follow the [versioned RAG guide](../integrations/versioned-rag.md).
Before upgrading, read [v0.3 migration](../migration-v0.3.md) and the
Before upgrading, read [v0.5 migration](../migration-v0.5.md), the [support matrix](../support-matrix.md), and the
[reliability contracts](../reliability.md).
28 changes: 14 additions & 14 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# LongCache

Semantic response reuse for Python LLM and RAG applications. **v0.4.0 is unreleased; Python 3.11 and 3.12 are the tested interpreters.**
Semantic response reuse for Python LLM and RAG applications. **v0.5.0 is the current development line; Python 3.11 and 3.12 are the tested interpreters.** See the [Support Matrix](support-matrix.md) and [Upgrading to v0.5](migration-v0.5.md).

LongCache finds similar requests with local embeddings and FAISS, then checks whether their execution context and reuse policy permit the same answer. Similarity alone does not establish correctness. Measure false hits and useful reuse on your own workload.

## Install

v0.4.0 is currently a development checkout. Package-index commands install the available published release. See [installation](getting-started/installation.md) for installing and validating this branch.
v0.5.0 is currently a development checkout. Package-index commands install the available published release. See [installation](getting-started/installation.md) for installing and validating this branch.

```bash
uv pip install longcache
Expand Down Expand Up @@ -92,17 +92,17 @@ Async applications use `await cache.alookup(...)`, `await cache.aget(...)`, and

## Supported integrations

| Path | v0.3 status |
| Path | v0.5 status |
| ---- | ----------- |
| Manual lookup/store | Supported with explicit trusted context; independent origin calls |
| `get_or_compute` / `aget_or_compute` and query-only decorators | Supported with exact scoped singleflight |
| OpenAI sync/async chat completions | Supported single-turn text subset with dict/SDK response replay |
| ASGI middleware | Supported bounded single-turn JSON subset with trusted scope resolution; no HTTP invocation coalescing |
| Memory, SQLite, synchronous Redis storage | Supported within one cache process |
| Opt-in Shared Redis mode (`deployment_mode="shared"`) | v0.4 development; multi-process deployment over one Redis authority, release qualification open; see [shared deployment](deployment.md) |
| Standalone async Redis backend | Experimental storage interface; unsupported through `LongCache` |
| Generic LangChain, LangGraph, and LlamaIndex adapters | Compatibility pass-through; opaque execution state is not cached |
| All streaming helpers | Pass-through; no cache reads or writes |
| Manual lookup/store | Supported (`stable-candidate`) with explicit trusted context; independent origin calls |
| `get_or_compute` / `aget_or_compute` and query-only decorators | Supported (`stable-candidate`) with exact scoped singleflight |
| OpenAI sync/async chat completions (`CachedOpenAI`) | Supported (`stable-candidate`) single-turn text subset with dict/SDK response replay |
| ASGI middleware (`LongCacheMiddleware`) | Supported (`stable-candidate`) bounded single-turn JSON subset with trusted scope resolution; no HTTP invocation coalescing |
| Memory, SQLite, synchronous Redis storage | Supported (`stable-candidate`) within one cache process |
| Opt-in Shared Redis mode (`deployment_mode="shared"`) | Experimental (`experimental`); multi-process deployment over one Redis authority, release qualification open; see [shared deployment](deployment.md) |
| Standalone async Redis backend (`AsyncRedisCacheBackend`) | Experimental (`experimental`) storage interface; unsupported through `LongCache` |
| Generic LangChain, LangGraph, and LlamaIndex adapters | Compatibility pass-through (`pass-through`); opaque execution state is not cached |
| All streaming helpers (`cached_stream`, `StreamingCacheAdapter`) | Pass-through (`pass-through`); no cache reads or writes |
| Multi-turn, tools, multimodal, structured-output replay | Bypass until their identity and replay contracts are supported |

### OpenAI
Expand Down Expand Up @@ -135,9 +135,9 @@ Inject `LongCache(..., embedder=my_embedder)` using `BaseEmbedder`. Supply an `E

One store generation has one embedding fingerprint. Equal dimensions do not make two models compatible. A revision or preprocessing change requires a fresh path/generation; mismatched stores fail before vector search or writes.

## Upgrade from v0.2
## Upgrade from v0.2–v0.4

Compatible format-2 stores need no reset. See [upgrading to v0.3](migration-v0.3.md) for new execution, timeout, failure, and ownership behavior. Separate lookup/store code must opt into shared execution explicitly.
Compatible format-2 stores need no reset. See [upgrading to v0.5](migration-v0.5.md) for API signature cleanups, PEP 561 typing, and `PUBLIC_API_STABILITY` tiers, and [upgrading to v0.3](migration-v0.3.md) for execution, timeout, failure, and ownership behavior. Separate lookup/store code must opt into shared execution explicitly.

## Legacy upgrade from v0.1.1

Expand Down
2 changes: 1 addition & 1 deletion docs/integrations/langchain.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LangChain compatibility

`CachedLLM` and `CachedChain` preserve invocation/proxy interfaces but **bypass cache reads and writes in v0.3**. Generic wrappers cannot prove that hidden model settings, bound arguments, memory, and replay types are represented safely.
`CachedLLM` and `CachedChain` preserve invocation/proxy interfaces (`pass-through` tier in `PUBLIC_API_STABILITY`) and **bypass cache reads and writes in v0.5** (`cache_bypass_reason = "unsupported_request_shape"`). Generic wrappers cannot prove that hidden model settings, bound arguments, memory, and replay types are represented safely.

For a proven single-turn text workflow, use a query-only `@cache.cached(context=...)` function with explicit operation/provider/model/instruction/source versions and supported JSON responses. Extra arguments and all stream helpers bypass.
2 changes: 1 addition & 1 deletion docs/integrations/langgraph.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LangGraph compatibility

`CachedState.check` / `acheck` return a miss and can preserve a query for caller compatibility. `save` / `asave` do not cache opaque graph state in v0.3. Conversation history, tool results, and hidden memory require a complete identity/replay contract before caching can be enabled.
`CachedState.check` / `acheck` return a miss and can preserve a query for caller compatibility (`pass-through` tier in `PUBLIC_API_STABILITY`). `save` / `asave` do not cache opaque graph state in v0.5 (`cache_bypass_reason = "unsupported_request_shape"`). Conversation history, tool results, and hidden memory require a complete identity/replay contract before caching can be enabled.

Use the [explicit manual interface](../api-reference.md) for a separately proven single-turn workload. A latest-message string alone is insufficient graph identity.
2 changes: 1 addition & 1 deletion docs/integrations/llamaindex.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LlamaIndex compatibility

`CachedQueryEngine` delegates `query` / `aquery` to the engine without cache reads or writes in v0.3. Opaque retrieval/model state and unproven response codecs cannot safely become cached hits.
`CachedQueryEngine` delegates `query` / `aquery` to the engine without cache reads or writes in v0.5 (`pass-through` tier in `PUBLIC_API_STABILITY`, `cache_bypass_reason = "unsupported_request_shape"`). Opaque retrieval/model state and unproven response codecs cannot safely become cached hits.

A separately implemented query-only workflow can use the manual interface with explicit corpus/document versions and a tested strict response type. Retrieval metadata is not automatically discovered or versioned.
Loading
Loading