mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-02 08:15:56 +01:00
show a warning when there are more than 20 images in a request (#305817)
* show a warning when there are more than 20 images in a request * address comments
This commit is contained in:
@@ -63,7 +63,7 @@ import { ITerminalService } from '../../../terminal/browser/terminal.js';
|
||||
import { IChatContentReference } from '../../common/chatService/chatService.js';
|
||||
import { coerceImageBuffer } from '../../common/chatImageExtraction.js';
|
||||
import { ChatConfiguration } from '../../common/constants.js';
|
||||
import { IChatRequestPasteVariableEntry, IChatRequestVariableEntry, IElementVariableEntry, INotebookOutputVariableEntry, IPromptFileVariableEntry, IPromptTextVariableEntry, ISCMHistoryItemVariableEntry, OmittedState, PromptFileVariableKind, ChatRequestToolReferenceEntry, ISCMHistoryItemChangeVariableEntry, ISCMHistoryItemChangeRangeVariableEntry, ITerminalVariableEntry, isStringVariableEntry } from '../../common/attachments/chatVariableEntries.js';
|
||||
import { IChatRequestPasteVariableEntry, IChatRequestVariableEntry, IElementVariableEntry, INotebookOutputVariableEntry, IPromptFileVariableEntry, IPromptTextVariableEntry, ISCMHistoryItemVariableEntry, MAX_IMAGES_PER_REQUEST, OmittedState, PromptFileVariableKind, ChatRequestToolReferenceEntry, ISCMHistoryItemChangeVariableEntry, ISCMHistoryItemChangeRangeVariableEntry, ITerminalVariableEntry, isStringVariableEntry } from '../../common/attachments/chatVariableEntries.js';
|
||||
import { ILanguageModelChatMetadataAndIdentifier, ILanguageModelsService } from '../../common/languageModels.js';
|
||||
import { IChatEntitlementService } from '../../../../services/chat/common/chatEntitlementService.js';
|
||||
import { ILanguageModelToolsService, isToolSet } from '../../common/tools/languageModelToolsService.js';
|
||||
@@ -432,6 +432,8 @@ export class ImageAttachmentWidget extends AbstractChatAttachmentWidget {
|
||||
ariaLabel = localize('chat.omittedImageAttachment', "Omitted this image: {0}", attachment.name);
|
||||
} else if (attachment.omittedState === OmittedState.Partial) {
|
||||
ariaLabel = localize('chat.partiallyOmittedImageAttachment', "Partially omitted this image: {0}", attachment.name);
|
||||
} else if (attachment.omittedState === OmittedState.ImageLimitExceeded) {
|
||||
ariaLabel = localize('chat.imageLimitExceededAttachment', "Image not sent due to limit: {0}", attachment.name);
|
||||
} else {
|
||||
ariaLabel = localize('chat.imageAttachment', "Attached image, {0}", attachment.name);
|
||||
}
|
||||
@@ -519,6 +521,13 @@ function createImageElements(resource: URI | undefined, name: string, fullName:
|
||||
content: hoverElement,
|
||||
style: HoverStyle.Pointer,
|
||||
}));
|
||||
} else if (omittedState === OmittedState.ImageLimitExceeded) {
|
||||
element.classList.add('warning');
|
||||
hoverElement.textContent = localize('chat.imageLimitExceededHover', "This image was not sent because the maximum of {0} images per request was exceeded.", MAX_IMAGES_PER_REQUEST);
|
||||
disposable.add(hoverService.setupDelayedHover(element, {
|
||||
content: hoverElement,
|
||||
style: HoverStyle.Pointer,
|
||||
}));
|
||||
} else {
|
||||
disposable.add(hoverService.setupDelayedHover(element, {
|
||||
content: hoverElement,
|
||||
|
||||
@@ -11,7 +11,7 @@ import { URI } from '../../../../../../base/common/uri.js';
|
||||
import { Range } from '../../../../../../editor/common/core/range.js';
|
||||
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js';
|
||||
import { ResourceLabels } from '../../../../../browser/labels.js';
|
||||
import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isPromptFileVariableEntry, isPromptTextVariableEntry, isSCMHistoryItemChangeRangeVariableEntry, isSCMHistoryItemChangeVariableEntry, isSCMHistoryItemVariableEntry, isTerminalVariableEntry, isWorkspaceVariableEntry, OmittedState } from '../../../common/attachments/chatVariableEntries.js';
|
||||
import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isPromptFileVariableEntry, isPromptTextVariableEntry, isSCMHistoryItemChangeRangeVariableEntry, isSCMHistoryItemChangeVariableEntry, isSCMHistoryItemVariableEntry, isTerminalVariableEntry, isWorkspaceVariableEntry, MAX_IMAGES_PER_REQUEST, OmittedState } from '../../../common/attachments/chatVariableEntries.js';
|
||||
import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../../../common/chatService/chatService.js';
|
||||
import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, PromptFileAttachmentWidget, PromptTextAttachmentWidget, SCMHistoryItemAttachmentWidget, SCMHistoryItemChangeAttachmentWidget, SCMHistoryItemChangeRangeAttachmentWidget, TerminalCommandAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../../attachments/chatAttachmentWidgets.js';
|
||||
import { IChatAttachmentWidgetRegistry } from '../../attachments/chatAttachmentWidgetRegistry.js';
|
||||
@@ -73,6 +73,8 @@ export class ChatAttachmentsContentPart extends Disposable {
|
||||
const visibleAttachments = this.getVisibleAttachments();
|
||||
const hasMoreAttachments = this.limit && this._variables.length > this.limit && !this._showingAll;
|
||||
|
||||
this.markImageLimitExceeded(this._variables);
|
||||
|
||||
for (const attachment of visibleAttachments) {
|
||||
this.renderAttachment(attachment, container);
|
||||
}
|
||||
@@ -89,6 +91,27 @@ export class ChatAttachmentsContentPart extends Disposable {
|
||||
return this._variables.slice(0, this.limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the total number of image attachments exceeds the per-request limit,
|
||||
* mark the oldest images (those that will be dropped by the backend) with
|
||||
* {@link OmittedState.ImageLimitExceeded}.
|
||||
*/
|
||||
private markImageLimitExceeded(attachments: readonly IChatRequestVariableEntry[]): void {
|
||||
const imageAttachments = attachments.filter(isImageVariableEntry);
|
||||
if (imageAttachments.length <= MAX_IMAGES_PER_REQUEST) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The backend keeps the most-recent images, so mark the oldest ones as exceeded.
|
||||
// Only overwrite NotOmitted or ImageLimitExceeded to avoid clobbering other states (e.g. Partial for GIFs).
|
||||
const excessCount = imageAttachments.length - MAX_IMAGES_PER_REQUEST;
|
||||
for (let i = 0; i < excessCount; i++) {
|
||||
if (imageAttachments[i].omittedState === OmittedState.NotOmitted || imageAttachments[i].omittedState === OmittedState.ImageLimitExceeded) {
|
||||
imageAttachments[i].omittedState = OmittedState.ImageLimitExceeded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private renderShowMoreButton(container: HTMLElement) {
|
||||
const remainingCount = this._variables.length - (this.limit ?? 0);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions, setupSimpleEd
|
||||
import { InlineChatConfigKeys } from '../../../../inlineChat/common/inlineChat.js';
|
||||
import { IChatViewTitleActionContext } from '../../../common/actions/chatActions.js';
|
||||
import { ChatContextKeys } from '../../../common/actions/chatContextKeys.js';
|
||||
import { ChatRequestVariableSet, IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isPromptFileVariableEntry, isPromptTextVariableEntry, isSCMHistoryItemChangeRangeVariableEntry, isSCMHistoryItemChangeVariableEntry, isSCMHistoryItemVariableEntry, isStringVariableEntry } from '../../../common/attachments/chatVariableEntries.js';
|
||||
import { ChatRequestVariableSet, IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isPromptFileVariableEntry, isPromptTextVariableEntry, isSCMHistoryItemChangeRangeVariableEntry, isSCMHistoryItemChangeVariableEntry, isSCMHistoryItemVariableEntry, isStringVariableEntry, MAX_IMAGES_PER_REQUEST, OmittedState } from '../../../common/attachments/chatVariableEntries.js';
|
||||
import { ChatMode, getModeNameForTelemetry, IChatMode, IChatModeService } from '../../../common/chatModes.js';
|
||||
import { IChatFollowup, IChatQuestionCarousel, IChatService, IChatSessionContext } from '../../../common/chatService/chatService.js';
|
||||
import { agentOptionId, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem, IChatSessionsService, isIChatSessionFileChange2, localChatSessionType } from '../../../common/chatSessionsService.js';
|
||||
@@ -2564,6 +2564,29 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
this._indexOfLastOpenedContext = -1;
|
||||
}
|
||||
|
||||
// Mark images that exceed the per-request limit so they render with a warning
|
||||
const imageAttachments = attachments.filter(([, a]) => isImageVariableEntry(a));
|
||||
if (imageAttachments.length > MAX_IMAGES_PER_REQUEST) {
|
||||
const excessCount = imageAttachments.length - MAX_IMAGES_PER_REQUEST;
|
||||
for (let i = 0; i < excessCount; i++) {
|
||||
const attachment = imageAttachments[i][1];
|
||||
if (attachment.omittedState === OmittedState.NotOmitted || attachment.omittedState === OmittedState.ImageLimitExceeded) {
|
||||
attachment.omittedState = OmittedState.ImageLimitExceeded;
|
||||
}
|
||||
}
|
||||
for (let i = excessCount; i < imageAttachments.length; i++) {
|
||||
if (imageAttachments[i][1].omittedState === OmittedState.ImageLimitExceeded) {
|
||||
imageAttachments[i][1].omittedState = OmittedState.NotOmitted;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const [, a] of imageAttachments) {
|
||||
if (a.omittedState === OmittedState.ImageLimitExceeded) {
|
||||
a.omittedState = OmittedState.NotOmitted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const [index, attachment] of attachments) {
|
||||
const resource = URI.isUri(attachment.value) ? attachment.value : isLocation(attachment.value) ? attachment.value.uri : undefined;
|
||||
|
||||
@@ -56,8 +56,15 @@ export const enum OmittedState {
|
||||
NotOmitted,
|
||||
Partial,
|
||||
Full,
|
||||
ImageLimitExceeded,
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of images allowed per request.
|
||||
* Claude has an upstream limit where more than 20 images causes issues.
|
||||
*/
|
||||
export const MAX_IMAGES_PER_REQUEST = 20;
|
||||
|
||||
export interface IChatRequestToolEntry extends IBaseChatRequestVariableEntry {
|
||||
readonly kind: 'tool';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user