Skip to content

Commit c9c93ea

Browse files
authored
fix(ui): eliminate N+1 reactive subscriptions in SessionTurn (#18924)
1 parent 3f1a4ab commit c9c93ea

2 files changed

Lines changed: 34 additions & 26 deletions

File tree

packages/app/src/pages/session/message-timeline.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,15 @@ export function MessageTimeline(props: {
923923
{(messageID) => {
924924
const active = createMemo(() => activeMessageID() === messageID)
925925
const comments = createMemo(() => messageComments(sync.data.part[messageID] ?? []), [], {
926-
equals: (a, b) => JSON.stringify(a) === JSON.stringify(b),
926+
equals: (a, b) =>
927+
a.length === b.length &&
928+
a.every(
929+
(c, i) =>
930+
c.path === b[i].path &&
931+
c.comment === b[i].comment &&
932+
c.selection?.startLine === b[i].selection?.startLine &&
933+
c.selection?.endLine === b[i].selection?.endLine,
934+
),
927935
})
928936
const commentCount = createMemo(() => comments().length)
929937
return (
@@ -979,6 +987,7 @@ export function MessageTimeline(props: {
979987
<SessionTurn
980988
sessionID={sessionID() ?? ""}
981989
messageID={messageID}
990+
messages={sessionMessages()}
982991
actions={props.actions}
983992
active={active()}
984993
status={active() ? sessionStatus() : undefined}

packages/ui/src/components/session-turn.tsx

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export function SessionTurn(
142142
props: ParentProps<{
143143
sessionID: string
144144
messageID: string
145+
messages?: MessageType[]
145146
actions?: UserActions
146147
showReasoningSummaries?: boolean
147148
shellToolDefaultOpen?: boolean
@@ -166,7 +167,7 @@ export function SessionTurn(
166167
const emptyDiffs: FileDiff[] = []
167168
const idle = { type: "idle" as const }
168169

169-
const allMessages = createMemo(() => list(data.store.message?.[props.sessionID], emptyMessages))
170+
const allMessages = createMemo(() => props.messages ?? list(data.store.message?.[props.sessionID], emptyMessages))
170171

171172
const messageIndex = createMemo(() => {
172173
const messages = allMessages() ?? emptyMessages
@@ -340,30 +341,28 @@ export function SessionTurn(
340341
if (end < start) return undefined
341342
return end - start
342343
})
343-
const assistantVisible = createMemo(() =>
344-
assistantMessages().reduce((count, message) => {
345-
const parts = list(data.store.part?.[message.id], emptyParts)
346-
return count + parts.filter((part) => partState(part, showReasoningSummaries()) === "visible").length
347-
}, 0),
348-
)
349-
const assistantTailVisible = createMemo(() =>
350-
assistantMessages()
351-
.flatMap((message) => list(data.store.part?.[message.id], emptyParts))
352-
.flatMap((part) => {
353-
if (partState(part, showReasoningSummaries()) !== "visible") return []
354-
if (part.type === "text") return ["text" as const]
355-
return ["other" as const]
356-
})
357-
.at(-1),
358-
)
359-
const reasoningHeading = createMemo(() =>
360-
assistantMessages()
361-
.flatMap((message) => list(data.store.part?.[message.id], emptyParts))
362-
.filter((part): part is PartType & { type: "reasoning"; text: string } => part.type === "reasoning")
363-
.map((part) => heading(part.text))
364-
.filter((text): text is string => !!text)
365-
.at(-1),
366-
)
344+
const assistantDerived = createMemo(() => {
345+
let visible = 0
346+
let tail: "text" | "other" | undefined
347+
let reason: string | undefined
348+
const show = showReasoningSummaries()
349+
for (const message of assistantMessages()) {
350+
for (const part of list(data.store.part?.[message.id], emptyParts)) {
351+
if (partState(part, show) === "visible") {
352+
visible++
353+
tail = part.type === "text" ? "text" : "other"
354+
}
355+
if (part.type === "reasoning" && part.text) {
356+
const h = heading(part.text)
357+
if (h) reason = h
358+
}
359+
}
360+
}
361+
return { visible, tail, reason }
362+
})
363+
const assistantVisible = createMemo(() => assistantDerived().visible)
364+
const assistantTailVisible = createMemo(() => assistantDerived().tail)
365+
const reasoningHeading = createMemo(() => assistantDerived().reason)
367366
const showThinking = createMemo(() => {
368367
if (!working() || !!error()) return false
369368
if (status().type === "retry") return false

0 commit comments

Comments
 (0)