Render images in history too (#3454)

This commit is contained in:
Logan Ramos
2026-02-04 16:38:53 -05:00
committed by GitHub
parent 196023d98a
commit e7bc310ccb
2 changed files with 38 additions and 2 deletions
@@ -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 <Image src={part.imageUrl.url} detail={part.imageUrl.detail} mimeType={part.imageUrl.mediaType} />;
return <HistoricalImage src={part.imageUrl.url} detail={part.imageUrl.detail} mimeType={part.imageUrl.mediaType} />;
} else if (part.type === Raw.ChatCompletionContentPartKind.CacheBreakpoint) {
return enableCacheBreakpoints && <cacheBreakpoint type={CacheType} />;
}
@@ -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<HistoricalImageProps, unknown> {
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 <BaseImage src={this.props.src} detail={this.props.detail} mimeType={this.props.mimeType} />;
}
}
export class Image extends PromptElement<ImageProps, unknown> {
constructor(
props: ImageProps,