@docsearch/react 5.0.0-beta.2 → 5.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/esm/{AskAiScreenState-Bw2WIgv_.d.ts → AskAiScreenState-Sqbn60f2.d.ts} +2 -2
  2. package/dist/esm/{DocSearch-CVj6U-nI.d.ts → DocSearch-BVqxFxTw.d.ts} +18 -27
  3. package/dist/esm/{DocSearchAskAiModal-BczGFkvR.js → DocSearchAskAiModal-ByqIW5ZA.js} +56 -31
  4. package/dist/esm/DocSearchAskAiModal-ByqIW5ZA.js.map +1 -0
  5. package/dist/esm/{DocSearchAskAiModal-MF2py4NM.d.ts → DocSearchAskAiModal-DpB7pLCC.d.ts} +4 -4
  6. package/dist/esm/{DocSearchModal-D_tfhoN1.js → DocSearchModal-CITTG0fe.js} +10 -8
  7. package/dist/esm/DocSearchModal-CITTG0fe.js.map +1 -0
  8. package/dist/esm/askaiModal.d.ts +1 -1
  9. package/dist/esm/askaiModal.js +1 -1
  10. package/dist/esm/docsearchAi.d.ts +10 -102
  11. package/dist/esm/docsearchAi.js +1 -1
  12. package/dist/esm/docsearchAi.js.map +1 -1
  13. package/dist/esm/index.d.ts +4 -4
  14. package/dist/esm/index.js +2 -2
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/modal.d.ts +1 -1
  17. package/dist/esm/modal.js +1 -1
  18. package/dist/esm/{normalizeDocSearchIndexes-D8P3VEXa.js → normalizeDocSearchIndexes-ChnVvoVt.js} +16 -20
  19. package/dist/esm/normalizeDocSearchIndexes-ChnVvoVt.js.map +1 -0
  20. package/dist/esm/sidepanel.d.ts +22 -7
  21. package/dist/esm/sidepanel.js +27 -10
  22. package/dist/esm/sidepanel.js.map +1 -1
  23. package/dist/esm/useDocSearchKeyboardEvents.js +1 -1
  24. package/dist/esm/useDocSearchKeyboardEvents.js.map +1 -1
  25. package/dist/esm/useSearchClient-mIHVB6ga.js.map +1 -1
  26. package/dist/esm/{useSuggestedQuestions-Ds7H1JCr.js → useSuggestedQuestions-BjSZvxwr.js} +233 -36
  27. package/dist/esm/useSuggestedQuestions-BjSZvxwr.js.map +1 -0
  28. package/dist/esm/version.d.ts +1 -1
  29. package/dist/esm/version.js +1 -1
  30. package/dist/esm/version.js.map +1 -1
  31. package/dist/umd/index.js +33 -33
  32. package/dist/umd/index.js.map +1 -1
  33. package/package.json +4 -4
  34. package/dist/esm/DocSearchAskAiModal-BczGFkvR.js.map +0 -1
  35. package/dist/esm/DocSearchModal-D_tfhoN1.js.map +0 -1
  36. package/dist/esm/normalizeDocSearchIndexes-D8P3VEXa.js.map +0 -1
  37. package/dist/esm/useSuggestedQuestions-Ds7H1JCr.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import "./index-Bqqv4HmN.js";
2
- import { f as ResultsScreenTranslations, h as StoredSearchesSectionsTranslations, m as ErrorScreenTranslations, p as NoResultsScreenTranslations } from "./DocSearch-CVj6U-nI.js";
2
+ import { _ as StoredSearchesSectionsTranslations, g as ErrorScreenTranslations, h as NoResultsScreenTranslations, m as ResultsScreenTranslations } from "./DocSearch-BVqxFxTw.js";
3
3
  import React, { JSX } from "react";
4
4
  import { AutocompleteState, BaseItem } from "@algolia/autocomplete-core";
5
5
  import "@ai-sdk/react";
@@ -106,4 +106,4 @@ type AskAiScreenStateTranslations = Partial<{
106
106
  }>;
107
107
  //#endregion
108
108
  export { NewConversationTranslations as n, ToolCallTranslations as r, AskAiScreenStateTranslations as t };
109
- //# sourceMappingURL=AskAiScreenState-Bw2WIgv_.d.ts.map
109
+ //# sourceMappingURL=AskAiScreenState-Sqbn60f2.d.ts.map
@@ -148,7 +148,7 @@ type DocSearchModalProps = DocSearchProps & {
148
148
  onClose?: () => void;
149
149
  translations?: ModalTranslations;
150
150
  };
151
- declare function DocSearchModal({ appId, apiKey, maxResultsPerGroup, theme, onClose, transformItems, hitComponent, resultsFooterComponent, navigator, initialScrollY, transformSearchClient, disableUserPersonalization, initialQuery: initialQueryFromProp, translations, getMissingResultsUrl, insights, recentSearchesLimit, recentSearchesWithFavoritesLimit, indices, facets, ...props }: DocSearchModalProps): JSX.Element;
151
+ declare function DocSearchModal({ appId, apiKey, maxResultsPerGroup, theme, onClose, transformItems, hitComponent, resultsFooterComponent, navigator, initialScrollY, transformSearchClient, disableUserPersonalization, initialQuery: initialQueryFromProp, translations, getMissingResultsUrl, insights, recentSearchesLimit, recentSearchesWithFavoritesLimit, indices, facets, footerAction, ...props }: DocSearchModalProps): JSX.Element;
152
152
  //#endregion
153
153
  //#region src/DocSearch.d.ts
154
154
  type DocSearchTranslations = Partial<{
@@ -168,6 +168,13 @@ interface DocSearchFacet {
168
168
  key: string;
169
169
  label?: string;
170
170
  }
171
+ interface HitComponentProps {
172
+ hit: InternalDocSearchHit | StoredDocSearchHit;
173
+ children: React.ReactNode;
174
+ }
175
+ interface ResultsFooterComponentProps {
176
+ state: AutocompleteState<InternalDocSearchHit>;
177
+ }
171
178
  interface DocSearchProps {
172
179
  /** Algolia application id used by the search client. */
173
180
  appId: string;
@@ -194,32 +201,16 @@ interface DocSearchProps {
194
201
  maxResultsPerGroup?: number;
195
202
  /** Hook to post-process hits before rendering. */
196
203
  transformItems?: (items: DocSearchHit[]) => DocSearchHit[];
204
+ /** Custom component to render an individual hit. */
205
+ hitComponent?: (props: HitComponentProps) => JSX.Element;
206
+ /** Custom component rendered at the bottom of the results panel. */
207
+ resultsFooterComponent?: (props: ResultsFooterComponentProps) => JSX.Element | null;
197
208
  /**
198
- * Custom component to render an individual hit. Supports template patterns:
199
- *
200
- * - HTML strings with html helper: (props, { html }) => html`<div>...</div>`
201
- * - JSX templates: (props) => <div>...</div>
202
- * - Function-based templates: (props) => string | JSX.Element | Function.
203
- */
204
- hitComponent?: (props: {
205
- hit: InternalDocSearchHit | StoredDocSearchHit;
206
- children: React.ReactNode;
207
- }, helpers?: {
208
- html: (template: TemplateStringsArray, ...values: any[]) => any;
209
- }) => JSX.Element;
210
- /**
211
- * Custom component rendered at the bottom of the results panel. Supports
212
- * template patterns:
213
- *
214
- * - HTML strings with html helper: (props, { html }) => html`<div>...</div>`
215
- * - JSX templates: (props) => <div>...</div>
216
- * - Function-based templates: (props) => string | JSX.Element | Function.
209
+ * A custom action that can be rendered in the Modal's footer before the
210
+ * Algolia logo. The component will be rendered as a child of `<div
211
+ * className="DocSearch-Footer-Action" />`.
217
212
  */
218
- resultsFooterComponent?: (props: {
219
- state: AutocompleteState<InternalDocSearchHit>;
220
- }, helpers?: {
221
- html: (template: TemplateStringsArray, ...values: any[]) => any;
222
- }) => JSX.Element | null;
213
+ footerAction?: React.ReactNode;
223
214
  /** Hook to wrap or modify the algolia search client. */
224
215
  transformSearchClient?: (searchClient: DocSearchTransformClient) => DocSearchTransformClient;
225
216
  /** Disable storage and usage of recent and favorite searches. */
@@ -277,5 +268,5 @@ interface DocSearchProps {
277
268
  declare const DocSearch$1: React.ForwardRefExoticComponent<DocSearchProps & React.RefAttributes<DocSearchRef>>;
278
269
  declare function DocSearchInner(props: Omit<DocSearchProps, 'appId' | 'apiKey'>): JSX.Element;
279
270
  //#endregion
280
- export { FacetBarTranslations as _, DocSearchProps as a, DocSearchTranslations as c, ModalTranslations as d, ResultsScreenTranslations as f, FooterTranslations as g, StoredSearchesSectionsTranslations as h, DocSearchInner as i, DocSearchModal as l, ErrorScreenTranslations as m, DocSearchFacet as n, DocSearchRef$1 as o, NoResultsScreenTranslations as p, DocSearchIndex as r, DocSearchTransformClient as s, DocSearch$1 as t, DocSearchModalProps as u, InternalDocSearchHit as v };
281
- //# sourceMappingURL=DocSearch-CVj6U-nI.d.ts.map
271
+ export { StoredSearchesSectionsTranslations as _, DocSearchProps as a, InternalDocSearchHit as b, DocSearchTranslations as c, DocSearchModal as d, DocSearchModalProps as f, ErrorScreenTranslations as g, NoResultsScreenTranslations as h, DocSearchInner as i, HitComponentProps as l, ResultsScreenTranslations as m, DocSearchFacet as n, DocSearchRef$1 as o, ModalTranslations as p, DocSearchIndex as r, DocSearchTransformClient as s, DocSearch$1 as t, ResultsFooterComponentProps as u, FooterTranslations as v, FacetBarTranslations as y };
272
+ //# sourceMappingURL=DocSearch-BVqxFxTw.d.ts.map
@@ -1,8 +1,8 @@
1
1
  import { t as _objectSpread2 } from "./objectSpread2-BNmiQYyW.js";
2
- import { C as noop, D as SOURCE_IDS, E as identity, O as getCollection, S as scrollTo, T as isModifierEvent, _ as Hit, a as NoResultsScreen, b as SearchBoxForm, c as Results, d as useRefreshOnInitialQuery, f as useModalRefs, g as useDocSearchFacets, h as useSendItemClickEvent, i as ResultsScreen, l as useStoredDocSearches, m as useInitialModalQuery, n as buildNoQuerySources, o as ErrorScreen, p as useModalEnvironment, r as buildQuerySources, s as StoredSearchesSections, t as normalizeDocSearchIndexes, u as useSaveRecentSearch, v as Footer, w as isQueryEmpty, x as FacetBar, y as ModalShell } from "./normalizeDocSearchIndexes-D8P3VEXa.js";
2
+ import { C as noop, D as SOURCE_IDS, E as identity, O as getCollection, S as scrollTo, T as isModifierEvent, _ as Hit, a as NoResultsScreen, b as SearchBoxForm, c as Results, d as useRefreshOnInitialQuery, f as useModalRefs, g as useDocSearchFacets, h as useSendItemClickEvent, i as ResultsScreen, l as useStoredDocSearches, m as useInitialModalQuery, n as buildNoQuerySources, o as ErrorScreen, p as useModalEnvironment, r as buildQuerySources, s as StoredSearchesSections, t as normalizeDocSearchIndexes, u as useSaveRecentSearch, v as Footer, w as isQueryEmpty, x as FacetBar, y as ModalShell } from "./normalizeDocSearchIndexes-ChnVvoVt.js";
3
3
  import { n as SearchIcon, t as _objectWithoutProperties } from "./objectWithoutProperties-phqYxDS0.js";
4
4
  import { l as CloseIcon, m as LoadingIcon, p as SparklesIcon, t as useSearchClient } from "./useSearchClient-mIHVB6ga.js";
5
- import { S as AlertIcon, _ as BackIcon, a as MemoizedMarkdown, b as MoreVerticalIcon, c as buildDummyAskAiHit, d as getMessageContent, f as isAIToolPart, g as ConversationPromptSuggestions, h as FeedbackActions, i as groupConsecutiveToolResults, l as extractLinksFromMessage, m as SourcesPanel, n as useAskAi, o as ToolCall, p as isThreadDepthError, r as Menu, s as EMPTY_TOOLS, t as useSuggestedQuestions, u as getAgentPromptSuggestions, v as NewConversationIcon, x as StopIcon, y as ConversationHistoryIcon } from "./useSuggestedQuestions-Ds7H1JCr.js";
5
+ import { C as ConversationHistoryIcon, E as AlertIcon, S as NewConversationIcon, T as StopIcon, _ as showAskAiBlockingBannerNewConversationLink, a as MemoizedMarkdown, b as ConversationPromptSuggestions, c as buildDummyAskAiHit, d as getAskAiBlockingBannerMessage, f as getMessageContent, g as isThreadDepthError, h as isAskAiPromptBlockingError, i as groupConsecutiveToolResults, l as extractLinksFromMessage, m as isAgentStudioTokenOutputLimitError, n as useAskAi, o as ToolCall, p as isAIToolPart, r as Menu, s as EMPTY_TOOLS, t as useSuggestedQuestions, u as getAgentPromptSuggestions, v as SourcesPanel, w as MoreVerticalIcon, x as BackIcon, y as FeedbackActions } from "./useSuggestedQuestions-BjSZvxwr.js";
6
6
  import React, { Fragment, useMemo } from "react";
7
7
  import { createAutocomplete } from "@algolia/autocomplete-core";
8
8
 
@@ -73,7 +73,7 @@ function AskAiExchangeCard({ exchange, askAiError, isLastExchange, loadingStatus
73
73
  const { userMessage, assistantMessage } = exchange;
74
74
  const { stoppedStreamingText = "You stopped this response", errorTitleText = "Chat error", relatedSourcesText, relatedSourcesTextPlural, suggestedPromptsTitleText = "Suggested prompts" } = translations;
75
75
  const toolCallTranslations = useMemo(() => toToolCallTranslations(translations), [translations]);
76
- const isThreadDepth = isThreadDepthError(askAiError);
76
+ const isPromptBlockingError = isAskAiPromptBlockingError(askAiError);
77
77
  const assistantContent = useMemo(() => getMessageContent(assistantMessage), [assistantMessage]);
78
78
  const userContent = useMemo(() => getMessageContent(userMessage), [userMessage]);
79
79
  const urlsToDisplay = React.useMemo(() => extractLinksFromMessage(assistantMessage), [assistantMessage]);
@@ -88,7 +88,7 @@ function AskAiExchangeCard({ exchange, askAiError, isLastExchange, loadingStatus
88
88
  const showActions = !wasStopped && (!isLastExchange || isLastExchange && loadingStatus === "ready" && Boolean(assistantMessage));
89
89
  const isThinking = ["submitted", "streaming"].includes(loadingStatus) && isLastExchange && !displayParts.some((part) => part.type !== "step-start");
90
90
  const messageId = (assistantMessage === null || assistantMessage === void 0 ? void 0 : assistantMessage.id) || exchange.id;
91
- return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Response-Container" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Response" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user" }, /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-Query" }, userContent !== null && userContent !== void 0 ? userContent : "")), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent" }, loadingStatus === "error" && askAiError && isLastExchange && !isThreadDepth && /* @__PURE__ */ React.createElement("div", {
91
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Response-Container" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Response" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user" }, /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-Query" }, userContent !== null && userContent !== void 0 ? userContent : "")), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent" }, loadingStatus === "error" && askAiError && isLastExchange && !isPromptBlockingError && /* @__PURE__ */ React.createElement("div", {
92
92
  className: "DocSearch-AskAiScreen-Error",
93
93
  role: "alert"
94
94
  }, /* @__PURE__ */ React.createElement(AlertIcon, { "aria-hidden": "true" }), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ React.createElement("h4", { className: "DocSearch-AskAiScreen-Error-Title" }, errorTitleText), /* @__PURE__ */ React.createElement(MemoizedMarkdown, {
@@ -155,9 +155,11 @@ function AskAiScreen(_ref) {
155
155
  let { translations = {} } = _ref, props = _objectWithoutProperties(_ref, _excluded$6);
156
156
  const { disclaimerText = "Answers are generated with AI which can make mistakes.", threadDepthExceededMessage = "This conversation is now closed to keep responses accurate.", startNewConversationButtonText = "Start a new conversation" } = translations;
157
157
  const { messages, tools, askAiError, status, memoryEnabled } = props;
158
- const hasThreadDepthError = useMemo(() => {
159
- return status === "error" && isThreadDepthError(askAiError);
158
+ const hasPromptBlockingError = useMemo(() => {
159
+ return status === "error" && isAskAiPromptBlockingError(askAiError);
160
160
  }, [status, askAiError]);
161
+ const blockingMessage = useMemo(() => getAskAiBlockingBannerMessage(askAiError), [askAiError]);
162
+ const showNewConversationLink = showAskAiBlockingBannerNewConversationLink(askAiError);
161
163
  const exchanges = useMemo(() => {
162
164
  const grouped = [];
163
165
  for (let i = 0; i < messages.length; i++) if (messages[i].role === "user") {
@@ -171,21 +173,21 @@ function AskAiScreen(_ref) {
171
173
  });
172
174
  if (assistantMessage) i++;
173
175
  }
174
- if (hasThreadDepthError && grouped.length > 0) {
175
- if (!grouped[grouped.length - 1].assistantMessage) grouped.pop();
176
- }
177
176
  return grouped;
178
- }, [messages, hasThreadDepthError]);
177
+ }, [messages]);
179
178
  const handleSearchQueryClick = (query) => {
180
179
  props.onAskAiToggle(false);
181
180
  props.setQuery(query);
182
181
  };
183
- const showThreadDepthError = hasThreadDepthError && messages.some((m) => m.role === "assistant");
184
- return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen DocSearch-AskAiScreen-Container" }, showThreadDepthError && /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ React.createElement("p", null, threadDepthExceededMessage, " ", /* @__PURE__ */ React.createElement("button", {
182
+ const showBlockingBanner = hasPromptBlockingError && (!isThreadDepthError(askAiError) || messages.some((message) => message.role === "assistant"));
183
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen DocSearch-AskAiScreen-Container" }, /* @__PURE__ */ React.createElement("div", {
184
+ id: props.promptBlockingErrorId,
185
+ role: "alert"
186
+ }, showBlockingBanner && /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-Error-Title" }, blockingMessage !== null && blockingMessage !== void 0 ? blockingMessage : isThreadDepthError(askAiError) ? threadDepthExceededMessage : "This conversation cannot continue."), showNewConversationLink && /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("button", {
185
187
  type: "button",
186
188
  className: "DocSearch-ThreadDepthError-Link",
187
189
  onClick: props.onNewConversation
188
- }, startNewConversationButtonText), " ", "to continue."))), /* @__PURE__ */ React.createElement(AskAiScreenDisclaimer, { disclaimerText }), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Body" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-ExchangesList" }, exchanges.slice().reverse().map((exchange, index) => /* @__PURE__ */ React.createElement(AskAiExchangeCard, {
190
+ }, startNewConversationButtonText), " ", "to continue.")))), /* @__PURE__ */ React.createElement(AskAiScreenDisclaimer, { disclaimerText }), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Body" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-ExchangesList" }, exchanges.slice().reverse().map((exchange, index) => /* @__PURE__ */ React.createElement(AskAiExchangeCard, {
189
191
  key: exchange.id,
190
192
  exchange,
191
193
  askAiError: props.askAiError,
@@ -351,10 +353,10 @@ function AskAiSearchBox(_ref) {
351
353
  const origOnChange = baseInputProps.onChange;
352
354
  const isAskAiStreaming = props.askAiStatus === "streaming" || props.askAiStatus === "submitted";
353
355
  const renderMoreOptions = props.isAskAiActive && askAiState !== "conversation-history";
354
- const isThreadDepthError = props.isThreadDepthError || false;
356
+ const isPromptBlocked = Boolean(props.promptBlockingChrome);
355
357
  let searchPlaceholder = props.placeholder;
356
358
  if (askAiState === "new-conversation") searchPlaceholder = newConversationPlaceholder;
357
- if (isThreadDepthError && props.isAskAiActive) searchPlaceholder = threadDepthErrorPlaceholder;
359
+ if (props.promptBlockingChrome === "full" && props.isAskAiActive) searchPlaceholder = threadDepthErrorPlaceholder;
358
360
  let heading = null;
359
361
  if (isAskAiStreaming) heading = placeholderTextAskAiStreaming;
360
362
  if (askAiState === "conversation-history") heading = conversationHistoryTitle;
@@ -372,6 +374,11 @@ function AskAiSearchBox(_ref) {
372
374
  const inputProps = {
373
375
  enterKeyHint: props.isAskAiActive ? "enter" : "search",
374
376
  onKeyDown: (e) => {
377
+ if (isPromptBlocked && props.isAskAiActive && blockedKeys.has(e.key)) {
378
+ e.preventDefault();
379
+ e.stopPropagation();
380
+ return;
381
+ }
375
382
  let askAiHandled = false;
376
383
  if (props.isAskAiActive && blockedKeys.has(e.key)) {
377
384
  if (e.key === "Enter" && !isAskAiStreaming && !isQueryEmpty(props.state.query)) props.onAskAgain(props.state.query);
@@ -385,6 +392,10 @@ function AskAiSearchBox(_ref) {
385
392
  origOnKeyDown === null || origOnKeyDown === void 0 || origOnKeyDown(e);
386
393
  },
387
394
  onChange: (e) => {
395
+ if (isPromptBlocked && props.isAskAiActive) {
396
+ e.preventDefault();
397
+ return;
398
+ }
388
399
  if (props.isAskAiActive) {
389
400
  props.setQuery(e.currentTarget.value);
390
401
  e.preventDefault();
@@ -393,10 +404,13 @@ function AskAiSearchBox(_ref) {
393
404
  }
394
405
  origOnChange === null || origOnChange === void 0 || origOnChange(e);
395
406
  },
396
- disabled: isAskAiStreaming || isThreadDepthError && props.isAskAiActive
407
+ disabled: isAskAiStreaming,
408
+ readOnly: isPromptBlocked && props.isAskAiActive,
409
+ "aria-disabled": isPromptBlocked && props.isAskAiActive,
410
+ "aria-describedby": isPromptBlocked && props.isAskAiActive ? props.promptBlockingErrorId : void 0
397
411
  };
398
412
  const handleAskAiBackClick = React.useCallback(() => {
399
- if (isThreadDepthError) {
413
+ if (isPromptBlocked) {
400
414
  props.onNewConversation();
401
415
  return;
402
416
  }
@@ -408,7 +422,7 @@ function AskAiSearchBox(_ref) {
408
422
  onAskAiToggle(false);
409
423
  }, [
410
424
  askAiState,
411
- isThreadDepthError,
425
+ isPromptBlocked,
412
426
  onAskAiToggle,
413
427
  setAskAiState,
414
428
  props
@@ -417,8 +431,8 @@ function AskAiSearchBox(_ref) {
417
431
  type: "button",
418
432
  tabIndex: 0,
419
433
  className: "DocSearch-Action DocSearch-AskAi-Return",
420
- title: backToKeywordSearchButtonText,
421
- "aria-label": backToKeywordSearchButtonAriaLabel,
434
+ title: isPromptBlocked ? startNewConversationText : backToKeywordSearchButtonText,
435
+ "aria-label": isPromptBlocked ? startNewConversationText : backToKeywordSearchButtonAriaLabel,
422
436
  onClick: handleAskAiBackClick
423
437
  }, /* @__PURE__ */ React.createElement(BackIcon, null)) : void 0;
424
438
  const inputOverlay = heading ? /* @__PURE__ */ React.createElement(ModalHeading, {
@@ -583,7 +597,8 @@ const _excluded = [
583
597
  "recentSearchesWithFavoritesLimit",
584
598
  "indices",
585
599
  "facets",
586
- "isHybridModeSupported"
600
+ "isHybridModeSupported",
601
+ "footerAction"
587
602
  ];
588
603
  const _excluded2 = [
589
604
  "footer",
@@ -592,7 +607,7 @@ const _excluded2 = [
592
607
  ];
593
608
  function DocSearchAskAiModal(_ref) {
594
609
  var _translations$searchB, _askAiConfig$memory$e, _askAiConfig$memory, _askAiConfig$tools;
595
- let { appId, apiKey, askAi, maxResultsPerGroup, theme, onClose = noop, transformItems = identity, hitComponent = Hit, resultsFooterComponent = () => null, navigator, initialScrollY = 0, transformSearchClient = identity, disableUserPersonalization = false, initialQuery: initialQueryFromProp = "", translations = {}, getMissingResultsUrl, insights = false, onAskAiToggle, interceptAskAiEvent, isAskAiActive = false, recentSearchesLimit = 7, recentSearchesWithFavoritesLimit = 4, indices, facets, isHybridModeSupported = false } = _ref, props = _objectWithoutProperties(_ref, _excluded);
610
+ let { appId, apiKey, askAi, maxResultsPerGroup, theme, onClose = noop, transformItems = identity, hitComponent = Hit, resultsFooterComponent = () => null, navigator, initialScrollY = 0, transformSearchClient = identity, disableUserPersonalization = false, initialQuery: initialQueryFromProp = "", translations = {}, getMissingResultsUrl, insights = false, onAskAiToggle, interceptAskAiEvent, isAskAiActive = false, recentSearchesLimit = 7, recentSearchesWithFavoritesLimit = 4, indices, facets, isHybridModeSupported = false, footerAction } = _ref, props = _objectWithoutProperties(_ref, _excluded);
596
611
  const { footer: footerTranslations, searchBox: searchBoxTranslations, facets: facetBarTranslations } = translations, screenStateTranslations = _objectWithoutProperties(translations, _excluded2);
597
612
  const [state, setState] = React.useState({
598
613
  query: "",
@@ -613,7 +628,8 @@ function DocSearchAskAiModal(_ref) {
613
628
  var _translations$searchB3;
614
629
  placeholder = (translations === null || translations === void 0 || (_translations$searchB3 = translations.searchBox) === null || _translations$searchB3 === void 0 ? void 0 : _translations$searchB3.placeholderTextAskAi) || "Ask another question...";
615
630
  }
616
- const { containerRef, modalRef, formElementRef, dropdownRef, inputRef, snippetLength } = useModalRefs();
631
+ const { containerRef, modalRef, formElementRef, dropdownRef, inputRef } = useModalRefs();
632
+ const promptBlockingErrorId = React.useId();
617
633
  const { initialQuery, initialQueryFromSelection } = useInitialModalQuery(initialQueryFromProp);
618
634
  const searchClient = useSearchClient(appId, apiKey, transformSearchClient);
619
635
  const askAiConfig = typeof askAi === "object" ? askAi : null;
@@ -670,9 +686,17 @@ function DocSearchAskAiModal(_ref) {
670
686
  stoppedStream,
671
687
  chatId
672
688
  ]);
673
- const hasThreadDepthError = React.useMemo(() => {
674
- return status === "error" && isThreadDepthError(askAiError);
675
- }, [status, askAiError]);
689
+ const shouldBlockPrompt = React.useMemo(() => {
690
+ return status === "error" && isAskAiPromptBlockingError(askAiError);
691
+ }, [status, askAiError]) && (!isThreadDepthError(askAiError) || messages.some((message) => message.role === "assistant"));
692
+ const promptBlockingChrome = React.useMemo(() => {
693
+ if (!shouldBlockPrompt || askAiState === "new-conversation" || askAiState === "conversation-history") return;
694
+ return isAgentStudioTokenOutputLimitError(askAiError) ? "minimal" : "full";
695
+ }, [
696
+ askAiError,
697
+ askAiState,
698
+ shouldBlockPrompt
699
+ ]);
676
700
  const saveRecentSearch = useSaveRecentSearch({
677
701
  favoriteSearches,
678
702
  recentSearches,
@@ -767,7 +791,6 @@ function DocSearchAskAiModal(_ref) {
767
791
  setStatus,
768
792
  searchClient,
769
793
  indexes,
770
- snippetLength,
771
794
  insights: Boolean(insights),
772
795
  appId,
773
796
  apiKey,
@@ -797,7 +820,6 @@ function DocSearchAskAiModal(_ref) {
797
820
  inputRef,
798
821
  initialScrollY,
799
822
  modalRef,
800
- snippetLength,
801
823
  theme
802
824
  });
803
825
  React.useEffect(() => {
@@ -864,7 +886,8 @@ function DocSearchAskAiModal(_ref) {
864
886
  askAiError,
865
887
  askAiState,
866
888
  setAskAiState,
867
- isThreadDepthError: hasThreadDepthError && askAiState !== "new-conversation",
889
+ promptBlockingChrome,
890
+ promptBlockingErrorId,
868
891
  onClose,
869
892
  onAskAiToggle,
870
893
  onAskAgain: (query) => {
@@ -906,6 +929,7 @@ function DocSearchAskAiModal(_ref) {
906
929
  selectSuggestedQuestion,
907
930
  memoryEnabled,
908
931
  resultBadgeKey: props.resultBadgeKey,
932
+ promptBlockingErrorId,
909
933
  onAskAiToggle,
910
934
  onNewConversation: handleNewConversation,
911
935
  onItemClick: (item, event) => {
@@ -936,7 +960,8 @@ function DocSearchAskAiModal(_ref) {
936
960
  })),
937
961
  footer: /* @__PURE__ */ React.createElement(Footer, {
938
962
  translations: footerTranslations,
939
- isAskAiActive
963
+ isAskAiActive,
964
+ footerAction
940
965
  }),
941
966
  onClose
942
967
  });
@@ -944,4 +969,4 @@ function DocSearchAskAiModal(_ref) {
944
969
 
945
970
  //#endregion
946
971
  export { DocSearchAskAiModal as t };
947
- //# sourceMappingURL=DocSearchAskAiModal-BczGFkvR.js.map
972
+ //# sourceMappingURL=DocSearchAskAiModal-ByqIW5ZA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocSearchAskAiModal-ByqIW5ZA.js","names":[],"sources":["../../src/icons/MessageIcon.tsx","../../src/AggregatedSearchBlock.tsx","../../src/AskAiScreen.tsx","../../src/components/ui/RecentConversationsResults.tsx","../../src/components/AskAiStartScreen.tsx","../../src/ConversationHistoryScreen.tsx","../../src/NewConversationScreen.tsx","../../src/AskAiScreenState.tsx","../../src/ModalHeading.tsx","../../src/components/AskAiSearchBox.tsx","../../src/utils/createAskAiSources.ts","../../src/DocSearchAskAiModal.tsx"],"sourcesContent":["import React, { type JSX } from 'react';\n\nexport function MessageIcon(): JSX.Element {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"13\"\n height=\"13\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n","import React, { type JSX, Fragment } from 'react';\n\nimport type { AskAiScreenTranslations } from './AskAiScreen';\nimport { SearchIcon } from './icons';\n\ninterface AggregatedSearchBlockProps {\n queries: string[];\n translations: AskAiScreenTranslations;\n onSearchQueryClick: (query: string) => void;\n}\n\n// allow translators to return either simple string parts or a fully custom node\nexport interface AggregatedToolCallParts {\n before?: string;\n separator?: string;\n lastSeparator?: string;\n after?: string;\n}\n\n// default english implementation (\"Searched for \\\"A\\\", \\\"B\\\" and \\\"C\\\"\")\nconst defaultAggregatedToolCallParts: AggregatedToolCallParts = {\n before: 'Searched for ',\n separator: ', ',\n lastSeparator: ' and ',\n after: '',\n};\n\nexport function AggregatedSearchBlock({\n queries,\n translations,\n onSearchQueryClick,\n}: AggregatedSearchBlockProps): JSX.Element | null {\n // no queries? no render\n if (queries.length === 0) return null;\n\n // if the translator provides a fully custom node, render it and bail out.\n if (typeof translations.aggregatedToolCallNode === 'function') {\n return (\n <>{translations.aggregatedToolCallNode(queries, onSearchQueryClick)}</>\n );\n }\n\n // otherwise fall back to the classic english-pattern renderer.\n const parts = translations.aggregatedToolCallText\n ? translations.aggregatedToolCallText(queries)\n : defaultAggregatedToolCallParts;\n\n const {\n before = '',\n separator = ', ',\n lastSeparator = ' and ',\n after = '',\n } = parts || {};\n\n return (\n <div className=\"DocSearch-AskAiScreen-MessageContent-Tool Tool--AggregatedResult\">\n <SearchIcon size={18} />\n <span>\n {before && <span>{before}</span>}\n {queries.map((q, idx) => (\n // eslint-disable-next-line react/no-array-index-key\n <Fragment key={q + idx}>\n <span\n role=\"button\"\n tabIndex={0}\n className=\"DocSearch-AskAiScreen-MessageContent-Tool-Query\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSearchQueryClick(q);\n }\n }}\n onClick={() => onSearchQueryClick(q)}\n >\n &quot;{q}&quot;\n </span>\n {idx < queries.length - 2 && separator}\n {idx === queries.length - 2 && lastSeparator}\n </Fragment>\n ))}\n {after && <span>{after}</span>}\n </span>\n </div>\n );\n}\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport React, { type JSX, useMemo } from 'react';\n\nimport { AggregatedSearchBlock } from './AggregatedSearchBlock';\nimport type { AskAiScreenStateProps } from './AskAiScreenState';\nimport { ConversationPromptSuggestions } from './components/ConversationPromptSuggestions';\nimport { FeedbackActions } from './components/FeedbackActions';\nimport { SourcesPanel } from './components/SourcesPanel';\nimport { ToolCall, type ToolCallTranslations } from './components/ToolCall';\nimport { AlertIcon, LoadingIcon, SparklesIcon } from './icons';\nimport { MemoizedMarkdown } from './MemoizedMarkdown';\nimport type { StoredSearchPlugin } from './stored-searches';\nimport type {\n InternalDocSearchHit,\n OnAskAiFeedback,\n StoredAskAiState,\n} from './types';\nimport { type AIMessage, type ToolCalls } from './types/AskiAi';\nimport {\n extractLinksFromMessage,\n getAskAiBlockingBannerMessage,\n getMessageContent,\n isAskAiPromptBlockingError,\n isThreadDepthError,\n showAskAiBlockingBannerNewConversationLink,\n isAIToolPart,\n getAgentPromptSuggestions,\n} from './utils/ai';\nimport { groupConsecutiveToolResults } from './utils/groupConsecutiveToolResults';\n\nexport type AskAiScreenTranslations = Partial<\n // Inherit the shared tool-call translations, but expose the search-related\n // keys under AskAiScreen's own public names (see mapping below).\n Omit<ToolCallTranslations, 'searchingText' | 'toolCallResultText'> & {\n // Misc texts\n disclaimerText: string;\n /** Text shown describing a singular related source. */\n relatedSourcesText: string;\n /** Text shown describing multiple related sources. */\n relatedSourcesTextPlural: string;\n thinkingText: string;\n copyButtonText: string;\n copyButtonCopiedText: string;\n // Feedback buttons\n copyButtonTitle: string;\n likeButtonTitle: string;\n dislikeButtonTitle: string;\n thanksForFeedbackText: string;\n // Negative feedback note panel\n feedbackPanelTitle: string;\n feedbackDetailsPlaceholder: string;\n feedbackDisclaimerText: string;\n feedbackSubmitButtonText: string;\n feedbackCloseButtonTitle: string;\n feedbackTagIncorrect: string;\n feedbackTagNotWhatIAsked: string;\n feedbackTagSlowOrBuggy: string;\n feedbackTagStyleOrTone: string;\n feedbackTagSafetyOrLegal: string;\n feedbackTagOther: string;\n // Tool call texts\n /**\n * Text shown while assistant is performing search tool call. Maps to\n * `ToolCallTranslations.searchingText`.\n */\n duringToolCallText: string;\n /**\n * Text shown while assistant is finished performing tool call. Maps to\n * `ToolCallTranslations.toolCallResultText`.\n */\n afterToolCallText: string;\n /**\n * Build the full jsx element for the aggregated search block. If provided,\n * completely overrides the default english renderer.\n */\n aggregatedToolCallNode?: (\n queries: string[],\n onSearchQueryClick: (query: string) => void\n ) => React.ReactNode;\n /**\n * Generate the list connective parts only (backwards compatibility).\n * Receives full list of queries and should return translation parts for\n * before/after/separators. Example: (qs) => ({ before: 'searched for ',\n * separator: ', ', lastSeparator: ' and ', after: '' }).\n */\n aggregatedToolCallText?: (queries: string[]) => {\n before?: string;\n separator?: string;\n lastSeparator?: string;\n after?: string;\n };\n /** Message that's shown when user has stopped the streaming of a message. */\n stoppedStreamingText: string;\n /** Error title shown if there is an error while chatting. */\n errorTitleText: string;\n /** Message shown when thread depth limit is exceeded (AI-217 error). */\n threadDepthExceededMessage: string;\n /** Button text for starting a new conversation after thread depth error. */\n startNewConversationButtonText: string;\n suggestedPromptsTitleText: string;\n }\n>;\n\n/**\n * Maps AskAiScreen's public translation keys to the shared\n * `ToolCallTranslations` shape consumed by the `ToolCall` component, applying\n * default English values.\n */\nfunction toToolCallTranslations(\n translations: AskAiScreenTranslations\n): ToolCallTranslations {\n const {\n preToolCallText = 'Searching...',\n duringToolCallText = 'Searching...',\n afterToolCallText = 'Searched for',\n savedMemoryToolResultText = 'Saved to memory',\n memoryToolResultText = 'Used memory to enhance results',\n } = translations;\n\n return {\n preToolCallText,\n searchingText: duringToolCallText,\n toolCallResultText: afterToolCallText,\n savedMemoryToolResultText,\n memoryToolResultText,\n };\n}\n\ntype AskAiScreenProps = Omit<\n AskAiScreenStateProps<InternalDocSearchHit>,\n 'translations'\n> & {\n messages: AIMessage[];\n tools: ToolCalls;\n status: UseChatHelpers<AIMessage>['status'];\n askAiError?: Error;\n translations?: AskAiScreenTranslations;\n onNewConversation: () => void;\n onSelectPromptSuggestion: (prompt: string) => void;\n memoryEnabled?: boolean;\n};\n\ninterface AskAiScreenHeaderProps {\n disclaimerText: string;\n}\n\nexport interface Exchange {\n id: string;\n userMessage: AIMessage;\n assistantMessage: AIMessage | null;\n}\n\nfunction AskAiScreenDisclaimer({\n disclaimerText,\n}: AskAiScreenHeaderProps): JSX.Element {\n return (\n <p className=\"DocSearch-AskAiScreen-Disclaimer\">\n <SparklesIcon /> {disclaimerText}\n </p>\n );\n}\n\ninterface AskAiExchangeCardProps {\n exchange: Exchange;\n askAiError?: Error;\n isLastExchange: boolean;\n loadingStatus: UseChatHelpers<AIMessage>['status'];\n onSearchQueryClick: (query: string) => void;\n translations: AskAiScreenTranslations;\n tools: ToolCalls;\n conversations: StoredSearchPlugin<StoredAskAiState>;\n onFeedback?: OnAskAiFeedback;\n memoryEnabled?: boolean;\n onSelectPromptSuggestion: (prompt: string) => void;\n}\n\nfunction AskAiExchangeCard({\n exchange,\n askAiError,\n isLastExchange,\n loadingStatus,\n onSearchQueryClick,\n translations,\n tools,\n conversations,\n onFeedback,\n memoryEnabled,\n onSelectPromptSuggestion,\n}: AskAiExchangeCardProps): JSX.Element {\n const { userMessage, assistantMessage } = exchange;\n\n const {\n stoppedStreamingText = 'You stopped this response',\n errorTitleText = 'Chat error',\n relatedSourcesText,\n relatedSourcesTextPlural,\n suggestedPromptsTitleText = 'Suggested prompts',\n } = translations;\n\n const toolCallTranslations = useMemo(\n () => toToolCallTranslations(translations),\n [translations]\n );\n\n const isPromptBlockingError = isAskAiPromptBlockingError(askAiError);\n\n const assistantContent = useMemo(\n () => getMessageContent(assistantMessage),\n [assistantMessage]\n );\n const userContent = useMemo(\n () => getMessageContent(userMessage),\n [userMessage]\n );\n\n const urlsToDisplay = React.useMemo(\n () => extractLinksFromMessage(assistantMessage),\n [assistantMessage]\n );\n\n const displayParts = React.useMemo(() => {\n return groupConsecutiveToolResults(assistantMessage?.parts || []);\n }, [assistantMessage]);\n\n const promptSuggestions = useMemo(() => {\n if (!isLastExchange) return [];\n return getAgentPromptSuggestions(assistantMessage?.parts || []);\n }, [assistantMessage, isLastExchange]);\n\n const wasStopped =\n userMessage.metadata?.stopped || assistantMessage?.metadata?.stopped;\n\n const showActions =\n !wasStopped &&\n (!isLastExchange ||\n (isLastExchange &&\n loadingStatus === 'ready' &&\n Boolean(assistantMessage)));\n\n const isThinking =\n ['submitted', 'streaming'].includes(loadingStatus) &&\n isLastExchange &&\n !displayParts.some((part) => part.type !== 'step-start');\n\n const messageId = assistantMessage?.id || exchange.id;\n\n return (\n <div className=\"DocSearch-AskAiScreen-Response-Container\">\n <div className=\"DocSearch-AskAiScreen-Response\">\n <div className=\"DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user\">\n <p className=\"DocSearch-AskAiScreen-Query\">{userContent ?? ''}</p>\n </div>\n <div className=\"DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant\">\n <div className=\"DocSearch-AskAiScreen-MessageContent\">\n {loadingStatus === 'error' &&\n askAiError &&\n isLastExchange &&\n !isPromptBlockingError && (\n <div className=\"DocSearch-AskAiScreen-Error\" role=\"alert\">\n <AlertIcon aria-hidden=\"true\" />\n <div className=\"DocSearch-AskAiScreen-Error-Content\">\n <h4 className=\"DocSearch-AskAiScreen-Error-Title\">\n {errorTitleText}\n </h4>\n <MemoizedMarkdown\n content={askAiError.message}\n copyButtonText=\"\"\n copyButtonCopiedText=\"\"\n isStreaming={false}\n />\n </div>\n </div>\n )}\n {isThinking && (\n <div\n className=\"DocSearch-AskAiScreen-MessageContent-Thinking\"\n role=\"status\"\n >\n <span className=\"DocSearch-shimmer\">\n {translations.thinkingText || 'Thinking...'}\n </span>\n <span className=\"DocSearch-AskAi-Thinking-Skeleton DocSearch-shimmer\" />\n <span className=\"DocSearch-AskAi-Thinking-Skeleton DocSearch-AskAi-Thinking-Skeleton--short DocSearch-shimmer\" />\n </div>\n )}\n {displayParts.map((part, idx) => {\n const index = idx;\n\n if (typeof part === 'string') {\n return (\n <MemoizedMarkdown\n key={index}\n content={part}\n copyButtonText={translations.copyButtonText || 'Copy'}\n copyButtonCopiedText={\n translations.copyButtonCopiedText || 'Copied!'\n }\n isStreaming={loadingStatus === 'streaming'}\n />\n );\n }\n\n if (isAIToolPart(part)) {\n return (\n <ToolCall\n key={index}\n translations={toolCallTranslations}\n part={part}\n tools={tools}\n memoryEnabled={memoryEnabled}\n onSearchQueryClick={onSearchQueryClick}\n />\n );\n }\n\n if (part.type === 'aggregated-tool-call') {\n return (\n <AggregatedSearchBlock\n key={index}\n queries={part.queries}\n translations={translations}\n onSearchQueryClick={onSearchQueryClick}\n />\n );\n }\n\n if (part.type === 'reasoning' && part.state === 'streaming') {\n return (\n <div\n key={index}\n className=\"DocSearch-AskAiScreen-MessageContent-Reasoning DocSearch-shimmer\"\n >\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n <span className=\"DocSearch-shimmer\">Reasoning...</span>\n </div>\n );\n }\n\n if (part.type === 'text') {\n return (\n <MemoizedMarkdown\n key={index}\n content={part.text}\n copyButtonText={translations.copyButtonText || 'Copy'}\n copyButtonCopiedText={\n translations.copyButtonCopiedText || 'Copied!'\n }\n isStreaming={part.state === 'streaming'}\n />\n );\n }\n\n // fallback for unknown part type\n return null;\n })}\n </div>\n\n {wasStopped && (\n <p className=\"DocSearch-AskAiScreen-MessageContent-Stopped\">\n {stoppedStreamingText}\n </p>\n )}\n </div>\n <div className=\"DocSearch-AskAiScreen-Answer-Footer\">\n <SourcesPanel\n links={urlsToDisplay}\n titleText={relatedSourcesText}\n pluralTitleText={relatedSourcesTextPlural}\n />\n <FeedbackActions\n id={messageId}\n showActions={showActions}\n latestAssistantMessageContent={assistantContent || null}\n translations={translations}\n conversations={conversations}\n onFeedback={onFeedback}\n />\n </div>\n\n {promptSuggestions.length > 0 && (\n <ConversationPromptSuggestions\n title={suggestedPromptsTitleText}\n suggestions={promptSuggestions}\n onSelectPromptSuggestion={onSelectPromptSuggestion}\n />\n )}\n </div>\n </div>\n );\n}\n\nexport function AskAiScreen({\n translations = {},\n ...props\n}: AskAiScreenProps): JSX.Element | null {\n const {\n disclaimerText = 'Answers are generated with AI which can make mistakes.',\n threadDepthExceededMessage = 'This conversation is now closed to keep responses accurate.',\n startNewConversationButtonText = 'Start a new conversation',\n } = translations;\n\n const { messages, tools, askAiError, status, memoryEnabled } = props;\n\n const hasPromptBlockingError = useMemo(() => {\n return status === 'error' && isAskAiPromptBlockingError(askAiError);\n }, [status, askAiError]);\n const blockingMessage = useMemo(\n () => getAskAiBlockingBannerMessage(askAiError),\n [askAiError]\n );\n const showNewConversationLink =\n showAskAiBlockingBannerNewConversationLink(askAiError);\n\n // Group messages into exchanges (user + assistant pairs)\n const exchanges: Exchange[] = useMemo(() => {\n const grouped: Exchange[] = [];\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].role === 'user') {\n const userMessage = messages[i];\n const assistantMessage =\n messages[i + 1]?.role === 'assistant' ? messages[i + 1] : null;\n grouped.push({ id: userMessage.id, userMessage, assistantMessage });\n if (assistantMessage) {\n i++;\n }\n }\n }\n\n return grouped;\n }, [messages]);\n\n const handleSearchQueryClick = (query: string): void => {\n props.onAskAiToggle(false);\n props.setQuery(query);\n };\n\n const showBlockingBanner =\n hasPromptBlockingError &&\n (!isThreadDepthError(askAiError) ||\n messages.some((message) => message.role === 'assistant'));\n\n return (\n <div className=\"DocSearch-AskAiScreen DocSearch-AskAiScreen-Container\">\n <div id={props.promptBlockingErrorId} role=\"alert\">\n {showBlockingBanner && (\n <div className=\"DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth\">\n <div className=\"DocSearch-AskAiScreen-Error-Content\">\n <p className=\"DocSearch-AskAiScreen-Error-Title\">\n {blockingMessage ??\n (isThreadDepthError(askAiError)\n ? threadDepthExceededMessage\n : 'This conversation cannot continue.')}\n </p>\n {showNewConversationLink && (\n <p>\n <button\n type=\"button\"\n className=\"DocSearch-ThreadDepthError-Link\"\n onClick={props.onNewConversation}\n >\n {startNewConversationButtonText}\n </button>{' '}\n to continue.\n </p>\n )}\n </div>\n </div>\n )}\n </div>\n\n <AskAiScreenDisclaimer disclaimerText={disclaimerText} />\n\n <div className=\"DocSearch-AskAiScreen-Body\">\n <div className=\"DocSearch-AskAiScreen-ExchangesList\">\n {exchanges\n .slice()\n .reverse()\n .map((exchange, index) => (\n <AskAiExchangeCard\n key={exchange.id}\n exchange={exchange}\n askAiError={props.askAiError}\n isLastExchange={index === 0}\n loadingStatus={props.status}\n translations={translations}\n tools={tools}\n conversations={props.conversations}\n memoryEnabled={memoryEnabled}\n onSearchQueryClick={handleSearchQueryClick}\n onFeedback={props.onFeedback}\n onSelectPromptSuggestion={props.onSelectPromptSuggestion}\n />\n ))}\n </div>\n </div>\n </div>\n );\n}\n","import React, { type JSX } from 'react';\n\nimport type { AskAiScreenStateProps } from '../../AskAiScreenState';\nimport { CloseIcon, MessageIcon } from '../../icons';\nimport { Results } from '../../Results';\nimport type { InternalDocSearchHit } from '../../types';\nimport { getCollection } from '../../utils';\n\nexport type RecentConversationsResultsTranslations = Partial<{\n recentConversationsTitle: string;\n removeRecentConversationButtonTitle: string;\n}>;\n\ntype RecentConversationsResultsProps = Omit<\n AskAiScreenStateProps<InternalDocSearchHit>,\n 'translations'\n> & {\n translations?: RecentConversationsResultsTranslations;\n};\n\nexport function RecentConversationsResults({\n translations = {},\n ...props\n}: RecentConversationsResultsProps): JSX.Element | null {\n const {\n recentConversationsTitle = 'Resume AI conversations',\n removeRecentConversationButtonTitle = 'Remove this conversation from history',\n } = translations;\n const recentConversations = getCollection(props.state, 'recentConversations');\n\n if (!recentConversations) {\n return null;\n }\n\n return (\n <Results\n {...props}\n title={recentConversationsTitle}\n collection={recentConversations}\n renderIcon={() => (\n <div className=\"DocSearch-Hit-icon DocSearch-Hit-icon--start\">\n <MessageIcon />\n </div>\n )}\n renderAction={({ item }) => (\n <div className=\"DocSearch-Hit-action\">\n <button\n className=\"DocSearch-Hit-action-button\"\n title={removeRecentConversationButtonTitle}\n type=\"submit\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n props.conversations.remove(item);\n props.refresh();\n }}\n >\n <CloseIcon />\n </button>\n </div>\n )}\n />\n );\n}\n","import React, { type JSX } from 'react';\n\nimport type { AskAiScreenStateProps } from '../AskAiScreenState';\nimport type { InternalDocSearchHit } from '../types';\n\nimport type { RecentConversationsResultsTranslations } from './ui/RecentConversationsResults';\nimport { RecentConversationsResults } from './ui/RecentConversationsResults';\nimport type { StoredSearchesSectionsTranslations } from './ui/StoredSearchesSections';\nimport { StoredSearchesSections } from './ui/StoredSearchesSections';\n\nexport type AskAiStartScreenTranslations =\n RecentConversationsResultsTranslations & StoredSearchesSectionsTranslations;\n\ntype AskAiStartScreenProps = Omit<\n AskAiScreenStateProps<InternalDocSearchHit>,\n 'translations'\n> & {\n hasCollections: boolean;\n translations?: AskAiStartScreenTranslations;\n};\n\nexport function AskAiStartScreen({\n translations = {},\n ...props\n}: AskAiStartScreenProps): JSX.Element | null {\n return (\n <div className=\"DocSearch-Dropdown-Container\">\n <RecentConversationsResults {...props} translations={translations} />\n <StoredSearchesSections {...props} translations={translations} />\n </div>\n );\n}\n","import type { JSX } from 'react';\nimport React from 'react';\n\nimport type { AskAiScreenStateProps } from './AskAiScreenState';\nimport { CloseIcon, SparklesIcon } from './icons';\nimport { Results } from './Results';\nimport type { ResultsScreenTranslations } from './ResultsScreen';\nimport type { InternalDocSearchHit } from './types';\nimport { getCollection } from './utils';\n\ntype ConversationHistoryScreenProps = Omit<\n AskAiScreenStateProps<InternalDocSearchHit>,\n 'translations'\n> & {\n translations?: ResultsScreenTranslations;\n};\n\nexport function ConversationHistoryScreen({\n onAskAiToggle,\n ...props\n}: ConversationHistoryScreenProps): JSX.Element | null {\n const collection = React.useMemo(\n () => getCollection(props.state, 'recentConversations'),\n [props.state]\n );\n\n React.useEffect(() => {\n if (!collection || collection.items.length === 0) {\n onAskAiToggle(true);\n }\n }, [collection, onAskAiToggle]);\n\n if (!collection) {\n return null;\n }\n\n return (\n <div className=\"DocSearch-Dropdown-Container DocSearch-Conversation-History\">\n <Results\n {...props}\n key={collection.source.sourceId}\n title=\"\"\n translations={props.translations}\n collection={collection}\n renderIcon={() => (\n <div className=\"DocSearch-Hit-icon\">\n <SparklesIcon />\n </div>\n )}\n renderAction={({ item }) => (\n <div className=\"DocSearch-Hit-action\">\n <button\n type=\"button\"\n className=\"DocSearch-Hit-action-button\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n props.conversations.remove(item);\n props.refresh();\n }}\n >\n <CloseIcon />\n </button>\n </div>\n )}\n />\n </div>\n );\n}\n","import React, { type JSX } from 'react';\n\nimport type { SuggestedQuestionHit } from './types';\n\nexport type NewConversationTranslations = Partial<{\n newConversationTitle: string;\n newConversationDescription: string;\n}>;\n\ninterface NewConversationProps {\n suggestedQuestions?: SuggestedQuestionHit[];\n selectSuggestedQuestion: (question: SuggestedQuestionHit) => void;\n translations?: NewConversationTranslations;\n}\n\nexport function NewConversationScreen({\n translations = {},\n suggestedQuestions = [],\n selectSuggestedQuestion,\n}: NewConversationProps): JSX.Element {\n const {\n newConversationTitle = 'How can I help you today?',\n newConversationDescription = 'I search through your documentation to help you find setup guides, feature details and troubleshooting tips, fast.',\n } = translations;\n\n return (\n <div className=\"DocSearch-NewConversationScreen\">\n <h3 className=\"DocSearch-NewConversationScreen-Title\">\n {newConversationTitle}\n </h3>\n <p className=\"DocSearch-NewConversationScreen-Description\">\n {newConversationDescription}\n </p>\n\n <div className=\"DocSearch-NewConversationScreen-SuggestedQuestions\">\n {suggestedQuestions.map((question) => (\n <button\n key={question.objectID}\n type=\"button\"\n className=\"DocSearch-NewConversationScreen-SuggestedQuestion\"\n onClick={() => selectSuggestedQuestion(question)}\n >\n {question.question}\n </button>\n ))}\n </div>\n </div>\n );\n}\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport type {\n AutocompleteApi,\n AutocompleteState,\n BaseItem,\n} from '@algolia/autocomplete-core';\nimport type { JSX } from 'react';\nimport React from 'react';\n\nimport type { AskAiScreenTranslations } from './AskAiScreen';\nimport { AskAiScreen } from './AskAiScreen';\nimport type { AskAiStartScreenTranslations } from './components/AskAiStartScreen';\nimport { AskAiStartScreen } from './components/AskAiStartScreen';\nimport { ConversationHistoryScreen } from './ConversationHistoryScreen';\nimport type { DocSearchProps } from './DocSearch';\nimport type { ErrorScreenTranslations } from './ErrorScreen';\nimport { ErrorScreen } from './ErrorScreen';\nimport type { NewConversationTranslations } from './NewConversationScreen';\nimport { NewConversationScreen } from './NewConversationScreen';\nimport type { NoResultsScreenTranslations } from './NoResultsScreen';\nimport { NoResultsScreen } from './NoResultsScreen';\nimport type { ResultsScreenTranslations } from './ResultsScreen';\nimport { ResultsScreen } from './ResultsScreen';\nimport type { StoredSearchPlugin } from './stored-searches';\nimport type {\n InternalDocSearchHit,\n OnAskAiFeedback,\n StoredAskAiState,\n StoredDocSearchHit,\n SuggestedQuestionHit,\n} from './types';\nimport type { AIMessage, AskAiState, ToolCalls } from './types/AskiAi';\nimport { isQueryEmpty } from './utils';\n\nexport type AskAiScreenStateTranslations = Partial<{\n errorScreen: ErrorScreenTranslations;\n startScreen: AskAiStartScreenTranslations;\n noResultsScreen: NoResultsScreenTranslations;\n resultsScreen: ResultsScreenTranslations;\n askAiScreen: AskAiScreenTranslations;\n newConversation: NewConversationTranslations;\n}>;\n\nexport interface AskAiScreenStateProps<\n TItem extends BaseItem,\n> extends AutocompleteApi<\n TItem,\n React.FormEvent,\n React.MouseEvent,\n React.KeyboardEvent\n> {\n state: AutocompleteState<TItem>;\n recentSearches: StoredSearchPlugin<StoredDocSearchHit>;\n favoriteSearches: StoredSearchPlugin<StoredDocSearchHit>;\n conversations: StoredSearchPlugin<StoredAskAiState>;\n onItemClick: (\n item: InternalDocSearchHit,\n event: KeyboardEvent | MouseEvent\n ) => void;\n onAskAiToggle: (toggle: boolean) => void;\n isAskAiActive: boolean;\n canHandleAskAi: boolean;\n inputRef: React.MutableRefObject<HTMLInputElement | null>;\n hitComponent: DocSearchProps['hitComponent'];\n indexName: string;\n messages: UseChatHelpers<AIMessage>['messages'];\n tools: ToolCalls;\n status: UseChatHelpers<AIMessage>['status'];\n askAiError?: Error;\n disableUserPersonalization: boolean;\n resultsFooterComponent: DocSearchProps['resultsFooterComponent'];\n translations: AskAiScreenStateTranslations;\n getMissingResultsUrl?: DocSearchProps['getMissingResultsUrl'];\n hasCollections: boolean;\n onFeedback?: OnAskAiFeedback;\n askAiState: AskAiState;\n selectAskAiQuestion: (toggle: boolean, query: string) => void;\n suggestedQuestions: SuggestedQuestionHit[];\n selectSuggestedQuestion: (question: SuggestedQuestionHit) => void;\n onNewConversation: () => void;\n memoryEnabled?: boolean;\n resultBadgeKey?: string;\n promptBlockingErrorId?: string;\n}\n\nexport const AskAiScreenState = React.memo(\n ({\n translations = {},\n selectAskAiQuestion,\n ...props\n }: AskAiScreenStateProps<InternalDocSearchHit>): JSX.Element => {\n const handleSelectPromptSuggestion = React.useCallback(\n (prompt: string) => {\n selectAskAiQuestion(true, prompt);\n },\n [selectAskAiQuestion]\n );\n\n if (\n props.canHandleAskAi &&\n props.isAskAiActive &&\n props.askAiState === 'conversation-history'\n ) {\n return (\n <ConversationHistoryScreen\n selectAskAiQuestion={selectAskAiQuestion}\n {...props}\n />\n );\n }\n\n if (\n props.canHandleAskAi &&\n props.isAskAiActive &&\n props.askAiState === 'new-conversation'\n ) {\n return (\n <NewConversationScreen\n translations={translations?.newConversation}\n selectSuggestedQuestion={props.selectSuggestedQuestion}\n suggestedQuestions={props.suggestedQuestions}\n />\n );\n }\n\n if (props.isAskAiActive && props.canHandleAskAi) {\n return (\n <AskAiScreen\n {...props}\n messages={props.messages}\n tools={props.tools}\n status={props.status}\n askAiError={props.askAiError}\n translations={translations?.askAiScreen}\n memoryEnabled={props.memoryEnabled}\n selectAskAiQuestion={selectAskAiQuestion}\n onSelectPromptSuggestion={handleSelectPromptSuggestion}\n />\n );\n }\n\n if (props.state?.status === 'error') {\n return <ErrorScreen translations={translations?.errorScreen} />;\n }\n\n if (isQueryEmpty(props.state.query)) {\n return (\n <AskAiStartScreen\n {...props}\n hasCollections={props.hasCollections}\n translations={translations?.startScreen}\n selectAskAiQuestion={selectAskAiQuestion}\n />\n );\n }\n\n if (!props.hasCollections && !props.canHandleAskAi) {\n return (\n <NoResultsScreen\n {...props}\n translations={translations?.noResultsScreen}\n />\n );\n }\n\n return (\n <>\n <ResultsScreen {...props} translations={translations?.resultsScreen} />\n {props.canHandleAskAi &&\n !props.hasCollections && (\n // if there's one collection it is the ask ai action, show the no results screen\n <NoResultsScreen\n {...props}\n translations={translations?.noResultsScreen}\n />\n )}\n </>\n );\n },\n function areEqual(prevProps, nextProps) {\n const askAiStateChanged =\n prevProps.isAskAiActive !== nextProps.isAskAiActive ||\n prevProps.askAiState !== nextProps.askAiState ||\n prevProps.canHandleAskAi !== nextProps.canHandleAskAi;\n\n // Something triggered an Ask AI related state change, perform a new render\n if (askAiStateChanged) {\n return false;\n }\n\n const isLoading =\n nextProps.state.status === 'loading' ||\n nextProps.state.status === 'stalled';\n\n const isWaitingForCollections =\n nextProps.state.status === 'idle' &&\n !isQueryEmpty(nextProps.state.query) &&\n prevProps.state.query !== nextProps.state.query &&\n prevProps.state.collections === nextProps.state.collections;\n\n return isLoading || isWaitingForCollections;\n }\n);\n","import React from 'react';\nimport type { JSX } from 'react';\n\ntype ModalHeadingProps = {\n heading: string;\n shimmer?: boolean;\n};\n\nexport function ModalHeading({\n heading,\n shimmer = false,\n}: ModalHeadingProps): JSX.Element {\n return (\n <span\n className={`DocSearch-Modal-heading${shimmer ? ' DocSearch-shimmer' : ''}`}\n >\n {heading}\n </span>\n );\n}\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport type {\n AutocompleteApi,\n AutocompleteState,\n} from '@algolia/autocomplete-core';\nimport React, { type JSX, type RefObject } from 'react';\n\nimport {\n ConversationHistoryIcon,\n MoreVerticalIcon,\n NewConversationIcon,\n StopIcon,\n BackIcon,\n} from '../icons';\nimport { Menu } from '../Menu';\nimport { ModalHeading } from '../ModalHeading';\nimport type { InternalDocSearchHit } from '../types';\nimport type { AIMessage, AskAiState } from '../types/AskiAi';\nimport { getCollection, isQueryEmpty } from '../utils';\n\nimport { SearchBoxForm } from './ui/SearchBoxForm';\n\nexport type AskAiSearchBoxTranslations = Partial<{\n clearButtonTitle: string;\n clearButtonAriaLabel: string;\n closeButtonText: string;\n closeButtonAriaLabel: string;\n placeholderText: string;\n placeholderTextAskAi: string;\n placeholderTextAskAiStreaming: string;\n enterKeyHint: string;\n enterKeyHintAskAi: string;\n searchInputLabel: string;\n backToKeywordSearchButtonText: string;\n backToKeywordSearchButtonAriaLabel: string;\n newConversationPlaceholder: string;\n conversationHistoryTitle: string;\n startNewConversationText: string;\n viewConversationHistoryText: string;\n threadDepthErrorPlaceholder: string;\n}>;\n\ninterface AskAiSearchBoxProps extends AutocompleteApi<\n InternalDocSearchHit,\n React.FormEvent,\n React.MouseEvent,\n React.KeyboardEvent\n> {\n state: AutocompleteState<InternalDocSearchHit>;\n autoFocus: boolean;\n inputRef: RefObject<HTMLInputElement | null>;\n onClose: () => void;\n onAskAiToggle: (toggle: boolean) => void;\n onAskAgain: (query: string) => void;\n onStopAskAiStreaming: () => Promise<void>;\n placeholder: string;\n isAskAiActive: boolean;\n askAiStatus: UseChatHelpers<AIMessage>['status'];\n askAiError?: Error;\n isFromSelection: boolean;\n translations?: AskAiSearchBoxTranslations;\n askAiState: AskAiState;\n setAskAiState: (state: AskAiState) => void;\n onNewConversation: () => void;\n onViewConversationHistory: () => void;\n promptBlockingChrome?: 'minimal' | 'full';\n promptBlockingErrorId?: string;\n}\n\nexport function AskAiSearchBox({\n translations = {},\n askAiState,\n onAskAiToggle,\n setAskAiState,\n ...props\n}: AskAiSearchBoxProps): JSX.Element {\n const {\n clearButtonTitle = 'Clear',\n clearButtonAriaLabel = 'Clear the query',\n closeButtonText = 'Close',\n closeButtonAriaLabel = 'Close',\n searchInputLabel = 'Search',\n backToKeywordSearchButtonText = 'Back to keyword search',\n backToKeywordSearchButtonAriaLabel = 'Back to keyword search',\n placeholderTextAskAiStreaming = 'Answering...',\n newConversationPlaceholder = 'Ask a question',\n conversationHistoryTitle = 'My conversation history',\n startNewConversationText = 'Start a new conversation',\n viewConversationHistoryText = 'Conversation history',\n threadDepthErrorPlaceholder = 'Conversation limit reached',\n } = translations;\n\n const hasRecentConversations = React.useMemo(() => {\n const askAiSource = getCollection(props.state, 'recentConversations');\n\n if (!askAiSource) {\n return false;\n }\n\n return askAiSource.items.length > 0;\n }, [props.state]);\n\n const baseInputProps = props.getInputProps({\n inputElement: props.inputRef.current!,\n autoFocus: props.autoFocus,\n });\n const blockedKeys = new Set(['ArrowUp', 'ArrowDown', 'Enter']);\n const origOnKeyDown = baseInputProps.onKeyDown;\n const origOnChange = baseInputProps.onChange;\n const isAskAiStreaming =\n props.askAiStatus === 'streaming' || props.askAiStatus === 'submitted';\n const renderMoreOptions =\n props.isAskAiActive && askAiState !== 'conversation-history';\n\n const isPromptBlocked = Boolean(props.promptBlockingChrome);\n let searchPlaceholder = props.placeholder;\n\n if (askAiState === 'new-conversation') {\n searchPlaceholder = newConversationPlaceholder;\n }\n\n if (props.promptBlockingChrome === 'full' && props.isAskAiActive) {\n searchPlaceholder = threadDepthErrorPlaceholder;\n }\n\n let heading: string | null = null;\n\n if (isAskAiStreaming) {\n heading = placeholderTextAskAiStreaming;\n }\n\n if (askAiState === 'conversation-history') {\n heading = conversationHistoryTitle;\n }\n\n // when returning to another status than streaming or submitted, we focus on the input\n React.useEffect(() => {\n if (\n props.askAiStatus !== 'streaming' &&\n props.askAiStatus !== 'submitted' &&\n props.inputRef.current\n ) {\n props.inputRef.current.focus();\n }\n }, [props.askAiStatus, props.inputRef]);\n\n /**\n * We need to block the default behavior of the input when Ask AI is active.\n * This is because the input is used to ask another question when the user\n * presses enter.\n *\n * Learn more on default autocomplete behavior:\n * https://github.com/algolia/autocomplete/blob/next/packages/autocomplete-core/src/getDefaultProps.ts.\n */\n const inputProps = {\n enterKeyHint: props.isAskAiActive\n ? ('enter' as const)\n : ('search' as const),\n onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>): void => {\n if (isPromptBlocked && props.isAskAiActive && blockedKeys.has(e.key)) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n let askAiHandled = false;\n // block these up, down, enter listeners when Ask AI is active\n if (props.isAskAiActive && blockedKeys.has(e.key)) {\n // enter key asks another question\n if (\n e.key === 'Enter' &&\n !isAskAiStreaming &&\n !isQueryEmpty(props.state.query)\n ) {\n props.onAskAgain(props.state.query);\n }\n\n askAiHandled = true;\n }\n\n if (askAiHandled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n origOnKeyDown?.(e);\n },\n onChange: (e: React.ChangeEvent<HTMLInputElement>): void => {\n if (isPromptBlocked && props.isAskAiActive) {\n e.preventDefault();\n return;\n }\n\n if (props.isAskAiActive) {\n props.setQuery(e.currentTarget.value);\n // block search when Ask AI is active\n // we don't want to trigger the search when the user types\n // we already know they are asking a question\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n origOnChange?.(e);\n },\n disabled: isAskAiStreaming,\n readOnly: isPromptBlocked && props.isAskAiActive,\n 'aria-disabled': isPromptBlocked && props.isAskAiActive,\n 'aria-describedby':\n isPromptBlocked && props.isAskAiActive\n ? props.promptBlockingErrorId\n : undefined,\n };\n\n const handleAskAiBackClick = React.useCallback((): void => {\n if (isPromptBlocked) {\n props.onNewConversation();\n return;\n }\n\n if (askAiState === 'conversation-history') {\n onAskAiToggle(true);\n setAskAiState('initial');\n return;\n }\n\n onAskAiToggle(false);\n }, [askAiState, isPromptBlocked, onAskAiToggle, setAskAiState, props]);\n\n const leadingElement = props.isAskAiActive ? (\n <button\n type=\"button\"\n tabIndex={0}\n className=\"DocSearch-Action DocSearch-AskAi-Return\"\n title={\n isPromptBlocked\n ? startNewConversationText\n : backToKeywordSearchButtonText\n }\n aria-label={\n isPromptBlocked\n ? startNewConversationText\n : backToKeywordSearchButtonAriaLabel\n }\n onClick={handleAskAiBackClick}\n >\n <BackIcon />\n </button>\n ) : undefined;\n const inputOverlay = heading ? (\n <ModalHeading heading={heading} shimmer={isAskAiStreaming} />\n ) : null;\n const actionsBeforeClose = (\n <>\n {!props.isAskAiActive && (\n <>\n <button\n className=\"DocSearch-Clear\"\n type=\"reset\"\n aria-label={clearButtonAriaLabel}\n hidden={!props.state.query}\n tabIndex={props.state.query ? 0 : -1}\n aria-hidden={!props.state.query ? 'true' : 'false'}\n >\n {clearButtonTitle}\n </button>\n\n {props.state.query && <div className=\"DocSearch-Divider\" />}\n </>\n )}\n\n {isAskAiStreaming && (\n <>\n <button\n type=\"button\"\n className=\"DocSearch-Action DocSearch-StopStreaming\"\n onClick={props.onStopAskAiStreaming}\n >\n <StopIcon />\n </button>\n\n <div className=\"DocSearch-Divider\" />\n </>\n )}\n\n {renderMoreOptions && (\n <>\n <Menu>\n <Menu.Trigger className=\"DocSearch-Action\">\n <MoreVerticalIcon />\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item onClick={props.onNewConversation}>\n <NewConversationIcon />\n {startNewConversationText}\n </Menu.Item>\n {hasRecentConversations && (\n <Menu.Item onClick={props.onViewConversationHistory}>\n <ConversationHistoryIcon />\n {viewConversationHistoryText}\n </Menu.Item>\n )}\n </Menu.Content>\n </Menu>\n\n <div className=\"DocSearch-Divider\" />\n </>\n )}\n </>\n );\n\n return (\n <SearchBoxForm\n {...props}\n placeholder={searchPlaceholder}\n clearButtonTitle={clearButtonTitle}\n clearButtonAriaLabel={clearButtonAriaLabel}\n closeButtonText={closeButtonText}\n closeButtonAriaLabel={closeButtonAriaLabel}\n searchInputLabel={searchInputLabel}\n leadingElement={leadingElement}\n inputOverlay={inputOverlay}\n hideInput={Boolean(heading)}\n actionsBeforeClose={actionsBeforeClose}\n inputProps={inputProps}\n />\n );\n}\n","import type { AutocompleteSource } from '@algolia/autocomplete-core';\nimport type { SearchResponse } from 'algoliasearch/lite';\n\nimport type { DocSearchTransformClient } from '../DocSearch';\nimport type { PromptSuggestions } from '../DocSearchAI';\nimport type { InternalDocSearchHit } from '../types';\nimport type { AIMessage, PromptSuggestion } from '../types/AskiAi';\n\nimport { SOURCE_IDS } from './collections';\n\nconst MAX_RECENT_CONVERSATIONS_DISPLAYED = 3;\n\nconst EMPTY_RESULT_CONTENT = {\n value: '',\n matchLevel: 'none',\n matchedWords: [],\n} satisfies InternalDocSearchHit['_highlightResult']['content'];\nconst EMPTY_HIERARCHY_HIGHLIGHT_RESULT = {\n lvl0: EMPTY_RESULT_CONTENT,\n lvl1: EMPTY_RESULT_CONTENT,\n lvl2: EMPTY_RESULT_CONTENT,\n lvl3: EMPTY_RESULT_CONTENT,\n lvl4: EMPTY_RESULT_CONTENT,\n lvl5: EMPTY_RESULT_CONTENT,\n lvl6: EMPTY_RESULT_CONTENT,\n} satisfies InternalDocSearchHit['_highlightResult']['hierarchy'];\nconst EMPTY_HIGHLIGHT_RESULT: InternalDocSearchHit['_highlightResult'] = {\n content: EMPTY_RESULT_CONTENT,\n hierarchy: EMPTY_HIERARCHY_HIGHLIGHT_RESULT,\n hierarchy_camel: [],\n};\nconst EMPTY_SNIPPET_RESULT: InternalDocSearchHit['_snippetResult'] = {\n content: EMPTY_RESULT_CONTENT,\n hierarchy: EMPTY_HIERARCHY_HIGHLIGHT_RESULT,\n hierarchy_camel: [],\n};\n\nexport function buildRecentConversationSources({\n conversations,\n disableUserPersonalization,\n setMessages,\n onAskAiToggle,\n}: {\n conversations: { getAll: () => unknown[] };\n disableUserPersonalization: boolean;\n setMessages: (messages: AIMessage[]) => void;\n onAskAiToggle: (toggle: boolean) => void;\n}): Array<\n AutocompleteSource<InternalDocSearchHit & { messages?: AIMessage[] }>\n> {\n return [\n {\n sourceId: SOURCE_IDS.recentConversations,\n getItems(): InternalDocSearchHit[] {\n if (disableUserPersonalization) {\n return [];\n }\n return (\n conversations.getAll() as unknown as InternalDocSearchHit[]\n ).slice(0, MAX_RECENT_CONVERSATIONS_DISPLAYED);\n },\n onSelect({ item }): void {\n if (item.messages) {\n setMessages(item.messages);\n onAskAiToggle(true);\n }\n },\n },\n ];\n}\n\nfunction createAskAiHit({\n query,\n objectID,\n lvl0,\n}: {\n query: string;\n objectID: string;\n lvl0: string;\n}): InternalDocSearchHit {\n return {\n type: 'askAI',\n query,\n url_without_anchor: '',\n objectID,\n content: null,\n url: '',\n anchor: null,\n hierarchy: {\n lvl0,\n lvl1: query,\n lvl2: null,\n lvl3: null,\n lvl4: null,\n lvl5: null,\n lvl6: null,\n },\n _highlightResult: EMPTY_HIGHLIGHT_RESULT,\n _snippetResult: EMPTY_SNIPPET_RESULT,\n __docsearch_parent: null,\n };\n}\n\nasync function getPromptSuggestions({\n query,\n indexName,\n searchClient,\n hitsPerPage = 3,\n}: {\n query: string;\n indexName: string;\n searchClient: DocSearchTransformClient;\n hitsPerPage?: number;\n}): Promise<InternalDocSearchHit[]> {\n try {\n const { results } = await searchClient.search<PromptSuggestion>({\n requests: [\n {\n query,\n indexName,\n hitsPerPage,\n attributesToRetrieve: ['prompt'],\n },\n ],\n });\n\n const res = results[0] as SearchResponse<PromptSuggestion>;\n\n return res.hits.map((hit) =>\n createAskAiHit({\n query: hit.prompt,\n objectID: hit.objectID,\n lvl0: 'Prompt Suggestions',\n })\n );\n // NOTE: Not checking the exception here and just returning empty array since this isn't the hot path\n } catch {\n return [];\n }\n}\n\nexport async function buildAskAiActionSources({\n query,\n handleSelectAskAiQuestion,\n promptSuggestionsOptions,\n searchClient,\n}: {\n query: string;\n handleSelectAskAiQuestion: (toggle: boolean, query: string) => void;\n promptSuggestionsOptions?: PromptSuggestions;\n searchClient: DocSearchTransformClient;\n}): Promise<Array<AutocompleteSource<InternalDocSearchHit>>> {\n const promptSuggestions = promptSuggestionsOptions\n ? await getPromptSuggestions({\n query,\n indexName: promptSuggestionsOptions.indexName,\n hitsPerPage: promptSuggestionsOptions.hitsPerPage,\n searchClient,\n })\n : [];\n\n return [\n {\n sourceId: SOURCE_IDS.askAI,\n getItems(): InternalDocSearchHit[] {\n return [\n createAskAiHit({ query, objectID: 'ask-ai-button', lvl0: 'Ask AI' }),\n ...promptSuggestions,\n ];\n },\n onSelect({ item }): void {\n if (item.type === 'askAI' && item.query) {\n handleSelectAskAiQuestion(true, item.query);\n }\n },\n },\n ];\n}\n","import { createAutocomplete } from '@algolia/autocomplete-core';\nimport type { InitialAskAiMessage, OnAskAiToggle } from '@docsearch/core';\nimport type { ChatRequestOptions } from 'ai';\nimport React, { type JSX } from 'react';\n\nimport type { AskAiScreenStateTranslations } from './AskAiScreenState';\nimport { AskAiScreenState } from './AskAiScreenState';\nimport type { AskAiSearchBoxTranslations } from './components/AskAiSearchBox';\nimport { AskAiSearchBox } from './components/AskAiSearchBox';\nimport type { FacetBarTranslations } from './components/FacetBar';\nimport { FacetBar } from './components/FacetBar';\nimport { ModalShell } from './components/ui/ModalShell';\nimport type { DocSearchAIProps } from './DocSearchAI';\nimport type { FooterTranslations } from './Footer';\nimport { Footer } from './Footer';\nimport { Hit } from './Hit';\nimport { useDocSearchFacets } from './hooks/useDocSearchFacets';\nimport { useSendItemClickEvent } from './hooks/useDocSearchInsights';\nimport { useInitialModalQuery } from './hooks/useInitialModalQuery';\nimport { useModalEnvironment } from './hooks/useModalEnvironment';\nimport { useModalRefs } from './hooks/useModalRefs';\nimport { useRefreshOnInitialQuery } from './hooks/useRefreshOnInitialQuery';\nimport { useSaveRecentSearch } from './hooks/useSaveRecentSearch';\nimport { useStoredDocSearches } from './hooks/useStoredDocSearches';\nimport type { NewConversationTranslations } from './NewConversationScreen';\nimport type {\n DocSearchState,\n InternalDocSearchHit,\n OnAskAiFeedback,\n StoredAskAiMessage,\n StoredAskAiState,\n SuggestedQuestionHit,\n} from './types';\nimport { type AskAiState } from './types/AskiAi';\nimport { useAskAi } from './useAskAi';\nimport { useSearchClient } from './useSearchClient';\nimport { useSuggestedQuestions } from './useSuggestedQuestions';\nimport {\n identity,\n isModifierEvent,\n isQueryEmpty,\n noop,\n scrollTo as scrollToUtils,\n SOURCE_IDS,\n} from './utils';\nimport {\n buildDummyAskAiHit,\n isAgentStudioTokenOutputLimitError,\n isAskAiPromptBlockingError,\n isThreadDepthError,\n EMPTY_TOOLS,\n} from './utils/ai';\nimport {\n buildAskAiActionSources,\n buildRecentConversationSources,\n} from './utils/createAskAiSources';\nimport {\n buildNoQuerySources,\n buildQuerySources,\n type BuildQuerySourcesState,\n} from './utils/createDocSearchSources';\nimport { normalizeDocSearchIndexes } from './utils/normalizeDocSearchIndexes';\n\nexport type DocSearchAskAiModalTranslations = AskAiScreenStateTranslations &\n Partial<{\n searchBox: AskAiSearchBoxTranslations;\n newConversation: NewConversationTranslations;\n footer: FooterTranslations;\n facets: FacetBarTranslations;\n }>;\n\nexport type DocSearchAskAiModalProps = DocSearchAIProps & {\n initialScrollY: number;\n onAskAiToggle: OnAskAiToggle;\n onClose?: () => void;\n isAskAiActive?: boolean;\n translations?: DocSearchAskAiModalTranslations;\n isHybridModeSupported?: boolean;\n};\n\nexport function DocSearchAskAiModal({\n appId,\n apiKey,\n askAi,\n maxResultsPerGroup,\n theme,\n onClose = noop,\n transformItems = identity,\n hitComponent = Hit,\n resultsFooterComponent = (): JSX.Element | null => null,\n navigator,\n initialScrollY = 0,\n transformSearchClient = identity,\n disableUserPersonalization = false,\n initialQuery: initialQueryFromProp = '',\n translations = {},\n getMissingResultsUrl,\n insights = false,\n onAskAiToggle,\n interceptAskAiEvent,\n isAskAiActive = false,\n recentSearchesLimit = 7,\n recentSearchesWithFavoritesLimit = 4,\n indices,\n facets,\n isHybridModeSupported = false,\n footerAction,\n ...props\n}: DocSearchAskAiModalProps): JSX.Element {\n const {\n footer: footerTranslations,\n searchBox: searchBoxTranslations,\n facets: facetBarTranslations,\n ...screenStateTranslations\n } = translations;\n const [state, setState] = React.useState<\n DocSearchState<InternalDocSearchHit>\n >({\n query: '',\n collections: [],\n completion: null,\n context: {},\n isOpen: false,\n activeItemId: null,\n status: 'idle',\n });\n\n // check if the instance is configured to handle ask ai\n const canHandleAskAi = Boolean(askAi);\n\n let placeholder =\n translations?.searchBox?.placeholderText ||\n props.placeholder ||\n 'Search docs';\n\n if (canHandleAskAi) {\n placeholder =\n translations?.searchBox?.placeholderText ||\n 'Search docs or ask AI a question';\n }\n\n if (isAskAiActive) {\n placeholder =\n translations?.searchBox?.placeholderTextAskAi ||\n 'Ask another question...';\n }\n\n const { containerRef, modalRef, formElementRef, dropdownRef, inputRef } =\n useModalRefs();\n const promptBlockingErrorId = React.useId();\n const { initialQuery, initialQueryFromSelection } =\n useInitialModalQuery(initialQueryFromProp);\n\n const searchClient = useSearchClient(appId, apiKey, transformSearchClient);\n\n const askAiConfig = typeof askAi === 'object' ? askAi : null;\n const askAiConfigurationId = askAiConfig\n ? askAiConfig.agentId\n : (askAi as string);\n const askAiSearchParameters = askAiConfig?.searchParameters;\n const [askAiState, setAskAiState] = React.useState<AskAiState>('initial');\n const suggestedQuestions = useSuggestedQuestions({\n agentId: askAiConfigurationId,\n searchClient,\n suggestedQuestionsEnabled: askAiConfig?.suggestedQuestions,\n });\n const memoryEnabled = askAiConfig?.memory?.enabled ?? false;\n const tools = askAiConfig?.tools ?? EMPTY_TOOLS;\n\n const indexes = React.useMemo(\n () =>\n normalizeDocSearchIndexes({\n indices,\n }),\n [indices]\n );\n const defaultIndexName = indexes[0].name;\n\n const autocompleteRef =\n React.useRef<\n ReturnType<\n typeof createAutocomplete<\n InternalDocSearchHit,\n React.FormEvent<HTMLFormElement>,\n React.MouseEvent,\n React.KeyboardEvent\n >\n >\n >(undefined);\n\n const {\n visibleFacets,\n facetSelections,\n facetSelectionsRef,\n handleFacetSelectionChange,\n clearFacetSelections,\n } = useDocSearchFacets({\n facets,\n indexes,\n searchClient,\n onSelectionsChange: () => autocompleteRef.current?.refresh(),\n });\n\n const { favoriteSearches, recentSearches } = useStoredDocSearches({\n defaultIndexName,\n recentSearchesLimit,\n recentSearchesWithFavoritesLimit,\n });\n\n const [stoppedStream, setStoppedStream] = React.useState(false);\n\n const {\n chatId,\n messages,\n status,\n setMessages,\n sendMessage,\n stopAskAiStreaming,\n askAiError,\n sendFeedback,\n conversations,\n startNewConversation,\n restoreConversation,\n } = useAskAi({\n agentId: askAiConfigurationId,\n apiKey: askAiConfig?.apiKey || apiKey,\n appId: askAiConfig?.appId || appId,\n searchParameters: askAiSearchParameters,\n tools,\n memory: askAiConfig?.memory,\n indices: askAiConfig?.indices,\n });\n\n const prevStatus = React.useRef(status);\n React.useEffect(() => {\n if (disableUserPersonalization) {\n return;\n }\n // if we just transitioned from \"streaming\" → \"ready\", persist\n if (prevStatus.current === 'streaming' && status === 'ready') {\n // if we stopped the stream, store it on the most recent message\n if (stoppedStream && messages.at(-1)) {\n messages.at(-1)!.metadata = {\n stopped: true,\n };\n }\n\n for (const part of messages[0].parts) {\n if (part.type === 'text') {\n conversations.add(buildDummyAskAiHit(part.text, messages, chatId));\n }\n }\n }\n prevStatus.current = status;\n }, [\n status,\n messages,\n conversations,\n disableUserPersonalization,\n stoppedStream,\n chatId,\n ]);\n\n const hasPromptBlockingError = React.useMemo(() => {\n return (\n status === 'error' &&\n isAskAiPromptBlockingError(askAiError as Error | undefined)\n );\n }, [status, askAiError]);\n const shouldBlockPrompt =\n hasPromptBlockingError &&\n (!isThreadDepthError(askAiError) ||\n messages.some((message) => message.role === 'assistant'));\n\n const promptBlockingChrome = React.useMemo(() => {\n if (\n !shouldBlockPrompt ||\n askAiState === 'new-conversation' ||\n askAiState === 'conversation-history'\n ) {\n return undefined;\n }\n\n return isAgentStudioTokenOutputLimitError(askAiError)\n ? ('minimal' as const)\n : ('full' as const);\n }, [askAiError, askAiState, shouldBlockPrompt]);\n\n const saveRecentSearch = useSaveRecentSearch({\n favoriteSearches,\n recentSearches,\n disableUserPersonalization,\n });\n const sendItemClickEvent = useSendItemClickEvent(state);\n\n const handleSelectAskAiQuestion = React.useCallback(\n (\n toggle: boolean,\n query: string,\n suggestedQuestion: SuggestedQuestionHit | undefined = undefined\n ) => {\n if (toggle) {\n const initialMessage: InitialAskAiMessage = {\n query,\n suggestedQuestionId: suggestedQuestion?.objectID,\n };\n\n if (interceptAskAiEvent?.(initialMessage)) {\n // Consumer handled it. Avoid *all* default Ask AI behavior.\n if (autocompleteRef.current) {\n autocompleteRef.current.setQuery('');\n }\n return;\n }\n }\n\n if (toggle && askAiState === 'new-conversation') {\n setAskAiState('initial');\n }\n\n onAskAiToggle(toggle, {\n query,\n suggestedQuestionId: suggestedQuestion?.objectID,\n });\n\n // If we're in hybrid mode, we don't need to send the message,\n // it will be handled by the Sidepanel.\n if (isHybridModeSupported) return;\n\n setStoppedStream(false);\n\n const messageOptions: ChatRequestOptions = {};\n\n if (suggestedQuestion) {\n messageOptions.body = {\n suggestedQuestionId: suggestedQuestion.objectID,\n };\n }\n\n sendMessage(\n {\n role: 'user',\n parts: [\n {\n type: 'text',\n text: query,\n },\n ],\n },\n messageOptions\n );\n\n if (dropdownRef.current) {\n // some test environments (like jsdom) don't implement element.scrollTo\n const el = dropdownRef.current;\n if (typeof (el as any).scrollTo === 'function') {\n el.scrollTo({ top: 0, behavior: 'smooth' });\n } else {\n // fallback for environments without scrollTo support\n el.scrollTop = 0;\n }\n }\n\n // clear the query\n if (autocompleteRef.current) {\n autocompleteRef.current.setQuery('');\n }\n },\n [\n askAiState,\n onAskAiToggle,\n isHybridModeSupported,\n sendMessage,\n dropdownRef,\n interceptAskAiEvent,\n ]\n );\n\n // feedback handler\n const handleFeedbackSubmit = React.useCallback<OnAskAiFeedback>(\n async (messageId, feedback): Promise<void> => {\n if (!askAiConfigurationId || !appId) return;\n await sendFeedback(messageId, feedback);\n },\n [askAiConfigurationId, appId, sendFeedback]\n );\n\n if (!autocompleteRef.current) {\n autocompleteRef.current = createAutocomplete({\n id: 'docsearch',\n defaultActiveItemId: 0,\n openOnFocus: true,\n initialState: {\n query: initialQuery,\n context: {\n searchSuggestions: [],\n },\n },\n insights: Boolean(insights),\n navigator,\n onStateChange(changes) {\n setState(changes.state);\n },\n async getSources({ query, state: sourcesState, setContext, setStatus }) {\n if (isQueryEmpty(query)) {\n const noQuerySources = buildNoQuerySources({\n recentSearches,\n favoriteSearches,\n saveRecentSearch,\n onClose,\n disableUserPersonalization,\n });\n\n const recentConversationSource = canHandleAskAi\n ? buildRecentConversationSources({\n conversations,\n disableUserPersonalization,\n setMessages,\n onAskAiToggle,\n })\n : [];\n return [...recentConversationSource, ...noQuerySources];\n }\n\n const querySourcesState: BuildQuerySourcesState = {\n context: sourcesState.context,\n };\n\n const algoliaSourcesPromise = buildQuerySources({\n query,\n state: querySourcesState,\n setContext,\n setStatus,\n searchClient,\n indexes,\n insights: Boolean(insights),\n appId,\n apiKey,\n maxResultsPerGroup,\n transformItems,\n saveRecentSearch,\n onClose,\n facetSelections: facetSelectionsRef,\n });\n\n const askAiSourcesPromise = canHandleAskAi\n ? buildAskAiActionSources({\n query,\n handleSelectAskAiQuestion,\n promptSuggestionsOptions: askAiConfig?.promptSuggestions,\n searchClient,\n })\n : Promise.resolve([]);\n\n const [askAiSources, algoliaSources] = await Promise.all([\n askAiSourcesPromise,\n algoliaSourcesPromise,\n ]);\n\n // Combine Algolia results (once resolved) with the Ask AI source\n return [...askAiSources, ...algoliaSources];\n },\n });\n }\n\n const autocomplete = autocompleteRef.current;\n\n const { getEnvironmentProps, getRootProps, refresh } = autocomplete;\n\n useModalEnvironment({\n getEnvironmentProps,\n containerRef,\n dropdownRef,\n formElementRef,\n inputRef,\n initialScrollY,\n modalRef,\n theme,\n });\n\n React.useEffect(() => {\n if (dropdownRef.current && !isAskAiActive) {\n scrollToUtils(dropdownRef.current);\n }\n }, [state.query, isAskAiActive, dropdownRef]);\n\n useRefreshOnInitialQuery({ initialQuery, inputRef, refresh });\n\n const hasCurrentMessages = messages.length > 0;\n\n // Refresh the autocomplete results when ask ai is toggled off\n // helps return to the previous ac state and start screen\n React.useEffect(() => {\n if (!isAskAiActive) {\n autocomplete.refresh();\n\n if (hasCurrentMessages) {\n startNewConversation();\n }\n }\n }, [isAskAiActive, autocomplete, startNewConversation, hasCurrentMessages]);\n\n // Track external state in order to manage internal askAiState\n React.useEffect(() => {\n setAskAiState('initial');\n }, [isAskAiActive, setAskAiState]);\n\n const onStopAskAiStreaming = async (): Promise<void> => {\n setStoppedStream(true);\n\n await stopAskAiStreaming();\n };\n\n const handleNewConversation = (): void => {\n startNewConversation();\n setAskAiState('new-conversation');\n };\n\n const handleViewConversationHistory = (): void => {\n setAskAiState('conversation-history');\n };\n\n const selectSuggestedQuestion = (\n suggestedQuestion: SuggestedQuestionHit\n ): void => {\n handleSelectAskAiQuestion(\n true,\n suggestedQuestion.question,\n suggestedQuestion\n );\n };\n\n // hide the dropdown on idle and no collections\n let showDocsearchDropdown = true;\n const hasCollections = state.collections.some(\n (collection) =>\n collection.source.sourceId !== SOURCE_IDS.askAI &&\n collection.items.length > 0\n );\n if (\n state.status === 'idle' &&\n hasCollections === false &&\n isQueryEmpty(state.query) &&\n !isAskAiActive\n ) {\n showDocsearchDropdown = false;\n }\n\n return (\n <ModalShell\n state={state}\n containerRef={containerRef}\n modalRef={modalRef}\n formElementRef={formElementRef}\n dropdownRef={dropdownRef}\n getRootProps={getRootProps}\n showDropdown={showDocsearchDropdown}\n searchBox={\n <AskAiSearchBox\n {...autocomplete}\n state={state}\n placeholder={placeholder || 'Search docs'}\n autoFocus={isQueryEmpty(initialQuery)}\n inputRef={inputRef}\n isFromSelection={\n Boolean(initialQuery) && initialQuery === initialQueryFromSelection\n }\n translations={searchBoxTranslations}\n isAskAiActive={isAskAiActive}\n askAiStatus={status}\n askAiError={askAiError}\n askAiState={askAiState}\n setAskAiState={setAskAiState}\n promptBlockingChrome={promptBlockingChrome}\n promptBlockingErrorId={promptBlockingErrorId}\n onClose={onClose}\n onAskAiToggle={onAskAiToggle}\n onAskAgain={(query) => {\n handleSelectAskAiQuestion(true, query);\n }}\n onStopAskAiStreaming={onStopAskAiStreaming}\n onNewConversation={handleNewConversation}\n onViewConversationHistory={handleViewConversationHistory}\n />\n }\n filterBar={\n !isAskAiActive && !isQueryEmpty(state.query) ? (\n <FacetBar\n facets={visibleFacets}\n selections={facetSelections}\n translations={facetBarTranslations}\n clearSelections={clearFacetSelections}\n onSelectionChange={handleFacetSelectionChange}\n />\n ) : null\n }\n screenState={\n <AskAiScreenState\n {...autocomplete}\n indexName={defaultIndexName}\n state={state}\n hitComponent={hitComponent}\n resultsFooterComponent={resultsFooterComponent}\n disableUserPersonalization={disableUserPersonalization}\n recentSearches={recentSearches}\n favoriteSearches={favoriteSearches}\n conversations={conversations}\n inputRef={inputRef}\n translations={screenStateTranslations}\n getMissingResultsUrl={getMissingResultsUrl}\n isAskAiActive={isAskAiActive}\n canHandleAskAi={canHandleAskAi}\n messages={messages}\n tools={tools}\n askAiError={askAiError}\n status={status}\n hasCollections={hasCollections}\n askAiState={askAiState}\n selectAskAiQuestion={handleSelectAskAiQuestion}\n suggestedQuestions={suggestedQuestions}\n selectSuggestedQuestion={selectSuggestedQuestion}\n memoryEnabled={memoryEnabled}\n resultBadgeKey={props.resultBadgeKey}\n promptBlockingErrorId={promptBlockingErrorId}\n onAskAiToggle={onAskAiToggle}\n onNewConversation={handleNewConversation}\n onItemClick={(item, event) => {\n if (item.type === 'askAI' && item.query) {\n if (item.anchor === 'stored' && 'messages' in item) {\n const hitMessages = item.messages as StoredAskAiMessage[];\n restoreConversation(\n hitMessages,\n (item as StoredAskAiState).chatId\n );\n const initialMessage: InitialAskAiMessage = {\n query: item.query,\n messageId: hitMessages[0].id,\n };\n\n if (interceptAskAiEvent?.(initialMessage)) {\n if (autocompleteRef.current) {\n autocompleteRef.current.setQuery('');\n }\n event.preventDefault();\n return;\n }\n\n onAskAiToggle(true, initialMessage);\n } else {\n handleSelectAskAiQuestion(true, item.query);\n }\n setAskAiState('initial');\n event.preventDefault();\n return;\n }\n\n sendItemClickEvent(item);\n saveRecentSearch(item);\n if (!isModifierEvent(event)) {\n onClose();\n }\n }}\n onFeedback={handleFeedbackSubmit}\n />\n }\n footer={\n <Footer\n translations={footerTranslations}\n isAskAiActive={isAskAiActive}\n footerAction={footerAction}\n />\n }\n onClose={onClose}\n />\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import "./index-Bqqv4HmN.js";
2
- import { _ as FacetBarTranslations, g as FooterTranslations } from "./DocSearch-CVj6U-nI.js";
2
+ import { v as FooterTranslations, y as FacetBarTranslations } from "./DocSearch-BVqxFxTw.js";
3
3
  import { DocSearchAIProps } from "./docsearchAi.js";
4
- import { n as NewConversationTranslations, t as AskAiScreenStateTranslations } from "./AskAiScreenState-Bw2WIgv_.js";
4
+ import { n as NewConversationTranslations, t as AskAiScreenStateTranslations } from "./AskAiScreenState-Sqbn60f2.js";
5
5
  import { OnAskAiToggle } from "@docsearch/core";
6
6
  import React, { JSX } from "react";
7
7
  import { AutocompleteState } from "@algolia/autocomplete-core";
@@ -42,7 +42,7 @@ type DocSearchAskAiModalProps = DocSearchAIProps & {
42
42
  translations?: DocSearchAskAiModalTranslations;
43
43
  isHybridModeSupported?: boolean;
44
44
  };
45
- declare function DocSearchAskAiModal({ appId, apiKey, askAi, maxResultsPerGroup, theme, onClose, transformItems, hitComponent, resultsFooterComponent, navigator, initialScrollY, transformSearchClient, disableUserPersonalization, initialQuery: initialQueryFromProp, translations, getMissingResultsUrl, insights, onAskAiToggle, interceptAskAiEvent, isAskAiActive, recentSearchesLimit, recentSearchesWithFavoritesLimit, indices, facets, isHybridModeSupported, ...props }: DocSearchAskAiModalProps): JSX.Element;
45
+ declare function DocSearchAskAiModal({ appId, apiKey, askAi, maxResultsPerGroup, theme, onClose, transformItems, hitComponent, resultsFooterComponent, navigator, initialScrollY, transformSearchClient, disableUserPersonalization, initialQuery: initialQueryFromProp, translations, getMissingResultsUrl, insights, onAskAiToggle, interceptAskAiEvent, isAskAiActive, recentSearchesLimit, recentSearchesWithFavoritesLimit, indices, facets, isHybridModeSupported, footerAction, ...props }: DocSearchAskAiModalProps): JSX.Element;
46
46
  //#endregion
47
47
  export { DocSearchAskAiModalProps as n, DocSearchAskAiModalTranslations as r, DocSearchAskAiModal as t };
48
- //# sourceMappingURL=DocSearchAskAiModal-MF2py4NM.d.ts.map
48
+ //# sourceMappingURL=DocSearchAskAiModal-DpB7pLCC.d.ts.map