From e7bc310ccb523a03ffd04dacba3ccb22e1952154 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Wed, 4 Feb 2026 16:38:53 -0500 Subject: [PATCH] Render images in history too (#3454) --- .../prompts/node/agent/agentPrompt.tsx | 5 +-- .../extension/prompts/node/panel/image.tsx | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx b/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx index bcf8fc7e909..7810eef1052 100644 --- a/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx +++ b/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { BasePromptElementProps, Chunk, Image, PromptElement, PromptPiece, PromptPieceChild, PromptSizing, Raw, SystemMessage, TokenLimit, UserMessage } from '@vscode/prompt-tsx'; +import { BasePromptElementProps, Chunk, PromptElement, PromptPiece, PromptPieceChild, PromptSizing, Raw, SystemMessage, TokenLimit, UserMessage } from '@vscode/prompt-tsx'; import type { ChatRequestEditedFileEvent, LanguageModelToolInformation, NotebookEditor, TaskDefinition, TextEditor } from 'vscode'; import { ChatLocation } from '../../../../platform/chat/common/commonTypes'; import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService'; @@ -35,6 +35,7 @@ import { Tag } from '../base/tag'; import { TerminalStatePromptElement } from '../base/terminalState'; import { ChatVariables, UserQuery } from '../panel/chatVariables'; import { CustomInstructions } from '../panel/customInstructions'; +import { HistoricalImage } from '../panel/image'; import { NotebookFormat, NotebookReminderInstructions } from '../panel/notebookEditCodePrompt'; import { NotebookSummaryChange } from '../panel/notebookSummaryChangePrompt'; import { UserPreferences } from '../panel/preferences'; @@ -417,7 +418,7 @@ export function renderedMessageToTsxChildren(message: string | readonly Raw.Chat if (part.type === Raw.ChatCompletionContentPartKind.Text) { return part.text; } else if (part.type === Raw.ChatCompletionContentPartKind.Image) { - return ; + return ; } else if (part.type === Raw.ChatCompletionContentPartKind.CacheBreakpoint) { return enableCacheBreakpoints && ; } diff --git a/extensions/copilot/src/extension/prompts/node/panel/image.tsx b/extensions/copilot/src/extension/prompts/node/panel/image.tsx index a795224add4..8bb900dd06b 100644 --- a/extensions/copilot/src/extension/prompts/node/panel/image.tsx +++ b/extensions/copilot/src/extension/prompts/node/panel/image.tsx @@ -23,6 +23,41 @@ export interface ImageProps extends BasePromptElementProps { reference?: Uri; } +/** + * Props for rendering an image that was previously rendered and stored in conversation history. + * These images are already processed (base64 or URL) and don't need re-uploading. + */ +export interface HistoricalImageProps extends BasePromptElementProps { + /** The image source - either a base64 string or URL */ + src: string; + /** The detail level for the image */ + detail?: 'auto' | 'low' | 'high'; + /** The MIME type of the image */ + mimeType?: string; +} + +/** + * Renders an image from conversation history. + * Checks if the current model supports vision and omits the image if not. + */ +export class HistoricalImage extends PromptElement { + constructor( + props: HistoricalImageProps, + @IPromptEndpoint private readonly promptEndpoint: IPromptEndpoint, + ) { + super(props); + } + + override async render(_state: unknown, sizing: PromptSizing) { + // If the model doesn't support vision, omit historical images + if (!this.promptEndpoint.supportsVision) { + return undefined; + } + + return ; + } +} + export class Image extends PromptElement { constructor( props: ImageProps,