fix(chat): pin existing-session sends to captured target (#2424)

* fix(chat): pin sends to captured session

* fix(chat): handle runtime cancellation consistently
This commit is contained in:
Wsyjq
2026-08-07 00:46:21 +03:00
committed by GitHub
parent 834d2edb87
commit 70226149ce
10 changed files with 222 additions and 31 deletions
+26 -10
View File
@@ -936,10 +936,18 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
setPrPickerOpen(true);
}, []);
const getSubmitErrorMessage = (error: unknown, fallback: string) => {
const message = error instanceof Error ? error.message : '';
return message.toLowerCase().includes('runtime changed')
? t('chat.chatInput.toast.messageSendFailed')
: message || fallback;
};
const handleSubmit = async (options?: SubmitOptions) => {
const queuedOnly = options?.queuedOnly ?? false;
const queuedMessageId = options?.queuedMessageId;
const delivery = options?.delivery === 'steer' && sessionPhase !== 'idle' ? 'steer' : undefined;
const capturedTarget = messageQueueTarget;
const inputSnapshot = options?.presetText != null
? {
message: options.presetText,
@@ -1012,7 +1020,9 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
}
}
const sendMessageOptions = delivery ? { delivery } : undefined;
const sendMessageOptions = capturedTarget
? { target: capturedTarget, ...(delivery ? { delivery } : {}) }
: delivery ? { delivery } : undefined;
// Inline review comments and synthetic context are consumed before
// assembly so a failed send can restore exactly what it took.
@@ -1058,10 +1068,10 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
if (outgoing.isEmpty) return;
// Clear queue and input
if (messageQueueTarget && queuedMessageId) {
removeFromQueue(messageQueueTarget, queuedMessageId);
} else if (messageQueueTarget && hasQueuedMessages) {
clearQueue(messageQueueTarget);
if (capturedTarget && queuedMessageId) {
removeFromQueue(capturedTarget, queuedMessageId);
} else if (capturedTarget && hasQueuedMessages) {
clearQueue(capturedTarget);
}
if (!queuedOnly) {
setMessage('');
@@ -1111,7 +1121,7 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
const compactDirectory = useSessionUIStore.getState().getDirectoryForSession(currentSessionId) || currentDirectory || undefined;
await opencodeClient.summarizeSession(currentSessionId, currentProviderId, currentModelId, compactDirectory);
} catch (error) {
toast.error(error instanceof Error ? error.message : t('chat.chatInput.toast.compactFailed'));
toast.error(getSubmitErrorMessage(error, t('chat.chatInput.toast.compactFailed')));
}
return;
}
@@ -1143,15 +1153,13 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
);
scrollToBottom?.();
} catch (error) {
toast.error(error instanceof Error ? error.message : t(command.errorToastKey));
toast.error(getSubmitErrorMessage(error, t(command.errorToastKey)));
}
return;
}
}
const currentSessionDirectory = currentSessionId
? useSessionUIStore.getState().getDirectoryForSession(currentSessionId) || currentDirectory
: currentDirectory;
const currentSessionDirectory = capturedTarget?.directory ?? currentDirectory;
const shouldAddResponseStyle = newSessionDraftOpen || (currentSessionId ? !hasUserMessages(currentSessionId, currentSessionDirectory) : false);
if (shouldAddResponseStyle) {
const responseStyleInstruction = await fetchResponseStyleInstruction().catch(() => null);
@@ -1258,6 +1266,14 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
return;
}
if (normalized.includes('runtime changed')) {
if (allAttachments.length > 0) {
useInputStore.getState().setAttachedFiles(allAttachments);
}
toast.error(t('chat.chatInput.toast.messageSendFailed'));
return;
}
if (allAttachments.length > 0) {
useInputStore.getState().setAttachedFiles(allAttachments);
}