diff --git a/src/components/AIStateIndicator/hooks/useAIState.ts b/src/components/AIStateIndicator/hooks/useAIState.ts index 2934c25cf..a3de43a63 100644 --- a/src/components/AIStateIndicator/hooks/useAIState.ts +++ b/src/components/AIStateIndicator/hooks/useAIState.ts @@ -6,6 +6,7 @@ export const AIStates = { ExternalSources: 'AI_STATE_EXTERNAL_SOURCES', Generating: 'AI_STATE_GENERATING', Idle: 'AI_STATE_IDLE', + Stop: 'AI_STATE_STOP', Thinking: 'AI_STATE_THINKING', }; @@ -37,9 +38,17 @@ export const useAIState = (channel?: Channel): { aiState: AIState } => { } }); + const indicatorStoppedListener = channel.on('ai_indicator.stop', (event) => { + const { cid } = event; + if (channel.cid === cid) { + setAiState(AIStates.Stop); + } + }); + return () => { indicatorChangedListener.unsubscribe(); indicatorClearedListener.unsubscribe(); + indicatorStoppedListener.unsubscribe(); }; }, [channel]); diff --git a/src/components/Message/StreamedMessageText.tsx b/src/components/Message/StreamedMessageText.tsx index 3f66e98fb..218ea2ba6 100644 --- a/src/components/Message/StreamedMessageText.tsx +++ b/src/components/Message/StreamedMessageText.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import type { MessageTextProps } from './MessageText'; import { MessageText } from './MessageText'; -import { useMessageContext } from '../../context'; +import { useChannelStateContext, useMessageContext } from '../../context'; import { useMessageTextStreaming } from './hooks'; export type StreamedMessageTextProps = Pick< @@ -22,14 +22,21 @@ export const StreamedMessageText = (props: StreamedMessageTextProps) => { streamingLetterIntervalMs, } = props; const { message: messageFromContext } = useMessageContext('StreamedMessageText'); + const { channel } = useChannelStateContext(); const message = messageFromProps || messageFromContext; const { text = '' } = message; - const { streamedMessageText } = useMessageTextStreaming({ + const { skipAnimation, streamedMessageText } = useMessageTextStreaming({ renderingLetterCount, streamingLetterIntervalMs, text, }); + useEffect(() => { + channel?.on('ai_indicator.stop', () => { + skipAnimation(); + }); + }, [channel, skipAnimation]); + return ( { +}: UseMessageTextStreamingProps) => { const [streamedMessageText, setStreamedMessageText] = useState(text); const textCursor = useRef(text.length); useEffect(() => { const textLength = text.length; + const interval = setInterval(() => { if (!text || textCursor.current >= textLength) { clearInterval(interval); + return; } const newCursorValue = textCursor.current + renderingLetterCount; const newText = text.substring(0, newCursorValue); @@ -43,5 +46,10 @@ export const useMessageTextStreaming = ({ }; }, [streamingLetterIntervalMs, renderingLetterCount, text]); - return { streamedMessageText }; + const skipAnimation = useStableCallback(() => { + textCursor.current = text.length; + setStreamedMessageText(text); + }); + + return { skipAnimation, streamedMessageText } as const; };