From 4aee082b419d7efc3937d957cd855ef362f3e1e5 Mon Sep 17 00:00:00 2001 From: agent-daryl Date: Mon, 1 Jun 2026 16:21:25 -0600 Subject: [PATCH] fix(ui): heal incomplete backticks in streaming text rendering Resolves #15774 --- packages/ui/src/components/markdown-stream.test.ts | 14 ++++++++++++++ packages/ui/src/components/markdown-stream.ts | 2 +- packages/ui/src/components/message-part.tsx | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/markdown-stream.test.ts b/packages/ui/src/components/markdown-stream.test.ts index 1ee63fc62e4a..930dc352dc12 100644 --- a/packages/ui/src/components/markdown-stream.test.ts +++ b/packages/ui/src/components/markdown-stream.test.ts @@ -20,6 +20,20 @@ describe("markdown stream", () => { ]) }) + test("heals incomplete backticks in trailing code fence tail", () => { + expect(stream("summary\n\n```sh\nrm -rf `", true)).toEqual([ + { raw: "summary\n\n", src: "summary\n\n", mode: "live" }, + { raw: "```sh\nrm -rf `", src: "```sh\nrm -rf ``", mode: "live" }, + ]) + }) + + test("handles backtick-heavy content that ends without trailing newline", () => { + const input = "run `git status` and `git" + const result = stream(input, true) + expect(result[0].raw).toBe(input) + expect(result[0].src).toContain("git status") + }) + test("keeps reference-style markdown as one block", () => { expect(stream("[docs][1]\n\n[1]: https://example.com", true)).toEqual([ { diff --git a/packages/ui/src/components/markdown-stream.ts b/packages/ui/src/components/markdown-stream.ts index ea35b0c140df..27fc9e63b028 100644 --- a/packages/ui/src/components/markdown-stream.ts +++ b/packages/ui/src/components/markdown-stream.ts @@ -44,6 +44,6 @@ export function stream(text: string, live: boolean) { if (!head) return [{ raw: code.raw, src: code.raw, mode: "live" }] satisfies Block[] return [ { raw: head, src: heal(head), mode: "live" }, - { raw: code.raw, src: code.raw, mode: "live" }, + { raw: code.raw, src: heal(code.raw), mode: "live" }, ] satisfies Block[] } diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 35912e119d40..e012d75ee963 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -188,7 +188,7 @@ export type PartComponent = Component export const PART_MAPPING: Record = {} const TEXT_RENDER_PACE_MS = 24 -const TEXT_RENDER_SNAP = /[\s.,!?;:)\]]/ +const TEXT_RENDER_SNAP = /[\s.,!?;:)\]\`]/ function step(size: number) { if (size <= 12) return 2