Skip to content

v1.0.0

Choose a tag to compare

@AlexJoaquimPereira AlexJoaquimPereira released this 13 Oct 17:42
· 164 commits to master since this release

OpenCode Cache Engine release v1.0.0

Dual-runtime release — one package, native support for OpenCode V1 and the OpenCode V2 adapter.

I'm proud to announce the release of the first stable milestone of the project!

After the v0.5.x provider line and the v0.6.0 shared-core consolidation, v1.0.0 ships a single npm package that loads on both OpenCode runtimes, keeps the mature V1 behavior intact, and adds a preview V2 adapter that reuses the same policy resolver and usage/accounting core.

Highlights

  • One package, two runtimes: opencode-cache-engine now registers cleanly on OpenCode V1 (1.18.35) and OpenCode V2 (2.0.26) by package name — verified end-to-end in isolated runtimes.
  • Dual default entry: ./server exposes both the V1 Plugin and a V2-compatible default object, with a lazy V2 import so V1 never initializes V2 code.
  • New ./v2 export — the OpenCode V2 adapter (preview).
  • Provider-aware cache stability across 11 model families (10 shipped + neutral fallback), with the shared core extracted for reuse.
  • 335 tests, 0 failures.

V2 compatibility:

This is the first release with full V2 compatibility.

The dual-entry model

./server (src/cache-engine.ts) now provides:

  • the named CacheEngine (the V1 Plugin), and
  • a default object { id, server: CacheEngine, setup(ctx) }, whose setup lazily import("./cache-engine-v2.mjs") and delegates.

V1 selects server(input, options); V2 selects setup(ctx). Package exports: ./server → src/cache-engine.ts, ./tui → src/tui.mjs, ./v2 → src/cache-engine-v2.mjs.

Verified loading (isolated, by package name)

  • V1 1.18.35 — opencode plugin -g opencode-cache-engine (writes plugin:["opencode-cache-engine"]) → run executed V1 hooks and emitted V1 telemetry (policy-resolution, prefix-observation, prefix-change, usage), 0 V2-only signals.
  • V2 2.0.26 — opencode plugin add opencode-cache-engine (writes plugins:["opencode-cache-engine"]) → run logged loading plugin id=opencode-cache-engine entrypoint=…/src/cache-engine.ts and the V2 adapter produced telemetry.

Important: install by name

  • Recommended: opencode-cache-engine (bare name).
  • Do not pass a subpath (opencode-cache-engine/v2): the loader reads it as an npm/Git spec and the install fails.

Preview caveats (please read)

  • Managed-config discovery/registration of ./v2 remains unverified beyond the isolated shim/name-based tests (project-local shim and by-name install verified).
  • GPT cache-key wire carriage — NOT PASS (Gate 4). The adapter mutates the request as designed, but on the tested routes the field could not be attributed to the adapter (the OpenAI-compatible schema strips it; the OpenAI/Azure route is independently pre-populated by the harness).
  • OpenRouter header attribution — unverified. Evidence shows preservation/fallback, not that the adapter attached the header in the integration path.
  • Usage accounting is best-effort, never exactly-once (volatile events, in-memory cursor, compaction truncation, eviction/mark-expiry edge cases).

Changes

V1 runtime (mature, unchanged behavior)

  • Hooks: chat.headers, chat.params, experimental.chat.system.transform, experimental.session.compacting, and friendlier event aggregation on session.idle.
  • Provider policies: passive by default, with narrowly scoped, evidence-backed interventions only where a documented benefit exists:
    • GPT‑5.6+ — inject only missing promptCacheKey/promptCacheOptions (implicit, 30m).
    • GLM‑5.3 / MiMo‑V2.6 — the single prompt-text transform: content-preserving relocation of the identifiable <env> block.
    • OpenRouter affinity — deterministic x-session-id for GLM/MiMo only, preserving any existing header.
    • Everything else (DeepSeek, Kimi, Claude, Gemini, Qwen, Grok, Meta Muse, MiniMax) stays loopback-passive and observes provider-reported usage.

V2 runtime (preview adapter)

  • ./v2 → src/cache-engine-v2.mjs: a plain { id, setup(ctx) } plugin that reuses the shared policy resolver and usage/accounting core.
  • Hooks:
    • context — GPT‑5.6+ missing-field cache key/options; GLM/MiMo structural <env> relocation (now multi-part-aware; it relocates exactly the single eligible system text part and leaves every other part untouched).
    • model.request — OpenRouter x-session-id affinity (guarded; it never duplicates a pre-existing session header).
    • Usage — session.usage.updated (primary) and session.idle (secondary) drive the shared history scan via session.context({ sessionID }), with a bounded per-session model (LRU cap + tombstones + evicted marks), cancellation, and fail-safe error handling.

Verification & evidence

  • Unit tests: 335 pass / 0 fail (Node's built-in runner).
  • Package: npm pack → 9 files, includes src/cache-engine-v2.mjs (~21 kB).
  • Isolated live load test (this release):
    • Tarball opencode-cache-engine-0.7.1.tgz sha256 4103ecb214d4f36c97707160de522f7f94d32ce1dd8566fb3974cc16eb176fa9.
    • Installed src/cache-engine.ts sha256 c449b2655a98362c156c14905ffa636e9ece5d0a4500243e88863390aa727d9e (matched the tarball).
    • V1 1.18.35 and V2 2.0.26 both installed by name from a disposable local registry and loaded/executed the plugin; no real provider traffic.
  • Isolation: all tests ran in bubblewrap --unshare-net with private HOME/XDG; the host managed service was never touched.

Detailed changes

Feature diff vs master@34ce537: 10 files, +3473 / −71.

File Change
src/cache-engine.ts +36 — dual V1/V2 default entry (lazy V2 import)
src/cache-engine-v2.mjs new (~505) — V2 adapter
src/cache-engine-core.mjs +73 — structural <env> eligibility (Platform: required), marker-after-<env> no-op, precise separator-newline contract
test/cache-engine.test.mjs +1255 — cross-version entry, V2 fault-injection, multi-part relocation, L1/L2, C1 separator regression
package.json adds ./v2 export; version → 1.0.0
docs/research-findings.md +913 — RF-OC-017…034 (V2 API/hook/event/usage, loader/CLI, <env> compatibility, separator contract)
docs/implementation-plan-v2.md +462 — V2 readiness §2B–§2D, Gate 0–4 results, limitations, closure
docs/cache-policy-inventory.md +6 — GLM/MiMo V2 relocation-compatibility note
README.md compatibility, installation, quick install (both runtimes), rollback
AGENTS.md +73 — V2/roadmap guidance

Key commits on the way to 1.0.0: cross-version tests (ac720c5); structural <env> core fix (7b085c6, 4ed1a8f, 36323e7); multi-part V2 relocation (e36d513); V2 surface fault-injection tests (ce31caf); dual entry (947bbdd); C1 clarification (2ab2423, af154f0); docs (8f230c8, 1f0d8b8, 9b6bf56, 0ed32bd, de169fb); merge (0336957); version bump (fc6f6fc); README quick install (b301668).

Known limitations (explicit)

  • The V2 adapter is preview, not production: managed-config registration is unproven; GPT wire carriage and OpenRouter header attribution are unresolved; compaction isolation, fork cache-root, and the secondary V1 diagnostics are not ported.
  • No exactly-once accounting. Usage is best-effort and can undercount (volatile events, restarts, compaction, eviction); expired marks can recount.
  • Loader behavior is version-specific (V1 default-object server selection; V2 ignoring the extra server key) — verified on 1.18.35 / 2.0.26; other versions are not asserted.

Not in this release

No public npm publish or git tag are performed here (the maintainer handles tagging/publishing; postpublish will create and push the v1.0.0 tag). The feature/v2-adapter-checkpoint branch remains available at its pre-merge tip.

Full Changelog: v0.7.1...v1.0.0


Thank you to everyone for using the plugin and helping make this project successful!


Provider-aware prompt-cache optimization and observability for OpenCode.

opencode-cache-engine is an OpenCode npm plugin that exposes three targets required by OpenCode's installed plugin model:

  • ./server — the V1 CacheEngine runtime, hooks, provider policies, and telemetry (verified on OpenCode 1.x).
  • ./tui — plugin-manager registration and enable/disable integration; it
    has no CacheEngine-specific UI.
  • ./v2 — the OpenCode V2 adapter (preview): implemented and
    offline-tested; isolated shim-based loading, setup, and hook
    registration/dispatch are verified
    in an isolated OpenCode 2.0.26 runtime,
    but managed-config discovery/registration remain unverified (and the direct
    plugins: ["opencode-cache-engine/v2"] entry did not resolve in the tested
    offline configuration)

CacheEngine is an OpenCode plugin designed for long-running agent sessions where prompt-cache efficiency affects both latency and cost. It keeps the harness conservative for providers whose cache behavior is already automatic, while applying provider-specific optimizations where the provider exposes useful cache controls or where prompt structure can be safely improved.

The plugin currently has eleven cache-policy families:

  • DeepSeek — passive cache observability; request structure is preserved.
  • GPT-5.6 and later — documented cache-key/options metadata, with prompt text unchanged. GPT-6 and future 5.6+/6+/7+ versions resolve through the same documented boundary.
  • GLM-5.3 and later — GLM implicit-cache baseline and diagnostics; GLM-5.3 additionally uses a narrow, content-preserving <env> relocation overlay.
  • MiMo V2.6 and later — MiMo implicit-cache baseline and diagnostics; MiMo V2.6 Flash/Pro additionally use a narrow content-preserving <env> relocation overlay.
  • Kimi — passive Moonshot/Kimi implicit-cache observability; the request is left unchanged. The Anthropic-compatible cache_control route is not implemented.
  • Claude (Anthropic) — passive classification and accounting; the request is left unchanged because OpenCode itself applies Anthropic cache_control breakpoints.
  • Google Gemini — passive classification and accounting; Gemini 2.5+ provider-managed implicit caching is left untouched. CacheEngine creates no CachedContent resources and injects no Gemini cache-control field.
  • Alibaba Qwen — passive classification and accounting; Qwen's provider-managed implicit caching is left untouched on every route. CacheEngine places no explicit block-level cache_control marker and adds no affinity, because the V1 hook cannot reach message content blocks and OpenCode already applies breakpoints on the Qwen Messages routes.
  • xAI Grok — passive classification and accounting. Grok caching is automatic on all Grok language models, and direct xAI already receives a stable conversation affinity key from OpenCode itself, so CacheEngine injects no header or key and rewrites nothing.
  • Meta Muse — passive classification and accounting. Muse caching is automatic positional prefix caching; Meta's prompt_cache_key must be an application-stable routing hint (never per-session) and prompt_cache_retention is a request-level policy, so CacheEngine injects neither and rewrites nothing.
  • MiniMax — passive classification and accounting, route-aware. MiniMax caching is automatic; M2.x additionally supports explicit Anthropic cache_control (M3 does not), but OpenCode already owns those breakpoints on the Anthropic-compatible routes, so CacheEngine injects nothing.

Initial models were personally chosen for their performance in max programming task completed per dollar. More models can be added based on newer releases or updates.

Future releases will be based on newer versions of models from the above providers, as well as any model that performs optimally over the Pareto distribution on OpenRouter as well as on personal discretion. Since cache stability policy doesn't change much for the providers, there's no need for a code rebase.

Installation

V1 (stable):

opencode plugin opencode-cache-engine          # TUI/CLI installer

or set config:

"plugin": ["opencode-cache-engine"]

V2 (preview):

opencode plugin add opencode-cache-engine      # TUI/CLI installer

or set config:

"plugins": ["opencode-cache-engine"]

Both install the package by name, and each runtime selects the interface it supports from the package's ./server export (V1 → server, V2 → setup). Do not pass opencode-cache-engine/v2 as the package specifier; use the bare name.

Best complemented with agents for the particular models configured at AlexJoaquimPereira/opencode-agent-config