mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-17 20:31:47 +02:00
ui : account for cache tokens on external backends
Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
@@ -224,10 +224,18 @@ function usageOf(raw: Record<string, unknown> | undefined): ApiChatCompletionUsa
|
||||
if (!raw) return undefined;
|
||||
|
||||
const usage: ApiChatCompletionUsage = {};
|
||||
const fields = [
|
||||
'cache_creation_input_tokens',
|
||||
'cache_read_input_tokens',
|
||||
'input_tokens',
|
||||
'output_tokens'
|
||||
] as const;
|
||||
|
||||
if (typeof raw.input_tokens === 'number') usage.input_tokens = raw.input_tokens;
|
||||
for (const field of fields) {
|
||||
const value = raw[field];
|
||||
|
||||
if (typeof raw.output_tokens === 'number') usage.output_tokens = raw.output_tokens;
|
||||
if (typeof value === 'number') usage[field] = value;
|
||||
}
|
||||
|
||||
return Object.keys(usage).length > 0 ? usage : undefined;
|
||||
}
|
||||
|
||||
Vendored
+5
@@ -379,10 +379,15 @@ export interface ApiChatCompletionStreamChunk {
|
||||
}
|
||||
|
||||
export interface ApiChatCompletionUsage {
|
||||
cache_creation_input_tokens?: number;
|
||||
cache_read_input_tokens?: number;
|
||||
cached_tokens?: number;
|
||||
completion_tokens?: number;
|
||||
input_tokens?: number;
|
||||
output_tokens?: number;
|
||||
prompt_cache_hit_tokens?: number;
|
||||
prompt_tokens?: number;
|
||||
prompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };
|
||||
total_tokens?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,33 @@ export interface StreamClock {
|
||||
lastTokenAt: number | null;
|
||||
}
|
||||
|
||||
/** Prompt/output token counts, accepting OpenAI and Anthropic usage fields. */
|
||||
/**
|
||||
* Prompt/output/cache token counts, accepting OpenAI and Anthropic usage
|
||||
* fields. `promptTokens` excludes the cache read tokens, which are returned
|
||||
* separately as `cacheTokens`, so the two always add up to the prompt size.
|
||||
*/
|
||||
export function usageTokenCounts(usage: ApiChatCompletionUsage | undefined): {
|
||||
promptTokens: number;
|
||||
cacheTokens: number;
|
||||
completionTokens: number;
|
||||
promptTokens: number;
|
||||
} {
|
||||
// Anthropic reports the input excluding cache tokens and splits reads from
|
||||
// writes; OpenAI-compatible servers report a total that includes the reads
|
||||
const isAnthropicStyle = usage?.input_tokens !== undefined;
|
||||
const cacheTokens = isAnthropicStyle
|
||||
? (usage?.cache_read_input_tokens ?? 0)
|
||||
: (usage?.prompt_tokens_details?.cached_tokens ??
|
||||
usage?.prompt_cache_hit_tokens ??
|
||||
usage?.cached_tokens ??
|
||||
0);
|
||||
const promptTotal = isAnthropicStyle
|
||||
? (usage?.input_tokens ?? 0) + (usage?.cache_creation_input_tokens ?? 0)
|
||||
: (usage?.prompt_tokens ?? 0);
|
||||
|
||||
return {
|
||||
cacheTokens,
|
||||
completionTokens: usage?.completion_tokens ?? usage?.output_tokens ?? 0,
|
||||
promptTokens: usage?.prompt_tokens ?? usage?.input_tokens ?? 0
|
||||
promptTokens: isAnthropicStyle ? promptTotal : Math.max(0, promptTotal - cacheTokens)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +52,7 @@ export function buildTimingsFromUsage(
|
||||
clock: StreamClock,
|
||||
fallbackTokens = 0
|
||||
): ChatMessageTimings | null {
|
||||
const { completionTokens, promptTokens } = usageTokenCounts(usage);
|
||||
const { cacheTokens, completionTokens, promptTokens } = usageTokenCounts(usage);
|
||||
const predictedN = completionTokens || fallbackTokens;
|
||||
|
||||
if (promptTokens === 0 && predictedN === 0) return null;
|
||||
@@ -42,6 +61,7 @@ export function buildTimingsFromUsage(
|
||||
const lastTokenAt = clock.lastTokenAt ?? firstTokenAt;
|
||||
|
||||
return {
|
||||
cache_n: cacheTokens,
|
||||
// clamp so a one-token reply still reports a positive duration
|
||||
predicted_ms: firstTokenAt && lastTokenAt ? Math.max(1, lastTokenAt - firstTokenAt) : undefined,
|
||||
predicted_n: predictedN,
|
||||
|
||||
Reference in New Issue
Block a user