






















@@ -117,7 +117,7 @@ describe("repairSessionFileIfNeeded", () => {
117117errorMessage: "transient stream failure",
118118},
119119};
120-// Follow-up so the session doesn't end on assistant (trailing-trim is tested separately).
120+// Follow-up keeps this case focused on empty error-turn repair.
121121const followUp = {
122122type: "message",
123123id: "msg-3",
@@ -293,7 +293,7 @@ describe("repairSessionFileIfNeeded", () => {
293293stopReason: "stop",
294294},
295295};
296-// Follow-up so the session doesn't end on assistant (trailing-trim is tested separately).
296+// Follow-up keeps this case focused on silent-reply preservation.
297297const followUp = {
298298type: "message",
299299id: "msg-3",
@@ -312,7 +312,7 @@ describe("repairSessionFileIfNeeded", () => {
312312expect(after).toBe(original);
313313});
314314315-it("trims trailing assistant messages from the session file", async () => {
315+it("preserves delivered trailing assistant messages in the session file", async () => {
316316const { file } = await createTempSessionPath();
317317const { header, message } = buildSessionHeaderAndMessage();
318318const assistantEntry = {
@@ -329,19 +329,15 @@ describe("repairSessionFileIfNeeded", () => {
329329const original = `${JSON.stringify(header)}\n${JSON.stringify(message)}\n${JSON.stringify(assistantEntry)}\n`;
330330await fs.writeFile(file, original, "utf-8");
331331332-const debug = vi.fn();
333-const result = await repairSessionFileIfNeeded({ sessionFile: file, debug });
332+const result = await repairSessionFileIfNeeded({ sessionFile: file });
334333335-expect(result.repaired).toBe(true);
336-expect(result.trimmedTrailingAssistantMessages).toBe(1);
337-expect(debug.mock.calls[0]?.[0]).toContain("trimmed 1 trailing assistant message(s)");
334+expect(result.repaired).toBe(false);
338335339-const repaired = await fs.readFile(file, "utf-8");
340-const repairedLines = repaired.trim().split("\n");
341-expect(repairedLines).toHaveLength(2);
336+const after = await fs.readFile(file, "utf-8");
337+expect(after).toBe(original);
342338});
343339344-it("trims multiple consecutive trailing assistant messages", async () => {
340+it("preserves multiple consecutive delivered trailing assistant messages", async () => {
345341const { file } = await createTempSessionPath();
346342const { header, message } = buildSessionHeaderAndMessage();
347343const assistantEntry1 = {
@@ -371,12 +367,10 @@ describe("repairSessionFileIfNeeded", () => {
371367372368const result = await repairSessionFileIfNeeded({ sessionFile: file });
373369374-expect(result.repaired).toBe(true);
375-expect(result.trimmedTrailingAssistantMessages).toBe(2);
370+expect(result.repaired).toBe(false);
376371377-const repaired = await fs.readFile(file, "utf-8");
378-const repairedLines = repaired.trim().split("\n");
379-expect(repairedLines).toHaveLength(2);
372+const after = await fs.readFile(file, "utf-8");
373+expect(after).toBe(original);
380374});
381375382376it("does not trim non-trailing assistant messages", async () => {
@@ -406,7 +400,6 @@ describe("repairSessionFileIfNeeded", () => {
406400const result = await repairSessionFileIfNeeded({ sessionFile: file });
407401408402expect(result.repaired).toBe(false);
409-expect(result.trimmedTrailingAssistantMessages ?? 0).toBe(0);
410403});
411404412405it("preserves trailing assistant messages that contain tool calls", async () => {
@@ -432,12 +425,11 @@ describe("repairSessionFileIfNeeded", () => {
432425const result = await repairSessionFileIfNeeded({ sessionFile: file });
433426434427expect(result.repaired).toBe(false);
435-expect(result.trimmedTrailingAssistantMessages ?? 0).toBe(0);
436428const after = await fs.readFile(file, "utf-8");
437429expect(after).toBe(original);
438430});
439431440-it("trims non-tool-call assistant but stops at tool-call assistant", async () => {
432+it("preserves adjacent trailing tool-call and text assistant messages", async () => {
441433const { file } = await createTempSessionPath();
442434const { header, message } = buildSessionHeaderAndMessage();
443435const toolCallAssistant = {
@@ -467,16 +459,13 @@ describe("repairSessionFileIfNeeded", () => {
467459468460const result = await repairSessionFileIfNeeded({ sessionFile: file });
469461470-expect(result.repaired).toBe(true);
471-expect(result.trimmedTrailingAssistantMessages).toBe(1);
462+expect(result.repaired).toBe(false);
472463473-const repaired = await fs.readFile(file, "utf-8");
474-const repairedLines = repaired.trim().split("\n");
475-expect(repairedLines).toHaveLength(3);
476-expect(JSON.parse(repairedLines[2]).id).toBe("msg-asst-tc");
464+const after = await fs.readFile(file, "utf-8");
465+expect(after).toBe(original);
477466});
478467479-it("never trims below the session header", async () => {
468+it("preserves assistant-only session history after the header", async () => {
480469const { file } = await createTempSessionPath();
481470const { header } = buildSessionHeaderAndMessage();
482471const assistantEntry = {
@@ -495,13 +484,10 @@ describe("repairSessionFileIfNeeded", () => {
495484496485const result = await repairSessionFileIfNeeded({ sessionFile: file });
497486498-expect(result.repaired).toBe(true);
499-expect(result.trimmedTrailingAssistantMessages).toBe(1);
487+expect(result.repaired).toBe(false);
500488501-const repaired = await fs.readFile(file, "utf-8");
502-const repairedLines = repaired.trim().split("\n");
503-expect(repairedLines).toHaveLength(1);
504-expect(JSON.parse(repairedLines[0]).type).toBe("session");
489+const after = await fs.readFile(file, "utf-8");
490+expect(after).toBe(original);
505491});
506492507493it("is a no-op on a session that was already repaired", async () => {
@@ -522,7 +508,7 @@ describe("repairSessionFileIfNeeded", () => {
522508stopReason: "error",
523509},
524510};
525-// Follow-up so the session doesn't end on assistant (trailing-trim is tested separately).
511+// Follow-up keeps this case focused on idempotent empty error-turn repair.
526512const followUp = {
527513type: "message",
528514id: "msg-3",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。