refactor(app): choose reasoning-only rows at turn construction

This commit is contained in:
Brendonovich
2026-09-24 10:27:09 +00:00
parent 0be1d53215
commit ee1d410dea
3 changed files with 33 additions and 15 deletions
@@ -67,8 +67,8 @@ for (const width of [1400, 390]) {
await expect(group).toHaveCount(0)
await expect(page.getByRole("button", { name: "Used 1 Thought" })).toHaveCount(0)
if (width === 390) return
await timeline.send(partUpdated(toolPart("prt_after_thought", "read", "running", { filePath: "package.json" })))
if (width === 390) await page.getByRole("button", { name: "Jump to latest" }).click()
await expect(group).toBeVisible()
await expect(group).toHaveAttribute("data-timeline-part-ids", `${assistantID}:reasoning:0,prt_after_thought`)
await expect(working).toBeVisible()
+18 -14
View File
@@ -248,10 +248,26 @@ export namespace Timeline {
: [],
),
]
const rowEntries =
detail?.thinking.placement === "grouped" &&
status.type === "busy" &&
turn.id === activeMessageID &&
turn.entries.length > 0 &&
turn.entries.every(
(entry) =>
entry.type === "assistant" &&
!entry.message.error &&
!entry.message.retry &&
entry.message.content.every(
(content) => content.type === "reasoning" || (content.type === "text" && !content.text.trim()),
),
)
? []
: turn.entries
return constructMessageRows(
turn.user,
turn.id,
turn.entries,
rowEntries,
index,
showReasoning,
status,
@@ -307,16 +323,6 @@ export namespace Timeline {
!lastAssistant?.retry &&
lastContent?.type === "reasoning" &&
lastContent.time?.completed === undefined
const onlyThinking =
detail?.thinking.placement === "grouped" &&
isActive &&
status.type === "busy" &&
!!lastAssistant &&
!lastAssistant.error &&
!lastAssistant.retry &&
entries.every(
(entry) => entry.type === "assistant" && entry.message.content.every((content) => content.type === "reasoning"),
)
if (previousUserMessage) rows.push(new TimelineRow.TurnGap({ userMessageID: turnID }))
if (userMessage) rows.push(new TimelineRow.UserMessage({ userMessageID: turnID }))
@@ -330,9 +336,7 @@ export namespace Timeline {
contentEntries(message)
.filter(
(entry) =>
isRenderable(entry.content, showReasoning, detail) &&
!(thinking && entry.content === lastContent) &&
!(onlyThinking && entry.content.type === "reasoning"),
isRenderable(entry.content, showReasoning, detail) && !(thinking && entry.content === lastContent),
)
.map((entry) => ({ messageID: message.id, messageIndex, partID: entry.id, content: entry.content })),
)
@@ -280,6 +280,7 @@ describe("current session timeline rows", () => {
expect(rows([{ ...thought, time: { created: 1 } }], true).map((row) => row._tag)).toEqual(["UserMessage"])
expect(rows([thought], true).map((row) => row._tag)).toEqual(["UserMessage"])
expect(rows([thought, { type: "text", text: "" }], true).map((row) => row._tag)).toEqual(["UserMessage"])
expect(rows([thought, { type: "text", text: "Answer" }], true).map((row) => row._tag)).toEqual([
"UserMessage",
"AssistantPart",
@@ -289,6 +290,19 @@ describe("current session timeline rows", () => {
rows([thought, storyTool("read", "read", "running", { filePath: "package.json" })], true).map((row) => row._tag),
).toEqual(["UserMessage", "AssistantPart"])
expect(rows([thought], false).map((row) => row._tag)).toEqual(["UserMessage", "AssistantPart"])
const failed = storyDocument([thought], true)
const messages = failed.messages.map((message) =>
message.type === "assistant" ? { ...message, error: { type: "provider.error", message: "Failed" } } : message,
)
expect(
createTimelineProjection({
sessionMessages: messages,
status: failed.status,
reasoningMode: "compact",
timelineDetail: timelinePresets[2].value,
}).rows.map((row) => row._tag),
).toEqual(["UserMessage", "AssistantPart", "Error"])
})
test("stops thinking on idle, message completion, errors and retries", () => {