diff options
| author | Adam Malczewski <[email protected]> | 2026-06-02 13:34:33 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-02 13:34:33 +0900 |
| commit | 48c120e5cd400b2e2b8afae0afcc7c8bc4d2ccb4 (patch) | |
| tree | 2c434aeba0db7d6ec5b87e2f7fe2c81352f0888c /packages/core/src/db | |
| parent | b734eb96bf0af267fdfbef85df51940ca0b4e8c7 (diff) | |
| download | dispatch-48c120e5cd400b2e2b8afae0afcc7c8bc4d2ccb4.tar.gz dispatch-48c120e5cd400b2e2b8afae0afcc7c8bc4d2ccb4.zip | |
fix: reconcile live cacheStats to DB truth on turn-sealed
Addresses the live-accumulator overshoot a Gemini review surfaced: the
frontend adds every streamed usage event to cacheStats, but a rate-limited
fallback attempt's usage is discarded server-side (never persisted). Live
numbers overshot until a reload re-seeded from the DB aggregate.
Fix: turn-sealed (emitted AFTER the atomic usage-row write) now carries the
authoritative getUsageStatsForTab aggregate. The store REPLACES (not adds)
cacheStats with it every turn — landing the just-sealed turn's usage AND
self-healing any live drift, including the discarded-fallback overshoot. No
extra round-trip (piggybacks turn-sealed); idempotent in the happy path.
- core: add UsageStats type; getUsageStatsForTab returns it; turn-sealed gains
optional usageStats field.
- api: agent-manager reads getUsageStatsForTab post-flush and attaches it to
the turn-sealed emit (try/catch: omit on DB error).
- frontend: turn-sealed handler replaces cacheStats (undefined ⇒ untouched
back-compat; null ⇒ clear).
Tests: frontend reconcile/self-heal/back-compat/null-clear; api turn-sealed
carries aggregate. 509 -> 514 passing; typecheck + biome green.
Diffstat (limited to 'packages/core/src/db')
| -rw-r--r-- | packages/core/src/db/chunks.ts | 23 |
1 files changed, 9 insertions, 14 deletions
diff --git a/packages/core/src/db/chunks.ts b/packages/core/src/db/chunks.ts index 509cbbd..e0aadf3 100644 --- a/packages/core/src/db/chunks.ts +++ b/packages/core/src/db/chunks.ts @@ -5,7 +5,14 @@ import { groupRowsToMessages, type MessageRow, } from "../chunks/transform.js"; -import type { ChunkData, ChunkRow, ChunkRowDraft, TextData, UsageData } from "../types/index.js"; +import type { + ChunkData, + ChunkRow, + ChunkRowDraft, + TextData, + UsageData, + UsageStats, +} from "../types/index.js"; import { getDatabase } from "./index.js"; // Re-export the DB-free transforms so existing barrel consumers @@ -173,19 +180,7 @@ export function getTotalChunkCount(tabId: string): number { * Sums in JS after selecting the rows (mirroring `mapRow`) to avoid relying on * `json_extract` over the freeform `data_json`. */ -export function getUsageStatsForTab(tabId: string): { - inputTokens: number; - outputTokens: number; - cacheReadTokens: number; - cacheWriteTokens: number; - requests: number; - last: { - inputTokens: number; - outputTokens: number; - cacheReadTokens: number; - cacheWriteTokens: number; - } | null; -} | null { +export function getUsageStatsForTab(tabId: string): UsageStats | null { const db = getDatabase(); const rows = db .query("SELECT data_json FROM chunks WHERE tab_id = $tabId AND type = 'usage' ORDER BY seq ASC") |
