Refactor LLM route-first provider API (#28523)

This commit is contained in:
Kit Langton
2026-05-20 20:15:52 -04:00
committed by GitHub
parent 5381795844
commit 41f6daf96a
87 changed files with 2450 additions and 1520 deletions

View File

@@ -0,0 +1,3 @@
export function readPartText(accum: Record<string, string> | undefined, part: { id: string; text?: string }): string {
return (accum?.[part.id] ?? part.text ?? "").trim()
}

View File

@@ -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")
})
})

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()}>