From 2bbcc86d315b9f4aae50224ff88809a39ad65476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9F=8E=E5=9F=8E?= Date: Fri, 23 Jan 2026 09:31:43 +0800 Subject: [PATCH 1/2] fix: cannot use custom prompts --- src/App.tsx | 9 +--- .../features/Assistant/PromptTabContent.tsx | 24 +++++---- src/services/AssistantService.ts | 51 ++++--------------- 3 files changed, 27 insertions(+), 57 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index add89e01d..b8f960c8a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,13 +1,12 @@ import '@/i18n' import 'react-native-reanimated' -import { DATABASE_NAME, db, expoDb } from '@db' +import { db, expoDb } from '@db' import { DarkTheme, DefaultTheme, NavigationContainer } from '@react-navigation/native' import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator' import { useDrizzleStudio } from 'expo-drizzle-studio-plugin' import { useFonts } from 'expo-font' import * as SplashScreen from 'expo-splash-screen' -import { SQLiteProvider } from 'expo-sqlite' import { HeroUINativeProvider } from 'heroui-native' import React, { Suspense, useEffect } from 'react' import { ActivityIndicator } from 'react-native' @@ -138,11 +137,7 @@ export default function App() { return ( - }> - - - - + ) diff --git a/src/componentsV2/features/Assistant/PromptTabContent.tsx b/src/componentsV2/features/Assistant/PromptTabContent.tsx index 305ad6256..5cf7c17ce 100644 --- a/src/componentsV2/features/Assistant/PromptTabContent.tsx +++ b/src/componentsV2/features/Assistant/PromptTabContent.tsx @@ -1,6 +1,7 @@ import { MotiView } from 'moti' import React, { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' +import { Pressable } from 'react-native' import { KeyboardAvoidingView } from 'react-native-keyboard-controller' import TextField from '@/componentsV2/base/TextField' @@ -69,7 +70,8 @@ export function PromptTabContent({ assistant, updateAssistant }: PromptTabConten {t('common.prompt')} - { presentPromptDetailSheet( formData.prompt, @@ -81,15 +83,17 @@ export function PromptTabContent({ assistant, updateAssistant }: PromptTabConten } } ) - }} - editable={false} - className="flex-1 rounded-lg px-3 py-3 text-sm" - placeholder={t('common.prompt')} - multiline - numberOfLines={20} - textAlignVertical="top" - value={formData.prompt} - /> + }}> + + diff --git a/src/services/AssistantService.ts b/src/services/AssistantService.ts index 21cb49ba4..3a54d3d9b 100644 --- a/src/services/AssistantService.ts +++ b/src/services/AssistantService.ts @@ -602,18 +602,12 @@ export class AssistantService { } /** - * Perform optimistic assistant update with rollback on failure + * Perform assistant update with database-first approach + * + * Sequence: Database Transaction → Cache Update → Notify Subscribers + * This prevents race conditions with dual database connections */ private async performAssistantUpdate(assistantId: string, updates: Partial>): Promise { - // Save old data for rollback - const oldSystemAssistant = this.systemAssistantsCache.get(assistantId) - ? { ...this.systemAssistantsCache.get(assistantId)! } - : null - const oldLRUAssistant = this.assistantCache.get(assistantId) ? { ...this.assistantCache.get(assistantId)! } : null - const oldAllAssistant = this.allAssistantsCache.get(assistantId) - ? { ...this.allAssistantsCache.get(assistantId)! } - : null - try { // Fetch current assistant data let currentAssistantData: Assistant @@ -639,44 +633,21 @@ export class AssistantService { id: assistantId } - // Optimistic update: update all caches + // Persist to database FIRST (before any cache updates or notifications) + await assistantDatabase.upsertAssistants([updatedAssistant]) + + // Update caches after successful database operation this.updateAssistantInCache(assistantId, updatedAssistant) - // Notify subscribers (UI updates immediately) + // Notify subscribers after database and cache are in sync this.notifyAssistantSubscribers(assistantId) - - // Persist to database - await assistantDatabase.upsertAssistants([updatedAssistant]) - - // Notify other subscribers this.notifyGlobalSubscribers() this.notifyAllAssistantsSubscribers() logger.debug(`Assistant updated successfully: ${assistantId}`) } catch (error) { - // Rollback on failure - logger.error('Failed to update assistant, rolling back:', error as Error) - - if (oldSystemAssistant) { - this.systemAssistantsCache.set(assistantId, oldSystemAssistant) - } else { - this.systemAssistantsCache.delete(assistantId) - } - - if (oldLRUAssistant) { - this.assistantCache.set(assistantId, oldLRUAssistant) - } else { - this.assistantCache.delete(assistantId) - } - - if (oldAllAssistant) { - this.allAssistantsCache.set(assistantId, oldAllAssistant) - } else { - this.allAssistantsCache.delete(assistantId) - } - - this.notifyAssistantSubscribers(assistantId) - + // No rollback needed since we didn't update caches before transaction + logger.error('Failed to update assistant:', error as Error) throw error } } From 63c7fd4fcb8a1de3b387cf3ce36b38f6dd3a1ca7 Mon Sep 17 00:00:00 2001 From: Pleasurecruise <3196812536@qq.com> Date: Sat, 24 Jan 2026 00:49:50 +0000 Subject: [PATCH 2/2] fix: set pointerEvents to 'none' on prompt input Added pointerEvents="none" to the TextField.Input component to ensure it does not respond to pointer events when editable is set to false. --- src/componentsV2/features/Assistant/PromptTabContent.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/componentsV2/features/Assistant/PromptTabContent.tsx b/src/componentsV2/features/Assistant/PromptTabContent.tsx index 5cf7c17ce..df2e077fc 100644 --- a/src/componentsV2/features/Assistant/PromptTabContent.tsx +++ b/src/componentsV2/features/Assistant/PromptTabContent.tsx @@ -86,6 +86,7 @@ export function PromptTabContent({ assistant, updateAssistant }: PromptTabConten }}>