opencode-cache-engine 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,7 +31,7 @@ The plugin currently has four cache-policy families:
31
31
  * **GPT-5.6 and later** — documented cache-key/options metadata, with prompt text
32
32
  unchanged. GPT-6 and future 5.6+/6+/7+ versions resolve through the same
33
33
  documented boundary.
34
- * **GLM-5.3** — narrow, content-preserving `<env>` relocation and diagnostics.
34
+ * **GLM-5.3 and later** — GLM implicit-cache baseline and diagnostics; GLM-5.3 additionally uses a narrow, content-preserving `<env>` relocation overlay.
35
35
  * **MiMo-V2.6** — narrow, content-preserving `<env>` relocation and diagnostics.
36
36
 
37
37
  Family classification is not hard-coded in the runtime. A pure policy registry
@@ -42,7 +42,7 @@ the single runtime source of policy classification. The first-party research
42
42
  behind each registry entry is recorded in
43
43
  [docs/cache-policy-inventory.md](docs/cache-policy-inventory.md).
44
44
 
45
- For both MiMo-V2.6 and GLM-5.3, CacheEngine adds its deterministic
45
+ For MiMo-V2.6 and the GLM-5.3-and-later family, CacheEngine adds its deterministic
46
46
  `x-session-id` request header only when OpenCode identifies the actual provider
47
47
  as `openrouter`. It does not add that OpenRouter-specific header for
48
48
  non-OpenRouter providers; direct provider endpoints retain their provider-native
@@ -205,6 +205,12 @@ GLM-5.3 and MiMo-V2.6 use the only prompt-text transformation in the current
205
205
  plugin: a narrow, content-preserving relocation of the identifiable `<env>`
206
206
  block for the eligible model family.
207
207
 
208
+ Since v0.4.4 the GLM **family baseline** and the GLM-5.3 **overlay** are
209
+ separate. A resolved GLM-5.3-and-later model inherits the implicit-cache baseline
210
+ and the non-mutating GLM diagnostics/transport, but the `<env>` relocation below
211
+ is a GLM-5.3-specific overlay and is **not** inherited by a newer GLM merely
212
+ because its version number is higher.
213
+
208
214
  The plugin identifies OpenCode's volatile `<env>` section and moves it to the **tail of the system prompt**.
209
215
 
210
216
  Conceptually:
@@ -428,7 +434,7 @@ and are reported diagnostically; the message content is left untouched.
428
434
  | ------------- | --------- | ------------------- | ----------------------- | -------------------------- | -------------------- |
429
435
  | DeepSeek | `deepseek` (V4-and-later family + passive fallback) | No | No | None | provider `cache.read` / `cache.write` |
430
436
  | GPT-5.6 and later | version boundary `gpt-<major>[.<minor>] ≥ 5.6` on OpenAI-ish endpoints (includes GPT-6) | No | Yes: `prompt_cache_key` + options | None | provider cache tokens |
431
- | GLM-5.3 | `glm-5.3*` | Yes, narrowly (`<env>` tail) | No provider cache key | `x-session-id` on OpenRouter only | provider cache tokens (GLM ratio) |
437
+ | GLM-5.3 and later | `glm-5.3+` | Yes, narrowly (`<env>` tail) on GLM-5.3 only | No provider cache key | `x-session-id` on OpenRouter only | provider cache tokens (GLM ratio) |
432
438
  | MiMo-V2.6 | Flash / Pro only | Yes, narrowly (`<env>` tail) | No: implicit caching only | `x-session-id` on OpenRouter only | `cached_tokens / prompt_tokens` |
433
439
 
434
440
  `x-session-id` is an HTTP affinity header, not a provider cache key or
@@ -1392,7 +1398,7 @@ not matched.
1392
1398
 
1393
1399
  ## OpenRouter affinity header is not added
1394
1400
 
1395
- CacheEngine adds its `x-session-id` only for a detected MiMo-V2.6 or GLM-5.3
1401
+ CacheEngine adds its `x-session-id` only for a detected MiMo-V2.6 or GLM-5.3-and-later
1396
1402
  request when the actual OpenCode `providerID` is exactly `openrouter`. A direct
1397
1403
  provider route or missing provider identity is bypassed. If a case-insensitive
1398
1404
  `x-session-id` is already present in model or plugin headers, it is preserved
@@ -288,7 +288,7 @@ made here); **hold** = do not inherit without first-party evidence.
288
288
  | DeepSeek | future-looking V4+ identifiers: `deepseek-v4.1`, `deepseek-v4`, `deepseek-v5` | Not documented as request ids (`deepseek-v4.1`/`deepseek-v4` invalid or version-string only) | Passive via the V4-and-later family predicate or the safe creator fallback (v0.4.3); no mutation | keep passive; treat as unknown-friendly | none | Medium (detection) / Low (future ids) | DeepSeek *Models & Pricing*; *Chat Completions API* | 2026-09-27 |
289
289
  | DeepSeek | pre-V4 negative controls: `deepseek-chat`, `deepseek-reasoner` | Retired names (retired 2026-07-24); no separate V4+ cache policy claimed | Passive | hold | n/a | High | DeepSeek *Change Log*; *news260424* | 2026-09-26 |
290
290
  | Z.AI | GLM 5.3: `glm-5.3`, `glm-5.3-flash`, `glm-5.3-flashx` | Implicit automatic caching; `cached_tokens`; stable-prompt-first guidance; no documented min/TTL/key | GLM policy: `<env>` relocation; OpenRouter `x-session-id` | keep (env relocation is an exact overlay, not a Z.AI control) | env relocation is the overlay; keep scoped to GLM-5.3 | Medium | Z.AI *Context Caching*; *Chat Completion*; *Pricing* | 2026-09-26 |
291
- | Z.AI | current later GLM generations (documented): none newer than 5.3; newest below is `glm-5.2`/`glm-5.1`/`glm-5`/`glm-4.7` | Same implicit mechanism documented service-wide; cached-input price per model | neutral (only `glm-5.3` matched) | **hold** — no doc says 5.3 overlay extends upward; none newer documented | n/a | High (no later gens documented) | Z.AI *New Released*; *Pricing* | 2026-09-26 |
291
+ | Z.AI | current later GLM generations (documented): none newer than 5.3; newest below is `glm-5.2`/`glm-5.1`/`glm-5`/`glm-4.7` | Same implicit mechanism documented service-wide; cached-input price per model | GLM-5.3 family baseline via the 5.3-and-later boundary; **no** `<env>` overlay (v0.4.4) | **baseline only** — overlay stays 5.3-explicit | none documented | High (no later gens documented) | Z.AI *New Released*; *Pricing* | 2026-09-27 |
292
292
  | Z.AI | 5.2 and earlier negative controls: `glm-5.2`, `glm-5.1`, `glm-5`, `glm-4.7`, `glm-4.6`, `glm-4.5`, `glm-4-32b-*` | Cacheable (except `glm-4-32b-0414-128k`), different cached-input pricing; no cache-semantics difference documented | neutral | hold | n/a | High | Z.AI *Pricing*; *Chat Completion* (enum) | 2026-09-26 |
293
293
  | Xiaomi | MiMo V2.6 Flash: `mimo-v2.6-flash` (OR `xiaomi/mimo-v2.6-flash`) | Provider-managed implicit caching; `cached_tokens`; no documented min/TTL/key/prefix rules | MiMo policy: `<env>` relocation; provider-change telemetry; OpenRouter `x-session-id` | keep scoped as exact-model overlay | env relocation unsupported by docs → treat as overlay | Medium | MiMo *Models*; *Pricing*; *openai-api* | 2026-09-26 |
294
294
  | Xiaomi | MiMo V2.6 Pro: `mimo-v2.6-pro` (OR `xiaomi/mimo-v2.6-pro`) | Same documented per-model implicit caching; per-model pricing | MiMo policy (same as Flash) | keep | none documented | Medium | MiMo *Models*; *Pricing* | 2026-09-26 |
@@ -384,3 +384,24 @@ a newer model inherits an older policy. They must not be resolved by guessing.
384
384
  - Evidence caveat: first-party pages conflict on whether `deepseek-v4-pro` still
385
385
  routes as a distinct model in late 2026; this does not affect the passive
386
386
  policy, which carries no mutation either way.
387
+
388
+ ### Follow-up: v0.4.4 GLM-5.3-and-later baseline vs GLM-5.3 overlay
389
+
390
+ - Z.AI docs were re-verified on **2026-09-27**. GLM-5.3 is the newest documented
391
+ text generation (no `glm-5.4`/`glm-6`); GLM-5.3 is explicitly "the same base
392
+ model as GLM-5.2" with post-training differences. Caching is implicit with no
393
+ `cache_control`/`prompt_cache_key`/breakpoint/TTL field; `cached_tokens` is the
394
+ reported field. Z.AI publishes **no** generational-inheritance rule.
395
+ - The `<env>` relocation has **no first-party basis** — it is a CacheEngine
396
+ implementation overlay. v0.4.4 therefore separates the concepts:
397
+ - **Family baseline** (`zai.glm-5.3-plus`, predicate `glm >= 5.3`): implicit
398
+ caching plus the non-mutating GLM diagnostics/transport (thinking-integrity
399
+ telemetry, GLM cache ratio, provider-change telemetry, OpenRouter
400
+ `x-session-id`). No prompt rewrite.
401
+ - **GLM-5.3 overlay**: the `<env>` relocation stays registered only on the
402
+ GLM-5.3 family entry, so a later GLM does **not** inherit it.
403
+ - GLM-5.2 and earlier remain neutral. No new GLM cache-control field is added,
404
+ and GLM-5.3 behavior is unchanged.
405
+ - Evidence caveat: because no later GLM generation is documented, the
406
+ "GLM-5.3 and later" boundary is a CacheEngine inference about a passive
407
+ baseline, not a Z.AI contract; it is safe because it introduces no mutation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-cache-engine",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "private": false,
5
5
  "description": "Provider-aware prompt-cache optimization and telemetry for OpenCode",
6
6
  "keywords": [
@@ -102,6 +102,25 @@ export function isDeepseekV4OrLater(slug) {
102
102
  return false
103
103
  }
104
104
 
105
+ // GLM-5.3-and-later family baseline (docs/cache-policy-inventory.md §3; Z.AI
106
+ // docs re-verified 2026-09-27). Z.AI publishes no generational-inheritance rule
107
+ // and no explicit cache control, so this is a CacheEngine inference about a
108
+ // passive/implicit baseline; it is safe because it grants no mutation. The
109
+ // GLM-5.3 `<env>` relocation is a separate, explicit overlay and is NOT granted
110
+ // by this predicate. GLM-5.2 and earlier stay outside this family.
111
+ export function isGlm53OrLater(slug) {
112
+ const text = String(slug ?? "").toLowerCase()
113
+ const re = /glm-(\d{1,3})(?:\.(\d))?(?![\d.])/g
114
+ let m
115
+ while ((m = re.exec(text)) !== null) {
116
+ const major = Number(m[1])
117
+ const minor = m[2] === undefined ? 0 : Number(m[2])
118
+ if (major > 5) return true
119
+ if (major === 5 && minor >= 3) return true
120
+ }
121
+ return false
122
+ }
123
+
105
124
  // Candidate ids for exact/alias lookup. Includes the raw apiID/modelID, the
106
125
  // lower-cased forms, and a single stripped transport/vendor prefix
107
126
  // (e.g. "openai/gpt-5.6-luna" -> "gpt-5.6-luna", "xiaomi/mimo-v2.6-flash" ->
@@ -344,6 +363,29 @@ export const POLICY_REGISTRY = [
344
363
  }),
345
364
  inventoryRef: "§3 Z.AI GLM",
346
365
  },
366
+ {
367
+ // v0.4.4: "GLM-5.3 and later" family baseline. A future 5.3+ model inherits
368
+ // the implicit-cache baseline and its non-mutating diagnostics/transport,
369
+ // but NOT the GLM-5.3-specific `<env>` relocation overlay (`overlays: []`
370
+ // and no `envRelocation` capability). GLM-5.2 and earlier stay neutral.
371
+ id: "zai.glm-5.3-plus",
372
+ creator: "z.ai",
373
+ family: "glm-5.3",
374
+ kind: "family",
375
+ predicate: isGlm53OrLater,
376
+ baseline: "zai.implicit-cache",
377
+ overlays: [],
378
+ legacy: true,
379
+ runtime: rt("glm53", {
380
+ thinkingIntegrity: true,
381
+ cacheRatio: "glm",
382
+ providerChange: "glm",
383
+ openRouterAffinity: true,
384
+ }),
385
+ boundary: "GLM-5.3 and later",
386
+ note: "Z.AI publishes no generational-inheritance rule and no explicit cache control. The baseline is implicit caching; the `<env>` relocation is a GLM-5.3-only CacheEngine overlay and is intentionally not inherited. No cache-control field is invented.",
387
+ inventoryRef: "§3 Z.AI GLM",
388
+ },
347
389
  {
348
390
  id: "xiaomi.mimo-v2.6",
349
391
  creator: "xiaomi",
@@ -54,6 +54,7 @@ import {
54
54
  OVERLAYS,
55
55
  POLICY_REGISTRY,
56
56
  isDeepseekV4OrLater,
57
+ isGlm53OrLater,
57
58
  isGpt56OrLater,
58
59
  resolveLegacyFamily,
59
60
  resolvePolicy,
@@ -1650,6 +1651,8 @@ async function runPolicyMigrationProbe() {
1650
1651
  { name: "deepseek-gateway", model: { providerID: "acme-gateway", id: "my-deepseek-mirror", api: { id: "my-deepseek-mirror" } }, expect: { policy: "deepseek", env: false, gpt: false, header: false } },
1651
1652
  { name: "glm-5.3-direct", model: { providerID: "zai", id: "glm-5.3", api: { id: "glm-5.3" } }, expect: { policy: "glm53", env: true, gpt: false, header: false } },
1652
1653
  { name: "glm-5.3-openrouter", model: { providerID: "openrouter", id: "z-ai/glm-5.3-flash", api: { id: "z-ai/glm-5.3-flash" } }, expect: { policy: "glm53", env: true, gpt: false, header: true } },
1654
+ { name: "glm-5.4-direct", model: { providerID: "zai", id: "glm-5.4", api: { id: "glm-5.4" } }, expect: { policy: "glm53", env: false, gpt: false, header: false } },
1655
+ { name: "glm-5.4-openrouter", model: { providerID: "openrouter", id: "z-ai/glm-5.4", api: { id: "z-ai/glm-5.4" } }, expect: { policy: "glm53", env: false, gpt: false, header: true } },
1653
1656
  { name: "glm-5.2", model: { providerID: "zai", id: "glm-5.2", api: { id: "glm-5.2" } }, expect: { policy: "neutral", env: false, gpt: false, header: false } },
1654
1657
  { name: "mimo-v2.6-flash-direct", model: { providerID: "xiaomi", id: "mimo-v2.6-flash", api: { id: "mimo-v2.6-flash" } }, expect: { policy: "mimo26", env: true, gpt: false, header: false } },
1655
1658
  { name: "mimo-v2.6-pro-openrouter", model: { providerID: "openrouter", id: "xiaomi/mimo-v2.6-pro", api: { id: "xiaomi/mimo-v2.6-pro" } }, expect: { policy: "mimo26", env: true, gpt: false, header: true } },
@@ -1915,3 +1918,95 @@ test("v0.4.3: DeepSeek never receives OpenRouter affinity or GPT/GLM/MiMo fields
1915
1918
  assert.equal(r.existingHeadersPreserved, true, `${name}: headers preserved`)
1916
1919
  }
1917
1920
  })
1921
+
1922
+ // ===========================================================================
1923
+ // v0.4.4 GLM-5.3-and-later family baseline vs the GLM-5.3-specific overlay
1924
+ //
1925
+ // Source: Z.AI docs re-verified 2026-09-27 (docs/cache-policy-inventory.md §3).
1926
+ // Z.AI documents implicit caching (no cache control) and publishes no
1927
+ // generational-inheritance rule; the `<env>` relocation is a CacheEngine overlay
1928
+ // with no first-party basis. GLM-5.2 and earlier stay neutral.
1929
+ // ===========================================================================
1930
+
1931
+ test("v0.4.4: isGlm53OrLater matches GLM-5.3+ version tokens only", () => {
1932
+ const inFamily = ["glm-5.3", "glm-5.3-flash", "glm-5.3-flashx", "glm-5.4", "glm-5.9", "glm-6", "z-ai/glm-5.3-flash"]
1933
+ for (const id of inFamily) assert.equal(isGlm53OrLater(id), true, `${id} is 5.3+`)
1934
+ const outOfFamily = ["glm-5.2", "glm-5.1", "glm-5", "glm-4.7", "glm-4.6", "glm-4.5", "glm-4.5-air", "glm-4-32b-0414-128k", ""]
1935
+ for (const id of outOfFamily) assert.equal(isGlm53OrLater(id), false, `${id} is pre-5.3`)
1936
+ })
1937
+
1938
+ test("v0.4.4: GLM-5.3 keeps its overlay; a later GLM gets the baseline only", () => {
1939
+ const g53 = resolvePolicy(M("zai", "glm-5.3"))
1940
+ assert.equal(g53.family, "glm-5.3")
1941
+ assert.equal(baseId(g53), "zai.implicit-cache")
1942
+ assert.deepEqual(overlayIds(g53), ["glm53.env-relocation"])
1943
+
1944
+ const g54 = resolvePolicy(M("zai", "glm-5.4"))
1945
+ assert.equal(g54.creator, "z.ai")
1946
+ assert.equal(g54.family, "glm-5.3")
1947
+ assert.equal(baseId(g54), "zai.implicit-cache") // same family baseline
1948
+ assert.deepEqual(overlayIds(g54), []) // overlay is NOT inherited
1949
+
1950
+ // Runtime capability separation: baseline diagnostics/transport yes, prompt rewrite no.
1951
+ const c53 = resolveRuntimePolicy(M("zai", "glm-5.3"))
1952
+ const c54 = resolveRuntimePolicy(M("zai", "glm-5.4"))
1953
+ assert.equal(c54.policy, "glm53")
1954
+ assert.equal(c54.envRelocation, null)
1955
+ assert.equal(c54.thinkingIntegrity, true)
1956
+ assert.equal(c54.cacheRatio, "glm")
1957
+ assert.equal(c54.providerChange, "glm")
1958
+ assert.equal(c54.openRouterAffinity, true)
1959
+ assert.equal(c53.envRelocation, "glm")
1960
+
1961
+ // Boundary metadata is traceable and the overlay is registered separately.
1962
+ const plus = POLICY_REGISTRY.find((e) => e.id === "zai.glm-5.3-plus")
1963
+ assert.equal(plus.boundary, "GLM-5.3 and later")
1964
+ assert.deepEqual(plus.overlays, [])
1965
+ assert.ok(plus.inventoryRef)
1966
+ })
1967
+
1968
+ test("v0.4.4: GLM-5.2 and earlier stay neutral", () => {
1969
+ for (const id of ["glm-5.2", "glm-5.1", "glm-5", "glm-4.7", "glm-4.6", "glm-4.5"]) {
1970
+ const r = resolvePolicy(M("zai", id))
1971
+ assert.equal(r.family, "neutral", `${id} neutral`)
1972
+ assert.deepEqual(overlayIds(r), [])
1973
+ assert.equal(resolveRuntimePolicy(M("zai", id)).policy, "neutral")
1974
+ }
1975
+ })
1976
+
1977
+ test("v0.4.4: legacy detectPolicy follows the GLM-5.3-and-later boundary", () => {
1978
+ assert.equal(detectPolicy(M("zai", "glm-5.3-flash")), POLICY_GLM53)
1979
+ assert.equal(detectPolicy(M("zai", "glm-5.4")), POLICY_GLM53)
1980
+ assert.equal(detectPolicy(M("zai", "glm-5.2")), POLICY_NEUTRAL)
1981
+ })
1982
+
1983
+ test("v0.4.4: <env> absent leaves system content unchanged", () => {
1984
+ const plain = "Stable instructions only.\nNo environment block here."
1985
+ const r = relocateVolatileEnvBlock(plain)
1986
+ assert.equal(r.changed, false)
1987
+ assert.equal(r.text, plain)
1988
+ })
1989
+
1990
+ test("v0.4.4: later GLM inherits the baseline but never the <env> rewrite (runtime)", async () => {
1991
+ const { results } = await policyMigrationResults()
1992
+ const g53 = results.find((r) => r.name === "glm-5.3-direct")
1993
+ const g54 = results.find((r) => r.name === "glm-5.4-direct")
1994
+ assert.ok(g53 && g54)
1995
+ // Identical system text with a valid <env> block present in both cases.
1996
+ assert.equal(g53.systemRelocated, true) // 5.3 overlay fires
1997
+ assert.equal(g54.systemRelocated, false) // later GLM does NOT inherit it
1998
+ assert.equal(g54.runtimePolicy, "glm53") // but the family baseline applies
1999
+ assert.equal(g54.gptOptionInjected, false)
2000
+ assert.equal(g54.affinityHeaderAttached, false)
2001
+ })
2002
+
2003
+ test("v0.4.4: GLM OpenRouter affinity is transport-gated for later GLM too", async () => {
2004
+ const { results } = await policyMigrationResults()
2005
+ const or = results.find((r) => r.name === "glm-5.4-openrouter")
2006
+ const direct = results.find((r) => r.name === "glm-5.4-direct")
2007
+ assert.equal(or.affinityHeaderAttached, true)
2008
+ assert.equal(or.systemRelocated, false)
2009
+ assert.equal(direct.affinityHeaderAttached, false)
2010
+ assert.equal(or.existingHeadersPreserved, true)
2011
+ assert.equal(direct.existingHeadersPreserved, true)
2012
+ })