opencode-cache-engine 0.3.3 → 0.3.5

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.3",
3
+ "version": "0.3.5",
4
4
  "private": false,
5
5
  "description": "Provider-aware prompt-cache optimization and telemetry for OpenCode",
6
6
  "keywords": [
@@ -500,14 +500,51 @@ export function isOpenRouterAffinityEligible(policyFamily, providerID) {
500
500
  )
501
501
  }
502
502
 
503
+ // Produce safe telemetry fields for one affinity-capable request. Provider
504
+ // identity is observable and recorded; header values are deliberately not.
505
+ // A supplied non-OpenRouter identity is classified from the observed value
506
+ // rather than guessed against a provider allowlist.
507
+ export function affinityTelemetryFields(policyFamily, providerID, headerSource) {
508
+ if (policyFamily !== POLICY_MIMO26 && policyFamily !== POLICY_GLM53) return null
509
+
510
+ const identity = typeof providerID === "string" && providerID.length > 0 ? providerID : null
511
+ const eligible = isOpenRouterAffinityEligible(policyFamily, identity)
512
+ if (!eligible) {
513
+ return {
514
+ reason: identity
515
+ ? "openrouter_affinity_bypassed_non_openrouter"
516
+ : "openrouter_affinity_bypassed_provider_missing_or_unknown",
517
+ eligible: false,
518
+ providerIdentityKnown: identity !== null,
519
+ provider: identity,
520
+ headerPresent: false,
521
+ headerAttached: false,
522
+ headerSource: "not_applicable",
523
+ }
524
+ }
525
+
526
+ const source = ["cache_engine", "preexisting", "unavailable"].includes(headerSource)
527
+ ? headerSource
528
+ : "unavailable"
529
+ const headerPresent = source === "cache_engine" || source === "preexisting"
530
+ return {
531
+ reason: "openrouter_affinity_eligible",
532
+ eligible: true,
533
+ providerIdentityKnown: true,
534
+ provider: identity,
535
+ headerPresent,
536
+ headerAttached: source === "cache_engine",
537
+ headerSource: source,
538
+ }
539
+ }
540
+
503
541
  // Derive a stable, session-scoped identifier suitable for OpenRouter's
504
542
  // documented `session_id` sticky-routing key. Pure function of the OpenCode
505
543
  // session id only: identical sessions map to identical ids, distinct sessions
506
- // map to distinct ids, and transient request contents cannot influence it.
507
- // The value is printable, contains no whitespace, and is far below the 256-char
508
- // cap (25 chars). NOTE: this runtime's OpenRouter request adapter does not emit
509
- // a top-level `session_id` (it forwards only usage/reasoning/prompt_cache_key),
510
- // so this id is currently recorded as telemetry only and is never injected.
544
+ // map to distinct ids, and transient request contents cannot influence it. The
545
+ // value is printable, contains no whitespace, and is far below the 256-char cap
546
+ // (25 chars). The plugin uses it as the existing OpenRouter x-session-id header
547
+ // value for eligible MiMo/GLM requests.
511
548
  export function mimoSessionIdFor(sessionID) {
512
549
  if (typeof sessionID !== "string" || sessionID.length === 0) return null
513
550
  return `mimo-ses-${shorthash(sessionID)}`
@@ -3,6 +3,7 @@ import type { Event, Message, Part } from "@opencode-ai/sdk"
3
3
  import {
4
4
  DEFAULT_CONFIG_PATH,
5
5
  DIGEST_TEMPLATE,
6
+ affinityTelemetryFields,
6
7
  POLICY_GLM53,
7
8
  POLICY_GPT56,
8
9
  POLICY_MIMO26,
@@ -127,6 +128,7 @@ type SessionState = {
127
128
  reasoningSeen: Map<string, number>
128
129
  reasoningLastSeq: string[] | null
129
130
  mimoProvider: { providerID: string; modelID: string } | null
131
+ glmProvider: { providerID: string; modelID: string } | null
130
132
  }
131
133
 
132
134
  const emptyShape = (): Shape => ({
@@ -175,6 +177,7 @@ export const CacheEngine: Plugin = async ({ client, directory }) => {
175
177
  reasoningSeen: new Map(),
176
178
  reasoningLastSeq: null,
177
179
  mimoProvider: null,
180
+ glmProvider: null,
178
181
  }
179
182
  sessions.set(sid, s)
180
183
  }
@@ -493,14 +496,37 @@ export const CacheEngine: Plugin = async ({ client, directory }) => {
493
496
  const model = input.model as unknown as ChatParamsModel
494
497
  const providerID = String(model?.providerID ?? "")
495
498
  const family = detectPolicy(model)
496
- if (providerID !== "openrouter" || (family !== POLICY_MIMO26 && family !== POLICY_GLM53)) return
499
+ if (family !== POLICY_MIMO26 && family !== POLICY_GLM53) return
497
500
 
498
501
  const hasSessionIDHeader = (headers?: Record<string, string>) =>
499
502
  Object.keys(headers ?? {}).some((name) => name.toLowerCase() === "x-session-id")
500
- if (hasSessionIDHeader(model?.headers) || hasSessionIDHeader(output.headers)) return
503
+ let headerSource = "not_applicable"
504
+ if (providerID === "openrouter") {
505
+ if (hasSessionIDHeader(model?.headers) || hasSessionIDHeader(output.headers)) {
506
+ headerSource = "preexisting"
507
+ } else {
508
+ const sessionID = mimoSessionIdFor(input.sessionID)
509
+ if (sessionID) {
510
+ output.headers["x-session-id"] = sessionID
511
+ headerSource = "cache_engine"
512
+ } else {
513
+ headerSource = "unavailable"
514
+ }
515
+ }
516
+ }
501
517
 
502
- const sessionID = mimoSessionIdFor(input.sessionID)
503
- if (sessionID) output.headers["x-session-id"] = sessionID
518
+ const telemetry = affinityTelemetryFields(family, providerID, headerSource)
519
+ if (telemetry) {
520
+ rec.record({
521
+ kind: "boundary",
522
+ sid: input.sessionID,
523
+ ts: Date.now(),
524
+ policy: family,
525
+ provider: telemetry.provider,
526
+ model: String(model?.api?.id ?? model?.id ?? "") || null,
527
+ ...telemetry,
528
+ })
529
+ }
504
530
  } catch (e) {
505
531
  rec.record({ kind: "telemetry-error", ts: Date.now(), error: String(e) })
506
532
  }
@@ -552,6 +578,33 @@ export const CacheEngine: Plugin = async ({ client, directory }) => {
552
578
  return
553
579
  }
554
580
 
581
+ // ---- GLM-5.3 provider identity observation (telemetry only) ----------
582
+ if (family === POLICY_GLM53 && policyEnabled(cfg, POLICY_GLM53) && info) {
583
+ const live = input.model as unknown as ChatParamsModel
584
+ const cur = {
585
+ providerID: String(live?.providerID ?? ""),
586
+ modelID: String(live?.api?.id ?? live?.id ?? ""),
587
+ }
588
+ if (cur.providerID) {
589
+ const s = get(input.sessionID)
590
+ const ev = providerChangeEvent(s.glmProvider, cur)
591
+ if (ev.changed) {
592
+ rec.record({
593
+ kind: "boundary",
594
+ sid: input.sessionID,
595
+ ts: Date.now(),
596
+ reason: "glm_provider_changed",
597
+ policy: POLICY_GLM53,
598
+ from: ev.from,
599
+ to: ev.to,
600
+ note: "OpenCode providerID changed; provider-specific upstream routing is not plugin-visible",
601
+ })
602
+ }
603
+ s.glmProvider = cur
604
+ }
605
+ return
606
+ }
607
+
555
608
  if (!(family === POLICY_GPT56 && policyEnabled(cfg, POLICY_GPT56))) {
556
609
  // DeepSeek / GLM / neutral: nothing to inject. GLM has no cache-key API;
557
610
  // DeepSeek caching is fully passive; we never mutate requests for them.
@@ -19,6 +19,7 @@ import {
19
19
  POLICY_GPT56,
20
20
  POLICY_MIMO26,
21
21
  POLICY_NEUTRAL,
22
+ affinityTelemetryFields,
22
23
  canonicalStringify,
23
24
  commonPrefixLength,
24
25
  createRecorder,
@@ -938,6 +939,42 @@ test("OpenRouter affinity is ineligible for unknown families and providers", ()
938
939
  assert.equal(isOpenRouterAffinityEligible(POLICY_MIMO26, undefined), false)
939
940
  })
940
941
 
942
+ test("affinity telemetry fields classify eligibility, attachment, bypass, and missing identity", () => {
943
+ assert.deepEqual(affinityTelemetryFields(POLICY_MIMO26, "openrouter", "cache_engine"), {
944
+ reason: "openrouter_affinity_eligible",
945
+ eligible: true,
946
+ providerIdentityKnown: true,
947
+ provider: "openrouter",
948
+ headerPresent: true,
949
+ headerAttached: true,
950
+ headerSource: "cache_engine",
951
+ })
952
+ assert.deepEqual(affinityTelemetryFields(POLICY_GLM53, "openrouter", "preexisting"), {
953
+ reason: "openrouter_affinity_eligible",
954
+ eligible: true,
955
+ providerIdentityKnown: true,
956
+ provider: "openrouter",
957
+ headerPresent: true,
958
+ headerAttached: false,
959
+ headerSource: "preexisting",
960
+ })
961
+ assert.equal(affinityTelemetryFields(POLICY_MIMO26, "xiaomi", "not_applicable").reason,
962
+ "openrouter_affinity_bypassed_non_openrouter")
963
+ assert.equal(affinityTelemetryFields(POLICY_GLM53, "unknown-provider", "not_applicable").reason,
964
+ "openrouter_affinity_bypassed_non_openrouter")
965
+ assert.deepEqual(affinityTelemetryFields(POLICY_MIMO26, "", "not_applicable"), {
966
+ reason: "openrouter_affinity_bypassed_provider_missing_or_unknown",
967
+ eligible: false,
968
+ providerIdentityKnown: false,
969
+ provider: null,
970
+ headerPresent: false,
971
+ headerAttached: false,
972
+ headerSource: "not_applicable",
973
+ })
974
+ assert.equal(affinityTelemetryFields(POLICY_DEEPSEEK, "openrouter", "not_applicable"), null)
975
+ assert.equal(affinityTelemetryFields(POLICY_GPT56, "openrouter", "not_applicable"), null)
976
+ })
977
+
941
978
  // ===========================================================================
942
979
  // MiMo-V2.6: cached/prompt token metrics
943
980
  // ===========================================================================
@@ -1019,8 +1056,10 @@ async function runMiMoHeaderHookProbe() {
1019
1056
  const coreURL = new URL("../src/cache-engine-core.mjs", import.meta.url).href
1020
1057
  const script = `
1021
1058
  import assert from "node:assert/strict"
1059
+ import { readFileSync } from "node:fs"
1060
+ process.env.CACHE_ENGINE_METRICS_FILE = process.env.HOME + "/affinity-metrics.jsonl"
1022
1061
  const { CacheEngine } = await import(${JSON.stringify(pluginURL)})
1023
- const { mimoSessionIdFor } = await import(${JSON.stringify(coreURL)})
1062
+ const { detectPolicy, mimoSessionIdFor, POLICY_GLM53, POLICY_MIMO26 } = await import(${JSON.stringify(coreURL)})
1024
1063
  const client = {
1025
1064
  app: { log: async () => ({}) },
1026
1065
  session: { get: async () => ({ data: { parentID: null } }) },
@@ -1031,14 +1070,29 @@ async function runMiMoHeaderHookProbe() {
1031
1070
  const invoke = async (model, sessionID, existingHeaders = {}) => {
1032
1071
  const output = { headers: { ...existingHeaders } }
1033
1072
  const headersRef = output.headers
1073
+ const family = detectPolicy(model)
1074
+ if (family === POLICY_MIMO26 || family === POLICY_GLM53) {
1075
+ await hooks["chat.params"]({
1076
+ sessionID,
1077
+ agent: "build",
1078
+ model,
1079
+ provider: { source: "config", info: { id: model.providerID }, options: {} },
1080
+ message: { id: "msg", sessionID, role: "user", content: "probe" },
1081
+ }, { options: {} })
1082
+ }
1034
1083
  await hooks["chat.headers"]({
1035
1084
  sessionID,
1036
1085
  agent: "build",
1037
1086
  model,
1038
- provider: { id: model.providerID },
1087
+ provider: { source: "config", info: { id: model.providerID }, options: {} },
1039
1088
  message: { id: "msg", sessionID, role: "user", content: "probe" },
1040
1089
  }, output)
1041
- return { headers: output.headers, sameObject: output.headers === headersRef, modelHeaders: model.headers }
1090
+ return {
1091
+ headers: output.headers,
1092
+ sameObject: output.headers === headersRef,
1093
+ outputKeys: Object.keys(output),
1094
+ modelHeaders: model.headers,
1095
+ }
1042
1096
  }
1043
1097
  const mimoOpenRouter = {
1044
1098
  providerID: "openrouter",
@@ -1057,6 +1111,33 @@ async function runMiMoHeaderHookProbe() {
1057
1111
  const glm2 = await invoke(glmOpenRouter, "ses_glm_same")
1058
1112
  const glmDifferent = await invoke(glmOpenRouter, "ses_glm_other")
1059
1113
  const glmDirect = await invoke({ ...glmOpenRouter, providerID: "zai" }, "ses_glm_direct", { "User-Agent": "preserve-glm" })
1114
+ const mimoSwitchOpen = await invoke(mimoOpenRouter, "ses_mimo_switch")
1115
+ const mimoSwitchDirect = await invoke({ ...mimoOpenRouter, providerID: "xiaomi" }, "ses_mimo_switch")
1116
+ const glmSwitchOpen = await invoke(glmOpenRouter, "ses_glm_switch")
1117
+ const glmSwitchDirect = await invoke({ ...glmOpenRouter, providerID: "zai" }, "ses_glm_switch")
1118
+ const nonOpenRouterMatrix = [
1119
+ ["mimo-direct", { ...mimoOpenRouter, providerID: "xiaomi" }],
1120
+ ["glm-direct", { ...glmOpenRouter, providerID: "zai" }],
1121
+ ["deepseek-direct", { providerID: "deepseek", id: "deepseek-v4.1-flash", api: { id: "deepseek-v4.1-flash" }, headers: {} }],
1122
+ ["gpt-openai", { providerID: "openai", id: "gpt-5.6", api: { id: "gpt-5.6", npm: "@ai-sdk/openai" }, headers: {} }],
1123
+ ["unknown-provider", { ...mimoOpenRouter, providerID: "unknown-provider" }],
1124
+ ["missing-provider", { ...mimoOpenRouter, providerID: undefined }],
1125
+ ["opencode-go-mimo", { ...mimoOpenRouter, providerID: "opencode" }],
1126
+ ["opencode-go-glm", { ...glmOpenRouter, providerID: "opencode" }],
1127
+ ]
1128
+ const compatibility = []
1129
+ for (const [name, model] of nonOpenRouterMatrix) {
1130
+ const existing = { "User-Agent": "preserve-" + name, "x-compat-test": name }
1131
+ compatibility.push({ name, ...(await invoke(model, "ses_" + name, existing)), expected: existing })
1132
+ }
1133
+ const gptOutput = { options: {} }
1134
+ await hooks["chat.params"]({
1135
+ sessionID: "ses_gpt_native_cache",
1136
+ agent: "build",
1137
+ model: { providerID: "openai", id: "gpt-5.6", api: { id: "gpt-5.6", npm: "@ai-sdk/openai" } },
1138
+ provider: { source: "config", info: { id: "openai" }, options: {} },
1139
+ message: { id: "msg-gpt", sessionID: "ses_gpt_native_cache", role: "user", content: "probe" },
1140
+ }, gptOutput)
1060
1141
  const configured = await invoke({
1061
1142
  ...mimoOpenRouter,
1062
1143
  headers: { "X-Session-Id": "user-configured-value" },
@@ -1073,6 +1154,12 @@ async function runMiMoHeaderHookProbe() {
1073
1154
  glm2,
1074
1155
  glmDifferent,
1075
1156
  glmDirect,
1157
+ mimoSwitchOpen,
1158
+ mimoSwitchDirect,
1159
+ glmSwitchOpen,
1160
+ glmSwitchDirect,
1161
+ compatibility,
1162
+ gptOptions: gptOutput.options,
1076
1163
  configured,
1077
1164
  configuredModelHeaders: configured.modelHeaders,
1078
1165
  earlierPlugin,
@@ -1080,6 +1167,8 @@ async function runMiMoHeaderHookProbe() {
1080
1167
  expectedOther: mimoSessionIdFor("ses_other"),
1081
1168
  expectedGlm: mimoSessionIdFor("ses_glm_same"),
1082
1169
  expectedGlmOther: mimoSessionIdFor("ses_glm_other"),
1170
+ telemetry: readFileSync(process.env.CACHE_ENGINE_METRICS_FILE, "utf8")
1171
+ .trim().split("\\n").filter(Boolean).map((line) => JSON.parse(line)),
1083
1172
  }
1084
1173
  assert.equal(configured.headers["x-session-id"], undefined)
1085
1174
  assert.equal(earlierPlugin.headers["X-SESSION-ID"], "earlier-plugin-value")
@@ -1139,3 +1228,91 @@ test("GLM direct Z.AI does not receive x-session-id", async () => {
1139
1228
  assert.equal(result.glmDirect.headers["x-session-id"], undefined)
1140
1229
  assert.deepEqual(result.glmDirect.headers, { "User-Agent": "preserve-glm" })
1141
1230
  })
1231
+
1232
+ test("non-OpenRouter endpoint matrix is x-session-id non-mutating and preserves unrelated headers", async () => {
1233
+ const result = await miMoHeaderResults()
1234
+ assert.equal(result.compatibility.length, 8)
1235
+ for (const item of result.compatibility) {
1236
+ assert.equal(item.headers["x-session-id"], undefined, `${item.name} must not receive OpenRouter affinity`)
1237
+ assert.deepEqual(item.headers, item.expected, `${item.name} unrelated headers must remain unchanged`)
1238
+ assert.equal(item.sameObject, true, `${item.name} headers object must be preserved`)
1239
+ assert.deepEqual(item.outputKeys, ["headers"], `${item.name} hook output remains headers-only`)
1240
+ }
1241
+ })
1242
+
1243
+ test("OpenAI GPT retains its existing chat.params cache options without affinity headers", async () => {
1244
+ const result = await miMoHeaderResults()
1245
+ assert.equal(typeof result.gptOptions.promptCacheKey, "string")
1246
+ assert.deepEqual(result.gptOptions.promptCacheOptions, { mode: "implicit", ttl: "30m" })
1247
+ })
1248
+
1249
+ test("affinity telemetry classifies eligible, attached, preexisting, bypassed, and missing-provider requests", async () => {
1250
+ const result = await miMoHeaderResults()
1251
+ const events = result.telemetry.filter((event) => event.reason?.startsWith("openrouter_affinity_"))
1252
+ const eventFor = (sid, policy) => events.find((event) => event.sid === sid && event.policy === policy)
1253
+
1254
+ for (const [sid, policy] of [
1255
+ ["ses_same", POLICY_MIMO26],
1256
+ ["ses_glm_same", POLICY_GLM53],
1257
+ ]) {
1258
+ const event = eventFor(sid, policy)
1259
+ assert.equal(event.reason, "openrouter_affinity_eligible")
1260
+ assert.equal(event.eligible, true)
1261
+ assert.equal(event.provider, "openrouter")
1262
+ assert.equal(event.headerPresent, true)
1263
+ assert.equal(event.headerAttached, true)
1264
+ assert.equal(event.headerSource, "cache_engine")
1265
+ }
1266
+
1267
+ const configured = eventFor("ses_configured", POLICY_MIMO26)
1268
+ assert.equal(configured.reason, "openrouter_affinity_eligible")
1269
+ assert.equal(configured.headerPresent, true)
1270
+ assert.equal(configured.headerAttached, false)
1271
+ assert.equal(configured.headerSource, "preexisting")
1272
+
1273
+ for (const [sid, policy, provider] of [
1274
+ ["ses_direct", POLICY_MIMO26, "xiaomi"],
1275
+ ["ses_glm_direct", POLICY_GLM53, "zai"],
1276
+ ["ses_unknown", POLICY_MIMO26, "unknown-provider"],
1277
+ ]) {
1278
+ const event = eventFor(sid, policy)
1279
+ assert.equal(event.reason, "openrouter_affinity_bypassed_non_openrouter")
1280
+ assert.equal(event.eligible, false)
1281
+ assert.equal(event.provider, provider)
1282
+ assert.equal(event.headerAttached, false)
1283
+ }
1284
+
1285
+ const missing = eventFor("ses_missing_provider", POLICY_MIMO26)
1286
+ assert.equal(missing.reason, "openrouter_affinity_bypassed_provider_missing_or_unknown")
1287
+ assert.equal(missing.providerIdentityKnown, false)
1288
+ assert.equal(missing.provider, null)
1289
+ assert.equal(missing.headerAttached, false)
1290
+
1291
+ // New affinity-observation records contain classifications, never the
1292
+ // generated or pre-existing x-session-id value.
1293
+ for (const event of events) {
1294
+ assert.equal(Object.hasOwn(event, "x-session-id"), false)
1295
+ assert.equal(Object.hasOwn(event, "headerValue"), false)
1296
+ }
1297
+ const serializedAffinityEvents = JSON.stringify(events)
1298
+ assert.equal(serializedAffinityEvents.includes(result.expectedSame), false)
1299
+ assert.equal(serializedAffinityEvents.includes(result.expectedGlm), false)
1300
+ })
1301
+
1302
+ test("affinity telemetry preserves non-OpenRouter families and reports provider changes", async () => {
1303
+ const result = await miMoHeaderResults()
1304
+ const events = result.telemetry
1305
+ const affinityEvents = events.filter((event) => event.reason?.startsWith("openrouter_affinity_"))
1306
+ assert.equal(affinityEvents.some((event) => event.policy === POLICY_DEEPSEEK), false)
1307
+ assert.equal(affinityEvents.some((event) => event.policy === POLICY_GPT56), false)
1308
+
1309
+ const mimoChange = events.find((event) => event.reason === "mimo_provider_changed" && event.sid === "ses_mimo_switch")
1310
+ assert.equal(mimoChange.from.providerID, "openrouter")
1311
+ assert.equal(mimoChange.to.providerID, "xiaomi")
1312
+
1313
+ const glmChange = events.find((event) => event.reason === "glm_provider_changed" && event.sid === "ses_glm_switch")
1314
+ assert.equal(glmChange.kind, "boundary")
1315
+ assert.equal(glmChange.from.providerID, "openrouter")
1316
+ assert.equal(glmChange.to.providerID, "zai")
1317
+ assert.equal(glmChange.policy, POLICY_GLM53)
1318
+ })