pi-cache-optimizer 2.6.11 → 2.6.13

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.
Files changed (2) hide show
  1. package/index.ts +69 -1
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -1717,6 +1717,51 @@ function keyForModelExt(model: { provider: string; id: string }): string {
1717
1717
  return `${model.provider}/${model.id}`;
1718
1718
  }
1719
1719
 
1720
+ /**
1721
+ * For direct (non-virtual-routing) providers, the upstream API may normalize or
1722
+ * rename the model id echoed in its response (e.g. a request to
1723
+ * `zai-org/GLM-5.2-FP8` returns a message whose `model` field is
1724
+ * `GLM5.2-FP8`). Writing stats under the echoed name fragments the bucket
1725
+ * away from the active-model key the footer reads (`totalsByModel[ctx.model]`),
1726
+ * so the footer shows 0% even when the backend is hitting cache.
1727
+ *
1728
+ * When the response-derived statsModel differs from the active context model
1729
+ * only in name (same provider + same cache adapter), consolidate stats back to
1730
+ * the active model identity. Virtual routing providers are excluded — their
1731
+ * message-local metadata is authoritative for router correctness (spec:
1732
+ * `message_end` MUST prefer assistant message metadata).
1733
+ *
1734
+ * Never merges across providers or across adapters, so genuinely different
1735
+ * models are never combined.
1736
+ */
1737
+ function consolidateDirectProviderStatsModel(
1738
+ statsModel: PiModel | undefined,
1739
+ ctxModel: PiModel | undefined,
1740
+ ctx?: Pick<ExtensionContext, "sessionManager">,
1741
+ ): PiModel | undefined {
1742
+ if (!statsModel || !ctxModel) return statsModel;
1743
+ // Virtual routing providers keep message-local stats identity.
1744
+ if (isVirtualRoutingModel(ctxModel, ctx)) return statsModel;
1745
+ // Only consolidate within the same provider.
1746
+ if (statsModel.provider !== ctxModel.provider) return statsModel;
1747
+ // Only consolidate when both resolve to the same cache adapter object, so
1748
+ // genuinely different models sharing a provider (or sharing the same adapter
1749
+ // family id, e.g. GPT and GLM both report family id "openai") are never
1750
+ // merged. `selectAdapterForModel` returns the precise adapter object, so
1751
+ // object identity is the correct criterion.
1752
+ const statsAdapter = selectAdapterForModel(statsModel);
1753
+ const ctxAdapter = selectAdapterForModel(ctxModel);
1754
+ if (!statsAdapter || !ctxAdapter || statsAdapter !== ctxAdapter) return statsModel;
1755
+ // No drift — nothing to consolidate.
1756
+ if (statsModel.id === ctxModel.id) return statsModel;
1757
+ // Consolidate: pin stats to the active-model identity the footer reads.
1758
+ return {
1759
+ ...statsModel,
1760
+ id: ctxModel.id,
1761
+ name: ctxModel.name || ctxModel.id,
1762
+ };
1763
+ }
1764
+
1720
1765
  function usageRecordFromAssistant(message: unknown): UnknownRecord | undefined {
1721
1766
  return asRecord(getAssistantRecord(message)?.usage);
1722
1767
  }
@@ -5715,6 +5760,7 @@ export const __internals_for_tests = {
5715
5760
  getAssistantMessageModelTokenValues,
5716
5761
  getCompat,
5717
5762
  modelKey,
5763
+ consolidateDirectProviderStatsModel,
5718
5764
  // Platform-friendly path helpers
5719
5765
  getModelsJsonDisplayPath,
5720
5766
  buildProviderCompatOverride,
@@ -6481,12 +6527,34 @@ export default function (pi: ExtensionAPI) {
6481
6527
  const adapter = selectAdapterForAssistantMessage(event.message, ctx.model);
6482
6528
  if (!adapter) return;
6483
6529
 
6530
+ // Skip stats for error/aborted messages (network retries, user aborts).
6531
+ // Pi's auto-retry emits message_end for the failed attempt before
6532
+ // removing it and retrying. The error message carries zero-usage fields
6533
+ // ({ input: 0, cacheRead: 0, cacheWrite: 0 }) that normalizeUsage
6534
+ // returns as a valid (non-undefined) snapshot, which would inflate
6535
+ // totalRequests and skew cache hit-rate accuracy. The final successful
6536
+ // response is emitted as a separate message_end with real usage data.
6537
+ const msgRecord = asRecord(event.message);
6538
+ if (msgRecord?.stopReason === "error" || msgRecord?.stopReason === "aborted") {
6539
+ return;
6540
+ }
6541
+
6484
6542
  const usage = adapter.normalizeUsage(event.message);
6485
6543
 
6486
6544
  // Completed message metadata is request-local and authoritative for virtual
6487
6545
  // routing providers. Use it whenever it supplies provider/model identity;
6488
6546
  // fall back to the active context model for direct providers.
6489
- const statsModel = modelFromAssistantMessage(event.message, ctx.model) ?? ctx.model;
6547
+ let statsModel = modelFromAssistantMessage(event.message, ctx.model) ?? ctx.model;
6548
+ // For direct (non-virtual-routing) providers, the upstream API may echo a
6549
+ // normalized/renamed model id in its response (e.g. request
6550
+ // `zai-org/GLM-5.2-FP8` but the message carries `GLM5.2-FP8`). Writing
6551
+ // stats under the echoed name fragments the bucket away from the
6552
+ // active-model key the footer reads, showing 0% even when the backend is
6553
+ // hitting cache. When the response model drifts from the active model only
6554
+ // in name (same provider, same cache adapter), consolidate stats back to
6555
+ // the active model id. Virtual routing providers keep message-local
6556
+ // identity (router correctness).
6557
+ statsModel = consolidateDirectProviderStatsModel(statsModel, ctx.model, ctx);
6490
6558
  let routedModelChanged = false;
6491
6559
  if (isVirtualRoutingModel(ctx.model, ctx) && statsModel && !isVirtualRoutingModel(statsModel, ctx)) {
6492
6560
  const nextRoutedModel: PersistedRoutedModelRef = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cache-optimizer",
3
- "version": "2.6.11",
3
+ "version": "2.6.13",
4
4
  "description": "Improve Pi prompt/KV cache hit rates with stable prompts, OpenAI-compatible cache keys, proxy compat warnings, and footer cache stats.",
5
5
  "keywords": [
6
6
  "pi-package",