Change:
Testing a large image () it into chat window freezes for a few seconds Seems we spent in the !
cc. is there a compromise on what we hash for the ID? ie, maybe half of the bytes instead of the full thing, or something of the sort, since ATM we are just hashing the entire received
It looks like the function is trying to hash the Uint8Array naively as an object (hashing each key and value for each element in the array) which is going to be extraordinarily slow. should complete in millisecond(s) :)
should our detect if it's web and if crypto is available and use that if so? I can see this happening again.
Yea, I think having it check for typed arrays and arraybuffers would make sense. Unfortunately is sync and webcrypto is async, however, so it would not be a drop-in replacement.
perhaps we could have a signature like to catch at compile time and redirect that use to the async version in ?

Discussion:
import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from '../../../search/browser/symbolsQuickAccess.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js'; <del> import { isImage } from '../chatImagePaste.js'; import { hash } from '../../../../../base/common/hash.js'; </del> <ins> import { imageToHash, isImage } from '../chatImagePaste.js'; </ins> import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ActiveEditorContext } from '../../../../common/contextkeys.js';

} else if ('kind' in pick && pick.kind === 'image') { const fileBuffer = await clipboardService.readImage(); toAttach.push({ <del> id: hash(fileBuffer).toString(), </del> <ins> id: await imageToHash(fileBuffer), </ins> name: localize('pastedImage', 'Pasted Image'), fullName: localize('pastedImage', 'Pasted Image'), value: fileBuffer,

if (isImage(imageData) && configurationService.getValue<boolean>('chat.experimental.imageAttachments')) { quickPickItems.push({ <del> id: hash(imageData).toString(), </del> <ins> id: await imageToHash(imageData), </ins> kind: 'image', label: localize('imageFromClipboard', 'Image from Clipboard'), iconClass: ThemeIcon.asClassName(Codicon.fileMedia),

import { IChatRequestVariableEntry } from '../common/chatModel.js'; import { ChatInputPart } from './chatInputPart.js'; import { localize } from '../../../../nls.js'; <del> import { hash } from '../../../../base/common/hash.js'; </del> import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; export class ChatImageDropAndPaste extends Disposable {

if (!currClipboard || !isImage(currClipboard)) { return; } <del> const context = getImageAttachContext(currClipboard); </del> <ins> const context = await getImageAttachContext(currClipboard); </ins> if (!context) { return; }

} } <del> function getImageAttachContext(data: Uint8Array): IChatRequestVariableEntry { </del> <ins> async function getImageAttachContext(data: Uint8Array): Promise<IChatRequestVariableEntry> { </ins> return { value: data, <del> id: hash(data).toString(), </del> <ins> id: await imageToHash(data), </ins> name: localize('pastedImage', 'Pasted Image'), isImage: true, icon: Codicon.fileMedia,

}; } <ins> export async function imageToHash(data: Uint8Array): Promise<string> { const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); } </ins> export function isImage(array: Uint8Array): boolean { if (array.length < 4) { return false;

widget.tabIndex = 0; if (!this.attachedContextDisposables.isDisposed) { <del> this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement)); </del> <ins> this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement, { trapFocus: false })); </ins> // No delay for keyboard this.attachedContextDisposables.add(dom.addDisposableListener(widget, 'keydown', (event) => {

.chat-attached-context-hover .chat-attached-context-image { height: auto; max-height: 500px; <ins> max-width: 400px; </ins> width: 100%; display: block; }