From cf7117517b2fbdaa184f3eb998e9e0eed4a9ed0f Mon Sep 17 00:00:00 2001 From: Marc McIntosh Date: Thu, 27 Mar 2025 12:50:45 +0100 Subject: [PATCH 1/5] wip: remove attach file checkbox. --- .../gui/src/components/ChatForm/ChatForm.tsx | 10 +----- .../src/components/ChatForm/useCheckBoxes.ts | 34 ++++--------------- .../useCommandCompletionAndPreviewFiles.ts | 9 ++--- .../gui/src/components/ChatForm/utils.ts | 5 +-- 4 files changed, 11 insertions(+), 47 deletions(-) diff --git a/refact-agent/gui/src/components/ChatForm/ChatForm.tsx b/refact-agent/gui/src/components/ChatForm/ChatForm.tsx index eb689f8c6..603f44e7f 100644 --- a/refact-agent/gui/src/components/ChatForm/ChatForm.tsx +++ b/refact-agent/gui/src/components/ChatForm/ChatForm.tsx @@ -19,7 +19,6 @@ import { useSendChatRequest, useCompressChat, useAutoFocusOnce, - // useTotalTokenUsage, } from "../../hooks"; import { ErrorCallout, Callout } from "../Callout"; import { ComboBox } from "../ComboBox"; @@ -35,7 +34,6 @@ import { useInputValue } from "./useInputValue"; import { clearInformation, getInformationMessage, - // setInformation, } from "../../features/Errors/informationSlice"; import { InformationCallout } from "../Callout/Callout"; import { ToolConfirmation } from "./ToolConfirmation"; @@ -51,7 +49,6 @@ import { selectLastSentCompression, selectMessages, selectPreventSend, - // selectThreadMaximumTokens, selectThreadToolUse, selectToolUse, } from "../../features/Chat"; @@ -59,7 +56,6 @@ import { telemetryApi } from "../../services/refact"; import { push } from "../../features/Pages/pagesSlice"; import { AgentCapabilities } from "./AgentCapabilities"; import { TokensPreview } from "./TokensPreview"; -// import { useUsageCounter } from "../UsageCounter/useUsageCounter"; import classNames from "classnames"; import { ArchiveIcon } from "@radix-ui/react-icons"; @@ -161,7 +157,6 @@ export const ChatForm: React.FC = ({ checkboxes, onToggleCheckbox, unCheckAll, - setFileInteracted, setLineSelectionInteracted, } = useCheckboxes(); @@ -188,7 +183,6 @@ export const ChatForm: React.FC = ({ trimmedValue, checkboxes, ); - setFileInteracted(false); setLineSelectionInteracted(false); onSubmit(valueIncludingChecks); setValue(() => ""); @@ -198,7 +192,6 @@ export const ChatForm: React.FC = ({ value, disableSend, checkboxes, - setFileInteracted, setLineSelectionInteracted, onSubmit, setValue, @@ -241,7 +234,6 @@ export const ChatForm: React.FC = ({ setValue(command); const trimmedCommand = command.trim(); if (!trimmedCommand) { - setFileInteracted(false); setLineSelectionInteracted(false); } @@ -251,7 +243,7 @@ export const ChatForm: React.FC = ({ handleHelpInfo(null); } }, - [handleHelpInfo, setValue, setFileInteracted, setLineSelectionInteracted], + [handleHelpInfo, setValue, setLineSelectionInteracted], ); const handleAgentIntegrationsClick = useCallback(() => { diff --git a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts index c9c7ea7f6..011314bdc 100644 --- a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts +++ b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts @@ -21,7 +21,8 @@ const messageLengthSelector = createSelector( (messages) => messages.length, ); -const useAttachActiveFile = ( +// TODO: delete this +const _useAttachActiveFile = ( interacted: boolean, hasSnippet: boolean, ): [Checkbox, () => void] => { @@ -167,66 +168,45 @@ const useAttachSelectedSnippet = ( }; export type Checkboxes = { - file_upload: Checkbox; + // file_upload: Checkbox; selected_lines: Checkbox; }; export const useCheckboxes = () => { - // creating 2 different states instead of only one being used for both checkboxes + // creating different states instead of only one being used for checkboxes const [lineSelectionInteracted, setLineSelectionInteracted] = useState(false); - const [fileInteracted, setFileInteracted] = useState(false); const [attachedSelectedSnippet, onToggleAttachedSelectedSnippet] = useAttachSelectedSnippet(lineSelectionInteracted); - const [attachFileCheckboxData, onToggleAttachFile] = useAttachActiveFile( - fileInteracted, - attachedSelectedSnippet.checked, - ); - const checkboxes = useMemo( () => ({ - file_upload: attachFileCheckboxData, selected_lines: attachedSelectedSnippet, }), - [attachFileCheckboxData, attachedSelectedSnippet], + [attachedSelectedSnippet], ); const onToggleCheckbox = useCallback( (name: string) => { switch (name) { - case "file_upload": - onToggleAttachFile(); - setFileInteracted(true); - break; case "selected_lines": onToggleAttachedSelectedSnippet(); - setFileInteracted(true); setLineSelectionInteracted(true); break; } }, - [onToggleAttachFile, onToggleAttachedSelectedSnippet], + [onToggleAttachedSelectedSnippet], ); const unCheckAll = useCallback(() => { - if (attachFileCheckboxData.checked) { - onToggleAttachFile(); - } if (attachedSelectedSnippet.checked) { onToggleAttachedSelectedSnippet(); } - }, [ - attachFileCheckboxData.checked, - attachedSelectedSnippet.checked, - onToggleAttachFile, - onToggleAttachedSelectedSnippet, - ]); + }, [attachedSelectedSnippet.checked, onToggleAttachedSelectedSnippet]); return { checkboxes, onToggleCheckbox, - setFileInteracted, setLineSelectionInteracted, unCheckAll, }; diff --git a/refact-agent/gui/src/components/ChatForm/useCommandCompletionAndPreviewFiles.ts b/refact-agent/gui/src/components/ChatForm/useCommandCompletionAndPreviewFiles.ts index 9626cb4bb..80663f75a 100644 --- a/refact-agent/gui/src/components/ChatForm/useCommandCompletionAndPreviewFiles.ts +++ b/refact-agent/gui/src/components/ChatForm/useCommandCompletionAndPreviewFiles.ts @@ -110,8 +110,7 @@ function useGetCommandPreviewQuery( function useGetPreviewFiles(query: string, checkboxes: Checkboxes) { const queryWithCheckboxes = useMemo( () => addCheckboxValuesToInput(query, checkboxes), - // eslint-disable-next-line react-hooks/exhaustive-deps - [checkboxes, query, checkboxes.file_upload.value], + [checkboxes, query], ); const [previewQuery, setPreviewQuery] = useState(queryWithCheckboxes); @@ -125,11 +124,7 @@ function useGetPreviewFiles(query: string, checkboxes: Checkboxes) { useEffect(() => { debounceSetPreviewQuery(queryWithCheckboxes); - }, [ - debounceSetPreviewQuery, - queryWithCheckboxes, - checkboxes.file_upload.value, - ]); + }, [debounceSetPreviewQuery, queryWithCheckboxes]); const previewFileResponse = useGetCommandPreviewQuery(previewQuery); return previewFileResponse; diff --git a/refact-agent/gui/src/components/ChatForm/utils.ts b/refact-agent/gui/src/components/ChatForm/utils.ts index 38a684930..839d4ab0f 100644 --- a/refact-agent/gui/src/components/ChatForm/utils.ts +++ b/refact-agent/gui/src/components/ChatForm/utils.ts @@ -16,10 +16,6 @@ export function addCheckboxValuesToInput( result = `${checkboxes.selected_lines.value ?? ""}\n` + result; } - if (checkboxes.file_upload.checked && checkboxes.file_upload.hide !== true) { - result = `@file ${checkboxes.file_upload.value ?? ""}\n` + result; - } - if (!result.endsWith("\n")) { result += "\n"; } @@ -27,6 +23,7 @@ export function addCheckboxValuesToInput( return result; } +// TODO: delete this if unused export function activeFileToContextFile(fileInfo: FileInfo): ChatContextFile { const content = fileInfo.content ?? ""; return { From 2d7fc07e53a09ced462ef35971e34962ebb91935 Mon Sep 17 00:00:00 2001 From: Marc McIntosh Date: Thu, 27 Mar 2025 16:20:25 +0100 Subject: [PATCH 2/5] feat: attach files button. --- .../src/components/ChatForm/ChatControls.tsx | 16 +++ .../gui/src/components/ChatForm/ChatForm.tsx | 18 ++- .../src/components/ChatForm/useCheckBoxes.ts | 113 +++++++----------- .../gui/src/components/Dropzone/Dropzone.tsx | 52 +++++--- .../gui/src/components/Dropzone/index.tsx | 2 +- 5 files changed, 108 insertions(+), 93 deletions(-) diff --git a/refact-agent/gui/src/components/ChatForm/ChatControls.tsx b/refact-agent/gui/src/components/ChatForm/ChatControls.tsx index dcb009663..b897ac364 100644 --- a/refact-agent/gui/src/components/ChatForm/ChatControls.tsx +++ b/refact-agent/gui/src/components/ChatForm/ChatControls.tsx @@ -8,6 +8,7 @@ import { Box, Switch, Badge, + Button, } from "@radix-ui/themes"; import { Select } from "../Select"; import { type Config } from "../../features/Config/configSlice"; @@ -36,6 +37,7 @@ import { setToolUse, } from "../../features/Chat/Thread"; import { useAppSelector, useAppDispatch, useCapsForToolUse } from "../../hooks"; +import { useAttachedFiles } from "./useCheckBoxes"; export const ApplyPatchSwitch: React.FC = () => { const dispatch = useAppDispatch(); @@ -223,6 +225,7 @@ export type ChatControlsProps = { ) => void; host: Config["host"]; + attachedFiles: ReturnType; }; const ChatControlCheckBox: React.FC<{ @@ -294,6 +297,7 @@ export const ChatControls: React.FC = ({ checkboxes, onCheckedChange, host, + attachedFiles, }) => { const refs = useTourRefs(); const dispatch = useAppDispatch(); @@ -343,6 +347,18 @@ export const ChatControls: React.FC = ({ ); })} + {host !== "web" && ( + + )} + {showControls && ( = ({ const lastSentCompression = useAppSelector(selectLastSentCompression); const { compressChat, compressChatRequest } = useCompressChat(); const autoFocus = useAutoFocusOnce(); + const attachedFiles = useAttachedFiles(); const shouldAgentCapabilitiesBeShown = useMemo(() => { return threadToolUse === "agent"; @@ -179,10 +180,12 @@ export const ChatForm: React.FC = ({ const handleSubmit = useCallback(() => { const trimmedValue = value.trim(); if (!disableSend && trimmedValue.length > 0) { + const valueWithFiles = attachedFiles.addFilesToInput(trimmedValue); const valueIncludingChecks = addCheckboxValuesToInput( - trimmedValue, + valueWithFiles, checkboxes, ); + // TODO: add @files setLineSelectionInteracted(false); onSubmit(valueIncludingChecks); setValue(() => ""); @@ -191,6 +194,7 @@ export const ChatForm: React.FC = ({ }, [ value, disableSend, + attachedFiles, checkboxes, setLineSelectionInteracted, onSubmit, @@ -415,7 +419,9 @@ export const ChatForm: React.FC = ({ /> )} {config.features?.images !== false && - isMultimodalitySupportedForCurrentModel && } + isMultimodalitySupportedForCurrentModel && ( + + )} {/* TODO: Reserved space for microphone button coming later on */} = ({ - + ); diff --git a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts index 011314bdc..70c6273d8 100644 --- a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts +++ b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts @@ -1,94 +1,61 @@ import { useState, useMemo, useCallback, useEffect } from "react"; import { selectSelectedSnippet } from "../../features/Chat/selectedSnippet"; -import { selectActiveFile } from "../../features/Chat/activeFile"; +import { FileInfo, selectActiveFile } from "../../features/Chat/activeFile"; import { useConfig, useAppSelector } from "../../hooks"; import type { Checkbox } from "./ChatControls"; -import { - selectIsStreaming, - selectMessages, -} from "../../features/Chat/Thread/selectors"; +import { selectMessages } from "../../features/Chat/Thread/selectors"; import { createSelector } from "@reduxjs/toolkit"; -const shouldShowSelector = createSelector( - [selectMessages, selectIsStreaming], - (messages, isStreaming) => { - return messages.length === 0 && !isStreaming; - }, -); - const messageLengthSelector = createSelector( [selectMessages], (messages) => messages.length, ); -// TODO: delete this -const _useAttachActiveFile = ( - interacted: boolean, - hasSnippet: boolean, -): [Checkbox, () => void] => { +export function useAttachedFiles() { + const [files, setFiles] = useState([]); const activeFile = useAppSelector(selectActiveFile); - const shouldShow = useAppSelector(shouldShowSelector); - const messageLength = useAppSelector(messageLengthSelector); - - const filePathWithLines = useMemo(() => { - const hasLines = activeFile.line1 !== null && activeFile.line2 !== null; - - if (!hasLines) return activeFile.path; - return `${activeFile.path}:${ - activeFile.cursor ? activeFile.cursor + 1 : activeFile.line1 - }`; - }, [activeFile.path, activeFile.cursor, activeFile.line1, activeFile.line2]); - - const [attachFileCheckboxData, setAttachFile] = useState({ - name: "file_upload", - checked: !!activeFile.name && messageLength === 0 && hasSnippet, - label: "Attach", - value: filePathWithLines, - disabled: !activeFile.name, - fileName: activeFile.name, - hide: !shouldShow, - info: { - text: "Attaches the current file as context. If the file is large, it prefers the code near the current cursor position. Equivalent to @file name.ext:CURSOR_LINE in the text.", - link: "https://docs.refact.ai/features/ai-chat/", - linkText: "documentation", - }, - }); - useEffect(() => { - if (!interacted) { - setAttachFile((prev) => { - return { - ...prev, - hide: !shouldShow, - value: filePathWithLines, - disabled: !activeFile.name, - fileName: activeFile.name, - // checked: interacted ? prev.checked : !!activeFile.name && shouldShow, - checked: !!activeFile.name && shouldShow && hasSnippet, - }; - }); - } - }, [activeFile.name, filePathWithLines, hasSnippet, interacted, shouldShow]); + const attached = useMemo(() => { + const maybeAttached = files.find((file) => file.path === activeFile.path); + return !!maybeAttached; + }, [activeFile.path, files]); - useEffect(() => { - if (messageLength > 0 && attachFileCheckboxData.hide === false) { - setAttachFile((prev) => { - return { ...prev, hide: true, checked: false }; - }); - } - }, [attachFileCheckboxData.hide, messageLength]); + const addFile = useCallback(() => { + if (attached) return; + setFiles((prev) => { + return [...prev, activeFile]; + }); + }, [attached, activeFile]); - const onToggleAttachFile = useCallback(() => { - setAttachFile((prev) => { - return { - ...prev, - checked: !prev.checked, - }; + const removeFile = useCallback((fileToRemove: FileInfo) => { + setFiles((prev) => { + return prev.filter((file) => file.path !== fileToRemove.path); }); }, []); - return [attachFileCheckboxData, onToggleAttachFile]; -}; + const addFilesToInput = useCallback( + (str: string) => { + if (files.length === 0) return str; + const result = files.reduce((acc, file) => { + const hasLines = file.line1 !== null && file.line2 !== null; + if (!hasLines) return `@file ${file.path}\n${acc}`; + const line = file.cursor ? file.cursor + 1 : file.line1; + return `@file ${file.path}:${line}\n${acc}`; + }, str); + return result; + }, + [files], + ); + + return { + files, + activeFile, + addFile, + removeFile, + attached, + addFilesToInput, + }; +} const useAttachSelectedSnippet = ( interacted: boolean, diff --git a/refact-agent/gui/src/components/Dropzone/Dropzone.tsx b/refact-agent/gui/src/components/Dropzone/Dropzone.tsx index 73168cc87..eeb28868f 100644 --- a/refact-agent/gui/src/components/Dropzone/Dropzone.tsx +++ b/refact-agent/gui/src/components/Dropzone/Dropzone.tsx @@ -6,6 +6,7 @@ import { useAttachedImages } from "../../hooks/useAttachedImages"; import { TruncateLeft } from "../Text"; import { telemetryApi } from "../../services/refact/telemetry"; import { useCapsForToolUse } from "../../hooks"; +import { useAttachedFiles } from "../ChatForm/useCheckBoxes"; export const FileUploadContext = createContext<{ open: () => void; @@ -77,7 +78,7 @@ export const DropzoneProvider: React.FC< export const DropzoneConsumer = FileUploadContext.Consumer; -export const AttachFileButton = () => { +export const AttachImagesButton = () => { const [sendTelemetryEvent] = telemetryApi.useLazySendTelemetryChatEventQuery(); const attachFileOnClick = useCallback( @@ -121,29 +122,52 @@ export const AttachFileButton = () => { ); }; -export const FileList = () => { +type FileListProps = { + attachedFiles: ReturnType; +}; +export const FileList: React.FC = ({ attachedFiles }) => { const { images, removeImage } = useAttachedImages(); - if (images.length === 0) return null; + if (images.length === 0 && attachedFiles.files.length === 0) return null; return ( {images.map((file, index) => { const key = `image-${file.name}-${index}`; return ( - + fileName={file.name} + /> + ); + })} + {attachedFiles.files.map((file, index) => { + const key = `file-${file.path}-${index}`; + return ( + attachedFiles.removeFile(file)} + /> ); })} ); }; + +const FileButton: React.FC<{ fileName: string; onClick: () => void }> = ({ + fileName, + onClick, +}) => { + return ( + + ); +}; diff --git a/refact-agent/gui/src/components/Dropzone/index.tsx b/refact-agent/gui/src/components/Dropzone/index.tsx index 164bf09b8..03debddab 100644 --- a/refact-agent/gui/src/components/Dropzone/index.tsx +++ b/refact-agent/gui/src/components/Dropzone/index.tsx @@ -2,6 +2,6 @@ export { DropzoneProvider, DropzoneConsumer, FileUploadContext, - AttachFileButton, + AttachImagesButton, FileList, } from "./Dropzone"; From 491db2b2a5ce75c16f0393111f320b3c1d2cb990 Mon Sep 17 00:00:00 2001 From: Marc McIntosh Date: Thu, 27 Mar 2025 16:26:32 +0100 Subject: [PATCH 3/5] test: active file is no longer attached by default. --- refact-agent/gui/src/components/ChatForm/ChatForm.test.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/refact-agent/gui/src/components/ChatForm/ChatForm.test.tsx b/refact-agent/gui/src/components/ChatForm/ChatForm.test.tsx index 5cc1a32eb..6e47cdcb7 100644 --- a/refact-agent/gui/src/components/ChatForm/ChatForm.test.tsx +++ b/refact-agent/gui/src/components/ChatForm/ChatForm.test.tsx @@ -115,11 +115,7 @@ describe("ChatForm", () => { await user.type(textarea, "foo"); await user.keyboard("{Enter}"); const markdown = "```python\nprint(1)\n```\n"; - const cursor = app.store.getState().active_file.cursor; - - const expected = `@file foo.txt:${ - cursor ? cursor + 1 : 1 - }\n${markdown}\nfoo\n`; + const expected = `${markdown}\nfoo\n`; expect(fakeOnSubmit).toHaveBeenCalledWith(expected); }); From f908c4d63793057d22ae6b62a2c1997966750f77 Mon Sep 17 00:00:00 2001 From: Marc McIntosh Date: Fri, 28 Mar 2025 17:16:22 +0100 Subject: [PATCH 4/5] add an event for the ide to attach a file to chat. --- .../src/components/ChatForm/useCheckBoxes.ts | 33 +++++++++++++++++++ refact-agent/gui/src/events/index.ts | 2 ++ refact-agent/gui/src/hooks/index.ts | 1 + .../gui/src/hooks/useEventBusForApp.ts | 3 ++ 4 files changed, 39 insertions(+) diff --git a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts index 70c6273d8..2ec744f1c 100644 --- a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts +++ b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts @@ -5,12 +5,16 @@ import { useConfig, useAppSelector } from "../../hooks"; import type { Checkbox } from "./ChatControls"; import { selectMessages } from "../../features/Chat/Thread/selectors"; import { createSelector } from "@reduxjs/toolkit"; +import { filename } from "../../utils"; +import { ideAttachFileToChat } from "../../hooks"; const messageLengthSelector = createSelector( [selectMessages], (messages) => messages.length, ); +// TODO: add ide event here. + export function useAttachedFiles() { const [files, setFiles] = useState([]); const activeFile = useAppSelector(selectActiveFile); @@ -47,6 +51,35 @@ export function useAttachedFiles() { [files], ); + useEffect(() => { + const handleIdeAttachFile = (filePath: string) => { + const fileInfo: FileInfo = { + name: filename(filePath), + path: filePath, + line1: null, + line2: null, + cursor: null, + can_paste: false, + }; + setFiles((prev) => { + const maybeEntered = prev.find((file) => file.path === filePath); + if (maybeEntered) return prev; + return [...prev, fileInfo]; + }); + }; + + const listener = (event: MessageEvent) => { + if (ideAttachFileToChat.match(event.data)) { + handleIdeAttachFile(event.data.payload); + } + }; + + window.addEventListener("message", listener); + return () => { + window.removeEventListener("message", listener); + }; + }, []); + return { files, activeFile, diff --git a/refact-agent/gui/src/events/index.ts b/refact-agent/gui/src/events/index.ts index dc897daa9..b6f987208 100644 --- a/refact-agent/gui/src/events/index.ts +++ b/refact-agent/gui/src/events/index.ts @@ -78,6 +78,8 @@ export { ideToolCallResponse, } from "../hooks/useEventBusForIDE"; +export { ideAttachFileToChat } from "../hooks/useEventBusForApp"; + export const fim = { request, ready, diff --git a/refact-agent/gui/src/hooks/index.ts b/refact-agent/gui/src/hooks/index.ts index 6dfb21e34..28be44bc3 100644 --- a/refact-agent/gui/src/hooks/index.ts +++ b/refact-agent/gui/src/hooks/index.ts @@ -35,3 +35,4 @@ export * from "./useCompressChat"; export * from "./useAutoFocusOnce"; export * from "./useHideScroll"; export * from "./useCompressionStop"; +export * from "./useEventBusForApp"; diff --git a/refact-agent/gui/src/hooks/useEventBusForApp.ts b/refact-agent/gui/src/hooks/useEventBusForApp.ts index 51738a162..269201c55 100644 --- a/refact-agent/gui/src/hooks/useEventBusForApp.ts +++ b/refact-agent/gui/src/hooks/useEventBusForApp.ts @@ -13,6 +13,9 @@ import { selectPages, } from "../features/Pages/pagesSlice"; import { ideToolCallResponse } from "./useEventBusForIDE"; +import { createAction } from "@reduxjs/toolkit/react"; + +export const ideAttachFileToChat = createAction("ide/attachFileToChat"); export function useEventBusForApp() { const config = useConfig(); From 9e4152ff05dce5c2b1a4bd0c7993da96f66547e3 Mon Sep 17 00:00:00 2001 From: Marc McIntosh Date: Fri, 28 Mar 2025 18:24:36 +0100 Subject: [PATCH 5/5] fix: remove attached files after submit. --- refact-agent/gui/src/components/ChatForm/ChatForm.tsx | 1 + refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/refact-agent/gui/src/components/ChatForm/ChatForm.tsx b/refact-agent/gui/src/components/ChatForm/ChatForm.tsx index d53d631ee..11e048ee0 100644 --- a/refact-agent/gui/src/components/ChatForm/ChatForm.tsx +++ b/refact-agent/gui/src/components/ChatForm/ChatForm.tsx @@ -190,6 +190,7 @@ export const ChatForm: React.FC = ({ onSubmit(valueIncludingChecks); setValue(() => ""); unCheckAll(); + attachedFiles.removeAll(); } }, [ value, diff --git a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts index 2ec744f1c..7727c0e99 100644 --- a/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts +++ b/refact-agent/gui/src/components/ChatForm/useCheckBoxes.ts @@ -51,6 +51,10 @@ export function useAttachedFiles() { [files], ); + const removeAll = useCallback(() => { + setFiles([]); + }, []); + useEffect(() => { const handleIdeAttachFile = (filePath: string) => { const fileInfo: FileInfo = { @@ -87,6 +91,7 @@ export function useAttachedFiles() { removeFile, attached, addFilesToInput, + removeAll, }; }