opencode-cache-engine 0.3.5 → 0.3.6
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 +129 -79
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,21 +3,35 @@
|
|
|
3
3
|
Provider-aware prompt-cache optimization and observability for
|
|
4
4
|
[OpenCode](https://opencode.ai).
|
|
5
5
|
|
|
6
|
-
`opencode-cache-engine` is an
|
|
6
|
+
`opencode-cache-engine` is distributed as an npm package. The Git repository is
|
|
7
|
+
the development source of truth; the published package is a release artifact.
|
|
8
|
+
The package exposes two separate targets required by OpenCode's installed
|
|
9
|
+
plugin model:
|
|
7
10
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
11
|
+
- **`./server`** — the CacheEngine runtime, hooks, provider policies, and telemetry.
|
|
12
|
+
- **`./tui`** — plugin-manager registration and enable/disable integration; it
|
|
13
|
+
has no CacheEngine-specific UI.
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
For local development, use the package from this Git checkout through the
|
|
16
|
+
repository's OpenCode/package development path. Do not maintain or edit a copied
|
|
17
|
+
plugin under `~/.config/opencode/plugins/`. For released installs where
|
|
18
|
+
reproducibility matters, pin an exact package version rather than relying on
|
|
19
|
+
`@latest` resolution or a moving cache entry; see [Installation](#installation).
|
|
12
20
|
|
|
13
21
|
`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.
|
|
14
22
|
|
|
15
23
|
The plugin currently has four cache-policy families:
|
|
16
24
|
|
|
17
|
-
* **DeepSeek
|
|
18
|
-
* **GPT-5.6
|
|
19
|
-
* **GLM-5.3
|
|
20
|
-
* **MiMo-V2.6
|
|
25
|
+
* **DeepSeek** — passive cache observability; request structure is preserved.
|
|
26
|
+
* **GPT-5.6** — documented cache-key/options metadata, with prompt text unchanged.
|
|
27
|
+
* **GLM-5.3** — narrow, content-preserving `<env>` relocation and diagnostics.
|
|
28
|
+
* **MiMo-V2.6** — narrow, content-preserving `<env>` relocation and diagnostics.
|
|
29
|
+
|
|
30
|
+
For both MiMo-V2.6 and GLM-5.3, CacheEngine adds its deterministic
|
|
31
|
+
`x-session-id` request header only when OpenCode identifies the actual provider
|
|
32
|
+
as `openrouter`. It does not add that OpenRouter-specific header for
|
|
33
|
+
non-OpenRouter providers; direct provider endpoints retain their provider-native
|
|
34
|
+
caching behavior.
|
|
21
35
|
|
|
22
36
|
The central design principle is:
|
|
23
37
|
|
|
@@ -38,7 +52,7 @@ It:
|
|
|
38
52
|
6. Applies GPT-5.6 cache-control metadata.
|
|
39
53
|
7. Applies the GLM-5.3 and MiMo-V2.6 volatile-environment relocation.
|
|
40
54
|
8. Records diagnostics that help determine whether prompt-shape changes correlate with cache behavior.
|
|
41
|
-
9. Records MiMo
|
|
55
|
+
9. Records MiMo/GLM affinity outcomes and provider-identity changes.
|
|
42
56
|
|
|
43
57
|
The plugin deliberately avoids pretending that a local hash is proof of a provider cache hit. Provider-reported token usage remains the authoritative signal.
|
|
44
58
|
|
|
@@ -165,7 +179,9 @@ This prevents a compaction-specific prompt from sharing the same GPT cache names
|
|
|
165
179
|
|
|
166
180
|
### Policy: input-shape optimization
|
|
167
181
|
|
|
168
|
-
GLM-5.3
|
|
182
|
+
GLM-5.3 and MiMo-V2.6 use the only prompt-text transformation in the current
|
|
183
|
+
plugin: a narrow, content-preserving relocation of the identifiable `<env>`
|
|
184
|
+
block for the eligible model family.
|
|
169
185
|
|
|
170
186
|
The plugin identifies OpenCode's volatile `<env>` section and moves it to the **tail of the system prompt**.
|
|
171
187
|
|
|
@@ -225,6 +241,22 @@ It only occurs when:
|
|
|
225
241
|
|
|
226
242
|
The plugin does not arbitrarily rearrange unrelated prompt content.
|
|
227
243
|
|
|
244
|
+
### OpenRouter session affinity
|
|
245
|
+
|
|
246
|
+
For GLM-5.3 requests whose actual OpenCode provider identity is `openrouter`,
|
|
247
|
+
CacheEngine adds its deterministic `x-session-id` request header unless a
|
|
248
|
+
case-insensitive `x-session-id` is already present in model or plugin headers.
|
|
249
|
+
The existing value is preserved. This header is affinity metadata, not a prompt
|
|
250
|
+
transformation or cache-control field.
|
|
251
|
+
|
|
252
|
+
For direct Z.AI or any other non-OpenRouter endpoint, CacheEngine does not add
|
|
253
|
+
the OpenRouter-specific affinity header. It leaves the endpoint's native cache
|
|
254
|
+
behavior intact.
|
|
255
|
+
|
|
256
|
+
Affinity observations record eligibility, the observed provider identity,
|
|
257
|
+
whether a header was already present or added, and provider-identity changes
|
|
258
|
+
(`glm_provider_changed`). They do not record the header value.
|
|
259
|
+
|
|
228
260
|
|
|
229
261
|
## MiMo-V2.6 (Flash / Pro)
|
|
230
262
|
|
|
@@ -287,28 +319,24 @@ Explicit telemetry events:
|
|
|
287
319
|
* `mimo_system_env_relocated`
|
|
288
320
|
* `mimo_system_prefix_changed`
|
|
289
321
|
|
|
290
|
-
### OpenRouter
|
|
291
|
-
|
|
292
|
-
OpenRouter documents a top-level `session_id` request field for sticky provider
|
|
293
|
-
routing, which keeps a session's requests on the same upstream provider so
|
|
294
|
-
provider-side prompt caches stay warm.
|
|
322
|
+
### OpenRouter session affinity
|
|
295
323
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
324
|
+
For MiMo-V2.6 requests whose actual OpenCode provider identity is `openrouter`,
|
|
325
|
+
CacheEngine adds its existing deterministic, session-scoped `x-session-id`
|
|
326
|
+
request header. If a case-insensitive `x-session-id` already exists in model or
|
|
327
|
+
plugin headers, CacheEngine preserves it and does not replace it. Eligibility
|
|
328
|
+
uses both the MiMo-V2.6 family and the actual provider identity; a matching model
|
|
329
|
+
slug on another endpoint is not enough.
|
|
299
330
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
and `mimo26.stickySession` currently gates that recording. If a future runtime
|
|
305
|
-
gains a verified `session_id` path, the helper is already in place.
|
|
331
|
+
For Xiaomi's direct endpoint and every other non-OpenRouter provider, CacheEngine
|
|
332
|
+
does not add its OpenRouter-specific `x-session-id`. Direct provider endpoints
|
|
333
|
+
retain their provider-native caching behavior. Any header already supplied by
|
|
334
|
+
the user or runtime is left untouched.
|
|
306
335
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
documented body `session_id`.
|
|
336
|
+
The `x-session-id` header is not a top-level request-body `session_id`, a
|
|
337
|
+
`promptCacheKey`, or a cache-control option. MiMo uses provider-managed implicit
|
|
338
|
+
caching: CacheEngine sends no undocumented `promptCacheKey`, `cacheControl`,
|
|
339
|
+
cache breakpoint, or TTL.
|
|
312
340
|
|
|
313
341
|
### MiMo cache metrics
|
|
314
342
|
|
|
@@ -374,12 +402,16 @@ and are reported diagnostically; the message content is left untouched.
|
|
|
374
402
|
|
|
375
403
|
# Provider comparison
|
|
376
404
|
|
|
377
|
-
|
|
|
378
|
-
|
|
|
379
|
-
| DeepSeek
|
|
380
|
-
| GPT-5.6
|
|
381
|
-
| GLM-5.3
|
|
382
|
-
| MiMo-V2.6
|
|
405
|
+
| Policy family | Detection | Prompt text changed? | Cache metadata changed? | OpenRouter affinity header | Primary cache signal |
|
|
406
|
+
| ------------- | --------- | ------------------- | ----------------------- | -------------------------- | -------------------- |
|
|
407
|
+
| DeepSeek | `deepseek` | No | No | None | provider `cache.read` / `cache.write` |
|
|
408
|
+
| GPT-5.6 | `gpt-5.6*` on OpenAI-ish endpoints | No | Yes: `prompt_cache_key` + options | None | provider cache tokens |
|
|
409
|
+
| 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) |
|
|
410
|
+
| MiMo-V2.6 | Flash / Pro only | Yes, narrowly (`<env>` tail) | No: implicit caching only | `x-session-id` on OpenRouter only | `cached_tokens / prompt_tokens` |
|
|
411
|
+
|
|
412
|
+
`x-session-id` is an HTTP affinity header, not a provider cache key or
|
|
413
|
+
cache-control field. Non-OpenRouter endpoints do not receive CacheEngine's
|
|
414
|
+
OpenRouter-specific affinity value; their native cache behavior is unchanged.
|
|
383
415
|
|
|
384
416
|
|
|
385
417
|
# Prompt-cache strategy
|
|
@@ -614,9 +646,17 @@ Telemetry is intended to answer questions such as:
|
|
|
614
646
|
* Did the GLM system stabilization actually change the observed prompt shape?
|
|
615
647
|
* Did MiMo's environment relocation fire (`mimo_system_env_relocated`)?
|
|
616
648
|
* Did MiMo's stable system prefix change (`mimo_system_prefix_changed`)?
|
|
617
|
-
*
|
|
649
|
+
* Was MiMo/GLM affinity eligible, and did CacheEngine add its header?
|
|
650
|
+
* Was affinity bypassed for a non-OpenRouter or missing provider identity?
|
|
651
|
+
* Did the MiMo provider change (`mimo_provider_changed`) or the GLM provider
|
|
652
|
+
change (`glm_provider_changed`) within a session?
|
|
618
653
|
* What was MiMo's provider-reported cache hit rate (`cacheHitRate`)?
|
|
619
654
|
|
|
655
|
+
Affinity observations are `boundary` records. They contain provider/model
|
|
656
|
+
identity and booleans/source classification such as `eligible`,
|
|
657
|
+
`headerPresent`, `headerAttached`, and `headerSource`; they do not include the
|
|
658
|
+
`x-session-id` header value or full request headers.
|
|
659
|
+
|
|
620
660
|
A MiMo usage record adds the provider-reported cache fields:
|
|
621
661
|
|
|
622
662
|
```json
|
|
@@ -792,6 +832,10 @@ Defaults to:
|
|
|
792
832
|
|
|
793
833
|
Existing request options are not overwritten by the plugin.
|
|
794
834
|
|
|
835
|
+
The established **272K pricing boundary** is controlled by user/harness-side
|
|
836
|
+
configuration and remains unchanged. CacheEngine does not set or raise GPT
|
|
837
|
+
context or output limits; apply the existing harness/user-side limits.
|
|
838
|
+
|
|
795
839
|
|
|
796
840
|
# GLM-5.3 configuration
|
|
797
841
|
|
|
@@ -844,10 +888,11 @@ Enables relocation of the volatile `<env>` section to the system-prompt tail
|
|
|
844
888
|
|
|
845
889
|
### `stickySession`
|
|
846
890
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
891
|
+
Controls whether MiMo usage/provider-change telemetry includes the derived
|
|
892
|
+
`stickySessionId` field. It does not control the existing `x-session-id` header
|
|
893
|
+
injection, which is gated by MiMo family plus actual `openrouter` provider
|
|
894
|
+
identity. The telemetry field contains the derived identifier, not request
|
|
895
|
+
headers or prompt data.
|
|
851
896
|
|
|
852
897
|
### `preserveThinkingIntegrity`
|
|
853
898
|
|
|
@@ -898,7 +943,10 @@ This plugin is compatible with OpenRouter because the cache policy is based on t
|
|
|
898
943
|
|
|
899
944
|
For cache-sensitive workloads, provider stability remains important.
|
|
900
945
|
|
|
901
|
-
The plugin does not attempt to compensate for provider switching by rewriting
|
|
946
|
+
The plugin does not attempt to compensate for provider switching by rewriting
|
|
947
|
+
prompts. For MiMo and GLM it records observed provider identity and provider
|
|
948
|
+
changes so routing instability is observable; it never overrides the selected
|
|
949
|
+
provider or inspects OpenRouter's hidden upstream provider selection.
|
|
902
950
|
|
|
903
951
|
For that reason, a stable provider route is preferable when your goal is to measure and maximize prefix reuse.
|
|
904
952
|
|
|
@@ -929,7 +977,9 @@ export const CacheEngine: Plugin = async ({ client, directory }) => {
|
|
|
929
977
|
}
|
|
930
978
|
```
|
|
931
979
|
|
|
932
|
-
|
|
980
|
+
`CacheEngine` is the exported plugin factory. The npm package name remains
|
|
981
|
+
`opencode-cache-engine`; the server and TUI package exports are listed in
|
|
982
|
+
[File layout](#file-layout).
|
|
933
983
|
|
|
934
984
|
---
|
|
935
985
|
|
|
@@ -1118,7 +1168,8 @@ For reliable cache measurements:
|
|
|
1118
1168
|
|
|
1119
1169
|
# File layout
|
|
1120
1170
|
|
|
1121
|
-
|
|
1171
|
+
This Git repository is the canonical development source. The npm package is
|
|
1172
|
+
built from this tree and exposes the runtime entry points separately:
|
|
1122
1173
|
|
|
1123
1174
|
```text
|
|
1124
1175
|
opencode-cache-engine/
|
|
@@ -1135,51 +1186,49 @@ opencode-cache-engine/
|
|
|
1135
1186
|
└── LICENSE
|
|
1136
1187
|
```
|
|
1137
1188
|
|
|
1138
|
-
The
|
|
1139
|
-
|
|
1140
|
-
```ts
|
|
1141
|
-
export const CacheEngine
|
|
1142
|
-
```
|
|
1143
|
-
|
|
1144
|
-
regardless of the eventual npm package name.
|
|
1145
|
-
|
|
1146
|
-
For example, the npm package could be named:
|
|
1189
|
+
The package exports in `package.json` are:
|
|
1147
1190
|
|
|
1148
|
-
```
|
|
1149
|
-
|
|
1191
|
+
```json
|
|
1192
|
+
{
|
|
1193
|
+
"./server": "./src/cache-engine.ts",
|
|
1194
|
+
"./tui": "./src/tui.mjs"
|
|
1195
|
+
}
|
|
1150
1196
|
```
|
|
1151
1197
|
|
|
1152
|
-
|
|
1198
|
+
The server target owns all CacheEngine runtime hooks and request behavior. The
|
|
1199
|
+
TUI target only registers the package with OpenCode's plugin manager; it does
|
|
1200
|
+
not duplicate server logic.
|
|
1153
1201
|
|
|
1154
1202
|
---
|
|
1155
1203
|
|
|
1156
1204
|
# Installation
|
|
1157
1205
|
|
|
1158
|
-
|
|
1206
|
+
### Local development
|
|
1159
1207
|
|
|
1160
|
-
|
|
1208
|
+
Develop against this repository/package checkout using the project's OpenCode
|
|
1209
|
+
plugin development path. Edit and test the Git working tree as the source of
|
|
1210
|
+
truth; do not copy the plugin into `~/.config/opencode/plugins/` or keep a
|
|
1211
|
+
second active source tree there.
|
|
1161
1212
|
|
|
1162
|
-
|
|
1213
|
+
### Released package
|
|
1163
1214
|
|
|
1164
|
-
|
|
1215
|
+
OpenCode loads the server and TUI targets from the npm package's separate
|
|
1216
|
+
exports. For reproducible released installs, pin an exact version. For this
|
|
1217
|
+
release, use:
|
|
1165
1218
|
|
|
1166
1219
|
```json
|
|
1167
1220
|
{
|
|
1168
1221
|
"plugin": [
|
|
1169
|
-
"opencode-cache-engine"
|
|
1222
|
+
"opencode-cache-engine@0.3.6"
|
|
1170
1223
|
]
|
|
1171
1224
|
}
|
|
1172
1225
|
```
|
|
1173
1226
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
```ts
|
|
1177
|
-
export const CacheEngine: Plugin = async ({ client, directory }) => {
|
|
1178
|
-
// ...
|
|
1179
|
-
}
|
|
1180
|
-
```
|
|
1227
|
+
Avoid a bare package name that resolves a moving `@latest` version when
|
|
1228
|
+
reproducibility matters. Update the pinned version deliberately when upgrading.
|
|
1181
1229
|
|
|
1182
|
-
After installation, verify that OpenCode loads the plugin successfully before
|
|
1230
|
+
After installation, verify that OpenCode loads the plugin successfully before
|
|
1231
|
+
benchmarking cache behavior.
|
|
1183
1232
|
|
|
1184
1233
|
---
|
|
1185
1234
|
|
|
@@ -1209,7 +1258,7 @@ GLM-5.3:
|
|
|
1209
1258
|
MiMo-V2.6:
|
|
1210
1259
|
volatile env block relocated when eligible
|
|
1211
1260
|
no GPT/GLM-only cache fields present
|
|
1212
|
-
|
|
1261
|
+
x-session-id added only for actual OpenRouter provider identity
|
|
1213
1262
|
telemetry carries provider/model/promptTokens/cachedTokens/cacheHitRate
|
|
1214
1263
|
```
|
|
1215
1264
|
|
|
@@ -1278,14 +1327,15 @@ not matched.
|
|
|
1278
1327
|
|
|
1279
1328
|
---
|
|
1280
1329
|
|
|
1281
|
-
##
|
|
1330
|
+
## OpenRouter affinity header is not added
|
|
1282
1331
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
`
|
|
1287
|
-
|
|
1288
|
-
|
|
1332
|
+
CacheEngine adds its `x-session-id` only for a detected MiMo-V2.6 or GLM-5.3
|
|
1333
|
+
request when the actual OpenCode `providerID` is exactly `openrouter`. A direct
|
|
1334
|
+
provider route or missing provider identity is bypassed. If a case-insensitive
|
|
1335
|
+
`x-session-id` is already present in model or plugin headers, it is preserved
|
|
1336
|
+
and CacheEngine does not replace it. Check the `openrouter_affinity_*` boundary
|
|
1337
|
+
records for eligibility, provider identity, and whether CacheEngine added the
|
|
1338
|
+
header; the record does not include the header value.
|
|
1289
1339
|
|
|
1290
1340
|
---
|
|
1291
1341
|
|
|
@@ -1311,9 +1361,9 @@ The current implementation is intentionally conservative:
|
|
|
1311
1361
|
|
|
1312
1362
|
```text
|
|
1313
1363
|
DeepSeek -> preserve and measure
|
|
1314
|
-
GPT-5.6 ->
|
|
1315
|
-
GLM-5.3 ->
|
|
1316
|
-
MiMo-V2.6 ->
|
|
1364
|
+
GPT-5.6 -> documented cache key/options; user/harness controls the 272K pricing boundary
|
|
1365
|
+
GLM-5.3 -> preserve-content <env> relocation + OpenRouter affinity header
|
|
1366
|
+
MiMo-V2.6 -> preserve-content <env> relocation + OpenRouter affinity header
|
|
1317
1367
|
```
|
|
1318
1368
|
|
|
1319
1369
|
That separation is the core design of the project.
|