



















@@ -322,6 +322,48 @@ describe("parseCliJsonl", () => {
322322});
323323});
324324325+it("does not let cumulative Claude result usage overwrite assistant usage", () => {
326+const result = parseCliJsonl(
327+[
328+JSON.stringify({ type: "init", session_id: "session-stream" }),
329+JSON.stringify({
330+type: "assistant",
331+message: {
332+id: "msg-1",
333+usage: { input_tokens: 10, output_tokens: 5, cache_read_input_tokens: 100 },
334+},
335+}),
336+JSON.stringify({
337+type: "assistant",
338+message: {
339+id: "msg-2",
340+usage: { input_tokens: 11, output_tokens: 6, cache_read_input_tokens: 125 },
341+},
342+}),
343+JSON.stringify({
344+type: "result",
345+session_id: "session-stream",
346+result: "done",
347+usage: { input_tokens: 30, output_tokens: 15, cache_read_input_tokens: 300 },
348+}),
349+].join("\n"),
350+{
351+command: "claude",
352+output: "jsonl",
353+sessionIdFields: ["session_id"],
354+},
355+"claude-cli",
356+);
357+358+expect(result?.usage).toEqual({
359+input: 11,
360+output: 6,
361+cacheRead: 125,
362+cacheWrite: undefined,
363+total: undefined,
364+});
365+});
366+325367it("preserves Claude session metadata even when the final result text is empty", () => {
326368const result = parseCliJsonl(
327369[
@@ -447,4 +489,52 @@ describe("createCliJsonlStreamingParser", () => {
447489{ text: "hello", delta: "hello", sessionId: "session-stream", usage: undefined },
448490]);
449491});
492+493+it("ignores cumulative usage from result events to avoid cache_read inflation", () => {
494+const parser = createCliJsonlStreamingParser({
495+backend: {
496+command: "local-cli",
497+output: "jsonl",
498+jsonlDialect: "claude-stream-json",
499+sessionIdFields: ["session_id"],
500+},
501+providerId: "local-cli",
502+onAssistantDelta: () => {},
503+});
504+505+parser.push(
506+[
507+JSON.stringify({ type: "init", session_id: "session-stream" }),
508+JSON.stringify({
509+type: "assistant",
510+message: {
511+id: "msg-1",
512+usage: { input_tokens: 10, output_tokens: 5, cache_read_input_tokens: 100 },
513+},
514+}),
515+JSON.stringify({
516+type: "assistant",
517+message: {
518+id: "msg-2",
519+usage: { input_tokens: 11, output_tokens: 6, cache_read_input_tokens: 125 },
520+},
521+}),
522+JSON.stringify({
523+type: "result",
524+result: "done",
525+usage: { input_tokens: 30, output_tokens: 15, cache_read_input_tokens: 300 },
526+}),
527+].join("\n"),
528+);
529+parser.finish();
530+531+const output = parser.getOutput();
532+expect(output?.usage).toEqual({
533+input: 11,
534+output: 6,
535+cacheRead: 125,
536+cacheWrite: undefined,
537+total: undefined,
538+});
539+});
450540});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。