opencode-cache-engine 0.3.2 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-cache-engine",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "private": false,
5
5
  "description": "Provider-aware prompt-cache optimization and telemetry for OpenCode",
6
6
  "keywords": [
@@ -482,17 +482,18 @@ export const CacheEngine: Plugin = async ({ client, directory }) => {
482
482
  // use a deterministic separate namespace (<root>:compact) so a compaction
483
483
  // cache write never interferes with the useful live-session cache.
484
484
  //
485
- // MiMo-V2.6 + OpenRouter session affinity. Gate on the actual OpenCode
486
- // provider identity as well as the detected family; a matching model slug
487
- // on a direct endpoint is not sufficient. The runtime merges model.headers
488
- // before this hook's output, so preserve a case-insensitive user/model or
489
- // earlier-plugin x-session-id rather than silently overwriting it. Otherwise
490
- // add the deterministic ID derived from the logical OpenCode session.
485
+ // MiMo-V2.6 / GLM-5.3 + OpenRouter session affinity. Gate on the actual
486
+ // OpenCode provider identity as well as the detected family; a matching
487
+ // model slug on a direct endpoint is not sufficient. The runtime merges
488
+ // model.headers before this hook's output, so preserve a case-insensitive
489
+ // user/model or earlier-plugin x-session-id rather than silently overwriting
490
+ // it. Otherwise add the deterministic ID derived from the logical session.
491
491
  "chat.headers": async (input, output) => {
492
492
  try {
493
493
  const model = input.model as unknown as ChatParamsModel
494
494
  const providerID = String(model?.providerID ?? "")
495
- if (providerID !== "openrouter" || detectPolicy(model) !== POLICY_MIMO26) return
495
+ const family = detectPolicy(model)
496
+ if (providerID !== "openrouter" || (family !== POLICY_MIMO26 && family !== POLICY_GLM53)) return
496
497
 
497
498
  const hasSessionIDHeader = (headers?: Record<string, string>) =>
498
499
  Object.keys(headers ?? {}).some((name) => name.toLowerCase() === "x-session-id")
@@ -1035,10 +1035,15 @@ async function runMiMoHeaderHookProbe() {
1035
1035
  sessionID,
1036
1036
  agent: "build",
1037
1037
  model,
1038
- provider: { id: model.providerID },
1038
+ provider: { source: "config", info: { id: model.providerID }, options: {} },
1039
1039
  message: { id: "msg", sessionID, role: "user", content: "probe" },
1040
1040
  }, output)
1041
- return { headers: output.headers, sameObject: output.headers === headersRef, modelHeaders: model.headers }
1041
+ return {
1042
+ headers: output.headers,
1043
+ sameObject: output.headers === headersRef,
1044
+ outputKeys: Object.keys(output),
1045
+ modelHeaders: model.headers,
1046
+ }
1042
1047
  }
1043
1048
  const mimoOpenRouter = {
1044
1049
  providerID: "openrouter",
@@ -1052,7 +1057,34 @@ async function runMiMoHeaderHookProbe() {
1052
1057
  const direct = await invoke({ ...mimoOpenRouter, providerID: "xiaomi" }, "ses_direct", { "User-Agent": "preserve-me" })
1053
1058
  const unknown = await invoke({ ...mimoOpenRouter, providerID: "unknown-provider" }, "ses_unknown")
1054
1059
  const missingProvider = await invoke({ ...mimoOpenRouter, providerID: undefined }, "ses_missing_provider")
1055
- const glm = await invoke({ providerID: "openrouter", id: "z-ai/glm-5.3", api: { id: "z-ai/glm-5.3" }, headers: {} }, "ses_glm")
1060
+ const glmOpenRouter = { providerID: "openrouter", id: "z-ai/glm-5.3", api: { id: "z-ai/glm-5.3" }, headers: {} }
1061
+ const glm1 = await invoke(glmOpenRouter, "ses_glm_same")
1062
+ const glm2 = await invoke(glmOpenRouter, "ses_glm_same")
1063
+ const glmDifferent = await invoke(glmOpenRouter, "ses_glm_other")
1064
+ const glmDirect = await invoke({ ...glmOpenRouter, providerID: "zai" }, "ses_glm_direct", { "User-Agent": "preserve-glm" })
1065
+ const nonOpenRouterMatrix = [
1066
+ ["mimo-direct", { ...mimoOpenRouter, providerID: "xiaomi" }],
1067
+ ["glm-direct", { ...glmOpenRouter, providerID: "zai" }],
1068
+ ["deepseek-direct", { providerID: "deepseek", id: "deepseek-v4.1-flash", api: { id: "deepseek-v4.1-flash" }, headers: {} }],
1069
+ ["gpt-openai", { providerID: "openai", id: "gpt-5.6", api: { id: "gpt-5.6", npm: "@ai-sdk/openai" }, headers: {} }],
1070
+ ["unknown-provider", { ...mimoOpenRouter, providerID: "unknown-provider" }],
1071
+ ["missing-provider", { ...mimoOpenRouter, providerID: undefined }],
1072
+ ["opencode-go-mimo", { ...mimoOpenRouter, providerID: "opencode" }],
1073
+ ["opencode-go-glm", { ...glmOpenRouter, providerID: "opencode" }],
1074
+ ]
1075
+ const compatibility = []
1076
+ for (const [name, model] of nonOpenRouterMatrix) {
1077
+ const existing = { "User-Agent": "preserve-" + name, "x-compat-test": name }
1078
+ compatibility.push({ name, ...(await invoke(model, "ses_" + name, existing)), expected: existing })
1079
+ }
1080
+ const gptOutput = { options: {} }
1081
+ await hooks["chat.params"]({
1082
+ sessionID: "ses_gpt_native_cache",
1083
+ agent: "build",
1084
+ model: { providerID: "openai", id: "gpt-5.6", api: { id: "gpt-5.6", npm: "@ai-sdk/openai" } },
1085
+ provider: { source: "config", info: { id: "openai" }, options: {} },
1086
+ message: { id: "msg-gpt", sessionID: "ses_gpt_native_cache", role: "user", content: "probe" },
1087
+ }, gptOutput)
1056
1088
  const configured = await invoke({
1057
1089
  ...mimoOpenRouter,
1058
1090
  headers: { "X-Session-Id": "user-configured-value" },
@@ -1065,12 +1097,19 @@ async function runMiMoHeaderHookProbe() {
1065
1097
  direct,
1066
1098
  unknown,
1067
1099
  missingProvider,
1068
- glm,
1100
+ glm1,
1101
+ glm2,
1102
+ glmDifferent,
1103
+ glmDirect,
1104
+ compatibility,
1105
+ gptOptions: gptOutput.options,
1069
1106
  configured,
1070
1107
  configuredModelHeaders: configured.modelHeaders,
1071
1108
  earlierPlugin,
1072
1109
  expectedSame: mimoSessionIdFor("ses_same"),
1073
1110
  expectedOther: mimoSessionIdFor("ses_other"),
1111
+ expectedGlm: mimoSessionIdFor("ses_glm_same"),
1112
+ expectedGlmOther: mimoSessionIdFor("ses_glm_other"),
1074
1113
  }
1075
1114
  assert.equal(configured.headers["x-session-id"], undefined)
1076
1115
  assert.equal(earlierPlugin.headers["X-SESSION-ID"], "earlier-plugin-value")
@@ -1117,7 +1156,33 @@ test("MiMo affinity preserves existing x-session-id values case-insensitively",
1117
1156
  assert.deepEqual(result.earlierPlugin.headers, { "X-SESSION-ID": "earlier-plugin-value" })
1118
1157
  })
1119
1158
 
1120
- test("MiMo-only affinity does not add x-session-id to GLM/OpenRouter", async () => {
1159
+ test("GLM/OpenRouter attaches the deterministic session ID", async () => {
1160
+ const result = await miMoHeaderResults()
1161
+ assert.equal(result.glm1.headers["x-session-id"], result.expectedGlm)
1162
+ assert.equal(result.glm2.headers["x-session-id"], result.expectedGlm)
1163
+ assert.equal(result.glmDifferent.headers["x-session-id"], result.expectedGlmOther)
1164
+ assert.notEqual(result.glmDifferent.headers["x-session-id"], result.glm1.headers["x-session-id"])
1165
+ })
1166
+
1167
+ test("GLM direct Z.AI does not receive x-session-id", async () => {
1168
+ const result = await miMoHeaderResults()
1169
+ assert.equal(result.glmDirect.headers["x-session-id"], undefined)
1170
+ assert.deepEqual(result.glmDirect.headers, { "User-Agent": "preserve-glm" })
1171
+ })
1172
+
1173
+ test("non-OpenRouter endpoint matrix is x-session-id non-mutating and preserves unrelated headers", async () => {
1174
+ const result = await miMoHeaderResults()
1175
+ assert.equal(result.compatibility.length, 8)
1176
+ for (const item of result.compatibility) {
1177
+ assert.equal(item.headers["x-session-id"], undefined, `${item.name} must not receive OpenRouter affinity`)
1178
+ assert.deepEqual(item.headers, item.expected, `${item.name} unrelated headers must remain unchanged`)
1179
+ assert.equal(item.sameObject, true, `${item.name} headers object must be preserved`)
1180
+ assert.deepEqual(item.outputKeys, ["headers"], `${item.name} hook output remains headers-only`)
1181
+ }
1182
+ })
1183
+
1184
+ test("OpenAI GPT retains its existing chat.params cache options without affinity headers", async () => {
1121
1185
  const result = await miMoHeaderResults()
1122
- assert.equal(result.glm.headers["x-session-id"], undefined)
1186
+ assert.equal(typeof result.gptOptions.promptCacheKey, "string")
1187
+ assert.deepEqual(result.gptOptions.promptCacheOptions, { mode: "implicit", ttl: "30m" })
1123
1188
  })