diff options
| author | Adam Malczewski <[email protected]> | 2026-05-30 18:53:42 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-30 18:53:42 +0900 |
| commit | 2228691e14be2368394e38e600bfa2ce227487b1 (patch) | |
| tree | d6b3cfffd11dc9f7eec8c88f5fc97a7ec81e61a0 /packages/frontend/tests | |
| parent | 497b397e873f96d6fde3d8a44b3318e1ee1cbef4 (diff) | |
| download | dispatch-2228691e14be2368394e38e600bfa2ce227487b1.tar.gz dispatch-2228691e14be2368394e38e600bfa2ce227487b1.zip | |
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
Diffstat (limited to 'packages/frontend/tests')
| -rw-r--r-- | packages/frontend/tests/chat-store.test.ts | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/packages/frontend/tests/chat-store.test.ts b/packages/frontend/tests/chat-store.test.ts index bafd79e..c485fc7 100644 --- a/packages/frontend/tests/chat-store.test.ts +++ b/packages/frontend/tests/chat-store.test.ts @@ -1050,3 +1050,50 @@ describe("handleEvent statuses with TabStatusSnapshot", () => { expect(msgA?.isStreaming).toBe(false); }); }); + +describe("tabStore — cache rate (usage events)", () => { + it("accumulates usage events into per-tab cacheStats and tracks the last request", async () => { + const { store, tabId } = await setupStoreWithTab(); + + // No usage yet. + expect(store.tabs.find((t) => t.id === tabId)?.cacheStats).toBeUndefined(); + + // First request: mostly a cache write (cold prefix). + store.handleEvent({ + type: "usage", + tabId, + usage: { inputTokens: 1000, outputTokens: 40, cacheReadTokens: 0, cacheWriteTokens: 900 }, + }); + // Second request: mostly a cache hit. + store.handleEvent({ + type: "usage", + tabId, + usage: { inputTokens: 1200, outputTokens: 60, cacheReadTokens: 1000, cacheWriteTokens: 100 }, + }); + + const stats = store.tabs.find((t) => t.id === tabId)?.cacheStats; + expect(stats).toBeDefined(); + expect(stats?.requests).toBe(2); + // Cumulative totals. + expect(stats?.inputTokens).toBe(2200); + expect(stats?.outputTokens).toBe(100); + expect(stats?.cacheReadTokens).toBe(1000); + expect(stats?.cacheWriteTokens).toBe(1000); + // `last` reflects only the most recent request. + expect(stats?.last).toEqual({ + inputTokens: 1200, + outputTokens: 60, + cacheReadTokens: 1000, + cacheWriteTokens: 100, + }); + }); + + it("ignores usage events with no tabId", async () => { + const { store } = await setupStoreWithTab(); + store.handleEvent({ + type: "usage", + usage: { inputTokens: 10, outputTokens: 1, cacheReadTokens: 5, cacheWriteTokens: 0 }, + }); + expect(store.tabs[0]?.cacheStats).toBeUndefined(); + }); +}); |
