From 2228691e14be2368394e38e600bfa2ce227487b1 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Sat, 30 May 2026 18:53:42 +0900 Subject: feat(cache): Anthropic prompt caching, usage telemetry, and Cache Rate view - send prompt-caching + oauth anthropic-beta headers on the Claude OAuth provider - restructure the OAuth request body (billing header, identity split, relocate third-party system prompt to the first user message) to match Claude Code - apply rolling cache_control breakpoints and group a turn's tool results into a single role:tool message for correct breakpoint placement - emit per-step usage events (cache read/write split) and add the Cache Rate sidebar panel - dedup byte-identical tool calls within a single batch --- .../src/lib/components/CacheRatePanel.svelte | 129 +++++++++++++++++++++ .../src/lib/components/SidebarPanel.svelte | 14 ++- 2 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 packages/frontend/src/lib/components/CacheRatePanel.svelte (limited to 'packages/frontend/src/lib/components') diff --git a/packages/frontend/src/lib/components/CacheRatePanel.svelte b/packages/frontend/src/lib/components/CacheRatePanel.svelte new file mode 100644 index 0000000..c35cbb5 --- /dev/null +++ b/packages/frontend/src/lib/components/CacheRatePanel.svelte @@ -0,0 +1,129 @@ + + +
+ {#if !cacheStats || cacheStats.requests === 0} +

+ No cache data yet. Send a message to a Claude model — prompt-cache usage + appears here after the first response. +

+ {:else} +
+
+ Cache Hit Rate + {#if tabTitle} + {tabTitle} + {/if} + {cacheStats.requests} req +
+ + +
+
+ Session (this tab) + {hitPct}% +
+ +
+ + + {#if cacheStats.last} +
+
+ Last request + {lastHitPct}% +
+ +
+ {/if} +
+ + +
+
Tokens (cumulative)
+
+
+ + readCache hits + + {fmt(cacheStats.cacheReadTokens)} +
+
+ + writeCache writes + + {fmt(cacheStats.cacheWriteTokens)} +
+
+ + freshUncached input + + {fmt(uncached)} +
+
+
+ Total input + {fmt(cacheStats.inputTokens)} +
+
+ Output + {fmt(cacheStats.outputTokens)} +
+
+
+ +

+ Cache reads cost ~10% of fresh input; writes cost ~25% more. A high hit + rate after the first turn means caching is working. Resets on reload. +

+ {/if} +
diff --git a/packages/frontend/src/lib/components/SidebarPanel.svelte b/packages/frontend/src/lib/components/SidebarPanel.svelte index fca53b7..33b2158 100644 --- a/packages/frontend/src/lib/components/SidebarPanel.svelte +++ b/packages/frontend/src/lib/components/SidebarPanel.svelte @@ -1,6 +1,7 @@ @@ -156,6 +162,8 @@ function contentClass(selected: string): string { /> {:else if panel.selected === "Key Usage"} + {:else if panel.selected === "Cache Rate"} + {:else if panel.selected === "Claude Reset"} {:else if panel.selected === "Model Status"} -- cgit v1.2.3