feat: show normalized prompt cache hit rates

Token usage previously showed cache reads and writes without a comparable hit rate. Activity usage now calculates a weighted cache hit rate using OpenAI-compatible input totals and Anthropic's separately reported input, cache-read, and cache-write tokens, then shows it in totals and grouped details.

Release note: Token 用量统计新增缓存命中率,并针对 OpenAI 兼容接口与 Anthropic Messages 的不同上报口径进行归一化计算。
This commit is contained in:
mesalogo
2026-08-15 22:01:49 +08:00
parent 0b96400e51
commit 36b38ce2a8
10 changed files with 138 additions and 9 deletions
@@ -2175,6 +2175,7 @@ describe('AssistantDatabase', () => {
output: 25,
cacheRead: 40,
cacheWrite: 12,
cacheInput: 177,
totalTokens: 150
},
records: [
@@ -2185,6 +2186,7 @@ describe('AssistantDatabase', () => {
output: 25,
cacheRead: 40,
cacheWrite: 12,
cacheInput: 177,
totalTokens: 150
})
]
@@ -2334,6 +2336,7 @@ describe('AssistantDatabase', () => {
output: 105,
cacheRead: 42,
cacheWrite: 15,
cacheInput: 312,
totalTokens: 360
})
expect(summary.records).toHaveLength(3)
@@ -2353,6 +2356,7 @@ describe('AssistantDatabase', () => {
output: 60,
cacheRead: 35,
cacheWrite: 12,
cacheInput: 197,
totalTokens: 210
}),
expect.objectContaining({
@@ -2684,6 +2688,7 @@ describe('AssistantDatabase', () => {
output: 0,
cacheRead: 0,
cacheWrite: 0,
cacheInput: 0,
totalTokens: 0
},
records: []
+25 -2
View File
@@ -317,6 +317,7 @@ type TokenUsageRecordRow = {
output_tokens: number
cache_read_tokens: number
cache_write_tokens: number
cache_input_tokens: number
}
type ComputerControlActionRow = {
@@ -2799,7 +2800,15 @@ export class AssistantDatabase {
SUM(usage.input_tokens) AS input_tokens,
SUM(usage.output_tokens) AS output_tokens,
SUM(usage.cache_read_tokens) AS cache_read_tokens,
SUM(usage.cache_write_tokens) AS cache_write_tokens
SUM(usage.cache_write_tokens) AS cache_write_tokens,
SUM(
usage.input_tokens +
CASE
WHEN LOWER(usage.provider) LIKE '%anthropic%'
THEN usage.cache_read_tokens + usage.cache_write_tokens
ELSE 0
END
) AS cache_input_tokens
FROM model_usage_calls usage
JOIN tasks ON tasks.id = usage.request_id
LEFT JOIN projects ON projects.id = tasks.project_id
@@ -2832,6 +2841,7 @@ export class AssistantDatabase {
output: row.output_tokens,
cacheRead: row.cache_read_tokens,
cacheWrite: row.cache_write_tokens,
cacheInput: row.cache_input_tokens,
totalTokens: row.input_tokens + row.output_tokens
}))
const totalRow = this.requireDatabase()
@@ -2841,7 +2851,18 @@ export class AssistantDatabase {
COALESCE(SUM(input_tokens), 0) AS input_tokens,
COALESCE(SUM(output_tokens), 0) AS output_tokens,
COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,
COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens
COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens,
COALESCE(
SUM(
input_tokens +
CASE
WHEN LOWER(provider) LIKE '%anthropic%'
THEN cache_read_tokens + cache_write_tokens
ELSE 0
END
),
0
) AS cache_input_tokens
FROM model_usage_calls`
)
.get() as {
@@ -2850,6 +2871,7 @@ export class AssistantDatabase {
output_tokens: number
cache_read_tokens: number
cache_write_tokens: number
cache_input_tokens: number
}
const totals = {
callCount: totalRow.call_count,
@@ -2857,6 +2879,7 @@ export class AssistantDatabase {
output: totalRow.output_tokens,
cacheRead: totalRow.cache_read_tokens,
cacheWrite: totalRow.cache_write_tokens,
cacheInput: totalRow.cache_input_tokens,
totalTokens: totalRow.input_tokens + totalRow.output_tokens
}
return { totals, records }