22<script setup lang="ts">
33import type { Doc , Id } from ' backend-convex/convex/_generated/dataModel'
44import type Lenis from ' lenis'
5- import { keyBy , randomStr , sleep , uniquePromise } from ' @namesmt/utils'
5+ import { keyBy , sleep , uniquePromise } from ' @namesmt/utils'
66import { api } from ' backend-convex/convex/_generated/api'
77import { useConvexClient } from ' convex-vue'
88import { countdown } from ' kontroll'
@@ -107,16 +107,20 @@ async function handleSubmit({ input, confirmMultiStream = false }: HandleSubmitA
107107
108108 chatInput .value = ' '
109109
110- doScrollBottom ()
110+ nextTick (() => { doScrollBottom () } )
111111
112112 // Create new thread
113113 if (! threadIdRef .value ) {
114+ // Set lockerKey to maintain permission if user is anonymous
115+ const lockerKey = $auth .loggedIn ? undefined : getRandomLockerKey ()
114116 const newThread = await createNewThread (convex , {
115117 title: userInput ,
116- // Set lockerKey to maintain permission if user is anonymous
117- lockerKey: $auth .loggedIn ? undefined : randomStr (32 ),
118+ lockerKey ,
118119 })
119120 ignorePathUpdate (() => { threadIdRef .value = newThread })
121+
122+ // Asynchronously generates a new initial thread title
123+ generateThreadTitle (convex , { threadId: newThread , lockerKey })
120124 }
121125
122126 await streamToMessage ({ message: messages .value [messages .value .length - 1 ]! , content: userInput })
@@ -137,16 +141,22 @@ async function resumeStreamProcess(streamSessionId: string, messageId: string) {
137141interface PollToMessageArgs {
138142 message: CustomMessage
139143 resumeStreamId: string
144+ threadId? : string
140145}
141- async function pollToMessage({ message , resumeStreamId }: PollToMessageArgs ) {
146+ async function pollToMessage({ message , resumeStreamId , threadId = threadIdRef .value }: PollToMessageArgs ) {
147+ if (threadId && threadId !== threadIdRef .value ) {
148+ console .warn (' User changed thread, poll stopped.' )
149+ return
150+ }
151+
142152 const messageId = message .id as Id <' messages' >
143153
144154 const messageFromConvex = await convex .query (api .messages .get , { messageId: messageId as Id <' messages' > })
145155 Object .assign (message , customMessageTransform (messageFromConvex ))
146156
147157 if (message .isStreaming ) {
148158 sleep (400 )
149- .then (() => { pollToMessage ({ message , resumeStreamId }) })
159+ .then (() => { pollToMessage ({ message , resumeStreamId , threadId }) })
150160 }
151161 else {
152162 console .log (' Poll completed' )
@@ -164,21 +174,24 @@ async function streamToMessage({ message, content, resumeStreamId }: StreamToMes
164174 try {
165175 ++ streamingMessages .value
166176
177+ const currentThreadId = threadIdRef .value
178+ const abortController = new AbortController ()
167179 const response = await fetch (` ${convexApiUrl }/api/ai/chat/stream ` , {
168180 method: ' POST' ,
169181 headers: {
170182 ' Content-Type' : ' application/json' ,
171183 ' Authorization' : ` Bearer ${$auth .token } ` ,
172184 },
173185 body: JSON .stringify ({
174- threadId: threadIdRef . value ,
186+ threadId: currentThreadId ,
175187 provider: ' openrouter' ,
176188 model: ' deepseek/deepseek-chat:free' ,
177189 apiKey: ' dummy' ,
178190 content ,
179191 resumeStreamId ,
180192 // lockerKey: undefined,
181193 }),
194+ signal: abortController .signal ,
182195 })
183196
184197 if (! response .ok ) {
@@ -196,6 +209,12 @@ async function streamToMessage({ message, content, resumeStreamId }: StreamToMes
196209 message .isStreaming = true
197210
198211 while (true ) {
212+ if (currentThreadId !== threadIdRef .value ) {
213+ console .warn (' User changed thread, stopping stream...' )
214+ abortController .abort ()
215+ break
216+ }
217+
199218 const { done, value } = await reader .read ()
200219 if (done )
201220 break
@@ -299,7 +318,7 @@ function alertIsStreaming(input: string) {
299318
300319 <div
301320 v-if =" !messages.length"
302- class =" relative z-2 whitespace-pre-wrap px-2 text-center text-5xl text-gray-400 font-medium tracking-tighter dark:text-gray-500 dark:text-white"
321+ class =" relative z-2 whitespace-pre-wrap px-2 text-center text-4xl text-gray-400 font-medium tracking-tighter dark:text-gray-500 dark:text-white"
303322 >
304323 <p >
305324 {{ threadIdRef ? $t('chat.interface.sendToStart') : $t('chat.interface.selectOrStart') }}
0 commit comments