Compatibility
Source:
COMPATIBILITY.mdat the repo root.
tapedeck operates at the Vercel AI SDK's wrapLanguageModel middleware
layer. The structural ceiling on the project's lifetime is that layer's
request/response shape, so this file is the public, dated record of what
tapedeck is tested against.
Language-model spec versions
Both spec versions are typed as of 0.4.0, not merely supported at
runtime. ai@6 takes a spec v3 middleware and ai@7 takes spec v4; the
two concrete types are mutually unassignable, so before 0.4.0 an ai@7 consumer had to write as unknown as LanguageModelMiddleware at the call
site. cassetteMiddleware now returns a structurally typed TapedeckMiddleware: it declares only the
fields tapedeck reads (prompt, tools, the sampling params, provider, modelId) and stays generic in the result type, so one
object is assignable to both. specificationVersion stays 'v3' because v4 hosts accept any string while v3 hosts accept only 'v3'.
Both provider majors are dev dependencies, and test/types.test-d.ts asserts assignability to both spec surfaces plus to wrapLanguageModel from whichever ai major the CI matrix leg installed. A spec v5 would
show up as a red type test, not as a silent consumer-side cast.
Tested versions
SDK (ai) | Date tested | tapedeck | Status | Notes |
|---|---|---|---|---|
| 7.0.58 | 2026-08-11 | 0.4.0 | ✅ pass | Spec v4 typed via TapedeckMiddleware; the as unknown as cast at wrapLanguageModel is gone. |
| 6.0.256 | 2026-08-11 | 0.4.0 | ✅ pass | Spec v3 typed via TapedeckMiddleware; type tests green. |
| 7.0.58 | 2026-08-03 | 0.3.0 | ✅ pass | Weekly cron; peer range widened to <8 in 0.3.1. |
| 7.0.37 | 2026-07-27 | 0.3.0 | ✅ pass | Weekly cron. |
| 6.0.0 | 2026-06-10 | 0.3.0 | ✅ pass | Multi-interaction named cassettes (v2 format); v1 cassettes replay as-is. |
| 6.0.0 | 2026-06-10 | 0.2.0 | ✅ pass | Same spec surface as the launch row. Hash digests and cassette format unchanged. |
| 6.0.0 | 2026-06-10 | 0.1.0 | ✅ pass | Launch row. Model spec v3: doGenerate returns content[]; doStream yields text-delta / tool-call parts. |
Edge runtimes (Cloudflare Workers, etc.)
As of 0.2.0 the core import graph is edge-safe: hashing uses WebCrypto, the
default filesystem store imports node:fs lazily (pass memoryCassetteStore() or a KV/R2-backed store and it never loads), and the
one static Node builtin left is node:async_hooks — provided by Cloudflare
Workers under the nodejs_compat flag.
A deployed-Worker smoke test is still TODO — treat Workers support as designed-for, not yet CI-verified. The CLI is Node-only by design.
Pinned peer range
{ "peerDependencies": { "ai": ">=6.0.0 <8" } } A new SDK major joins the peer range only after the weekly cron proves it
green: ai@7 passed at 7.0.37 and 7.0.58, so 0.3.1 widened the pin to <8. What forces a tapedeck major is a language-model spec shape
change deep enough to break the fields tapedeck reads, not an SDK major
that renumbers the spec. The cassette version field
(tapedeck@<pkg>) and the recorded modelProvider / modelId make a format boundary loud at replay time.
What "pass" means
A row is ✅ pass when:
pnpm typechecksucceeds against the SDK version.pnpm testis green (the suite usesMockLanguageModelV3— no live API calls), including the*.test-d.tstype assertions.- A round-trip holds: a cassette recorded under
recordreplays byte-identical stream parts underreplay, and a changed prompt or tool schema misses.
A row is ⚠️ partial when the suite passes but a known shape change
required a documented workaround (linked in Notes).
A row is ❌ fail when the suite breaks against a new SDK version.
ai major only forces a tapedeck major if it changes the
request/response shape cassettes are serialized against, which is why ai@7 joined the peer range without one. The cassette version field (tapedeck@<pkg>) together
with the recorded modelProvider / modelId makes that boundary loud at replay time: a cassette written under an
incompatible version fails rather than replaying silently.