Skip to content

chat: add "Copy Final Response" context menu action#306184

Merged
roblourens merged 2 commits intomainfrom
copilot/poised-bass
Mar 30, 2026
Merged

chat: add "Copy Final Response" context menu action#306184
roblourens merged 2 commits intomainfrom
copilot/poised-bass

Conversation

@roblourens
Copy link
Copy Markdown
Member

@roblourens roblourens commented Mar 30, 2026

Summary

Adds a new "Copy Final Response" action to the chat context menu. Unlike "Copy" (which copies the entire response) and "Copy All" (which copies the whole session), this action copies only the last contiguous block of non-empty markdown from a response — the final textual answer the model gave.

This is useful when a response ends with tool calls followed by empty markdown parts, but the user wants to quickly copy just the final prose answer.

Changes

New getFinalResponse() method on IResponse

  • Walks backwards through response parts, skipping trailing tool calls, empty markdown, and other non-text parts
  • Collects the last contiguous block of markdownContent, markdownVuln, and inlineReference parts
  • Added to AbstractResponse in chatModel.ts

New CopyFinalResponseAction

  • Registered in MenuId.ChatContext under the copy group
  • Only visible on response items (gated by ChatContextKeys.isResponse)
  • Calls response.getFinalResponse() and writes to clipboard

Context key fix

  • Added ChatContextKeys.isResponse to the context menu overlay in chatListWidget.ts so that when clauses referencing this key work correctly in the context menu

Tests

  • 5 unit tests covering: trailing markdown after tool calls, skipping empty markdown, inline references, empty responses, and all-markdown responses

Fixes #306185

Copilot AI review requested due to automatic review settings March 30, 2026 00:39
@roblourens roblourens enabled auto-merge (squash) March 30, 2026 00:39
@vs-code-engineering vs-code-engineering bot added this to the Backlog milestone Mar 30, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “Copy Final Response” command to the chat response context menu, backed by a new IResponse.getFinalResponse() API that extracts only the last contiguous block of meaningful markdown/inline-reference text from a response.

Changes:

  • Add IResponse.getFinalResponse() and implement it in AbstractResponse (chatModel.ts).
  • Register Copy Final Response in MenuId.ChatContext and wire it to the clipboard (chatCopyActions.ts).
  • Fix context menu scoping by providing ChatContextKeys.isResponse in the chat list overlay (chatListWidget.ts).
  • Add unit tests for the new extraction behavior and update mocks for the interface change.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/vs/workbench/contrib/chat/common/model/chatModel.ts Adds getFinalResponse() to IResponse and implements the extraction logic in AbstractResponse.
src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.ts Introduces the new context menu action that copies response.getFinalResponse() to the clipboard.
src/vs/workbench/contrib/chat/browser/widget/chatListWidget.ts Sets ChatContextKeys.isResponse in the context menu overlay so when clauses work correctly.
src/vs/workbench/contrib/chat/test/common/model/chatModel.test.ts Adds unit tests for getFinalResponse() behavior.
src/vs/workbench/contrib/chat/test/browser/agentSessions/*.test.ts Updates test mocks to satisfy the updated IResponse interface.
Comments suppressed due to low confidence (1)

src/vs/workbench/contrib/chat/common/model/chatModel.ts:521

  • In the segment concatenation loop, getFinalResponse again checks part.content.value.length > 0 before adding markdown. If you switch the backward scan to a trimmed-blank check, this should be updated too; otherwise whitespace-only markdown can still be included in the copied text.
			} else if (part.kind === 'markdownContent' || part.kind === 'markdownVuln') {
				if (part.content.value.length > 0) {
					segments.push(part.content.value);
				}

@roblourens roblourens merged commit 24982fe into main Mar 30, 2026
22 checks passed
@roblourens roblourens deleted the copilot/poised-bass branch March 30, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chat: "Copy Final Response" context menu action

3 participants