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,