pi-deepseek-cache
DeepSeek prefix-cache extension for pi — hit-rate telemetry, prefix guard, and cache-friendly compaction.
Package details
Install pi-deepseek-cache from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-deepseek-cache- Package
pi-deepseek-cache- Version
0.5.0- Published
- Oct 15, 2026
- Downloads
- 622/mo · 74/wk
- Author
- ruanbw
- License
- MIT
- Types
- extension
- Size
- 174.7 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
🚀 pi-deepseek-cache
Squeeze the most out of DeepSeek's context caching inside the Pi coding agent.
Stable prompt prefixes · higher cache-hit rates · live cache stats — so long sessions pay the cache-hit rate on most of their input.
✨ Why this exists
DeepSeek's API has Context Caching on Disk built in: any request whose prompt prefix fully matches a previously persisted cache prefix unit is billed at the much cheaper cache-hit rate. The catch — your prompt prefixes must stay stable across turns, token-for-token.
In long agent sessions that's surprisingly hard:
- the system prompt or tool list changes subtly between turns
- conversation history grows and shifts
- large / non-deterministic tool outputs break the prefix
- repeated metadata blocks aren't aligned
pi-deepseek-cache keeps your DeepSeek prompts cache-friendly and shows you exactly how well it's working — on the official API and on any third-party deployment that serves DeepSeek behind an OpenAI-compatible endpoint.
🎯 Features
- Prefix Guard — strips
volatile-scratchmessages from the context to keep the prompt prefix stable across turns - Stable Tool Ordering — lexicographically sorts
toolsinbefore_provider_request(HarnessorderToolsparity) so tool-list order jitter never breaks the cache - Cache Break Diagnostics — fingerprints the full
system+tools+messagesprefix (stable-JSON + SHA-256) and warns only when an existing prefix is rewritten, not on normal append; returning to any still-live earlier prefix counts as a valid hit; empty/unknown payloads are silently skipped - Hit Rate Telemetry — accumulates
cacheRead/input/cacheWrite/turnsper model from every response and persists to disk, so switching models never blends two different price points into one number - Live Status Bar — see the current model's cumulative hit rate and turn count in the Pi footer after every message
- ASCII Trend Chart — visualize the all-models-cumulative hit rate over time with
/cache-graph(flat-rate handling + fixed chart labels) - Cost Savings Estimation — savings priced from the active model's
costin the model catalog (models.json/ Pi's built-in catalog), which is the correct source for both official and third-party deployments. Only for the officialdeepseekprovider does the official Models & Pricing table and its peak/off-peak windows still apply; a model the catalog prices at zero shows—instead of an invented number./cache-statsshows cumulative and per-request hit rates, the model, where the price came from, the unit prices used, and a per-model breakdown - Cache-Friendly Compaction — summarizes at temperature 0 with official
deepseek-flash(legacydeepseek-v4-flashfallback) when that model exists, otherwise with the current model when it is already aflash-tier model, otherwise with aflash-tier model of the current provider, otherwise the current model; results are SHA-256–cached and persisted across sessions (LRU capped at 64). Note: this is a standalone cold call, not a verbatim replay of the routed request — see §7.4 - Atomic Persistence —
tmp + renamewrites + debounced async flush +session_start/session_shutdownlifecycle guarantees, no torn JSON /cache-reset— clear all stats, history, and summary cache with one command
📦 Installation
Requires Pi and Node.js ≥ 18.
pi install npm:pi-deepseek-cache
Or install from git:
pi install git:github.com/ruanbw/pi-deepseek-cache
🚦 Quick start
- Make sure a DeepSeek provider is configured (
DEEPSEEK_API_KEYset). - Select a DeepSeek model such as
deepseek/deepseek-v4-flash. - Start coding — the extension activates automatically and reports cache stats in the footer.
export DEEPSEEK_API_KEY=sk-...
pi --model deepseek/deepseek-v4-flash
Using a third-party DeepSeek deployment (OpenRouter, a self-hosted endpoint, a local router)? No DeepSeek API key or deepseek provider is required — see the next section.
🔌 Third-party DeepSeek deployments
Every hook is provider-agnostic: telemetry reads usage.cacheRead / usage.input from whatever the endpoint reports, and the prefix guard plus the break diagnostics operate on the outgoing wire payload. So a DeepSeek model served by a self-hosted vLLM/SGLang endpoint, a hosted router, or a local gateway works too — the extension does not care which provider id you put in front of it.
What differs from the official API:
| Layer | On the official deepseek provider |
On a third-party deployment |
|---|---|---|
| Hit-rate telemetry | prompt_cache_hit_tokens / prompt_cache_miss_tokens |
Works whenever the endpoint reports cached prompt tokens (e.g. prompt_tokens_details.cached_tokens). If it reports none, every turn looks like a miss |
| Pricing | Official price table + peak/off-peak halving | The active model's cost from the model catalog, flat — peak/off-peak is DeepSeek's billing policy, not the host's. No catalog price → — instead of a guess |
| Prefix guard · tool ordering · break diagnostics | same | same — byte-stable prefixes help any prefix-cache implementation |
| Compaction summarizer | deepseek-flash (legacy deepseek-v4-flash fallback) |
Current model when it is already flash-tier, else a flash-tier model of the current provider (deepseek in the name preferred), else the current model |
Two caveats specific to third-party hosts:
- Instance affinity. Self-hosted engines usually keep the prefix cache per instance, so a cache miss can mean "the router sent this turn to a different replica", not "the prefix was rewritten". The break diagnostics cannot tell those apart. If your router can pin a session to one backend (magpie does this through
compat.sendSessionAffinityHeaders), keep that on. - Billing follows the host, not DeepSeek. Hosts differ on how cached input is billed — flat discount, free, or not discounted at all. Savings are estimated from the catalog price you configured, so keep
cost.input/cost.cacheReadinmodels.jsonaccurate: for non-official providers that is the only pricing input the extension trusts.
// ~/.pi/agent/models.json — a third-party DeepSeek deployment
{
"providers": {
"my-router": {
"api": "openai-completions",
"baseUrl": "https://my-router.example/v1",
"apiKey": "...",
"models": [
{
"id": "deepseek-v4.1-flash",
"name": "DeepSeek V4.1 Flash (my-router)",
"contextWindow": 1000000,
"maxTokens": 384000,
"cost": { "input": 0.15, "output": 0.28, "cacheRead": 0.003, "cacheWrite": 0 },
},
],
},
},
}
pi --model my-router/deepseek-v4.1-flash
🧩 Commands
| Command | Description |
|---|---|
/cache-stats |
Overlay popup with hit rate, cached/missed tokens, turns, estimated savings, pricing source, per-model breakdown |
/cache-graph |
Overlay popup with ASCII trend chart of the all-models-cumulative hit rate over time |
/cache-reset |
Reset all stats, history, and summary cache (clears both memory and disk) |
🔍 How it works
| Layer | What it does | Harness lineage |
|---|---|---|
| P1 — Telemetry | Accumulates cacheRead / input / cacheWrite / turns per model (provider + id) from message_end events, persists atomically to ~/.pi/agent/extensions/deepseek-cache/stats.json (override the directory with PI_DEEPSEEK_CACHE_DIR); prices savings from the model catalog, or from the official table + peak/off-peak window when the provider is the official deepseek |
TokenUsage DISJOINT (translate.ts:mapUsage) — input = prompt_tokens - cacheRead |
| P2 — Prefix Guard | Filters volatile-scratch in context; sorts tools lexicographically in before_provider_request; fingerprints system + tools + messages with stable-JSON + inclusion check against a bounded set of known prefixes |
orderTools / sameSchema / canonicalHeader / headerEquals (packages/core/system-prompt, packages/core/session) |
| P3 — Compaction | On session_before_compact, summarizes history as a single user message at temperature 0 with the official deepseek-flash model (legacy name fallback), else a flash-tier model of the current provider, else the current model. Summaries are SHA-256–cached (LRU 64) and atomically persisted |
No parity — Harness compaction-basic/summarizer.ts replays system+tools+shadowed messages + trailing instruction to reuse a warm prefix; this path is a standalone cold call. Rationale in §7.4 |
📖 Deep dive: Prefix Cache Principle — official Context Caching on Disk (SWA-based independent cache prefix units, 3 persistence timings, best-effort) + Harness 5-layer enforcement + Pi mapping
🛠️ Troubleshooting
- Cache hit rate is low → usually a changing static prefix. Avoid injecting timestamps, random IDs, or volatile tool output near the start of the prompt. Note that adding or removing an extension changes the
toolsblock, which invalidates the prefix just as a history rewrite does. - "Cache prefix change" warning → something in the earlier conversation history, the tool set, or a tool's schema was modified. Check if a tool or extension is mutating past messages or registering/unregistering tools between turns. On a third-party host this can also mean the router moved you to another replica (see instance affinity).
- Footer shows nothing → confirm a DeepSeek-serving model is selected and its provider has working credentials.
- Hit rate stays at 0% on a third-party endpoint → that endpoint reports no cached-token count in
usage; the extension has nothing to measure. Check a raw response, not the extension. - Estimated savings shows
—→ the model has no usablecost.inputin the catalog (free / unpriced model). Addcostto the model entry inmodels.jsonto get a number.
🧪 Test
npm test # 80 tests (70 unit + 10 integration)
🤝 Contributing
Issues and PRs welcome! Please run npm test before submitting.
npm run lint # ESLint + Prettier check
npm test # Unit + integration tests
📄 License
MIT © ruanbw