Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,12 @@ export class Task extends EventEmitter<TaskEvents> {
private async addToClineMessages(message: ClineMessage) {
this.clineMessages.push(message)
const provider = this.providerRef.deref()
await provider?.postStateToWebview()

// Use incremental update instead of posting full state for better performance
await provider?.postIncrementalUpdateToWebview({
newMessages: [message],
})

this.emit("message", { action: "created", message })
await this.saveClineMessages()

Expand All @@ -566,7 +571,12 @@ export class Task extends EventEmitter<TaskEvents> {

private async updateClineMessage(message: ClineMessage) {
const provider = this.providerRef.deref()
await provider?.postMessageToWebview({ type: "messageUpdated", clineMessage: message })

// Use incremental update for message updates as well
await provider?.postIncrementalUpdateToWebview({
updatedMessages: [message],
})

this.emit("message", { action: "updated", message })

const shouldCaptureMessage = message.partial !== true && CloudService.isEnabled()
Expand Down Expand Up @@ -598,7 +608,13 @@ export class Task extends EventEmitter<TaskEvents> {

this.emit("taskTokenUsageUpdated", this.taskId, tokenUsage)

await this.providerRef.deref()?.updateTaskHistory(historyItem)
const provider = this.providerRef.deref()
await provider?.updateTaskHistory(historyItem)

// Send incremental update for task history
await provider?.postIncrementalUpdateToWebview({
taskHistoryUpdate: historyItem,
})
} catch (error) {
console.error("Failed to save Roo messages:", error)
}
Expand Down Expand Up @@ -926,6 +942,7 @@ export class Task extends EventEmitter<TaskEvents> {
// messages from previous session).
this.clineMessages = []
this.apiConversationHistory = []
// Use full state update for initial task start
await this.providerRef.deref()?.postStateToWebview()

await this.say("text", task, images)
Expand Down
16 changes: 16 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,22 @@ export class ClineProvider
}
}

/**
* Posts incremental updates to the webview instead of the full state.
* This significantly improves performance for long conversations by only
* sending new or updated messages instead of the entire conversation history.
*/
async postIncrementalUpdateToWebview(options: {
newMessages?: import("@roo-code/types").ClineMessage[]
updatedMessages?: import("@roo-code/types").ClineMessage[]
taskHistoryUpdate?: import("@roo-code/types").HistoryItem
}) {
await this.postMessageToWebview({
type: "incrementalStateUpdate",
incrementalUpdate: options,
})
}

/**
* Fetches marketplace data on demand to avoid blocking main state updates
*/
Expand Down
6 changes: 6 additions & 0 deletions src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface ExtensionMessage {
type:
| "action"
| "state"
| "incrementalStateUpdate"
| "selectedImages"
| "theme"
| "workspaceUpdated"
Expand Down Expand Up @@ -135,6 +136,11 @@ export interface ExtensionMessage {
| "switchTab"
invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
state?: ExtensionState
incrementalUpdate?: {
newMessages?: ClineMessage[]
updatedMessages?: ClineMessage[]
taskHistoryUpdate?: HistoryItem
}
images?: string[]
filePaths?: string[]
openedTabs?: Array<{
Expand Down
42 changes: 42 additions & 0 deletions webview-ui/src/context/ExtensionStateContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,48 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
}
break
}
case "incrementalStateUpdate": {
const update = message.incrementalUpdate!
setState((prevState) => {
let newClineMessages = [...prevState.clineMessages]

// Add new messages
if (update.newMessages) {
newClineMessages.push(...update.newMessages)
}

// Update existing messages
if (update.updatedMessages) {
for (const updatedMessage of update.updatedMessages) {
const index = findLastIndex(newClineMessages, (msg) => msg.ts === updatedMessage.ts)
if (index !== -1) {
newClineMessages[index] = updatedMessage
}
}
}

// Update task history if provided
let newTaskHistory = prevState.taskHistory
if (update.taskHistoryUpdate) {
const historyIndex = newTaskHistory.findIndex(
(item) => item.id === update.taskHistoryUpdate!.id,
)
if (historyIndex !== -1) {
newTaskHistory = [...newTaskHistory]
newTaskHistory[historyIndex] = update.taskHistoryUpdate
} else {
newTaskHistory = [...newTaskHistory, update.taskHistoryUpdate]
}
}

return {
...prevState,
clineMessages: newClineMessages,
taskHistory: newTaskHistory,
}
})
break
}
case "theme": {
if (message.text) {
setTheme(convertTextMateToHljs(JSON.parse(message.text)))
Expand Down
Loading