Compare commits

...

1 Commits

Author SHA1 Message Date
Kit Langton 3480fe56e9 refactor(ui): extract readPartText helper with regression test for #28212 2026-05-18 19:21:21 -04:00
3 changed files with 37 additions and 2 deletions
@@ -0,0 +1,6 @@
export function readPartText(
accum: Record<string, string> | undefined,
part: { id: string; text?: string },
): string {
return (accum?.[part.id] ?? part.text ?? "").trim()
}
@@ -0,0 +1,28 @@
import { describe, expect, test } from "bun:test"
import { readPartText } from "./message-part-text"
describe("readPartText", () => {
test("returns empty string when accum is undefined and part text is undefined", () => {
expect(readPartText(undefined, { id: "part_1" })).toBe("")
})
test("returns trimmed part text when accum is undefined", () => {
expect(readPartText(undefined, { id: "part_1", text: " hello " })).toBe("hello")
})
test("prefers accum value over part text when accum has a hit", () => {
expect(readPartText({ part_1: " from accum " }, { id: "part_1", text: "from part" })).toBe("from accum")
})
test("falls back to part text when accum misses", () => {
expect(readPartText({ other_part: "ignored" }, { id: "part_1", text: " from part " })).toBe("from part")
})
test("returns empty string for whitespace-only text", () => {
expect(readPartText(undefined, { id: "part_1", text: " \n\t " })).toBe("")
})
test("trims leading and trailing whitespace", () => {
expect(readPartText(undefined, { id: "part_1", text: "\n body \n" })).toBe("body")
})
})
+3 -2
View File
@@ -57,6 +57,7 @@ import { patchFiles } from "./apply-patch-file"
import { animate } from "motion"
import { useLocation } from "@solidjs/router"
import { attached, inline, kind } from "./message-file"
import { readPartText } from "./message-part-text"
async function writeClipboard(text: string): Promise<boolean> {
const body = typeof document === "undefined" ? undefined : document.body
@@ -1497,7 +1498,7 @@ PART_MAPPING["text"] = function TextPartDisplay(props) {
const streaming = createMemo(
() => props.message.role === "assistant" && typeof (props.message as AssistantMessage).time.completed !== "number",
)
const text = () => (data.store.part_text_accum_delta?.[part().id] ?? part().text ?? "").trim()
const text = () => readPartText(data.store.part_text_accum_delta, part())
const isLastTextPart = createMemo(() => {
const last = (data.store.part?.[props.message.id] ?? [])
.filter((item): item is TextPart => item?.type === "text" && !!item.text?.trim())
@@ -1563,7 +1564,7 @@ PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props) {
const streaming = createMemo(
() => props.message.role === "assistant" && typeof (props.message as AssistantMessage).time.completed !== "number",
)
const text = () => (data.store.part_text_accum_delta?.[part().id] ?? part().text ?? "").trim()
const text = () => readPartText(data.store.part_text_accum_delta, part())
return (
<Show when={text()}>