fix(ai): preserved zero cache placeholder usage
- Required positive cache-read fields before treating terminal usage accounting as complete. - Covered zero placeholder usage followed by trailing cached-token details. Fixes #5022
This commit is contained in:
@@ -156,16 +156,16 @@ function firstPositiveNumber(...values: unknown[]): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function hasCacheReadTokenField(rawUsage: object): boolean {
|
||||
function hasPositiveCacheReadTokenField(rawUsage: object): boolean {
|
||||
const usageLike = rawUsage as OpenAICompletionsUsageLike;
|
||||
if (typeof usageLike.cached_tokens === "number") return true;
|
||||
if (typeof usageLike.prompt_cache_hit_tokens === "number") return true;
|
||||
if (typeof usageLike.cached_tokens === "number" && usageLike.cached_tokens > 0) return true;
|
||||
if (typeof usageLike.prompt_cache_hit_tokens === "number" && usageLike.prompt_cache_hit_tokens > 0) return true;
|
||||
|
||||
const rawPromptTokenDetails = usageLike.prompt_tokens_details;
|
||||
if (typeof rawPromptTokenDetails !== "object" || rawPromptTokenDetails === null) return false;
|
||||
|
||||
const promptTokenDetails = rawPromptTokenDetails as OpenAICompletionsPromptTokenDetails;
|
||||
return typeof promptTokenDetails.cached_tokens === "number";
|
||||
return typeof promptTokenDetails.cached_tokens === "number" && promptTokenDetails.cached_tokens > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1012,7 +1012,7 @@ const streamOpenAICompletionsOnce = (
|
||||
const applyUsagePayload = (rawUsage: object): void => {
|
||||
output.usage = parseChunkUsage(rawUsage, model, premiumRequestsTotal);
|
||||
sawUsagePayload = true;
|
||||
awaitTrailingUsageDetails = !hasCacheReadTokenField(rawUsage);
|
||||
awaitTrailingUsageDetails = !hasPositiveCacheReadTokenField(rawUsage);
|
||||
};
|
||||
const timedOpenaiStream = iterateWithIdleTimeout(openaiStream, {
|
||||
idleTimeoutMs,
|
||||
|
||||
@@ -88,11 +88,16 @@ describe("terminal frame without connection close", () => {
|
||||
expect(Date.now() - startedAt).toBeLessThan(2_000);
|
||||
}, 10_000);
|
||||
|
||||
it("openai-completions: keeps reading usage-only cache details after finish usage", async () => {
|
||||
it("openai-completions: ignores zero cache placeholder until trailing positive cache details arrive", async () => {
|
||||
const fetchMock = createNeverClosingFetch([
|
||||
completionChunk({
|
||||
choices: [{ index: 0, delta: { role: "assistant", content: "Hello" }, finish_reason: "stop" }],
|
||||
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
|
||||
usage: {
|
||||
prompt_tokens: 10,
|
||||
completion_tokens: 5,
|
||||
total_tokens: 15,
|
||||
prompt_tokens_details: { cached_tokens: 0 },
|
||||
},
|
||||
}),
|
||||
completionChunk({
|
||||
choices: [],
|
||||
|
||||
Reference in New Issue
Block a user