Skip to content

Commit 03d28f9

Browse files
committed
fix(task): address review feedback — move visibility check into flush, atomic batch swap, drop/log deltas when hidden
1 parent 1f7e78e commit 03d28f9

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

src/core/task/Task.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -654,40 +654,55 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
654654
this.emit(RooCodeEventName.Message, { action: "updated", message })
655655

656656
// Telemetry capture remains unchanged below
657-
658657
const shouldCaptureMessage = message.partial !== true && CloudService.isEnabled()
659-
660658
if (shouldCaptureMessage) {
661659
CloudService.instance.captureEvent({
662660
event: TelemetryEventName.TASK_MESSAGE,
663661
properties: { taskId: this.taskId, message },
664662
})
665663
}
666664

667-
// If provider is unavailable, or panel is hidden, skip UI delta updates.
668-
// The UI will resync on next visibility or full state push.
669-
if (!provider || (typeof (provider as any).isVisible === "function" && !(provider as any).isVisible())) {
670-
return
671-
}
672-
673665
// Batch UI updates within a short window to avoid overwhelming the webview
674666
const ts = (message as any)?.ts as number | undefined
675667
if (typeof ts === "number") {
676668
this.messageUpdateBuffer.set(ts, message)
677669
} else {
678-
// Fallback: no timestamp, just send immediately
670+
// Fallback: no timestamp - only send if panel is visible and provider exists
671+
if (!provider || !provider.isVisible()) {
672+
// Drop non-essential delta; UI will resync on next visibility/state push
673+
return
674+
}
679675
await provider.postMessageToWebview({ type: "messageUpdated", clineMessage: message })
680676
return
681677
}
682678

683679
if (!this.messageUpdateTimer) {
684680
this.messageUpdateTimer = setTimeout(async () => {
685681
try {
686-
const batch = Array.from(this.messageUpdateBuffer.values())
687-
this.messageUpdateBuffer.clear()
682+
// Atomically swap buffers so new arrivals during flush aren't lost
683+
const batchMap = this.messageUpdateBuffer
684+
this.messageUpdateBuffer = new Map()
688685
this.messageUpdateTimer = undefined
686+
687+
const batch = Array.from(batchMap.values())
688+
689+
const providerNow = this.providerRef.deref()
690+
if (!providerNow) {
691+
console.warn(
692+
`[Task#updateClineMessage] Dropping ${batch.length} messageUpdated deltas: provider unavailable`,
693+
)
694+
return
695+
}
696+
if (!providerNow.isVisible()) {
697+
// Drop deltas while hidden; UI will receive a full state sync on visibility
698+
console.debug(
699+
`[Task#updateClineMessage] Dropping ${batch.length} messageUpdated deltas while hidden`,
700+
)
701+
return
702+
}
703+
689704
for (const m of batch) {
690-
await provider.postMessageToWebview({ type: "messageUpdated", clineMessage: m })
705+
await providerNow.postMessageToWebview({ type: "messageUpdated", clineMessage: m })
691706
}
692707
} catch (e) {
693708
console.error("[Task#updateClineMessage] Failed to flush message updates:", e)

0 commit comments

Comments
 (0)