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;
queuedMessageId?: string;
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 () => {});
@@ -1822,7 +1826,12 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
const queuedOnly = options?.queuedOnly ?? false;
const queuedMessageId = options?.queuedMessageId;
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
? queuedMessages.filter((message) => message.id === queuedMessageId)
: queuedMessages;
@@ -2360,12 +2369,10 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
// getCurrentInputSnapshot reads textareaRef.current.value first, so setting it
// synchronously lets handleSubmit pick up the preset text in the same tick.
const submitPresetPrompt = React.useCallback((text: string) => {
const textarea = textareaRef.current;
if (textarea) {
textarea.value = text;
}
setMessage(text);
void handleSubmitRef.current();
// The text goes straight into the submit (see SubmitOptions.presetText)
// instead of through the composer input — the collapsed mobile pill has
// no mounted textarea to stage it in.
void handleSubmitRef.current({ presetText: text });
}, []);
// Dictation: insert the transcript inline; optionally submit immediately.