From 932a40cfd936e4abc2430f1e97f2f51259c20f92 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Thu, 2 Jul 2026 01:53:51 +0530 Subject: [PATCH] fix(tui): pin queued prompts below output (#34791) --- packages/tui/src/routes/session/rows.ts | 46 ++++++++++++++++++------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/tui/src/routes/session/rows.ts b/packages/tui/src/routes/session/rows.ts index b489404f4fa..f1c47142764 100644 --- a/packages/tui/src/routes/session/rows.ts +++ b/packages/tui/src/routes/session/rows.ts @@ -73,8 +73,10 @@ export function createSessionRows(sessionID: Accessor) { setRows( produce((draft) => { if (draft.some((row) => row.type === "message" && row.messageID === messageID)) return - completePrevious(draft) - draft.push({ type: "message", messageID }) + const queued = isQueued(messageID) + const index = queued ? draft.length : queuedStart(draft) + if (!queued) completePrevious(draft, index) + draft.splice(index, 0, { type: "message", messageID }) }), ) @@ -82,14 +84,15 @@ export function createSessionRows(sessionID: Accessor) { setRows( produce((draft) => { if (hasPart(draft, ref)) return + const index = queuedStart(draft) if (name && exploration(name)) { - const previous = draft.at(-1) + const previous = draft[index - 1] if (previous?.type === "group" && previous.kind === "exploration") { previous.refs.push(ref) return } - completePrevious(draft) - draft.push({ + completePrevious(draft, index) + draft.splice(index, 0, { type: "group", kind: "exploration", refs: [ref], @@ -98,8 +101,8 @@ export function createSessionRows(sessionID: Accessor) { }) return } - completePrevious(draft) - draft.push({ type: "part", ref }) + completePrevious(draft, index) + draft.splice(index, 0, { type: "part", ref }) }), ) @@ -107,11 +110,22 @@ export function createSessionRows(sessionID: Accessor) { setRows( produce((draft) => { if (draft.some((row) => row.type === "assistant-footer" && row.messageID === messageID)) return - completePrevious(draft) - draft.push({ type: "assistant-footer", messageID }) + const index = queuedStart(draft) + completePrevious(draft, index) + draft.splice(index, 0, { type: "assistant-footer", messageID }) }), ) + const isQueued = (messageID: string) => { + const message = data.session.message.get(sessionID(), messageID) + return message?.type === "user" && message.metadata?.queued === true + } + + const queuedStart = (rows: SessionRow[]) => { + const index = rows.findIndex((row) => row.type === "message" && isQueued(row.messageID)) + return index === -1 ? rows.length : index + } + const message = (event: { data: { sessionID: string; messageID: string } }) => { if (event.data.sessionID === sessionID()) appendMessage(event.data.messageID) } @@ -160,10 +174,12 @@ export function createSessionRows(sessionID: Accessor) { } export function reduceSessionRows(messages: SessionMessage[]) { - return messages.reduce((rows, message) => { + return [...messages.filter((message) => !isQueuedMessage(message)), ...messages.filter(isQueuedMessage)].reduce< + SessionRow[] + >((rows, message) => { if (message.type !== "assistant") { if (message.type === "synthetic" && !message.description?.trim()) return rows - completePrevious(rows) + if (!isQueuedMessage(message)) completePrevious(rows) rows.push({ type: "message", messageID: message.id }) return rows } @@ -179,6 +195,10 @@ export function reduceSessionRows(messages: SessionMessage[]) { }, []) } +function isQueuedMessage(message: SessionMessage) { + return message.type === "user" && message.metadata?.queued === true +} + function append(rows: SessionRow[], ref: PartRef, part: SessionMessageAssistant["content"][number]) { if (part.type === "tool") { if (exploration(part.name)) { @@ -196,8 +216,8 @@ function append(rows: SessionRow[], ref: PartRef, part: SessionMessageAssistant[ rows.push({ type: "part", ref }) } -function completePrevious(rows: SessionRow[]) { - const previous = rows.at(-1) +function completePrevious(rows: SessionRow[], index = rows.length) { + const previous = rows[index - 1] if (previous?.type === "group") previous.completed = true }