feat(usage): track cached tokens + correct input/output/cache cost (#2209)

Normalize every provider to one cache-inclusive convention via
canonicalizeUsage() before persist, and price cached + cache_creation as
subsets of prompt_tokens in calculateCostFromTokens() to stop
double-counting. usageRepo now delegates cost math to a single source.
Surface Cached tokens/cost across dashboard (overview, tokens, cost,
details). Merge Claude message_start cache with message_delta output so
cache counts survive. Compatible LLM nodes now allow multiple API-key
connections (key pool).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
hodtienandCursor authored and decolua committed 2026-07-03 15:18:27 +07:00
1 parent 960f8a0379
commit 54e3245ace
17 files changed
+558 -71

No files matched your search

@@ -38,6 +38,9 @@ function ValueCells({ item, viewMode, isSummary = false }) {
<td className="px-6 py-3 text-right text-text-muted">
{isSummary && item.promptTokens === undefined ? "—" : fmt(item.promptTokens)}
</td>
<td className="px-6 py-3 text-right text-text-muted">
{item.cachedTokens ? fmt(item.cachedTokens) : "—"}
</td>
<td className="px-6 py-3 text-right text-text-muted">
{isSummary && item.completionTokens === undefined ? "—" : fmt(item.completionTokens)}
</td>
@@ -52,6 +55,9 @@ function ValueCells({ item, viewMode, isSummary = false }) {
<td className="px-6 py-3 text-right text-text-muted">
{isSummary && item.inputCost === undefined ? "—" : fmtCost(item.inputCost)}
</td>
<td className="px-6 py-3 text-right text-text-muted">
{item.cachedCost ? fmtCost(item.cachedCost) : "—"}
</td>
<td className="px-6 py-3 text-right text-text-muted">
{isSummary && item.outputCost === undefined ? "—" : fmtCost(item.outputCost)}
</td>
@@ -133,12 +139,14 @@ export default function UsageTable({
if (viewMode === "tokens") {
return [
{ field: "promptTokens", label: "Input Tokens" },
{ field: "cachedTokens", label: "Cached" },
{ field: "completionTokens", label: "Output Tokens" },
{ field: "totalTokens", label: "Total Tokens" },
];
}
return [
{ field: "promptTokens", label: "Input Cost" },
{ field: "cachedCost", label: "Cached Cost" },
{ field: "completionTokens", label: "Output Cost" },
{ field: "cost", label: "Total Cost" },
];