feat: implement incremental message updates for improved UI performance

- Modified Task.ts to send only new messages instead of entire state
- Added messageCreated and messageUpdated event types to ExtensionMessage
- Updated webview handler to process incremental message updates
- Enhanced postStateToWebview to handle existing tasks with incremental loading
- Improved performance by reducing data transfer and UI re-renders

This change significantly improves UI responsiveness, especially for tasks with many messages.
This commit is contained in:
hannesrudolph 2025-07-31 16:19:14 -06:00 committed by Roo Code
parent b975ced81b
commit ce06371ca9
4 changed files with 34 additions and 2 deletions

View file

@ -562,7 +562,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
private async addToClineMessages(message: ClineMessage) {
this.clineMessages.push(message)
const provider = this.providerRef.deref()
await provider?.postStateToWebview()
// Send only the new message instead of the entire state
await provider?.postMessageToWebview({ type: "messageCreated", clineMessage: message })
this.emit(RooCodeEventName.Message, { action: "created", message })
await this.saveClineMessages()
@ -1172,6 +1173,9 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
// the task first.
this.apiConversationHistory = await this.getSavedApiConversationHistory()
// Send initial state to webview (this will now handle incremental message loading)
await this.providerRef.deref()?.postStateToWebview()
const lastClineMessage = this.clineMessages
.slice()
.reverse()

View file

@ -1550,7 +1550,26 @@ export class ClineProvider
async postStateToWebview() {
const state = await this.getStateToPostToWebview()
this.postMessageToWebview({ type: "state", state })
// Check if we're loading an existing task with messages
const currentCline = this.getCurrentCline()
const hasExistingMessages = currentCline && currentCline.clineMessages.length > 0
if (hasExistingMessages) {
// Send state without messages first
const stateWithoutMessages = { ...state, clineMessages: [] }
await this.postMessageToWebview({ type: "state", state: stateWithoutMessages })
// Then send messages incrementally with a small delay for smooth rendering
for (const message of currentCline.clineMessages) {
await this.postMessageToWebview({ type: "messageCreated", clineMessage: message })
// Small delay to prevent overwhelming the webview
await delay(10)
}
} else {
// Normal state update for new tasks or tasks without messages
await this.postMessageToWebview({ type: "state", state })
}
// Check MDM compliance and send user to account tab if not compliant
if (!this.checkMdmCompliance()) {

View file

@ -66,6 +66,7 @@ export interface ExtensionMessage {
| "workspaceUpdated"
| "invoke"
| "messageUpdated"
| "messageCreated"
| "mcpServers"
| "enhancedPrompt"
| "commitSearchResults"

View file

@ -333,6 +333,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setCommands(message.commands ?? [])
break
}
case "messageCreated": {
const clineMessage = message.clineMessage!
setState((prevState) => ({
...prevState,
clineMessages: [...prevState.clineMessages, clineMessage],
}))
break
}
case "messageUpdated": {
const clineMessage = message.clineMessage!
setState((prevState) => {