Skip to content

Commit 77759e2

Browse files
committed
fix: prevent first PDF send foreign key race
1 parent db3d768 commit 77759e2

3 files changed

Lines changed: 50 additions & 19 deletions

File tree

components/chat-screen/ChatBar.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ interface Props {
3939
userInput: string,
4040
imagePath?: string,
4141
attachments?: Attachment[]
42-
) => void;
42+
) => void | Promise<void>;
4343
onSelectModel: () => void;
4444
onSelectPrompt: (prompt: string) => void;
4545
ref: Ref<{
@@ -142,7 +142,7 @@ const ChatBar = ({
142142
onBarGrow?.();
143143
}
144144
},
145-
[extraContentPadding, onHeightChange, hasMessages]
145+
[extraContentPadding, onHeightChange, onBarGrow, hasMessages]
146146
);
147147

148148
const {
@@ -169,8 +169,17 @@ const ChatBar = ({
169169

170170
const handleSend = useCallback(() => {
171171
if (hasLoadingAttachment) return;
172-
onSend(userInput, imageAttachment?.uri, attachments);
173-
clearAll();
172+
const attachmentsToSend = attachments;
173+
const imageUriToSend = imageAttachment?.uri;
174+
const inputToSend = userInput;
175+
176+
setUserInput('');
177+
clearAll({ cleanupSources: false });
178+
Promise.resolve(
179+
onSend(inputToSend, imageUriToSend, attachmentsToSend)
180+
).catch((error) => {
181+
console.error('Failed to send message:', error);
182+
});
174183
}, [
175184
onSend,
176185
userInput,
@@ -235,8 +244,14 @@ const ChatBar = ({
235244
const handleSubmit = (transcript: string) => {
236245
setShowSpeechInput(false);
237246
if (transcript) {
238-
onSend(transcript, imageAttachment?.uri, attachments);
239-
clearAll();
247+
const attachmentsToSend = attachments;
248+
const imageUriToSend = imageAttachment?.uri;
249+
clearAll({ cleanupSources: false });
250+
Promise.resolve(
251+
onSend(transcript, imageUriToSend, attachmentsToSend)
252+
).catch((error) => {
253+
console.error('Failed to send transcript:', error);
254+
});
240255
}
241256
};
242257

components/chat-screen/ChatScreen.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Keyboard, StyleSheet, useWindowDimensions, View } from 'react-native';
99
import { LinearGradient } from 'expo-linear-gradient';
1010
import { BottomSheetModal } from '@gorhom/bottom-sheet';
1111
import { KeyboardStickyView } from 'react-native-keyboard-controller';
12+
import { router } from 'expo-router';
1213
import Animated, {
1314
useAnimatedStyle,
1415
useSharedValue,
@@ -94,6 +95,7 @@ export default function ChatScreen({
9495
isGenerating,
9596
sendChatMessage,
9697
loadModel,
98+
setActiveChatId,
9799
model: loadedModel,
98100
} = useLLMStore();
99101
const { getModelById } = useModelStore();
@@ -153,14 +155,21 @@ export default function ChatScreen({
153155
const hasDocuments = attachments?.some((a) => a.type === 'document');
154156
if ((!userInput.trim() && !imagePath && !hasDocuments) || isGenerating)
155157
return;
156-
if (!(await checkIfChatExists(db, chatId!))) {
158+
159+
let targetChatId = chatId!;
160+
if (!(await checkIfChatExists(db, targetChatId))) {
157161
const docName = attachments?.find((a) => a.type === 'document')?.name;
158162
const titleSource = userInput.trim() || docName || 'New chat';
159163
const newChatTitle =
160164
titleSource.length > 25
161165
? titleSource.slice(0, 25) + '...'
162166
: titleSource;
163-
await addChat(newChatTitle, model!.id);
167+
const newChatId = await addChat(newChatTitle, model!.id);
168+
if (!newChatId) return;
169+
170+
targetChatId = newChatId;
171+
await setActiveChatId(targetChatId);
172+
router.replace(`/chat/${targetChatId}`);
164173
}
165174

166175
let persistedImagePath: string | undefined = imagePath;
@@ -177,9 +186,8 @@ export default function ChatScreen({
177186
}
178187
}
179188

180-
inputRef.current?.clear();
181189
Keyboard.dismiss();
182-
updateLastUsed(chatId!);
190+
updateLastUsed(targetChatId);
183191

184192
// Notify Messages that a send is in flight. It will seed blankSpace to
185193
// the full container height, then derive the final value from measured
@@ -221,7 +229,7 @@ export default function ChatScreen({
221229
// Enable new sources for this chat (persists for future messages)
222230
for (const sourceId of attachmentSourceIds) {
223231
if (!enabledSources.includes(sourceId)) {
224-
await enableSource(chatId!, sourceId);
232+
await enableSource(targetChatId, sourceId);
225233
}
226234
}
227235

@@ -239,7 +247,7 @@ export default function ChatScreen({
239247
.join(', ') || undefined;
240248
await sendChatMessage(
241249
userInput,
242-
chatId!,
250+
targetChatId,
243251
context,
244252
settings,
245253
persistedImagePath,

hooks/useAttachment.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export interface Attachment {
1616
sourceId?: number;
1717
}
1818

19+
interface ClearAllOptions {
20+
cleanupSources?: boolean;
21+
}
22+
1923
const requestAndroidGalleryPermission = async (): Promise<boolean> => {
2024
if (Platform.OS !== 'android') return true;
2125

@@ -175,13 +179,17 @@ export const useAttachment = () => {
175179
[vectorStore]
176180
);
177181

178-
const clearAll = useCallback(() => {
179-
const hadDocuments = attachmentsRef.current.some((a) => a.sourceId);
180-
setAttachments([]);
181-
if (hadDocuments && vectorStore) {
182-
useSourceStore.getState().cleanupOrphanedSources(vectorStore);
183-
}
184-
}, [vectorStore]);
182+
const clearAll = useCallback(
183+
(options: ClearAllOptions = {}) => {
184+
const cleanupSources = options.cleanupSources ?? true;
185+
const hadDocuments = attachmentsRef.current.some((a) => a.sourceId);
186+
setAttachments([]);
187+
if (cleanupSources && hadDocuments && vectorStore) {
188+
useSourceStore.getState().cleanupOrphanedSources(vectorStore);
189+
}
190+
},
191+
[vectorStore]
192+
);
185193

186194
const openSheet = useCallback(() => {
187195
sheetRef.current?.present();

0 commit comments

Comments
 (0)