11import { message } from "@tauri-apps/plugin-dialog" ;
2- import { useRef , useState } from "react" ;
2+ import { useCallback , useEffect , useRef , useState } from "react" ;
33
44import { useLicense } from "@/hooks/use-license" ;
55import { commands as analyticsCommands } from "@hypr/plugin-analytics" ;
@@ -56,10 +56,25 @@ export function useChatLogic({
5656 const [ isGenerating , setIsGenerating ] = useState ( false ) ;
5757 const [ isStreamingText , setIsStreamingText ] = useState ( false ) ;
5858 const isGeneratingRef = useRef ( false ) ;
59+ const abortControllerRef = useRef < AbortController | null > ( null ) ;
5960 const sessions = useSessions ( ( state ) => state . sessions ) ;
6061 const { getLicense } = useLicense ( ) ;
6162 const queryClient = useQueryClient ( ) ;
6263
64+ // Reset generation state and abort ongoing streams when session changes
65+ useEffect ( ( ) => {
66+ // Abort any ongoing generation when session changes
67+ if ( abortControllerRef . current ) {
68+ abortControllerRef . current . abort ( ) ;
69+ abortControllerRef . current = null ;
70+ }
71+
72+ // Reset generation state for new session
73+ setIsGenerating ( false ) ;
74+ setIsStreamingText ( false ) ;
75+ isGeneratingRef . current = false ;
76+ } , [ sessionId ] ) ;
77+
6378 const handleApplyMarkdown = async ( markdownContent : string ) => {
6479 if ( ! sessionId ) {
6580 console . error ( "No session ID available" ) ;
@@ -92,14 +107,14 @@ export function useChatLogic({
92107
93108 const userMessageCount = messages . filter ( msg => msg . isUser ) . length ;
94109
95- if ( userMessageCount >= 3 && ! getLicense . data ?. valid ) {
110+ if ( userMessageCount >= 4 && ! getLicense . data ?. valid ) {
96111 if ( userId ) {
97112 await analyticsCommands . event ( {
98113 event : "pro_license_required_chat" ,
99114 distinct_id : userId ,
100115 } ) ;
101116 }
102- await message ( "3 messages are allowed per conversation for free users." , {
117+ await message ( "4 messages are allowed per conversation for free users." , {
103118 title : "Pro License Required" ,
104119 kind : "info" ,
105120 } ) ;
@@ -266,6 +281,9 @@ export function useChatLogic({
266281 } ,
267282 } ) ;
268283
284+ const abortController = new AbortController ( ) ;
285+ abortControllerRef . current = abortController ;
286+
269287 const { fullStream } = streamText ( {
270288 model,
271289 messages : await prepareMessageHistory (
@@ -295,6 +313,7 @@ export function useChatLogic({
295313 client . close ( ) ;
296314 }
297315 } ,
316+ abortSignal : abortController . signal ,
298317 } ) ;
299318
300319 let aiResponse = "" ;
@@ -456,29 +475,42 @@ export function useChatLogic({
456475 setIsGenerating ( false ) ;
457476 setIsStreamingText ( false ) ;
458477 isGeneratingRef . current = false ;
478+ abortControllerRef . current = null ; // Clear the abort controller on successful completion
459479 } catch ( error ) {
460- console . error ( "AI error:" , error ) ;
461-
462- const errorMsg = ( error as any ) ?. error || "Unknown error" ;
480+ console . error ( error ) ;
481+
482+ let errorMsg = "Unknown error" ;
483+ if ( typeof error === "string" ) {
484+ errorMsg = error ;
485+ } else if ( error instanceof Error ) {
486+ errorMsg = error . message || error . name || "Unknown error" ;
487+ } else if ( ( error as any ) ?. error ) {
488+ errorMsg = ( error as any ) . error ;
489+ } else if ( ( error as any ) ?. message ) {
490+ errorMsg = ( error as any ) . message ;
491+ }
463492
464- let finalErrorMesage = "" ;
493+ let finalErrorMessage = "" ;
465494
466495 if ( String ( errorMsg ) . includes ( "too large" ) ) {
467- finalErrorMesage =
496+ finalErrorMessage =
468497 "Sorry, I encountered an error. Please try again. Your transcript or meeting notes might be too large. Please try again with a smaller transcript or meeting notes."
469498 + "\n\n" + errorMsg ;
499+ } else if ( String ( errorMsg ) . includes ( "Request cancelled" ) || String ( errorMsg ) . includes ( "Request canceled" ) ) {
500+ finalErrorMessage = "Request was cancelled mid-stream. Try again with a different message." ;
470501 } else {
471- finalErrorMesage = "Sorry, I encountered an error. Please try again. " + "\n\n" + errorMsg ;
502+ finalErrorMessage = "Sorry, I encountered an error. Please try again. " + "\n\n" + errorMsg ;
472503 }
473504
474505 setIsGenerating ( false ) ;
475506 setIsStreamingText ( false ) ;
476507 isGeneratingRef . current = false ;
508+ abortControllerRef . current = null ; // Clear the abort controller on error
477509
478510 // Create error message
479511 const errorMessage : Message = {
480512 id : aiMessageId ,
481- content : finalErrorMesage ,
513+ content : finalErrorMessage ,
482514 isUser : false ,
483515 timestamp : new Date ( ) ,
484516 type : "text-delta" ,
@@ -491,7 +523,7 @@ export function useChatLogic({
491523 group_id : groupId ,
492524 created_at : new Date ( ) . toISOString ( ) ,
493525 role : "Assistant" ,
494- content : finalErrorMesage ,
526+ content : finalErrorMessage ,
495527 type : "text-delta" ,
496528 } ) ;
497529 }
@@ -516,12 +548,20 @@ export function useChatLogic({
516548 }
517549 } ;
518550
551+ const handleStop = useCallback ( ( ) => {
552+ if ( abortControllerRef . current ) {
553+ abortControllerRef . current . abort ( ) ;
554+ abortControllerRef . current = null ;
555+ }
556+ } , [ ] ) ;
557+
519558 return {
520559 isGenerating,
521560 isStreamingText,
522561 handleSubmit,
523562 handleQuickAction,
524563 handleApplyMarkdown,
525564 handleKeyDown,
565+ handleStop,
526566 } ;
527567}
0 commit comments