@docsearch/js 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.
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @docsearch/js 5.0.0-beta.2 (UNRELEASED c7e1a88) | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */
1
+ /*! @docsearch/js 5.0.0-beta.4 (UNRELEASED 11d6ed4) | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */
2
2
  //#region \0rolldown/runtime.js
3
3
  var __create = Object.create;
4
4
  var __defProp$1 = Object.defineProperty;
@@ -1188,7 +1188,7 @@ function DocSearchButtonKey({ reactsToKey, children }) {
1188
1188
 
1189
1189
  //#endregion
1190
1190
  //#region ../docsearch-react/dist/esm/version.js
1191
- const version$2 = "5.0.0-beta.2";
1191
+ const version$2 = "5.0.0-beta.4";
1192
1192
 
1193
1193
  //#endregion
1194
1194
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/OverloadYield.js
@@ -12496,7 +12496,7 @@ function useMenuParent() {
12496
12496
  }
12497
12497
 
12498
12498
  //#endregion
12499
- //#region ../docsearch-react/dist/esm/normalizeDocSearchIndexes-D8P3VEXa.js
12499
+ //#region ../docsearch-react/dist/esm/normalizeDocSearchIndexes-ChnVvoVt.js
12500
12500
  init_compat();
12501
12501
  function capitalize(text) {
12502
12502
  return `${text.charAt(0).toLocaleUpperCase()}${text.substring(1)}`;
@@ -12952,12 +12952,13 @@ function CommandIcon(props) {
12952
12952
  strokeWidth: "1.4"
12953
12953
  }, props.children));
12954
12954
  }
12955
- function Footer({ translations = {}, isAskAiActive = false }) {
12955
+ function Footer({ translations = {}, isAskAiActive = false, footerAction }) {
12956
12956
  const { selectText = "Select", selectKeyAriaLabel = "Enter key", submitQuestionText = "Submit question", navigateText = "Navigate", navigateUpKeyAriaLabel = "Arrow up", navigateDownKeyAriaLabel = "Arrow down", closeText = "Close", backToSearchText = "Back to search", closeKeyAriaLabel = "Escape key", poweredByText = "Powered by" } = translations;
12957
- return /* @__PURE__ */ En.createElement(En.Fragment, null, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-Logo" }, /* @__PURE__ */ En.createElement(AlgoliaLogo, { translations: { poweredByText } })), /* @__PURE__ */ En.createElement("ul", { className: "DocSearch-Commands" }, /* @__PURE__ */ En.createElement("li", null, /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement(CommandIcon, { ariaLabel: navigateDownKeyAriaLabel }, /* @__PURE__ */ En.createElement("path", { d: "M12 5v14" }), /* @__PURE__ */ En.createElement("path", { d: "m19 12-7 7-7-7" }))), /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement(CommandIcon, { ariaLabel: navigateUpKeyAriaLabel }, /* @__PURE__ */ En.createElement("path", { d: "m5 12 7-7 7 7" }), /* @__PURE__ */ En.createElement("path", { d: "M12 19V5" }))), /* @__PURE__ */ En.createElement("span", { className: "DocSearch-Label" }, navigateText)), /* @__PURE__ */ En.createElement("li", null, /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement(CommandIcon, { ariaLabel: selectKeyAriaLabel }, /* @__PURE__ */ En.createElement("polyline", { points: "9 10 4 15 9 20" }), /* @__PURE__ */ En.createElement("path", { d: "M20 4v7a4 4 0 0 1-4 4H4" }))), /* @__PURE__ */ En.createElement("span", { className: "DocSearch-Label" }, isAskAiActive ? submitQuestionText : selectText)), /* @__PURE__ */ En.createElement("li", null, /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement("span", { className: "DocSearch-Escape-Key" }, "ESC")), /* @__PURE__ */ En.createElement("span", {
12957
+ const hasFooterAction = footerAction !== null && footerAction !== void 0 && typeof footerAction !== "boolean";
12958
+ return /* @__PURE__ */ En.createElement(En.Fragment, null, /* @__PURE__ */ En.createElement("ul", { className: "DocSearch-Commands" }, /* @__PURE__ */ En.createElement("li", null, /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement(CommandIcon, { ariaLabel: navigateDownKeyAriaLabel }, /* @__PURE__ */ En.createElement("path", { d: "M12 5v14" }), /* @__PURE__ */ En.createElement("path", { d: "m19 12-7 7-7-7" }))), /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement(CommandIcon, { ariaLabel: navigateUpKeyAriaLabel }, /* @__PURE__ */ En.createElement("path", { d: "m5 12 7-7 7 7" }), /* @__PURE__ */ En.createElement("path", { d: "M12 19V5" }))), /* @__PURE__ */ En.createElement("span", { className: "DocSearch-Label" }, navigateText)), /* @__PURE__ */ En.createElement("li", null, /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement(CommandIcon, { ariaLabel: selectKeyAriaLabel }, /* @__PURE__ */ En.createElement("polyline", { points: "9 10 4 15 9 20" }), /* @__PURE__ */ En.createElement("path", { d: "M20 4v7a4 4 0 0 1-4 4H4" }))), /* @__PURE__ */ En.createElement("span", { className: "DocSearch-Label" }, isAskAiActive ? submitQuestionText : selectText)), /* @__PURE__ */ En.createElement("li", null, /* @__PURE__ */ En.createElement("kbd", { className: "DocSearch-Commands-Key" }, /* @__PURE__ */ En.createElement("span", { className: "DocSearch-Escape-Key" }, "ESC")), /* @__PURE__ */ En.createElement("span", {
12958
12959
  className: "DocSearch-Label",
12959
12960
  "aria-label": closeKeyAriaLabel
12960
- }, isAskAiActive ? backToSearchText : closeText))));
12961
+ }, isAskAiActive ? backToSearchText : closeText))), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-Footer-Actions" }, hasFooterAction && /* @__PURE__ */ En.createElement("div", { className: "DocSearch-Footer-Action" }, footerAction), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-Logo" }, /* @__PURE__ */ En.createElement(AlgoliaLogo, { translations: { poweredByText } }))));
12961
12962
  }
12962
12963
  function Hit({ hit, children }) {
12963
12964
  return /* @__PURE__ */ En.createElement("a", { href: hit.url }, children);
@@ -13115,7 +13116,7 @@ function useTrapFocus({ container }) {
13115
13116
  };
13116
13117
  }, [container]);
13117
13118
  }
13118
- function useDocSearchModalEffects({ initialScrollY, modalRef, snippetLength, theme }) {
13119
+ function useDocSearchModalEffects({ initialScrollY, modalRef, theme }) {
13119
13120
  useTheme({ theme });
13120
13121
  En.useEffect(() => {
13121
13122
  document.body.classList.add("DocSearch--active");
@@ -13135,9 +13136,6 @@ function useDocSearchModalEffects({ initialScrollY, modalRef, snippetLength, the
13135
13136
  document.body.style.marginInlineEnd = "0px";
13136
13137
  };
13137
13138
  }, []);
13138
- En.useEffect(() => {
13139
- if (window.matchMedia("(max-width: 768px)").matches) snippetLength.current = 5;
13140
- }, [snippetLength]);
13141
13139
  En.useEffect(() => {
13142
13140
  function setFullViewportHeight() {
13143
13141
  if (modalRef.current) {
@@ -13152,7 +13150,7 @@ function useDocSearchModalEffects({ initialScrollY, modalRef, snippetLength, the
13152
13150
  };
13153
13151
  }, [modalRef]);
13154
13152
  }
13155
- function useModalEnvironment({ getEnvironmentProps, containerRef, dropdownRef, formElementRef, inputRef, initialScrollY, modalRef, snippetLength, theme }) {
13153
+ function useModalEnvironment({ getEnvironmentProps, containerRef, dropdownRef, formElementRef, inputRef, initialScrollY, modalRef, theme }) {
13156
13154
  useTouchEvents({
13157
13155
  getEnvironmentProps,
13158
13156
  panelElement: dropdownRef.current,
@@ -13163,7 +13161,6 @@ function useModalEnvironment({ getEnvironmentProps, containerRef, dropdownRef, f
13163
13161
  useDocSearchModalEffects({
13164
13162
  initialScrollY,
13165
13163
  modalRef,
13166
- snippetLength,
13167
13164
  theme
13168
13165
  });
13169
13166
  }
@@ -13173,8 +13170,7 @@ function useModalRefs() {
13173
13170
  modalRef: En.useRef(null),
13174
13171
  formElementRef: En.useRef(null),
13175
13172
  dropdownRef: En.useRef(null),
13176
- inputRef: En.useRef(null),
13177
- snippetLength: En.useRef(15)
13173
+ inputRef: En.useRef(null)
13178
13174
  };
13179
13175
  }
13180
13176
  function useRefreshOnInitialQuery({ initialQuery, inputRef, refresh }) {
@@ -13528,7 +13524,7 @@ function buildNoQuerySources({ recentSearches, favoriteSearches, saveRecentSearc
13528
13524
  }
13529
13525
  }];
13530
13526
  }
13531
- async function buildQuerySources({ query, state: sourcesState, setContext, setStatus, searchClient, indexes, snippetLength, insights, appId, apiKey, maxResultsPerGroup, transformItems = identity, saveRecentSearch, onClose, facetSelections }) {
13527
+ async function buildQuerySources({ query, state: sourcesState, setContext, setStatus, searchClient, indexes, insights, appId, apiKey, maxResultsPerGroup, transformItems = identity, saveRecentSearch, onClose, facetSelections }) {
13532
13528
  const insightsActive = insights;
13533
13529
  try {
13534
13530
  const { results } = await searchClient.search({ requests: indexes.map((index) => {
@@ -13552,13 +13548,13 @@ async function buildQuerySources({ query, state: sourcesState, setContext, setSt
13552
13548
  "url"
13553
13549
  ],
13554
13550
  attributesToSnippet: (_searchParams$attribu2 = searchParams === null || searchParams === void 0 ? void 0 : searchParams.attributesToSnippet) !== null && _searchParams$attribu2 !== void 0 ? _searchParams$attribu2 : [
13555
- `hierarchy.lvl1:${snippetLength.current}`,
13556
- `hierarchy.lvl2:${snippetLength.current}`,
13557
- `hierarchy.lvl3:${snippetLength.current}`,
13558
- `hierarchy.lvl4:${snippetLength.current}`,
13559
- `hierarchy.lvl5:${snippetLength.current}`,
13560
- `hierarchy.lvl6:${snippetLength.current}`,
13561
- `content:${snippetLength.current}`
13551
+ `hierarchy.lvl1:15`,
13552
+ `hierarchy.lvl2:15`,
13553
+ `hierarchy.lvl3:15`,
13554
+ `hierarchy.lvl4:15`,
13555
+ `hierarchy.lvl5:15`,
13556
+ `hierarchy.lvl6:15`,
13557
+ `content:15`
13562
13558
  ],
13563
13559
  snippetEllipsisText: (_searchParams$snippet = searchParams === null || searchParams === void 0 ? void 0 : searchParams.snippetEllipsisText) !== null && _searchParams$snippet !== void 0 ? _searchParams$snippet : "…",
13564
13560
  highlightPreTag: (_searchParams$highlig = searchParams === null || searchParams === void 0 ? void 0 : searchParams.highlightPreTag) !== null && _searchParams$highlig !== void 0 ? _searchParams$highlig : "<mark>",
@@ -27408,7 +27404,7 @@ function useChat(_ref2 = {}) {
27408
27404
  }
27409
27405
 
27410
27406
  //#endregion
27411
- //#region ../docsearch-react/dist/esm/useSuggestedQuestions-Ds7H1JCr.js
27407
+ //#region ../docsearch-react/dist/esm/useSuggestedQuestions-BjSZvxwr.js
27412
27408
  init_compat();
27413
27409
  function AlertIcon(props) {
27414
27410
  return /* @__PURE__ */ En.createElement("svg", _objectSpread2$2({
@@ -27864,19 +27860,131 @@ function SourcesPanel({ links, titleText = "Source", pluralTitleText = "Sources"
27864
27860
  rel: "noopener noreferrer"
27865
27861
  }, /* @__PURE__ */ En.createElement(ContentIcon, null), /* @__PURE__ */ En.createElement("span", { className: "DocSearch-AskAiScreen-Sources-source-title" }, l.title || l.url)))))));
27866
27862
  }
27867
- /**
27868
- * Escapes HTML special characters to prevent XSS attacks. This should be used
27869
- * for any user-provided content that will be displayed.
27870
- */
27871
- function escapeHtml$1(unsafe) {
27863
+ const PROMPT_BLOCKING_CODES = /* @__PURE__ */ new Set([
27864
+ "AI-203",
27865
+ "AI-205",
27866
+ "AI-224",
27867
+ "AI-225"
27868
+ ]);
27869
+ function readStringField(value, key) {
27870
+ for (const [field, fieldValue] of Object.entries(value)) if (field.toLowerCase() === key.toLowerCase() && typeof fieldValue === "string" && fieldValue.trim() !== "") return fieldValue.trim();
27871
+ }
27872
+ function extractErrorCode(message) {
27873
+ const directMatch = /\b(AI-\d{3})\b/i.exec(message);
27874
+ if (directMatch) return directMatch[1].toUpperCase();
27875
+ }
27876
+ function parseJson(message) {
27877
+ try {
27878
+ const parsed = JSON.parse(message);
27879
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
27880
+ } catch (_unused) {}
27881
+ return null;
27882
+ }
27883
+ function matchesDomainBlock(message) {
27884
+ return /\brequest blocked for this domain\b/.test(message) || /\bblocked for this domain\b/.test(message);
27885
+ }
27886
+ function matchesRateLimit(message) {
27887
+ return /\b429\b/.test(message) || /\brate\s*limit/.test(message) || /\bretry\s+after\s+\d+/.test(message) || /\btoo\s+many\s+attempts\b/.test(message) || /\btoo_many_requests\b/.test(message);
27888
+ }
27889
+ function matchesTokenOutputLimit(message) {
27890
+ return /\btokenoutputlimiterror\b/.test(message) || /could not complete response due to token output limits/.test(message);
27891
+ }
27892
+ function matchesAccessOrLimit(message) {
27893
+ return /\bwhitelist(?:ed)?\b/.test(message) || /\bnot\s+allowed\s+for\s+this\s+domain\b/.test(message) || /\bcontext\s+length\b/.test(message) || /\b(?:max|maximum)\s+tokens?\b/.test(message) || /\btoken\s+limit\b/.test(message) || /\btoken\s+output\b/.test(message) || /\boutput\s+limits?\b/.test(message) || /\bstep\s+limit\b/.test(message) || /\b(?:max|maximum)(?:\s+agent)?\s+steps?\b/.test(message);
27894
+ }
27895
+ function jsonImpliesCostControl(value) {
27896
+ var _readStringField, _readStringField2, _readStringField3;
27897
+ const type = (_readStringField = readStringField(value, "type")) !== null && _readStringField !== void 0 ? _readStringField : "";
27898
+ const error = (_readStringField2 = readStringField(value, "error")) !== null && _readStringField2 !== void 0 ? _readStringField2 : "";
27899
+ const message = (_readStringField3 = readStringField(value, "message")) !== null && _readStringField3 !== void 0 ? _readStringField3 : "";
27900
+ return /tokenoutput|outputlimit|steplimit|maxstep|ratelimit|domainnotallowed/i.test(type) || error.toUpperCase() === "TOO_MANY_REQUESTS" || matchesRateLimit(`${error} ${message}`.toLowerCase()) || matchesAccessOrLimit(`${error} ${message}`.toLowerCase());
27901
+ }
27902
+ const BLOCKING_MATCHERS = [
27903
+ { matches: ({ code }) => Boolean(code && PROMPT_BLOCKING_CODES.has(code)) },
27904
+ {
27905
+ matches: ({ parsedJson }) => {
27906
+ var _readStringField4;
27907
+ return Boolean(parsedJson && matchesDomainBlock(((_readStringField4 = readStringField(parsedJson, "message")) !== null && _readStringField4 !== void 0 ? _readStringField4 : "").toLowerCase()));
27908
+ },
27909
+ showNewConversationLink: false
27910
+ },
27911
+ { matches: ({ parsedJson }) => Boolean(parsedJson && jsonImpliesCostControl(parsedJson)) },
27912
+ {
27913
+ matches: ({ messageLower }) => matchesTokenOutputLimit(messageLower),
27914
+ showNewConversationLink: false
27915
+ },
27916
+ { matches: ({ messageLower }) => matchesRateLimit(messageLower) },
27917
+ {
27918
+ matches: ({ messageLower }) => matchesDomainBlock(messageLower),
27919
+ showNewConversationLink: false
27920
+ },
27921
+ { matches: ({ messageLower }) => matchesAccessOrLimit(messageLower) }
27922
+ ];
27923
+ function resolvePromptBlockingError(error) {
27924
+ var _error$message;
27925
+ const message = (_error$message = error.message) !== null && _error$message !== void 0 ? _error$message : "";
27926
+ const context = {
27927
+ message,
27928
+ messageLower: message.toLowerCase(),
27929
+ parsedJson: parseJson(message),
27930
+ code: extractErrorCode(message)
27931
+ };
27932
+ const matches = BLOCKING_MATCHERS.filter((matcher) => matcher.matches(context));
27933
+ return {
27934
+ blocking: matches.length > 0,
27935
+ showNewConversationLink: matches.every((matcher) => matcher.showNewConversationLink !== false)
27936
+ };
27937
+ }
27938
+ function isTokenOutputLimitError(error) {
27939
+ var _error$message2;
27940
+ return Boolean(error && matchesTokenOutputLimit(((_error$message2 = error.message) !== null && _error$message2 !== void 0 ? _error$message2 : "").toLowerCase()));
27941
+ }
27942
+ /** Escapes HTML special characters for safe interpolation into HTML strings. */
27943
+ function escapeHtml(unsafe) {
27872
27944
  return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
27873
27945
  }
27946
+ /** Strips HTML tags and escapes the remainder for plain-text React children. */
27947
+ function sanitizeUserInput(input) {
27948
+ return escapeHtml(input.replace(/<[^>]*>/g, ""));
27949
+ }
27950
+ function decodeUrlForSchemeCheck(value) {
27951
+ let current = value;
27952
+ for (let i = 0; i < 3; i += 1) try {
27953
+ const decoded = decodeURIComponent(current);
27954
+ if (decoded === current) break;
27955
+ current = decoded;
27956
+ } catch (_unused) {
27957
+ break;
27958
+ }
27959
+ return current;
27960
+ }
27961
+ function stripControlsAndWhitespace(value) {
27962
+ let result = "";
27963
+ for (let i = 0; i < value.length; i += 1) {
27964
+ const code = value.charCodeAt(i);
27965
+ if (code > 32 && code !== 127) result += value[i];
27966
+ }
27967
+ return result;
27968
+ }
27874
27969
  /**
27875
- * Sanitizes user input to prevent XSS attacks. Removes any HTML tags and
27876
- * escapes special characters.
27970
+ * Returns a URL safe for href/src, or '' if unsafe. Does not HTML-escape
27971
+ * callers building HTML strings must escape separately.
27877
27972
  */
27878
- function sanitizeUserInput(input) {
27879
- return escapeHtml$1(input.replace(/<[^>]*>/g, ""));
27973
+ function sanitizeUrl(url) {
27974
+ if (!url) return "";
27975
+ const trimmed = url.trim();
27976
+ if (!trimmed) return "";
27977
+ const normalized = stripControlsAndWhitespace(decodeUrlForSchemeCheck(trimmed));
27978
+ if (!normalized) return "";
27979
+ if (normalized.startsWith("//")) return "";
27980
+ if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(normalized)) return trimmed;
27981
+ try {
27982
+ const parsed = new URL(normalized);
27983
+ if (parsed.protocol === "http:" || parsed.protocol === "https:" || parsed.protocol === "mailto:") return normalized;
27984
+ } catch (_unused2) {
27985
+ return "";
27986
+ }
27987
+ return "";
27880
27988
  }
27881
27989
  function extractLinksFromMessage(message) {
27882
27990
  const links = [];
@@ -27891,8 +27999,8 @@ function extractLinksFromMessage(message) {
27891
27999
  const markdownMatches = cleanText.matchAll(markdownLinkRegex);
27892
28000
  for (const match of markdownMatches) {
27893
28001
  const title = match[1].trim();
27894
- const url = match[2];
27895
- if (!seen.has(url)) {
28002
+ const url = sanitizeUrl(match[2]);
28003
+ if (url && !seen.has(url)) {
27896
28004
  seen.add(url);
27897
28005
  links.push({
27898
28006
  url,
@@ -27902,8 +28010,8 @@ function extractLinksFromMessage(message) {
27902
28010
  }
27903
28011
  const plainUrls = cleanText.matchAll(plainLinkRegex);
27904
28012
  for (const match of plainUrls) {
27905
- const cleanUrl = match[0].replace(/[.,;:!?]+$/, "");
27906
- if (!seen.has(cleanUrl)) {
28013
+ const cleanUrl = sanitizeUrl(match[0].replace(/[.,;:!?]+$/, ""));
28014
+ if (cleanUrl && !seen.has(cleanUrl)) {
27907
28015
  seen.add(cleanUrl);
27908
28016
  links.push({ url: cleanUrl });
27909
28017
  }
@@ -27939,11 +28047,56 @@ const getMessageContent = (message) => {
27939
28047
  var _message$parts;
27940
28048
  return ((_message$parts = message === null || message === void 0 ? void 0 : message.parts) !== null && _message$parts !== void 0 ? _message$parts : []).filter((part) => part.type === "text").map((part) => part.text).join("\n\n");
27941
28049
  };
27942
- /** Helper function to check if error is a thread depth error (AI-217). */
28050
+ /** Helper function to check if an error reports the conversation depth limit. */
27943
28051
  function isThreadDepthError(error) {
27944
28052
  var _error$message;
27945
28053
  if (!error) return false;
27946
- return ((_error$message = error.message) === null || _error$message === void 0 ? void 0 : _error$message.includes("AI-217")) || false;
28054
+ return /(?:ai-217|conversation\s+depth)/i.test((_error$message = error.message) !== null && _error$message !== void 0 ? _error$message : "");
28055
+ }
28056
+ function isAskAiPromptBlockingError(error) {
28057
+ return Boolean(error && (isThreadDepthError(error) || resolvePromptBlockingError(error).blocking));
28058
+ }
28059
+ function isAgentStudioTokenOutputLimitError(error) {
28060
+ return isTokenOutputLimitError(error);
28061
+ }
28062
+ function showAskAiBlockingBannerNewConversationLink(error) {
28063
+ if (!error || isThreadDepthError(error)) return true;
28064
+ return resolvePromptBlockingError(error).showNewConversationLink;
28065
+ }
28066
+ function extractAgentStudioErrorFieldMessage(raw) {
28067
+ let value = raw.trim();
28068
+ for (let iteration = 0; iteration < 10 && value; iteration++) try {
28069
+ var _exec, _fieldMatch$;
28070
+ const parsed = JSON.parse(value);
28071
+ if (typeof parsed === "string") {
28072
+ value = parsed.trim();
28073
+ continue;
28074
+ }
28075
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
28076
+ const record = parsed;
28077
+ const message = readStringField(record, "message");
28078
+ const error = readStringField(record, "error");
28079
+ if (message) return message;
28080
+ if (error) return error;
28081
+ }
28082
+ const fieldMatch = (_exec = /"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(value)) !== null && _exec !== void 0 ? _exec : /"error"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(value);
28083
+ return fieldMatch === null || fieldMatch === void 0 || (_fieldMatch$ = fieldMatch[1]) === null || _fieldMatch$ === void 0 ? void 0 : _fieldMatch$.replace(/\\"/g, "\"").replace(/\\\\/g, "\\").trim();
28084
+ } catch (_unused) {
28085
+ if (value.includes("\\\"")) {
28086
+ value = value.replace(/\\"/g, "\"").replace(/\\\\/g, "\\").trim();
28087
+ continue;
28088
+ }
28089
+ return;
28090
+ }
28091
+ }
28092
+ function getAskAiBlockingBannerMessage(error) {
28093
+ var _error$message2;
28094
+ if (!error) return;
28095
+ const extracted = extractAgentStudioErrorFieldMessage((_error$message2 = error.message) !== null && _error$message2 !== void 0 ? _error$message2 : "");
28096
+ if (isThreadDepthError(error) && (/^\s*AI-217\s*$/i.test(error.message) || /^\s*\{.*\}\s*$/.test(error.message) && !extracted)) return;
28097
+ const message = (extracted !== null && extracted !== void 0 ? extracted : error.message.replace(/\s*\(AI-\d{3}\)\s*$/i, "")).trim();
28098
+ if (message && !(message.startsWith("{") && message.endsWith("}"))) return message;
28099
+ if (isAgentStudioTokenOutputLimitError(error)) return "Could not complete response due to token output limits";
27947
28100
  }
27948
28101
  const EMPTY_TOOLS = Object.freeze({});
27949
28102
  function isAIToolPart(part) {
@@ -28091,12 +28244,10 @@ function ToolCall({ part, translations, tools, onSearchQueryClick, memoryEnabled
28091
28244
  });
28092
28245
  return null;
28093
28246
  }
28094
- function escapeHtml(html) {
28095
- return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
28096
- }
28097
28247
  const renderer = new k.Renderer();
28098
28248
  renderer.code = ({ text, lang = "", escaped }) => {
28099
- const languageClass = lang ? `language-${lang}` : "";
28249
+ const safeLang = /^[a-zA-Z0-9_-]+$/.test(lang) ? lang : "";
28250
+ const languageClass = safeLang ? `language-${safeLang}` : "";
28100
28251
  const safeCode = escaped ? text : escapeHtml(text);
28101
28252
  return `
28102
28253
  <div class="DocSearch-CodeSnippet">
@@ -28106,15 +28257,28 @@ renderer.code = ({ text, lang = "", escaped }) => {
28106
28257
  `;
28107
28258
  };
28108
28259
  renderer.link = ({ href, title, text }) => {
28260
+ const safeHref = escapeHtml(sanitizeUrl(href));
28261
+ const textEscaped = escapeHtml(text);
28262
+ if (!safeHref) return textEscaped;
28263
+ return `<a href="${safeHref}"${title ? ` title="${escapeHtml(title)}"` : ""} target="_blank" rel="noopener noreferrer">${textEscaped}</a>`;
28264
+ };
28265
+ renderer.image = ({ href, title, text }) => {
28266
+ const safeHref = escapeHtml(sanitizeUrl(href));
28267
+ if (!safeHref) return escapeHtml(text);
28109
28268
  const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
28110
- return `<a href="${href ? escapeHtml(href) : ""}"${titleAttr} target="_blank" rel="noopener noreferrer">${escapeHtml(text)}</a>`;
28269
+ return `<img src="${safeHref}" alt="${escapeHtml(text)}"${titleAttr} />`;
28111
28270
  };
28112
- const MemoizedMarkdown = D$1(({ content, copyButtonText, copyButtonCopiedText, isStreaming }) => {
28113
- const html = q$2(() => k.parse(content, {
28271
+ renderer.html = ({ text }) => escapeHtml(text);
28272
+ /** Parses markdown into HTML safe for `dangerouslySetInnerHTML`. */
28273
+ function parseMarkdownToSafeHtml(content) {
28274
+ return k.parse(content, {
28114
28275
  gfm: true,
28115
28276
  breaks: true,
28116
28277
  renderer
28117
- }), [content]);
28278
+ });
28279
+ }
28280
+ const MemoizedMarkdown = D$1(({ content, copyButtonText, copyButtonCopiedText, isStreaming }) => {
28281
+ const html = q$2(() => parseMarkdownToSafeHtml(content), [content]);
28118
28282
  const containerRef = F$2(null);
28119
28283
  _$1(() => {
28120
28284
  const container = containerRef.current;
@@ -28256,17 +28420,40 @@ function MenuItem(_ref) {
28256
28420
  Menu.Item = MenuItem;
28257
28421
  const agentStudioBaseUrl = (appId) => `https://${appId}.algolia.net/agent-studio/1`;
28258
28422
  const getAgentStudioErrorMessage = (error) => {
28259
- let errorMessage = error.message;
28423
+ var _parsedError$code;
28424
+ const raw = error.message;
28425
+ let parsed;
28260
28426
  try {
28261
- const parsedError = JSON.parse(error.message);
28262
- if (parsedError.name === "ValidationError") {
28263
- const validationError = parsedError;
28264
- if (validationError.detail && validationError.detail.length > 0) {
28265
- const { msg, loc } = validationError.detail[0];
28266
- errorMessage = `${msg}: ${loc.at(-1)}`;
28267
- }
28268
- } else errorMessage = parsedError.message;
28269
- } catch (_unused) {}
28427
+ parsed = JSON.parse(raw);
28428
+ } catch (_unused) {
28429
+ return new Error(raw);
28430
+ }
28431
+ let iterations = 0;
28432
+ while (typeof parsed === "string" && iterations < 10) {
28433
+ iterations += 1;
28434
+ const serializedError = parsed.trim();
28435
+ try {
28436
+ parsed = JSON.parse(serializedError);
28437
+ } catch (_unused2) {
28438
+ return new Error(serializedError);
28439
+ }
28440
+ }
28441
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return new Error(raw);
28442
+ const parsedRecord = parsed;
28443
+ const parsedError = parsed;
28444
+ let errorMessage = raw;
28445
+ if (parsedError.name === "ValidationError") {
28446
+ const validationError = parsedError;
28447
+ if (validationError.detail && validationError.detail.length > 0) {
28448
+ const { msg, loc } = validationError.detail[0];
28449
+ errorMessage = `${msg}: ${loc.at(-1)}`;
28450
+ }
28451
+ } else {
28452
+ var _ref, _readStringField;
28453
+ errorMessage = (_ref = (_readStringField = readStringField(parsedRecord, "message")) !== null && _readStringField !== void 0 ? _readStringField : readStringField(parsedRecord, "error")) !== null && _ref !== void 0 ? _ref : raw;
28454
+ }
28455
+ const code = (_parsedError$code = parsedError.code) !== null && _parsedError$code !== void 0 ? _parsedError$code : parsedError.errorCode;
28456
+ if (typeof code === "string" && code.trim() && !errorMessage.toUpperCase().includes(code.trim().toUpperCase())) errorMessage = `${errorMessage} (${code.trim()})`;
28270
28457
  return new Error(errorMessage);
28271
28458
  };
28272
28459
  const postAgentStudioFeedback = ({ agentId, vote, messageId, appId, apiKey, abortSignal, notes, tags }) => {
@@ -31268,7 +31455,7 @@ function createAutocomplete(options) {
31268
31455
  }
31269
31456
 
31270
31457
  //#endregion
31271
- //#region ../docsearch-react/dist/esm/DocSearchAskAiModal-BczGFkvR.js
31458
+ //#region ../docsearch-react/dist/esm/DocSearchAskAiModal-ByqIW5ZA.js
31272
31459
  init_compat();
31273
31460
  function MessageIcon() {
31274
31461
  return /* @__PURE__ */ En.createElement("svg", {
@@ -31330,7 +31517,7 @@ function AskAiExchangeCard({ exchange, askAiError, isLastExchange, loadingStatus
31330
31517
  const { userMessage, assistantMessage } = exchange;
31331
31518
  const { stoppedStreamingText = "You stopped this response", errorTitleText = "Chat error", relatedSourcesText, relatedSourcesTextPlural, suggestedPromptsTitleText = "Suggested prompts" } = translations;
31332
31519
  const toolCallTranslations = q$2(() => toToolCallTranslations(translations), [translations]);
31333
- const isThreadDepth = isThreadDepthError(askAiError);
31520
+ const isPromptBlockingError = isAskAiPromptBlockingError(askAiError);
31334
31521
  const assistantContent = q$2(() => getMessageContent(assistantMessage), [assistantMessage]);
31335
31522
  const userContent = q$2(() => getMessageContent(userMessage), [userMessage]);
31336
31523
  const urlsToDisplay = En.useMemo(() => extractLinksFromMessage(assistantMessage), [assistantMessage]);
@@ -31345,7 +31532,7 @@ function AskAiExchangeCard({ exchange, askAiError, isLastExchange, loadingStatus
31345
31532
  const showActions = !wasStopped && (!isLastExchange || isLastExchange && loadingStatus === "ready" && Boolean(assistantMessage));
31346
31533
  const isThinking = ["submitted", "streaming"].includes(loadingStatus) && isLastExchange && !displayParts.some((part) => part.type !== "step-start");
31347
31534
  const messageId = (assistantMessage === null || assistantMessage === void 0 ? void 0 : assistantMessage.id) || exchange.id;
31348
- return /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Response-Container" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Response" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user" }, /* @__PURE__ */ En.createElement("p", { className: "DocSearch-AskAiScreen-Query" }, userContent !== null && userContent !== void 0 ? userContent : "")), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent" }, loadingStatus === "error" && askAiError && isLastExchange && !isThreadDepth && /* @__PURE__ */ En.createElement("div", {
31535
+ return /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Response-Container" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Response" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user" }, /* @__PURE__ */ En.createElement("p", { className: "DocSearch-AskAiScreen-Query" }, userContent !== null && userContent !== void 0 ? userContent : "")), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent" }, loadingStatus === "error" && askAiError && isLastExchange && !isPromptBlockingError && /* @__PURE__ */ En.createElement("div", {
31349
31536
  className: "DocSearch-AskAiScreen-Error",
31350
31537
  role: "alert"
31351
31538
  }, /* @__PURE__ */ En.createElement(AlertIcon, { "aria-hidden": "true" }), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ En.createElement("h4", { className: "DocSearch-AskAiScreen-Error-Title" }, errorTitleText), /* @__PURE__ */ En.createElement(MemoizedMarkdown, {
@@ -31412,9 +31599,11 @@ function AskAiScreen(_ref) {
31412
31599
  let { translations = {} } = _ref, props = _objectWithoutProperties$6(_ref, _excluded$6);
31413
31600
  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;
31414
31601
  const { messages, tools, askAiError, status, memoryEnabled } = props;
31415
- const hasThreadDepthError = q$2(() => {
31416
- return status === "error" && isThreadDepthError(askAiError);
31602
+ const hasPromptBlockingError = q$2(() => {
31603
+ return status === "error" && isAskAiPromptBlockingError(askAiError);
31417
31604
  }, [status, askAiError]);
31605
+ const blockingMessage = q$2(() => getAskAiBlockingBannerMessage(askAiError), [askAiError]);
31606
+ const showNewConversationLink = showAskAiBlockingBannerNewConversationLink(askAiError);
31418
31607
  const exchanges = q$2(() => {
31419
31608
  const grouped = [];
31420
31609
  for (let i = 0; i < messages.length; i++) if (messages[i].role === "user") {
@@ -31428,21 +31617,21 @@ function AskAiScreen(_ref) {
31428
31617
  });
31429
31618
  if (assistantMessage) i++;
31430
31619
  }
31431
- if (hasThreadDepthError && grouped.length > 0) {
31432
- if (!grouped[grouped.length - 1].assistantMessage) grouped.pop();
31433
- }
31434
31620
  return grouped;
31435
- }, [messages, hasThreadDepthError]);
31621
+ }, [messages]);
31436
31622
  const handleSearchQueryClick = (query) => {
31437
31623
  props.onAskAiToggle(false);
31438
31624
  props.setQuery(query);
31439
31625
  };
31440
- const showThreadDepthError = hasThreadDepthError && messages.some((m) => m.role === "assistant");
31441
- return /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen DocSearch-AskAiScreen-Container" }, showThreadDepthError && /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ En.createElement("p", null, threadDepthExceededMessage, " ", /* @__PURE__ */ En.createElement("button", {
31626
+ const showBlockingBanner = hasPromptBlockingError && (!isThreadDepthError(askAiError) || messages.some((message) => message.role === "assistant"));
31627
+ return /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen DocSearch-AskAiScreen-Container" }, /* @__PURE__ */ En.createElement("div", {
31628
+ id: props.promptBlockingErrorId,
31629
+ role: "alert"
31630
+ }, showBlockingBanner && /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ En.createElement("p", { className: "DocSearch-AskAiScreen-Error-Title" }, blockingMessage !== null && blockingMessage !== void 0 ? blockingMessage : isThreadDepthError(askAiError) ? threadDepthExceededMessage : "This conversation cannot continue."), showNewConversationLink && /* @__PURE__ */ En.createElement("p", null, /* @__PURE__ */ En.createElement("button", {
31442
31631
  type: "button",
31443
31632
  className: "DocSearch-ThreadDepthError-Link",
31444
31633
  onClick: props.onNewConversation
31445
- }, startNewConversationButtonText), " ", "to continue."))), /* @__PURE__ */ En.createElement(AskAiScreenDisclaimer, { disclaimerText }), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Body" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-ExchangesList" }, exchanges.slice().reverse().map((exchange, index) => /* @__PURE__ */ En.createElement(AskAiExchangeCard, {
31634
+ }, startNewConversationButtonText), " ", "to continue.")))), /* @__PURE__ */ En.createElement(AskAiScreenDisclaimer, { disclaimerText }), /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-Body" }, /* @__PURE__ */ En.createElement("div", { className: "DocSearch-AskAiScreen-ExchangesList" }, exchanges.slice().reverse().map((exchange, index) => /* @__PURE__ */ En.createElement(AskAiExchangeCard, {
31446
31635
  key: exchange.id,
31447
31636
  exchange,
31448
31637
  askAiError: props.askAiError,
@@ -31587,10 +31776,10 @@ function AskAiSearchBox(_ref) {
31587
31776
  const origOnChange = baseInputProps.onChange;
31588
31777
  const isAskAiStreaming = props.askAiStatus === "streaming" || props.askAiStatus === "submitted";
31589
31778
  const renderMoreOptions = props.isAskAiActive && askAiState !== "conversation-history";
31590
- const isThreadDepthError = props.isThreadDepthError || false;
31779
+ const isPromptBlocked = Boolean(props.promptBlockingChrome);
31591
31780
  let searchPlaceholder = props.placeholder;
31592
31781
  if (askAiState === "new-conversation") searchPlaceholder = newConversationPlaceholder;
31593
- if (isThreadDepthError && props.isAskAiActive) searchPlaceholder = threadDepthErrorPlaceholder;
31782
+ if (props.promptBlockingChrome === "full" && props.isAskAiActive) searchPlaceholder = threadDepthErrorPlaceholder;
31594
31783
  let heading = null;
31595
31784
  if (isAskAiStreaming) heading = placeholderTextAskAiStreaming;
31596
31785
  if (askAiState === "conversation-history") heading = conversationHistoryTitle;
@@ -31608,6 +31797,11 @@ function AskAiSearchBox(_ref) {
31608
31797
  const inputProps = {
31609
31798
  enterKeyHint: props.isAskAiActive ? "enter" : "search",
31610
31799
  onKeyDown: (e) => {
31800
+ if (isPromptBlocked && props.isAskAiActive && blockedKeys.has(e.key)) {
31801
+ e.preventDefault();
31802
+ e.stopPropagation();
31803
+ return;
31804
+ }
31611
31805
  let askAiHandled = false;
31612
31806
  if (props.isAskAiActive && blockedKeys.has(e.key)) {
31613
31807
  if (e.key === "Enter" && !isAskAiStreaming && !isQueryEmpty(props.state.query)) props.onAskAgain(props.state.query);
@@ -31621,6 +31815,10 @@ function AskAiSearchBox(_ref) {
31621
31815
  origOnKeyDown === null || origOnKeyDown === void 0 || origOnKeyDown(e);
31622
31816
  },
31623
31817
  onChange: (e) => {
31818
+ if (isPromptBlocked && props.isAskAiActive) {
31819
+ e.preventDefault();
31820
+ return;
31821
+ }
31624
31822
  if (props.isAskAiActive) {
31625
31823
  props.setQuery(e.currentTarget.value);
31626
31824
  e.preventDefault();
@@ -31629,10 +31827,13 @@ function AskAiSearchBox(_ref) {
31629
31827
  }
31630
31828
  origOnChange === null || origOnChange === void 0 || origOnChange(e);
31631
31829
  },
31632
- disabled: isAskAiStreaming || isThreadDepthError && props.isAskAiActive
31830
+ disabled: isAskAiStreaming,
31831
+ readOnly: isPromptBlocked && props.isAskAiActive,
31832
+ "aria-disabled": isPromptBlocked && props.isAskAiActive,
31833
+ "aria-describedby": isPromptBlocked && props.isAskAiActive ? props.promptBlockingErrorId : void 0
31633
31834
  };
31634
31835
  const handleAskAiBackClick = En.useCallback(() => {
31635
- if (isThreadDepthError) {
31836
+ if (isPromptBlocked) {
31636
31837
  props.onNewConversation();
31637
31838
  return;
31638
31839
  }
@@ -31644,7 +31845,7 @@ function AskAiSearchBox(_ref) {
31644
31845
  onAskAiToggle(false);
31645
31846
  }, [
31646
31847
  askAiState,
31647
- isThreadDepthError,
31848
+ isPromptBlocked,
31648
31849
  onAskAiToggle,
31649
31850
  setAskAiState,
31650
31851
  props
@@ -31653,8 +31854,8 @@ function AskAiSearchBox(_ref) {
31653
31854
  type: "button",
31654
31855
  tabIndex: 0,
31655
31856
  className: "DocSearch-Action DocSearch-AskAi-Return",
31656
- title: backToKeywordSearchButtonText,
31657
- "aria-label": backToKeywordSearchButtonAriaLabel,
31857
+ title: isPromptBlocked ? startNewConversationText : backToKeywordSearchButtonText,
31858
+ "aria-label": isPromptBlocked ? startNewConversationText : backToKeywordSearchButtonAriaLabel,
31658
31859
  onClick: handleAskAiBackClick
31659
31860
  }, /* @__PURE__ */ En.createElement(BackIcon, null)) : void 0;
31660
31861
  const inputOverlay = heading ? /* @__PURE__ */ En.createElement(ModalHeading, {
@@ -31813,7 +32014,8 @@ const _excluded$7 = [
31813
32014
  "recentSearchesWithFavoritesLimit",
31814
32015
  "indices",
31815
32016
  "facets",
31816
- "isHybridModeSupported"
32017
+ "isHybridModeSupported",
32018
+ "footerAction"
31817
32019
  ];
31818
32020
  const _excluded2 = [
31819
32021
  "footer",
@@ -31822,7 +32024,7 @@ const _excluded2 = [
31822
32024
  ];
31823
32025
  function DocSearchAskAiModal(_ref) {
31824
32026
  var _translations$searchB, _askAiConfig$memory$e, _askAiConfig$memory, _askAiConfig$tools;
31825
- let { appId, apiKey, askAi, maxResultsPerGroup, theme, onClose = noop$2, 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$6(_ref, _excluded$7);
32027
+ let { appId, apiKey, askAi, maxResultsPerGroup, theme, onClose = noop$2, 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$6(_ref, _excluded$7);
31826
32028
  const { footer: footerTranslations, searchBox: searchBoxTranslations, facets: facetBarTranslations } = translations, screenStateTranslations = _objectWithoutProperties$6(translations, _excluded2);
31827
32029
  const [state, setState] = En.useState({
31828
32030
  query: "",
@@ -31843,7 +32045,8 @@ function DocSearchAskAiModal(_ref) {
31843
32045
  var _translations$searchB3;
31844
32046
  placeholder = (translations === null || translations === void 0 || (_translations$searchB3 = translations.searchBox) === null || _translations$searchB3 === void 0 ? void 0 : _translations$searchB3.placeholderTextAskAi) || "Ask another question...";
31845
32047
  }
31846
- const { containerRef, modalRef, formElementRef, dropdownRef, inputRef, snippetLength } = useModalRefs();
32048
+ const { containerRef, modalRef, formElementRef, dropdownRef, inputRef } = useModalRefs();
32049
+ const promptBlockingErrorId = En.useId();
31847
32050
  const { initialQuery, initialQueryFromSelection } = useInitialModalQuery(initialQueryFromProp);
31848
32051
  const searchClient = useSearchClient(appId, apiKey, transformSearchClient);
31849
32052
  const askAiConfig = typeof askAi === "object" ? askAi : null;
@@ -31900,9 +32103,17 @@ function DocSearchAskAiModal(_ref) {
31900
32103
  stoppedStream,
31901
32104
  chatId
31902
32105
  ]);
31903
- const hasThreadDepthError = En.useMemo(() => {
31904
- return status === "error" && isThreadDepthError(askAiError);
31905
- }, [status, askAiError]);
32106
+ const shouldBlockPrompt = En.useMemo(() => {
32107
+ return status === "error" && isAskAiPromptBlockingError(askAiError);
32108
+ }, [status, askAiError]) && (!isThreadDepthError(askAiError) || messages.some((message) => message.role === "assistant"));
32109
+ const promptBlockingChrome = En.useMemo(() => {
32110
+ if (!shouldBlockPrompt || askAiState === "new-conversation" || askAiState === "conversation-history") return;
32111
+ return isAgentStudioTokenOutputLimitError(askAiError) ? "minimal" : "full";
32112
+ }, [
32113
+ askAiError,
32114
+ askAiState,
32115
+ shouldBlockPrompt
32116
+ ]);
31906
32117
  const saveRecentSearch = useSaveRecentSearch({
31907
32118
  favoriteSearches,
31908
32119
  recentSearches,
@@ -31997,7 +32208,6 @@ function DocSearchAskAiModal(_ref) {
31997
32208
  setStatus,
31998
32209
  searchClient,
31999
32210
  indexes,
32000
- snippetLength,
32001
32211
  insights: Boolean(insights),
32002
32212
  appId,
32003
32213
  apiKey,
@@ -32027,7 +32237,6 @@ function DocSearchAskAiModal(_ref) {
32027
32237
  inputRef,
32028
32238
  initialScrollY,
32029
32239
  modalRef,
32030
- snippetLength,
32031
32240
  theme
32032
32241
  });
32033
32242
  En.useEffect(() => {
@@ -32094,7 +32303,8 @@ function DocSearchAskAiModal(_ref) {
32094
32303
  askAiError,
32095
32304
  askAiState,
32096
32305
  setAskAiState,
32097
- isThreadDepthError: hasThreadDepthError && askAiState !== "new-conversation",
32306
+ promptBlockingChrome,
32307
+ promptBlockingErrorId,
32098
32308
  onClose,
32099
32309
  onAskAiToggle,
32100
32310
  onAskAgain: (query) => {
@@ -32136,6 +32346,7 @@ function DocSearchAskAiModal(_ref) {
32136
32346
  selectSuggestedQuestion,
32137
32347
  memoryEnabled,
32138
32348
  resultBadgeKey: props.resultBadgeKey,
32349
+ promptBlockingErrorId,
32139
32350
  onAskAiToggle,
32140
32351
  onNewConversation: handleNewConversation,
32141
32352
  onItemClick: (item, event) => {
@@ -32166,7 +32377,8 @@ function DocSearchAskAiModal(_ref) {
32166
32377
  })),
32167
32378
  footer: /* @__PURE__ */ En.createElement(Footer, {
32168
32379
  translations: footerTranslations,
32169
- isAskAiActive
32380
+ isAskAiActive,
32381
+ footerAction
32170
32382
  }),
32171
32383
  onClose
32172
32384
  });
@@ -32251,7 +32463,7 @@ init_compat();
32251
32463
  function isEditingContent(event) {
32252
32464
  const element = event.composedPath()[0];
32253
32465
  const tagName = element.tagName;
32254
- return element.isContentEditable || tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA";
32466
+ return element.isContentEditable || tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA" || tagName === "BUTTON";
32255
32467
  }
32256
32468
  function useDocSearchKeyboardEvents({ isOpen, isAskAiActive, onAskAiToggle, onClose, onOpen, keyboardShortcuts = DEFAULT_KEYBOARD_SHORTCUTS }) {
32257
32469
  En.useEffect(() => {
@@ -32549,7 +32761,8 @@ const _excluded = [
32549
32761
  "environment",
32550
32762
  "transformSearchClient",
32551
32763
  "hitComponent",
32552
- "resultsFooterComponent"
32764
+ "resultsFooterComponent",
32765
+ "footerAction"
32553
32766
  ];
32554
32767
  function getHTMLElement(value, env) {
32555
32768
  if (typeof value !== "string") return value;
@@ -32572,14 +32785,16 @@ function createTemplateFunction(original) {
32572
32785
  function createDocSearch(Component, version) {
32573
32786
  return (allProps) => {
32574
32787
  const input = allProps;
32575
- const { container, environment, transformSearchClient, hitComponent, resultsFooterComponent } = input, rest = _objectWithoutProperties$5(input, _excluded);
32788
+ const { container, environment, transformSearchClient, hitComponent, resultsFooterComponent, footerAction } = input, rest = _objectWithoutProperties$5(input, _excluded);
32576
32789
  const containerElement = getHTMLElement(container, environment || (typeof window !== "undefined" ? window : void 0));
32577
32790
  const ref = b$2();
32578
32791
  let isReady = false;
32792
+ const FooterAction = createTemplateFunction(footerAction);
32579
32793
  J$1(_$2(Component, _objectSpread2$1(_objectSpread2$1({}, rest), {}, {
32580
32794
  ref,
32581
32795
  hitComponent: createTemplateFunction(hitComponent),
32582
32796
  resultsFooterComponent: createTemplateFunction(resultsFooterComponent),
32797
+ footerAction: FooterAction ? _$2(FooterAction, null) : void 0,
32583
32798
  transformSearchClient: (searchClient) => {
32584
32799
  if (typeof searchClient === "object" && searchClient !== null && "addAlgoliaAgent" in searchClient && typeof searchClient.addAlgoliaAgent === "function") searchClient.addAlgoliaAgent("docsearch.js", version);
32585
32800
  return typeof transformSearchClient === "function" ? transformSearchClient(searchClient) : searchClient;