diff --git a/packages/ai/test/transcript-render.test.ts b/packages/ai/test/transcript-render.test.ts index eff7dd4bc..c76f0ecaf 100644 --- a/packages/ai/test/transcript-render.test.ts +++ b/packages/ai/test/transcript-render.test.ts @@ -93,4 +93,50 @@ describe("dialect transcript rendering", () => { expect(new Set(outputs).size).toBe(outputs.length); }); + + it("does not double-wrap thinking blocks already stored with literal envelopes", () => { + const wrapped: Message[] = [ + { + role: "assistant", + content: [{ type: "thinking", thinking: "\nCheck logs first.\n" }], + api: "mock", + provider: "mock", + model: "mock", + usage: usage(), + stopReason: "stop", + timestamp: 1, + }, + ]; + + // Anthropic dialect must unwrap the literal envelope instead of nesting a second one. + const anthropic = getDialectDefinition("anthropic").renderTranscript(wrapped); + expect(anthropic).toContain("Assistant: \nCheck logs first.\n"); + expect(anthropic).not.toContain("\n"); + + // A envelope must not be confused with the qwen3 delimiter (prefix safety). + const qwen3 = getDialectDefinition("qwen3").renderTranscript(wrapped); + expect(qwen3).toContain("\n\nCheck logs first.\n\n"); + }); + + it("unwraps sibling literal thinking envelopes independently", () => { + const siblings: Message[] = [ + { + role: "assistant", + content: [ + { type: "thinking", thinking: "\nfirst\n\n\nsecond\n" }, + ], + api: "mock", + provider: "mock", + model: "mock", + usage: usage(), + stopReason: "stop", + timestamp: 1, + }, + ]; + + // Each literal envelope is unwrapped on its own; no malformed close/open boundary leaks through. + const out = getDialectDefinition("anthropic").renderTranscript(siblings); + expect(out).toContain("Assistant: \nfirst\nsecond\n"); + expect(out).not.toContain("first\n\n\nsecond"); + }); });