fix(chat): send preset starters directly instead of staging them in the composer

Starter chips route their text into the submit as an explicit override;
the previous flow staged it in the textarea, which doesn't exist while
the mobile composer is collapsed into the pill, so the submit read an
empty snapshot and silently bailed, leaving the command text sitting in
the input.
This commit is contained in:
Bohdan Triapitsyn
2026-07-05 02:32:40 +03:00
parent 743f3fbdb5
commit da78de3a21
+14 -7
View File
@@ -1749,6 +1749,10 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
queuedOnly?: boolean; queuedOnly?: boolean;
queuedMessageId?: string; queuedMessageId?: string;
delivery?: 'steer'; delivery?: 'steer';
/** Submit this text instead of the composer input. Used by preset
starter chips: on mobile the collapsed pill has no mounted textarea,
so the DOM-first input snapshot would read empty content. */
presetText?: string;
}; };
const handleSubmitRef = React.useRef<(options?: SubmitOptions) => Promise<void>>(async () => {}); const handleSubmitRef = React.useRef<(options?: SubmitOptions) => Promise<void>>(async () => {});
@@ -1822,7 +1826,12 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
const queuedOnly = options?.queuedOnly ?? false; const queuedOnly = options?.queuedOnly ?? false;
const queuedMessageId = options?.queuedMessageId; const queuedMessageId = options?.queuedMessageId;
const delivery = options?.delivery === 'steer' && sessionPhase !== 'idle' ? 'steer' : undefined; const delivery = options?.delivery === 'steer' && sessionPhase !== 'idle' ? 'steer' : undefined;
const inputSnapshot = getCurrentInputSnapshot(); const inputSnapshot = options?.presetText != null
? {
message: options.presetText,
hasContent: options.presetText.trim().length > 0 || sendableAttachedFiles.length > 0 || hasDrafts,
}
: getCurrentInputSnapshot();
const queuedMessagesToSend = queuedMessageId const queuedMessagesToSend = queuedMessageId
? queuedMessages.filter((message) => message.id === queuedMessageId) ? queuedMessages.filter((message) => message.id === queuedMessageId)
: queuedMessages; : queuedMessages;
@@ -2360,12 +2369,10 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
// getCurrentInputSnapshot reads textareaRef.current.value first, so setting it // getCurrentInputSnapshot reads textareaRef.current.value first, so setting it
// synchronously lets handleSubmit pick up the preset text in the same tick. // synchronously lets handleSubmit pick up the preset text in the same tick.
const submitPresetPrompt = React.useCallback((text: string) => { const submitPresetPrompt = React.useCallback((text: string) => {
const textarea = textareaRef.current; // The text goes straight into the submit (see SubmitOptions.presetText)
if (textarea) { // instead of through the composer input — the collapsed mobile pill has
textarea.value = text; // no mounted textarea to stage it in.
} void handleSubmitRef.current({ presetText: text });
setMessage(text);
void handleSubmitRef.current();
}, []); }, []);
// Dictation: insert the transcript inline; optionally submit immediately. // Dictation: insert the transcript inline; optionally submit immediately.