diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts index c90760806406e..c7f5ba07ee4a2 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts @@ -561,7 +561,7 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen context = this.currentThinkingValue.substring(0, 1000); } - const prompt = `Summarize the following actions in a SINGLE sentence (under 10 words) using past tense. Follow these rules strictly: + const prompt = `Summarize the following content in a SINGLE sentence (under 10 words) using past tense. Follow these rules strictly: OUTPUT FORMAT: - MUST be a single sentence @@ -569,9 +569,9 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen - No quotes, no trailing punctuation GENERAL: - - The actions may include tool calls (file edits, reads, searches, terminal commands) AND/OR non-tool reasoning/analysis - - If there are ONLY thinking headers or reasoning (no tool calls), summarize WHAT was considered/planned, NOT what was done - - For thinking-only summaries, use phrases like: "Considered...", "Planned...", "Analyzed approach for...", "Reviewed options for..." + - The content may include tool invocations (file edits, reads, searches, terminal commands), reasoning headers, or raw thinking text + - For reasoning headers or thinking text (no tool calls), summarize WHAT was considered/analyzed, NOT that thinking occurred + - For thinking-only summaries, use phrases like: "Considered...", "Planned...", "Analyzed...", "Reviewed..." TOOL NAME FILTERING: - NEVER include tool names like "Replace String in File", "Multi Replace String in File", "Create File", "Read File", etc. in the output @@ -584,8 +584,8 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen - For creates: "Created", "Added", "Generated" - For searches: "Searched for", "Looked up", "Investigated" - For terminal: "Ran command", "Executed" - - For thinking-only (no tools): "Considered", "Planned", "Analyzed approach", "Reviewed options" - - Choose the synonym that best fits the context of what was done + - For reasoning/thinking: "Considered", "Planned", "Analyzed", "Reviewed", "Evaluated" + - Choose the synonym that best fits the context RULES FOR TOOL CALLS: 1. If the SAME file was both edited AND read: Use a combined phrase like "Reviewed and updated " @@ -598,11 +598,19 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen 8. After the file info, you may add a brief summary of other actions if space permits 9. NEVER say "1 file" - always use the actual filename when there's only one file - RULES FOR THINKING-ONLY (no tool calls): - 1. If the input contains only reasoning/analysis headers without actual tool invocations, summarize the planning/consideration + RULES FOR REASONING HEADERS (no tool calls): + 1. If the input contains reasoning/analysis headers without actual tool invocations, summarize the main topic and what was considered 2. Use past tense verbs that indicate thinking, not doing: "Considered", "Planned", "Analyzed", "Evaluated" 3. Focus on WHAT was being thought about, not that thinking occurred + RULES FOR RAW THINKING TEXT: + 1. Extract the main topic or question being considered from the text + 2. Identify any specific files, functions, or concepts mentioned + 3. Summarize as "Analyzed " or "Considered " + 4. If discussing code structure: "Reviewed " + 5. If discussing a problem: "Analyzed " + 6. If discussing implementation: "Planned " + EXAMPLES WITH TOOLS: - "Read HomePage.tsx, Edited HomePage.tsx" → "Reviewed and updated HomePage.tsx" - "Edited HomePage.tsx" → "Updated HomePage.tsx" @@ -618,14 +626,20 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen - "Edited Button.tsx, Edited Button.css, Edited index.ts" → "Modified 3 files" - "Searched codebase for error handling" → "Looked up error handling" - EXAMPLES WITHOUT TOOLS (thinking-only): + EXAMPLES WITH REASONING HEADERS (no tools): - "Analyzing component architecture" → "Considered component architecture" - "Planning refactor strategy" → "Planned refactor strategy" - "Reviewing error handling approach, Considering edge cases" → "Analyzed error handling approach" - "Understanding the codebase structure" → "Reviewed codebase structure" - "Thinking about implementation options" → "Considered implementation options" - Tool calls and reasoning: ${context}`; + EXAMPLES WITH RAW THINKING TEXT: + - "I need to understand how the authentication flow works in this app..." → "Analyzed authentication flow" + - "Let me think about how to refactor this component to be more maintainable..." → "Planned component refactoring" + - "The error seems to be coming from the database connection..." → "Investigated database connection issue" + - "Looking at the UserService class, I see it handles..." → "Reviewed UserService implementation" + + Content: ${context}`; const response = await this.languageModelsService.sendChatRequest( models[0], @@ -794,6 +808,84 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen toolCallLabel = message; this.toolInvocations.push(toolInvocationOrMarkdown); + + // track state for live/still streaming tools, excluding serialized tools + if (toolInvocationOrMarkdown.kind === 'toolInvocation') { + let currentToolLabel = toolCallLabel; + let isComplete = false; + + const updateTitle = (updatedMessage: string) => { + if (updatedMessage && updatedMessage !== currentToolLabel) { + // replace old title if exists, otherwise add new + const oldIndex = this.extractedTitles.indexOf(currentToolLabel); + const updatedIndex = this.extractedTitles.indexOf(updatedMessage); + + if (oldIndex !== -1) { + if (updatedIndex !== -1 && updatedIndex !== oldIndex) { + this.extractedTitles.splice(oldIndex, 1); + } else { + this.extractedTitles[oldIndex] = updatedMessage; + } + } else if (updatedIndex === -1) { + this.extractedTitles.push(updatedMessage); + } + currentToolLabel = updatedMessage; + this.lastExtractedTitle = updatedMessage; + + // make sure not to set title if expanded + if (!this.fixedScrollingMode && !this._isExpanded.read(undefined)) { + this.setTitle(updatedMessage); + } + } + }; + + this._register(autorun(reader => { + if (isComplete) { + return; + } + + const currentState = toolInvocationOrMarkdown.state.read(reader); + + if (currentState.type === IChatToolInvocation.StateKind.Completed || + currentState.type === IChatToolInvocation.StateKind.Cancelled) { + isComplete = true; + return; + } + + // streaming + if (currentState.type === IChatToolInvocation.StateKind.Streaming) { + const streamingMessage = currentState.streamingMessage.read(reader); + if (streamingMessage) { + const updatedMessage = typeof streamingMessage === 'string' ? streamingMessage : streamingMessage.value; + updateTitle(updatedMessage); + } + return; + } + + // executing (something like `Replacing 67 lines.....`) + if (currentState.type === IChatToolInvocation.StateKind.Executing) { + const progressData = currentState.progress.read(reader); + if (progressData.message) { + const updatedMessage = typeof progressData.message === 'string' ? progressData.message : progressData.message.value; + updateTitle(updatedMessage); + } else { + const invocationMsg = toolInvocationOrMarkdown.invocationMessage; + if (invocationMsg) { + const updatedMessage = typeof invocationMsg === 'string' ? invocationMsg : invocationMsg.value; + updateTitle(updatedMessage); + } + } + return; + } + + // confirmations, failures, completed, other, etc + const invocationMsg = toolInvocationOrMarkdown.invocationMessage; + if (invocationMsg) { + const updatedMessage = typeof invocationMsg === 'string' ? invocationMsg : invocationMsg.value; + updateTitle(updatedMessage); + } + })); + } } else if (toolInvocationOrMarkdown?.kind === 'markdownContent') { const codeblockInfo = extractCodeblockUrisFromText(toolInvocationOrMarkdown.content.value); if (codeblockInfo?.uri) { @@ -811,6 +903,8 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen this.extractedTitles.push(toolCallLabel); } + this.lastExtractedTitle = toolCallLabel; + if (!this.fixedScrollingMode && !this._isExpanded.get()) { this.setTitle(toolCallLabel); }