@@ -8,7 +8,7 @@ import type { ScreenStateProps } from './ScreenState';
88import type { StoredSearchPlugin } from './stored-searches' ;
99import type { InternalDocSearchHit , StoredAskAiState } from './types' ;
1010import type { AIMessage } from './types/AskiAi' ;
11- import { extractLinksFromMessage , getMessageContent } from './utils/ai' ;
11+ import { extractLinksFromMessage , getMessageContent , isThreadDepthError } from './utils/ai' ;
1212import { groupConsecutiveToolResults } from './utils/groupConsecutiveToolResults' ;
1313
1414export type AskAiScreenTranslations = Partial < {
@@ -52,13 +52,22 @@ export type AskAiScreenTranslations = Partial<{
5252 * Error title shown if there is an error while chatting.
5353 */
5454 errorTitleText : string ;
55+ /**
56+ * Message shown when thread depth limit is exceeded (AI-217 error).
57+ */
58+ threadDepthExceededMessage : string ;
59+ /**
60+ * Button text for starting a new conversation after thread depth error.
61+ */
62+ startNewConversationButtonText : string ;
5563} > ;
5664
5765type AskAiScreenProps = Omit < ScreenStateProps < InternalDocSearchHit > , 'translations' > & {
5866 messages : AIMessage [ ] ;
5967 status : UseChatHelpers < AIMessage > [ 'status' ] ;
6068 askAiError ?: Error ;
6169 translations ?: AskAiScreenTranslations ;
70+ onNewConversation : ( ) => void ;
6271} ;
6372
6473interface AskAiScreenHeaderProps {
@@ -100,6 +109,8 @@ function AskAiExchangeCard({
100109
101110 const { stoppedStreamingText = 'You stopped this response' , errorTitleText = 'Chat error' } = translations ;
102111
112+ const isThreadDepth = isThreadDepthError ( askAiError ) ;
113+
103114 const assistantContent = useMemo ( ( ) => getMessageContent ( assistantMessage ) , [ assistantMessage ] ) ;
104115 const userContent = useMemo ( ( ) => getMessageContent ( userMessage ) , [ userMessage ] ) ;
105116
@@ -127,7 +138,7 @@ function AskAiExchangeCard({
127138 </ div >
128139 < div className = "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant" >
129140 < div className = "DocSearch-AskAiScreen-MessageContent" >
130- { loadingStatus === 'error' && askAiError && isLastExchange && (
141+ { loadingStatus === 'error' && askAiError && isLastExchange && ! isThreadDepth && (
131142 < div className = "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error" >
132143 < AlertIcon />
133144 < div className = "DocSearch-AskAiScreen-Error-Content" >
@@ -375,9 +386,18 @@ function AskAiSourcesPanel({ urlsToDisplay, relatedSourcesText }: AskAiSourcesPa
375386}
376387
377388export function AskAiScreen ( { translations = { } , ...props } : AskAiScreenProps ) : JSX . Element | null {
378- const { disclaimerText = 'Answers are generated with AI which can make mistakes. Verify responses.' } = translations ;
389+ const {
390+ disclaimerText = 'Answers are generated with AI which can make mistakes. Verify responses.' ,
391+ threadDepthExceededMessage = 'This conversation is now closed to keep responses accurate.' ,
392+ startNewConversationButtonText = 'Start a new conversation' ,
393+ } = translations ;
379394
380- const { messages } = props ;
395+ const { messages, askAiError, status } = props ;
396+
397+ // Check if there's a thread depth error
398+ const hasThreadDepthError = useMemo ( ( ) => {
399+ return status === 'error' && isThreadDepthError ( askAiError ) ;
400+ } , [ status , askAiError ] ) ;
381401
382402 // Group messages into exchanges (user + assistant pairs)
383403 const exchanges : Exchange [ ] = useMemo ( ( ) => {
@@ -392,17 +412,47 @@ export function AskAiScreen({ translations = {}, ...props }: AskAiScreenProps):
392412 }
393413 }
394414 }
415+
416+ // If there's a thread depth error, remove the last exchange (the one that triggered the error)
417+ // We only want to show successful exchanges
418+ if ( hasThreadDepthError && grouped . length > 0 ) {
419+ // Check if the last exchange has no assistant message (failed to complete)
420+ const lastExchange = grouped [ grouped . length - 1 ] ;
421+ if ( ! lastExchange . assistantMessage ) {
422+ grouped . pop ( ) ;
423+ }
424+ }
425+
395426 return grouped ;
396- } , [ messages ] ) ;
427+ } , [ messages , hasThreadDepthError ] ) ;
397428
398429 const handleSearchQueryClick = ( query : string ) : void => {
399430 props . onAskAiToggle ( false ) ;
400431 props . setQuery ( query ) ;
401432 } ;
402433
434+ // Only show the thread depth error if we have assistant messages
435+ const showThreadDepthError = hasThreadDepthError && messages . some ( ( m ) => m . role === 'assistant' ) ;
436+
403437 return (
404438 < div className = "DocSearch-AskAiScreen DocSearch-AskAiScreen-Container" >
439+ { /* Thread Depth Error */ }
440+ { showThreadDepthError && (
441+ < div className = "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth" >
442+ < div className = "DocSearch-AskAiScreen-Error-Content" >
443+ < p >
444+ { threadDepthExceededMessage } { ' ' }
445+ < button type = "button" className = "DocSearch-ThreadDepthError-Link" onClick = { props . onNewConversation } >
446+ { startNewConversationButtonText }
447+ </ button > { ' ' }
448+ to continue.
449+ </ p >
450+ </ div >
451+ </ div >
452+ ) }
453+
405454 < AskAiScreenHeader disclaimerText = { disclaimerText } />
455+
406456 < div className = "DocSearch-AskAiScreen-Body" >
407457 < div className = "DocSearch-AskAiScreen-ExchangesList" >
408458 { exchanges
0 commit comments