feat(askai): Handle errors better for Ask AI (#2803)
This commit is contained in:
parent
5ef01ecd4d
commit
d531137f14
6 changed files with 50 additions and 39 deletions
|
|
@ -871,10 +871,14 @@ assistive tech users */
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-MessageContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 1em;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-Error {
|
||||
padding: var(--docsearch-spacing);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
padding: 1em;
|
||||
gap: 8px;
|
||||
color: var(--docsearch-error-color);
|
||||
|
|
@ -882,12 +886,11 @@ assistive tech users */
|
|||
border-radius: 4px;
|
||||
font-size: 1em;
|
||||
font-weight: 400;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-MessageContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 1em;
|
||||
.DocSearch-AskAiScreen-Error svg {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-Error svg,
|
||||
|
|
@ -901,6 +904,17 @@ assistive tech users */
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-Error-Content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 0%;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-Error-Title {
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.DocSearch-AskAiScreen-Error .DocSearch-Markdown-Content {
|
||||
color: var(--docsearch-error-color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,13 +48,16 @@ export type AskAiScreenTranslations = Partial<{
|
|||
* Message that's shown when user has stopped the streaming of a message.
|
||||
*/
|
||||
stoppedStreamingText: string;
|
||||
/**
|
||||
* Error title shown if there is an error while chatting.
|
||||
*/
|
||||
errorTitleText: string;
|
||||
}>;
|
||||
|
||||
type AskAiScreenProps = Omit<ScreenStateProps<InternalDocSearchHit>, 'translations'> & {
|
||||
messages: AIMessage[];
|
||||
status: UseChatHelpers<AIMessage>['status'];
|
||||
askAiStreamError: Error | null;
|
||||
askAiFetchError: Error | undefined;
|
||||
askAiError?: Error;
|
||||
translations?: AskAiScreenTranslations;
|
||||
};
|
||||
|
||||
|
|
@ -74,7 +77,7 @@ function AskAiScreenHeader({ disclaimerText }: AskAiScreenHeaderProps): JSX.Elem
|
|||
|
||||
interface AskAiExchangeCardProps {
|
||||
exchange: Exchange;
|
||||
askAiStreamError: Error | null;
|
||||
askAiError?: Error;
|
||||
isLastExchange: boolean;
|
||||
loadingStatus: UseChatHelpers<AIMessage>['status'];
|
||||
onSearchQueryClick: (query: string) => void;
|
||||
|
|
@ -85,7 +88,7 @@ interface AskAiExchangeCardProps {
|
|||
|
||||
function AskAiExchangeCard({
|
||||
exchange,
|
||||
askAiStreamError,
|
||||
askAiError,
|
||||
isLastExchange,
|
||||
loadingStatus,
|
||||
onSearchQueryClick,
|
||||
|
|
@ -95,7 +98,7 @@ function AskAiExchangeCard({
|
|||
}: AskAiExchangeCardProps): JSX.Element {
|
||||
const { userMessage, assistantMessage } = exchange;
|
||||
|
||||
const { stoppedStreamingText = 'You stopped this response' } = translations;
|
||||
const { stoppedStreamingText = 'You stopped this response', errorTitleText = 'Chat error' } = translations;
|
||||
|
||||
const assistantContent = useMemo(() => getMessageContent(assistantMessage), [assistantMessage]);
|
||||
const userContent = useMemo(() => getMessageContent(userMessage), [userMessage]);
|
||||
|
|
@ -124,15 +127,18 @@ function AskAiExchangeCard({
|
|||
</div>
|
||||
<div className="DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant">
|
||||
<div className="DocSearch-AskAiScreen-MessageContent">
|
||||
{loadingStatus === 'error' && askAiStreamError && isLastExchange && (
|
||||
{loadingStatus === 'error' && askAiError && isLastExchange && (
|
||||
<div className="DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error">
|
||||
<AlertIcon />
|
||||
<MemoizedMarkdown
|
||||
content={askAiStreamError.message}
|
||||
copyButtonText=""
|
||||
copyButtonCopiedText=""
|
||||
isStreaming={false}
|
||||
/>
|
||||
<div className="DocSearch-AskAiScreen-Error-Content">
|
||||
<h4 className="DocSearch-AskAiScreen-Error-Title">{errorTitleText}</h4>
|
||||
<MemoizedMarkdown
|
||||
content={askAiError.message}
|
||||
copyButtonText=""
|
||||
copyButtonCopiedText=""
|
||||
isStreaming={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isThinking && (
|
||||
|
|
@ -406,7 +412,7 @@ export function AskAiScreen({ translations = {}, ...props }: AskAiScreenProps):
|
|||
<AskAiExchangeCard
|
||||
key={exchange.id}
|
||||
exchange={exchange}
|
||||
askAiStreamError={props.askAiStreamError}
|
||||
askAiError={props.askAiError}
|
||||
isLastExchange={index === 0}
|
||||
loadingStatus={props.status}
|
||||
translations={translations}
|
||||
|
|
|
|||
|
|
@ -397,7 +397,6 @@ export function DocSearchModal({
|
|||
}),
|
||||
).current;
|
||||
|
||||
const [askAiStreamError, setAskAiStreamError] = React.useState<Error | null>(null);
|
||||
const [stoppedStream, setStoppedStream] = React.useState(false);
|
||||
|
||||
const {
|
||||
|
|
@ -405,7 +404,7 @@ export function DocSearchModal({
|
|||
sendMessage,
|
||||
status,
|
||||
setMessages,
|
||||
error: askAiFetchError,
|
||||
error: askAiError,
|
||||
stop: stopAskAiStreaming,
|
||||
} = useChat<AIMessage>({
|
||||
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
||||
|
|
@ -426,7 +425,6 @@ export function DocSearchModal({
|
|||
|
||||
return {
|
||||
...(token ? { authorization: `TOKEN ${token}` } : {}),
|
||||
// 'Content-Type': 'application/json',
|
||||
'X-Algolia-API-Key': askAiConfig?.apiKey || apiKey,
|
||||
'X-Algolia-Application-Id': askAiConfig?.appId || appId,
|
||||
'X-Algolia-Index-Name': askAiConfig?.indexName || defaultIndexName,
|
||||
|
|
@ -436,9 +434,6 @@ export function DocSearchModal({
|
|||
},
|
||||
body: askAiSearchParameters ? { searchParameters: askAiSearchParameters } : {},
|
||||
}),
|
||||
onError(streamError) {
|
||||
setAskAiStreamError(streamError);
|
||||
},
|
||||
});
|
||||
|
||||
const prevStatus = React.useRef(status);
|
||||
|
|
@ -907,8 +902,7 @@ export function DocSearchModal({
|
|||
isAskAiActive={isAskAiActive}
|
||||
canHandleAskAi={canHandleAskAi}
|
||||
messages={messages}
|
||||
askAiStreamError={askAiStreamError}
|
||||
askAiFetchError={askAiFetchError}
|
||||
askAiError={askAiError}
|
||||
status={status}
|
||||
hasCollections={hasCollections}
|
||||
askAiState={askAiState}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ export interface ScreenStateProps<TItem extends BaseItem>
|
|||
indexName: DocSearchProps['indexName'];
|
||||
messages: UseChatHelpers<AIMessage>['messages'];
|
||||
status: UseChatHelpers<AIMessage>['status'];
|
||||
askAiStreamError: Error | null;
|
||||
askAiFetchError: Error | undefined;
|
||||
askAiError?: Error;
|
||||
disableUserPersonalization: boolean;
|
||||
resultsFooterComponent: DocSearchProps['resultsFooterComponent'];
|
||||
translations: ScreenStateTranslations;
|
||||
|
|
@ -80,8 +79,7 @@ export const ScreenState = React.memo(
|
|||
{...props}
|
||||
messages={props.messages}
|
||||
status={props.status}
|
||||
askAiStreamError={props.askAiStreamError}
|
||||
askAiFetchError={props.askAiFetchError}
|
||||
askAiError={props.askAiError}
|
||||
translations={translations?.askAiScreen}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -37,13 +37,7 @@ describe('AskAiScreen', () => {
|
|||
];
|
||||
|
||||
const { getByText } = render(
|
||||
<AskAiScreen
|
||||
{...baseProps}
|
||||
messages={messages}
|
||||
status="error"
|
||||
askAiStreamError={new Error('oh no')}
|
||||
askAiFetchError={undefined}
|
||||
/>,
|
||||
<AskAiScreen {...baseProps} messages={messages} status="error" askAiError={new Error('oh no')} />,
|
||||
);
|
||||
|
||||
expect(getByText('oh no')).toBeInTheDocument();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,12 @@ export const getValidToken = async ({ assistantId }: { assistantId: string }): P
|
|||
},
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then(({ token }) => {
|
||||
.then(({ token, success, message }) => {
|
||||
// If request was unsuccessful, throw an error to prevent calling `/chat` without a token
|
||||
if (!success && message) {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
sessionStorage.setItem(TOKEN_KEY, token);
|
||||
return token;
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue