diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 53b8ef5b87..37ea859cf2 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -1670,6 +1670,8 @@ export class Task extends EventEmitter { profileThresholds = {}, } = state ?? {} + this.deduplicateReadFileHistory() + // Get condensing configuration for automatic triggers const customCondensingPrompt = state?.customCondensingPrompt const condensingApiConfigId = state?.condensingApiConfigId @@ -1893,6 +1895,41 @@ export class Task extends EventEmitter { yield* iterator } + deduplicateReadFileHistory() { + for (let i = this.apiConversationHistory.length - 1; i >= 0; i--) { + const conversation = this.apiConversationHistory[i] + + if (conversation.role !== "user") continue + + const content = conversation.content + if (typeof content === "string") continue + + const firstItem = content[0] + if (typeof firstItem === "string" || !("type" in firstItem) || firstItem.type !== "text") continue + + const toolUseText = firstItem.text + if (!toolUseText || !toolUseText.startsWith("[read_file for ")) continue + + for (let j = i - 1; j >= 0; j--) { + const prevConversation = this.apiConversationHistory[j] + + if (prevConversation.role === "assistant") continue + + const prevContent = prevConversation.content + if (typeof prevContent === "string") continue + + const prevFirstItem = prevContent[0] + if (typeof prevFirstItem === "string" || !("type" in prevFirstItem) || prevFirstItem.type !== "text") + continue + + if (prevFirstItem.text === toolUseText && prevContent.length === 3) { + prevContent.splice(1, 1) + break + } + } + } + } + // Checkpoints public async checkpointSave(force: boolean = false) {