mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-10 09:49:20 +00:00
feat(kimi-code): show cache read details in debug timing (#1074)
* feat(kimi-code): show cache read details in debug timing * chore: remove changeset
This commit is contained in:
parent
ff177155ca
commit
b62b3a147f
2 changed files with 68 additions and 3 deletions
|
|
@ -1,7 +1,16 @@
|
|||
import { formatTokenCount } from './usage-format';
|
||||
|
||||
interface DebugTokenUsage {
|
||||
readonly inputOther?: number;
|
||||
readonly inputCacheRead?: number;
|
||||
readonly inputCacheCreation?: number;
|
||||
readonly output?: number;
|
||||
}
|
||||
|
||||
export interface StepTimingInput {
|
||||
readonly llmFirstTokenLatencyMs?: number | undefined;
|
||||
readonly llmStreamDurationMs?: number | undefined;
|
||||
readonly usage?: { readonly output: number } | undefined;
|
||||
readonly llmFirstTokenLatencyMs?: number;
|
||||
readonly llmStreamDurationMs?: number;
|
||||
readonly usage?: DebugTokenUsage;
|
||||
}
|
||||
|
||||
// Decode TPS is only meaningful when the output actually streamed over a
|
||||
|
|
@ -29,9 +38,33 @@ export function formatStepDebugTiming(input: StepTimingInput): string | undefine
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const inputTokens = usageInputTotal(input.usage);
|
||||
const hasInputUsage =
|
||||
input.usage !== undefined &&
|
||||
(input.usage.inputOther !== undefined ||
|
||||
input.usage.inputCacheRead !== undefined ||
|
||||
input.usage.inputCacheCreation !== undefined);
|
||||
if (hasInputUsage && (inputTokens > 0 || (outputTokens ?? 0) > 0)) {
|
||||
const cacheReadTokens = input.usage.inputCacheRead ?? 0;
|
||||
const cacheCreationTokens = input.usage.inputCacheCreation ?? 0;
|
||||
const cacheHitRate = inputTokens > 0 ? Math.round((cacheReadTokens / inputTokens) * 100) : 0;
|
||||
const cacheParts = [`cache read ${formatTokenCount(cacheReadTokens)} (${cacheHitRate}%)`];
|
||||
if (cacheCreationTokens > 0) {
|
||||
cacheParts.push(`write ${formatTokenCount(cacheCreationTokens)}`);
|
||||
}
|
||||
parts.push(`tokens in ${formatTokenCount(inputTokens)}`);
|
||||
parts.push(cacheParts.join(' / '));
|
||||
}
|
||||
|
||||
return `[Debug] ${parts.join(' | ')}`;
|
||||
}
|
||||
|
||||
function usageInputTotal(usage: DebugTokenUsage | undefined): number {
|
||||
if (usage === undefined) return 0;
|
||||
return (usage.inputOther ?? 0) + (usage.inputCacheRead ?? 0) + (usage.inputCacheCreation ?? 0);
|
||||
}
|
||||
|
||||
function formatDuration(ms: number): string {
|
||||
if (ms < 1000) return `${Math.round(ms)}ms`;
|
||||
return `${(ms / 1000).toFixed(1)}s`;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,38 @@ describe('formatStepDebugTiming', () => {
|
|||
expect(result).toBe('[Debug] TTFT: 800ms | TPS: 40.0 tok/s (200 tokens in 5.0s)');
|
||||
});
|
||||
|
||||
it('formats input tokens and cache read/write counts', () => {
|
||||
const result = formatStepDebugTiming({
|
||||
llmFirstTokenLatencyMs: 800,
|
||||
llmStreamDurationMs: 5000,
|
||||
usage: {
|
||||
inputOther: 700,
|
||||
inputCacheRead: 1200,
|
||||
inputCacheCreation: 100,
|
||||
output: 200,
|
||||
},
|
||||
});
|
||||
expect(result).toBe(
|
||||
'[Debug] TTFT: 800ms | TPS: 40.0 tok/s (200 tokens in 5.0s) | tokens in 2.0k | cache read 1.2k (60%) / write 100',
|
||||
);
|
||||
});
|
||||
|
||||
it('omits cache write count when it is zero', () => {
|
||||
const result = formatStepDebugTiming({
|
||||
llmFirstTokenLatencyMs: 800,
|
||||
llmStreamDurationMs: 5000,
|
||||
usage: {
|
||||
inputOther: 1000,
|
||||
inputCacheRead: 0,
|
||||
inputCacheCreation: 0,
|
||||
output: 200,
|
||||
},
|
||||
});
|
||||
expect(result).toContain('tokens in 1.0k');
|
||||
expect(result).toContain('cache read 0 (0%)');
|
||||
expect(result).not.toContain('/ write 0');
|
||||
});
|
||||
|
||||
it('omits TPS when the streamed window is too short to measure', () => {
|
||||
const result = formatStepDebugTiming({
|
||||
llmFirstTokenLatencyMs: 1200,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue