fix(frontend): wait for async chat submit before clearing (#2940)

* fix(frontend): wait for async chat submit before clearing

* test(frontend): cover pending attachment uploads

* fix(frontend): preserve sync submit semantics
This commit is contained in:
Admire
2026-05-15 22:27:10 +08:00
committed by GitHub
parent 7a2670eaea
commit 7c42ab3e16
5 changed files with 120 additions and 17 deletions
@@ -110,6 +110,7 @@ export function InputBox({
threadId,
initialValue,
onContextChange,
onFollowupsVisibilityChange,
onSubmit,
onStop,
...props
@@ -142,7 +143,8 @@ export function InputBox({
reasoning_effort?: "minimal" | "low" | "medium" | "high";
},
) => void;
onSubmit?: (message: PromptInputMessage) => void;
onFollowupsVisibilityChange?: (visible: boolean) => void;
onSubmit?: (message: PromptInputMessage) => void | Promise<void>;
onStop?: () => void;
}) {
const { t } = useI18n();
@@ -251,12 +253,12 @@ export function InputBox({
);
const handleSubmit = useCallback(
async (message: PromptInputMessage) => {
(message: PromptInputMessage) => {
if (status === "streaming") {
onStop?.();
return;
}
if (!message.text) {
if (!message.text.trim() && message.files.length === 0) {
return;
}
setFollowups([]);
@@ -274,11 +276,14 @@ export function InputBox({
selectedModel?.supports_thinking ?? false,
),
});
setTimeout(() => onSubmit?.(message), 0);
return;
return new Promise<void>((resolve, reject) => {
setTimeout(() => {
Promise.resolve(onSubmit?.(message)).then(resolve).catch(reject);
}, 0);
});
}
onSubmit?.(message);
return onSubmit?.(message);
},
[
context,
@@ -348,6 +353,14 @@ export function InputBox({
!followupsHidden &&
(followupsLoading || followups.length > 0);
useEffect(() => {
onFollowupsVisibilityChange?.(showFollowups);
}, [onFollowupsVisibilityChange, showFollowups]);
useEffect(() => {
return () => onFollowupsVisibilityChange?.(false);
}, [onFollowupsVisibilityChange]);
useEffect(() => {
messagesRef.current = thread.messages;
}, [thread.messages]);