feat: normalize and filter chat attachments

Attachment pickers now share an allowlist for supported file types
Local attachments are normalized to consistent MIME types before upload
VS Code file picker now respects extension filters and larger files are allowed
This commit is contained in:
Bohdan Triapitsyn
2026-07-22 11:33:22 +03:00
parent 6525c11042
commit d3a2564cf6
8 changed files with 245 additions and 21 deletions
+11 -7
View File
@@ -10,7 +10,7 @@ import { createMessageQueueTarget, getMessageQueueKey, useMessageQueueStore, typ
import { useAutoReviewStore } from '@/stores/useAutoReviewStore';
import { useSessionUIStore } from '@/sync/session-ui-store';
import { useSelectionStore } from '@/sync/selection-store';
import { useInputStore } from '@/sync/input-store';
import { ACCEPTED_ATTACHMENT_EXTENSIONS, ATTACHMENT_ACCEPT, useInputStore } from '@/sync/input-store';
import type { AttachedFile } from '@/stores/types/sessionTypes';
import * as sessionActions from '@/sync/session-actions';
import { useDirectorySync, useUserMessageHistory } from '@/sync/sync-context';
@@ -3716,14 +3716,15 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
}
if (files.length > 0) {
let attached = false;
for (const file of files) {
try {
await addAttachedFile(file);
attached = (await addAttachedFile(file)) || attached;
} catch (error) {
console.error('File attach failed', error);
toast.error(error instanceof Error ? error.message : t('chat.chatInput.toast.attachFileFailed'));
}
}
if (!attached) toast.error(t('chat.chatInput.toast.attachFileFailed'));
}
clearDropTextSuppression();
};
@@ -3744,20 +3745,23 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
const attachFiles = React.useCallback(async (files: FileList | File[]) => {
const list = Array.isArray(files) ? files : Array.from(files);
let attached = false;
for (const file of list) {
try {
await addAttachedFile(file);
attached = (await addAttachedFile(file)) || attached;
} catch (error) {
console.error('File attach failed', error);
toast.error(error instanceof Error ? error.message : t('chat.chatInput.toast.attachFileFailed'));
}
}
if (list.length > 0 && !attached) {
toast.error(t('chat.chatInput.toast.attachFileFailed'));
}
}, [addAttachedFile, t]);
const handleVSCodePickFiles = React.useCallback(async () => {
try {
const data = (await vscodeApi?.pickFiles?.()) as {
const data = (await vscodeApi?.pickFiles?.({ extensions: ACCEPTED_ATTACHMENT_EXTENSIONS })) as {
files?: Array<{ name: string; mimeType?: string; dataUrl?: string }>;
skipped?: Array<{ name?: string; reason?: string }>;
} | undefined;
@@ -5592,7 +5596,7 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
multiple
className="hidden"
onChange={handleLocalFileSelect}
accept="*/*"
accept={ATTACHMENT_ACCEPT}
/>
{/* Mobile attachment sheet: replaces the dropdown (which stole focus and