diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts
index 689675999f..6554d6a5c0 100644
--- a/src/core/assistant-message/presentAssistantMessage.ts
+++ b/src/core/assistant-message/presentAssistantMessage.ts
@@ -101,13 +101,19 @@ export async function presentAssistantMessage(cline: Task) {
// here for reference.
// content = content.replace(/<\/?t(?:h(?:i(?:n(?:k(?:i(?:n(?:g)?)?)?$/, "")
//
- // Remove all instances of (with optional line break
- // after) and (with optional line break before).
- // - Needs to be separate since we dont want to remove the line
- // break before the first tag.
- // - Needs to happen before the xml parsing below.
- content = content.replace(/\s?/g, "")
- content = content.replace(/\s?<\/thinking>/g, "")
+ // Check if we should preserve thinking sections
+ // Preserve thinking sections during consecutive tool uses (no user messages in between)
+ const shouldPreserveThinking = cline.isConsecutiveToolUse()
+
+ if (!shouldPreserveThinking) {
+ // Remove all instances of (with optional line break
+ // after) and (with optional line break before).
+ // - Needs to be separate since we dont want to remove the line
+ // break before the first tag.
+ // - Needs to happen before the xml parsing below.
+ content = content.replace(/\s?/g, "")
+ content = content.replace(/\s?<\/thinking>/g, "")
+ }
// Remove partial XML tag at the very end of the content (for
// tool use and thinking tags), Prevents scrollview from
diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts
index cf16df8dcc..5aa0d8a80b 100644
--- a/src/core/task/Task.ts
+++ b/src/core/task/Task.ts
@@ -2932,4 +2932,53 @@ export class Task extends EventEmitter implements TaskLike {
console.error(`[Task] Queue processing error:`, e)
}
}
+
+ /**
+ * Check if the current message is a consecutive tool use without user intervention.
+ * This is used to determine whether to preserve thinking sections for reasoning models.
+ *
+ * @returns true if the last non-system message was from the assistant (consecutive tool use),
+ * false if it was from the user or if there are no previous messages
+ */
+ public isConsecutiveToolUse(): boolean {
+ // Look at the conversation history to determine if this is consecutive tool use
+ if (this.apiConversationHistory.length === 0) {
+ return false
+ }
+
+ // Find the last message that isn't the current one being processed
+ // We need to check if the previous message was from the assistant (consecutive tool use)
+ // or from the user (new interaction)
+ const lastMessage = this.apiConversationHistory[this.apiConversationHistory.length - 1]
+
+ // If the last message is from the user, this is not a consecutive tool use
+ if (lastMessage.role === "user") {
+ // Check if this is just environment details or actual user content
+ // Environment details are added automatically and shouldn't count as user intervention
+ if (Array.isArray(lastMessage.content)) {
+ // Check if the content only contains environment details
+ const hasUserContent = lastMessage.content.some((block) => {
+ if (block.type === "text") {
+ const text = block.text.trim()
+ // Check if this is just environment details or tool results
+ return (
+ !text.startsWith("environment_details:") &&
+ !text.includes("[Tool Use:") &&
+ !text.includes("Result:") &&
+ text.length > 0
+ )
+ }
+ // Images or other content types indicate user interaction
+ return block.type === "image"
+ })
+
+ // If there's actual user content, this is not consecutive tool use
+ return !hasUserContent
+ }
+ return false
+ }
+
+ // If the last message is from the assistant, this is consecutive tool use
+ return lastMessage.role === "assistant"
+ }
}