@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
@@ -496,21 +496,136 @@ function SourcesPanel({ links, titleText = "Source", pluralTitleText = "Sources"
496
496
  }, /* @__PURE__ */ React.createElement(ContentIcon, null), /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-Sources-source-title" }, l.title || l.url)))))));
497
497
  }
498
498
 
499
+ //#endregion
500
+ //#region src/utils/askAiBlockingMatchers.ts
501
+ const PROMPT_BLOCKING_CODES = /* @__PURE__ */ new Set([
502
+ "AI-203",
503
+ "AI-205",
504
+ "AI-224",
505
+ "AI-225"
506
+ ]);
507
+ function readStringField(value, key) {
508
+ for (const [field, fieldValue] of Object.entries(value)) if (field.toLowerCase() === key.toLowerCase() && typeof fieldValue === "string" && fieldValue.trim() !== "") return fieldValue.trim();
509
+ }
510
+ function extractErrorCode(message) {
511
+ const directMatch = /\b(AI-\d{3})\b/i.exec(message);
512
+ if (directMatch) return directMatch[1].toUpperCase();
513
+ }
514
+ function parseJson(message) {
515
+ try {
516
+ const parsed = JSON.parse(message);
517
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
518
+ } catch (_unused) {}
519
+ return null;
520
+ }
521
+ function matchesDomainBlock(message) {
522
+ return /\brequest blocked for this domain\b/.test(message) || /\bblocked for this domain\b/.test(message);
523
+ }
524
+ function matchesRateLimit(message) {
525
+ 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);
526
+ }
527
+ function matchesTokenOutputLimit(message) {
528
+ return /\btokenoutputlimiterror\b/.test(message) || /could not complete response due to token output limits/.test(message);
529
+ }
530
+ function matchesAccessOrLimit(message) {
531
+ 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);
532
+ }
533
+ function jsonImpliesCostControl(value) {
534
+ var _readStringField, _readStringField2, _readStringField3;
535
+ const type = (_readStringField = readStringField(value, "type")) !== null && _readStringField !== void 0 ? _readStringField : "";
536
+ const error = (_readStringField2 = readStringField(value, "error")) !== null && _readStringField2 !== void 0 ? _readStringField2 : "";
537
+ const message = (_readStringField3 = readStringField(value, "message")) !== null && _readStringField3 !== void 0 ? _readStringField3 : "";
538
+ return /tokenoutput|outputlimit|steplimit|maxstep|ratelimit|domainnotallowed/i.test(type) || error.toUpperCase() === "TOO_MANY_REQUESTS" || matchesRateLimit(`${error} ${message}`.toLowerCase()) || matchesAccessOrLimit(`${error} ${message}`.toLowerCase());
539
+ }
540
+ const BLOCKING_MATCHERS = [
541
+ { matches: ({ code }) => Boolean(code && PROMPT_BLOCKING_CODES.has(code)) },
542
+ {
543
+ matches: ({ parsedJson }) => {
544
+ var _readStringField4;
545
+ return Boolean(parsedJson && matchesDomainBlock(((_readStringField4 = readStringField(parsedJson, "message")) !== null && _readStringField4 !== void 0 ? _readStringField4 : "").toLowerCase()));
546
+ },
547
+ showNewConversationLink: false
548
+ },
549
+ { matches: ({ parsedJson }) => Boolean(parsedJson && jsonImpliesCostControl(parsedJson)) },
550
+ {
551
+ matches: ({ messageLower }) => matchesTokenOutputLimit(messageLower),
552
+ showNewConversationLink: false
553
+ },
554
+ { matches: ({ messageLower }) => matchesRateLimit(messageLower) },
555
+ {
556
+ matches: ({ messageLower }) => matchesDomainBlock(messageLower),
557
+ showNewConversationLink: false
558
+ },
559
+ { matches: ({ messageLower }) => matchesAccessOrLimit(messageLower) }
560
+ ];
561
+ function resolvePromptBlockingError(error) {
562
+ var _error$message;
563
+ const message = (_error$message = error.message) !== null && _error$message !== void 0 ? _error$message : "";
564
+ const context = {
565
+ message,
566
+ messageLower: message.toLowerCase(),
567
+ parsedJson: parseJson(message),
568
+ code: extractErrorCode(message)
569
+ };
570
+ const matches = BLOCKING_MATCHERS.filter((matcher) => matcher.matches(context));
571
+ return {
572
+ blocking: matches.length > 0,
573
+ showNewConversationLink: matches.every((matcher) => matcher.showNewConversationLink !== false)
574
+ };
575
+ }
576
+ function isTokenOutputLimitError(error) {
577
+ var _error$message2;
578
+ return Boolean(error && matchesTokenOutputLimit(((_error$message2 = error.message) !== null && _error$message2 !== void 0 ? _error$message2 : "").toLowerCase()));
579
+ }
580
+
499
581
  //#endregion
500
582
  //#region src/utils/sanitize.ts
501
- /**
502
- * Escapes HTML special characters to prevent XSS attacks. This should be used
503
- * for any user-provided content that will be displayed.
504
- */
505
- function escapeHtml$1(unsafe) {
583
+ /** Escapes HTML special characters for safe interpolation into HTML strings. */
584
+ function escapeHtml(unsafe) {
506
585
  return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
507
586
  }
587
+ /** Strips HTML tags and escapes the remainder for plain-text React children. */
588
+ function sanitizeUserInput(input) {
589
+ return escapeHtml(input.replace(/<[^>]*>/g, ""));
590
+ }
591
+ function decodeUrlForSchemeCheck(value) {
592
+ let current = value;
593
+ for (let i = 0; i < 3; i += 1) try {
594
+ const decoded = decodeURIComponent(current);
595
+ if (decoded === current) break;
596
+ current = decoded;
597
+ } catch (_unused) {
598
+ break;
599
+ }
600
+ return current;
601
+ }
602
+ function stripControlsAndWhitespace(value) {
603
+ let result = "";
604
+ for (let i = 0; i < value.length; i += 1) {
605
+ const code = value.charCodeAt(i);
606
+ if (code > 32 && code !== 127) result += value[i];
607
+ }
608
+ return result;
609
+ }
508
610
  /**
509
- * Sanitizes user input to prevent XSS attacks. Removes any HTML tags and
510
- * escapes special characters.
611
+ * Returns a URL safe for href/src, or '' if unsafe. Does not HTML-escape
612
+ * callers building HTML strings must escape separately.
511
613
  */
512
- function sanitizeUserInput(input) {
513
- return escapeHtml$1(input.replace(/<[^>]*>/g, ""));
614
+ function sanitizeUrl(url) {
615
+ if (!url) return "";
616
+ const trimmed = url.trim();
617
+ if (!trimmed) return "";
618
+ const normalized = stripControlsAndWhitespace(decodeUrlForSchemeCheck(trimmed));
619
+ if (!normalized) return "";
620
+ if (normalized.startsWith("//")) return "";
621
+ if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(normalized)) return trimmed;
622
+ try {
623
+ const parsed = new URL(normalized);
624
+ if (parsed.protocol === "http:" || parsed.protocol === "https:" || parsed.protocol === "mailto:") return normalized;
625
+ } catch (_unused2) {
626
+ return "";
627
+ }
628
+ return "";
514
629
  }
515
630
 
516
631
  //#endregion
@@ -528,8 +643,8 @@ function extractLinksFromMessage(message) {
528
643
  const markdownMatches = cleanText.matchAll(markdownLinkRegex);
529
644
  for (const match of markdownMatches) {
530
645
  const title = match[1].trim();
531
- const url = match[2];
532
- if (!seen.has(url)) {
646
+ const url = sanitizeUrl(match[2]);
647
+ if (url && !seen.has(url)) {
533
648
  seen.add(url);
534
649
  links.push({
535
650
  url,
@@ -539,8 +654,8 @@ function extractLinksFromMessage(message) {
539
654
  }
540
655
  const plainUrls = cleanText.matchAll(plainLinkRegex);
541
656
  for (const match of plainUrls) {
542
- const cleanUrl = match[0].replace(/[.,;:!?]+$/, "");
543
- if (!seen.has(cleanUrl)) {
657
+ const cleanUrl = sanitizeUrl(match[0].replace(/[.,;:!?]+$/, ""));
658
+ if (cleanUrl && !seen.has(cleanUrl)) {
544
659
  seen.add(cleanUrl);
545
660
  links.push({ url: cleanUrl });
546
661
  }
@@ -576,11 +691,56 @@ const getMessageContent = (message) => {
576
691
  var _message$parts;
577
692
  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");
578
693
  };
579
- /** Helper function to check if error is a thread depth error (AI-217). */
694
+ /** Helper function to check if an error reports the conversation depth limit. */
580
695
  function isThreadDepthError(error) {
581
696
  var _error$message;
582
697
  if (!error) return false;
583
- return ((_error$message = error.message) === null || _error$message === void 0 ? void 0 : _error$message.includes("AI-217")) || false;
698
+ return /(?:ai-217|conversation\s+depth)/i.test((_error$message = error.message) !== null && _error$message !== void 0 ? _error$message : "");
699
+ }
700
+ function isAskAiPromptBlockingError(error) {
701
+ return Boolean(error && (isThreadDepthError(error) || resolvePromptBlockingError(error).blocking));
702
+ }
703
+ function isAgentStudioTokenOutputLimitError(error) {
704
+ return isTokenOutputLimitError(error);
705
+ }
706
+ function showAskAiBlockingBannerNewConversationLink(error) {
707
+ if (!error || isThreadDepthError(error)) return true;
708
+ return resolvePromptBlockingError(error).showNewConversationLink;
709
+ }
710
+ function extractAgentStudioErrorFieldMessage(raw) {
711
+ let value = raw.trim();
712
+ for (let iteration = 0; iteration < 10 && value; iteration++) try {
713
+ var _exec, _fieldMatch$;
714
+ const parsed = JSON.parse(value);
715
+ if (typeof parsed === "string") {
716
+ value = parsed.trim();
717
+ continue;
718
+ }
719
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
720
+ const record = parsed;
721
+ const message = readStringField(record, "message");
722
+ const error = readStringField(record, "error");
723
+ if (message) return message;
724
+ if (error) return error;
725
+ }
726
+ const fieldMatch = (_exec = /"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(value)) !== null && _exec !== void 0 ? _exec : /"error"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(value);
727
+ return fieldMatch === null || fieldMatch === void 0 || (_fieldMatch$ = fieldMatch[1]) === null || _fieldMatch$ === void 0 ? void 0 : _fieldMatch$.replace(/\\"/g, "\"").replace(/\\\\/g, "\\").trim();
728
+ } catch (_unused) {
729
+ if (value.includes("\\\"")) {
730
+ value = value.replace(/\\"/g, "\"").replace(/\\\\/g, "\\").trim();
731
+ continue;
732
+ }
733
+ return;
734
+ }
735
+ }
736
+ function getAskAiBlockingBannerMessage(error) {
737
+ var _error$message2;
738
+ if (!error) return;
739
+ const extracted = extractAgentStudioErrorFieldMessage((_error$message2 = error.message) !== null && _error$message2 !== void 0 ? _error$message2 : "");
740
+ if (isThreadDepthError(error) && (/^\s*AI-217\s*$/i.test(error.message) || /^\s*\{.*\}\s*$/.test(error.message) && !extracted)) return;
741
+ const message = (extracted !== null && extracted !== void 0 ? extracted : error.message.replace(/\s*\(AI-\d{3}\)\s*$/i, "")).trim();
742
+ if (message && !(message.startsWith("{") && message.endsWith("}"))) return message;
743
+ if (isAgentStudioTokenOutputLimitError(error)) return "Could not complete response due to token output limits";
584
744
  }
585
745
  const EMPTY_TOOLS = Object.freeze({});
586
746
  function isAIToolPart(part) {
@@ -736,13 +896,11 @@ function ToolCall({ part, translations, tools, onSearchQueryClick, memoryEnabled
736
896
  }
737
897
 
738
898
  //#endregion
739
- //#region src/MemoizedMarkdown.tsx
740
- function escapeHtml(html) {
741
- return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
742
- }
899
+ //#region src/utils/markdown.ts
743
900
  const renderer = new marked.Renderer();
744
901
  renderer.code = ({ text, lang = "", escaped }) => {
745
- const languageClass = lang ? `language-${lang}` : "";
902
+ const safeLang = /^[a-zA-Z0-9_-]+$/.test(lang) ? lang : "";
903
+ const languageClass = safeLang ? `language-${safeLang}` : "";
746
904
  const safeCode = escaped ? text : escapeHtml(text);
747
905
  return `
748
906
  <div class="DocSearch-CodeSnippet">
@@ -752,15 +910,31 @@ renderer.code = ({ text, lang = "", escaped }) => {
752
910
  `;
753
911
  };
754
912
  renderer.link = ({ href, title, text }) => {
913
+ const safeHref = escapeHtml(sanitizeUrl(href));
914
+ const textEscaped = escapeHtml(text);
915
+ if (!safeHref) return textEscaped;
916
+ return `<a href="${safeHref}"${title ? ` title="${escapeHtml(title)}"` : ""} target="_blank" rel="noopener noreferrer">${textEscaped}</a>`;
917
+ };
918
+ renderer.image = ({ href, title, text }) => {
919
+ const safeHref = escapeHtml(sanitizeUrl(href));
920
+ if (!safeHref) return escapeHtml(text);
755
921
  const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
756
- return `<a href="${href ? escapeHtml(href) : ""}"${titleAttr} target="_blank" rel="noopener noreferrer">${escapeHtml(text)}</a>`;
922
+ return `<img src="${safeHref}" alt="${escapeHtml(text)}"${titleAttr} />`;
757
923
  };
758
- const MemoizedMarkdown = memo(({ content, copyButtonText, copyButtonCopiedText, isStreaming }) => {
759
- const html = useMemo(() => marked.parse(content, {
924
+ renderer.html = ({ text }) => escapeHtml(text);
925
+ /** Parses markdown into HTML safe for `dangerouslySetInnerHTML`. */
926
+ function parseMarkdownToSafeHtml(content) {
927
+ return marked.parse(content, {
760
928
  gfm: true,
761
929
  breaks: true,
762
930
  renderer
763
- }), [content]);
931
+ });
932
+ }
933
+
934
+ //#endregion
935
+ //#region src/MemoizedMarkdown.tsx
936
+ const MemoizedMarkdown = memo(({ content, copyButtonText, copyButtonCopiedText, isStreaming }) => {
937
+ const html = useMemo(() => parseMarkdownToSafeHtml(content), [content]);
764
938
  const containerRef = useRef(null);
765
939
  useEffect(() => {
766
940
  const container = containerRef.current;
@@ -911,17 +1085,40 @@ Menu.Item = MenuItem;
911
1085
  //#region src/askai.ts
912
1086
  const agentStudioBaseUrl = (appId) => `https://${appId}.algolia.net/agent-studio/1`;
913
1087
  const getAgentStudioErrorMessage = (error) => {
914
- let errorMessage = error.message;
1088
+ var _parsedError$code;
1089
+ const raw = error.message;
1090
+ let parsed;
915
1091
  try {
916
- const parsedError = JSON.parse(error.message);
917
- if (parsedError.name === "ValidationError") {
918
- const validationError = parsedError;
919
- if (validationError.detail && validationError.detail.length > 0) {
920
- const { msg, loc } = validationError.detail[0];
921
- errorMessage = `${msg}: ${loc.at(-1)}`;
922
- }
923
- } else errorMessage = parsedError.message;
924
- } catch (_unused) {}
1092
+ parsed = JSON.parse(raw);
1093
+ } catch (_unused) {
1094
+ return new Error(raw);
1095
+ }
1096
+ let iterations = 0;
1097
+ while (typeof parsed === "string" && iterations < 10) {
1098
+ iterations += 1;
1099
+ const serializedError = parsed.trim();
1100
+ try {
1101
+ parsed = JSON.parse(serializedError);
1102
+ } catch (_unused2) {
1103
+ return new Error(serializedError);
1104
+ }
1105
+ }
1106
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return new Error(raw);
1107
+ const parsedRecord = parsed;
1108
+ const parsedError = parsed;
1109
+ let errorMessage = raw;
1110
+ if (parsedError.name === "ValidationError") {
1111
+ const validationError = parsedError;
1112
+ if (validationError.detail && validationError.detail.length > 0) {
1113
+ const { msg, loc } = validationError.detail[0];
1114
+ errorMessage = `${msg}: ${loc.at(-1)}`;
1115
+ }
1116
+ } else {
1117
+ var _ref, _readStringField;
1118
+ errorMessage = (_ref = (_readStringField = readStringField(parsedRecord, "message")) !== null && _readStringField !== void 0 ? _readStringField : readStringField(parsedRecord, "error")) !== null && _ref !== void 0 ? _ref : raw;
1119
+ }
1120
+ const code = (_parsedError$code = parsedError.code) !== null && _parsedError$code !== void 0 ? _parsedError$code : parsedError.errorCode;
1121
+ if (typeof code === "string" && code.trim() && !errorMessage.toUpperCase().includes(code.trim().toUpperCase())) errorMessage = `${errorMessage} (${code.trim()})`;
925
1122
  return new Error(errorMessage);
926
1123
  };
927
1124
  const postAgentStudioFeedback = ({ agentId, vote, messageId, appId, apiKey, abortSignal, notes, tags }) => {
@@ -1122,5 +1319,5 @@ const useSuggestedQuestions = ({ agentId, searchClient, suggestedQuestionsEnable
1122
1319
  };
1123
1320
 
1124
1321
  //#endregion
1125
- export { AlertIcon as S, BackIcon as _, MemoizedMarkdown as a, MoreVerticalIcon as b, buildDummyAskAiHit as c, getMessageContent as d, isAIToolPart as f, ConversationPromptSuggestions as g, FeedbackActions as h, groupConsecutiveToolResults as i, extractLinksFromMessage as l, SourcesPanel as m, useAskAi as n, ToolCall as o, isThreadDepthError as p, Menu as r, EMPTY_TOOLS as s, useSuggestedQuestions as t, getAgentPromptSuggestions as u, NewConversationIcon as v, StopIcon as x, ConversationHistoryIcon as y };
1126
- //# sourceMappingURL=useSuggestedQuestions-Ds7H1JCr.js.map
1322
+ export { ConversationHistoryIcon as C, AlertIcon as E, NewConversationIcon as S, StopIcon as T, showAskAiBlockingBannerNewConversationLink as _, MemoizedMarkdown as a, ConversationPromptSuggestions as b, buildDummyAskAiHit as c, getAskAiBlockingBannerMessage as d, getMessageContent as f, isThreadDepthError as g, isAskAiPromptBlockingError as h, groupConsecutiveToolResults as i, extractLinksFromMessage as l, isAgentStudioTokenOutputLimitError as m, useAskAi as n, ToolCall as o, isAIToolPart as p, Menu as r, EMPTY_TOOLS as s, useSuggestedQuestions as t, getAgentPromptSuggestions as u, SourcesPanel as v, MoreVerticalIcon as w, BackIcon as x, FeedbackActions as y };
1323
+ //# sourceMappingURL=useSuggestedQuestions-BjSZvxwr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSuggestedQuestions-BjSZvxwr.js","names":["Popover","PopoverPrimitive","Popover"],"sources":["../../src/icons/AlertIcon.tsx","../../src/icons/StopIcon.tsx","../../src/icons/MoreVerticalIcon.tsx","../../src/icons/ConversationHistoryIcon.tsx","../../src/icons/NewConversationIcon.tsx","../../src/icons/ToolIcon.tsx","../../src/icons/MemoryIcon.tsx","../../src/icons/BackIcon.tsx","../../src/components/ConversationPromptSuggestions.tsx","../../src/components/FeedbackActions.tsx","../../src/components/ui/Popover.tsx","../../src/components/SourcesPanel.tsx","../../src/utils/askAiBlockingMatchers.ts","../../src/utils/sanitize.ts","../../src/utils/ai.ts","../../src/components/ui/ToolState.tsx","../../src/components/ToolCall.tsx","../../src/utils/markdown.ts","../../src/MemoizedMarkdown.tsx","../../src/utils/groupConsecutiveToolResults.ts","../../src/Menu.tsx","../../src/askai.ts","../../src/useAskAi.ts","../../src/useSuggestedQuestions.ts"],"sourcesContent":["import React, { type JSX } from 'react';\n\nexport function AlertIcon(props: React.SVGProps<SVGSVGElement>): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n fillRule=\"evenodd\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n {...props}\n >\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n );\n}\n","import React, { type JSX } from 'react';\n\nexport function StopIcon(): JSX.Element {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={18}\n height={18}\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M8.99984 1.29102C4.74264 1.29102 1.2915 4.74215 1.2915 8.99935C1.2915 13.2565 4.74264 16.7077 8.99984 16.7077C13.257 16.7077 16.7082 13.2565 16.7082 8.99935C16.7082 4.74215 13.257 1.29102 8.99984 1.29102ZM0.0415039 8.99935C0.0415039 4.0518 4.05229 0.0410156 8.99984 0.0410156C13.9474 0.0410156 17.9582 4.0518 17.9582 8.99935C17.9582 13.9469 13.9474 17.9577 8.99984 17.9577C4.05229 17.9577 0.0415039 13.9469 0.0415039 8.99935ZM5.87484 6.49935C5.87484 6.15417 6.15466 5.87435 6.49984 5.87435H11.4998C11.845 5.87435 12.1248 6.15417 12.1248 6.49935V11.4993C12.1248 11.8445 11.845 12.1243 11.4998 12.1243H6.49984C6.15466 12.1243 5.87484 11.8445 5.87484 11.4993V6.49935ZM7.12484 7.12435V10.8743H10.8748V7.12435H7.12484Z\"\n fill=\"currentcolor\"\n />\n </svg>\n );\n}\n","import React, { type JSX } from 'react';\n\nexport function MoreVerticalIcon(): JSX.Element {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={4}\n height={16}\n viewBox=\"0 0 4 16\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M1.99984 1.95898C1.88478 1.95898 1.7915 2.05226 1.7915 2.16732C1.7915 2.28238 1.88478 2.37565 1.99984 2.37565C2.1149 2.37565 2.20817 2.28238 2.20817 2.16732C2.20817 2.05226 2.1149 1.95898 1.99984 1.95898ZM0.541504 2.16732C0.541504 1.3619 1.19442 0.708984 1.99984 0.708984C2.80525 0.708984 3.45817 1.3619 3.45817 2.16732C3.45817 2.97273 2.80525 3.62565 1.99984 3.62565C1.19442 3.62565 0.541504 2.97273 0.541504 2.16732ZM1.99984 7.79232C1.88478 7.79232 1.7915 7.88559 1.7915 8.00065C1.7915 8.11571 1.88478 8.20898 1.99984 8.20898C2.1149 8.20898 2.20817 8.11571 2.20817 8.00065C2.20817 7.88559 2.1149 7.79232 1.99984 7.79232ZM0.541504 8.00065C0.541504 7.19524 1.19442 6.54232 1.99984 6.54232C2.80525 6.54232 3.45817 7.19524 3.45817 8.00065C3.45817 8.80607 2.80525 9.45898 1.99984 9.45898C1.19442 9.45898 0.541504 8.80607 0.541504 8.00065ZM1.99984 13.6257C1.88478 13.6257 1.7915 13.7189 1.7915 13.834C1.7915 13.949 1.88478 14.0423 1.99984 14.0423C2.1149 14.0423 2.20817 13.949 2.20817 13.834C2.20817 13.7189 2.1149 13.6257 1.99984 13.6257ZM0.541504 13.834C0.541504 13.0286 1.19442 12.3757 1.99984 12.3757C2.80525 12.3757 3.45817 13.0286 3.45817 13.834C3.45817 14.6394 2.80525 15.2923 1.99984 15.2923C1.19442 15.2923 0.541504 14.6394 0.541504 13.834Z\"\n fill=\"currentcolor\"\n />\n </svg>\n );\n}\n","import React, { type JSX } from 'react';\n\nexport function ConversationHistoryIcon(): JSX.Element {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n >\n <path\n d=\"M9 0.875C10.6068 0.875 12.1776 1.35149 13.5137 2.24414C14.8498 3.13693 15.8919 4.40598 16.5068 5.89062C17.1218 7.37522 17.2822 9.00892 16.9688 10.585C16.6552 12.1611 15.8814 13.6088 14.7451 14.7451C13.6088 15.8814 12.1611 16.6552 10.585 16.9688C9.00892 17.2822 7.37523 17.1218 5.89062 16.5068C4.40598 15.8919 3.13693 14.8498 2.24414 13.5137C1.35149 12.1776 0.875 10.6068 0.875 9C0.875 8.65482 1.15482 8.375 1.5 8.375C1.84518 8.375 2.125 8.65482 2.125 9C2.125 10.3596 2.52792 11.6888 3.2832 12.8193C4.03864 13.9499 5.1129 14.8312 6.36914 15.3516C7.62523 15.8718 9.00736 16.0083 10.3408 15.7432C11.6744 15.4779 12.8998 14.8228 13.8613 13.8613C14.8228 12.8998 15.4779 11.6744 15.7432 10.3408C16.0083 9.00736 15.8718 7.62523 15.3516 6.36914C14.8312 5.1129 13.9499 4.03864 12.8193 3.2832C11.6888 2.52792 10.3596 2.125 9 2.125C7.06829 2.125 5.21604 2.89096 3.82129 4.22949L3.00879 5.04199H5.66699C6.01202 5.04217 6.29199 5.32192 6.29199 5.66699C6.29182 6.01191 6.01191 6.29182 5.66699 6.29199H1.5C1.45939 6.29199 1.41889 6.28716 1.37891 6.2793C1.36148 6.27587 1.345 6.26949 1.32812 6.26465C1.267 6.24714 1.20782 6.22205 1.15332 6.18555C1.08536 6.14005 1.02604 6.08256 0.980469 6.01465C0.970244 5.99942 0.962841 5.98268 0.954102 5.9668C0.904937 5.87756 0.875056 5.77606 0.875 5.66699V1.5C0.875 1.15482 1.15482 0.875002 1.5 0.875C1.84518 0.875 2.125 1.15482 2.125 1.5V4.15723L2.94141 3.3418L2.9502 3.33301C4.57158 1.77433 6.73388 0.875 9 0.875ZM9.33301 4.20801C9.67808 4.20801 9.95783 4.48798 9.95801 4.83301V9.44727L12.9463 10.9414C13.2548 11.0958 13.3798 11.4707 13.2256 11.7793C13.0712 12.088 12.6955 12.213 12.3867 12.0586L9.05371 10.3926C8.84198 10.2867 8.70801 10.0697 8.70801 9.83301V4.83301C8.70818 4.48809 8.98809 4.20819 9.33301 4.20801Z\"\n fill=\"currentcolor\"\n />\n </svg>\n );\n}\n","import type { JSX } from 'react';\nimport React from 'react';\n\nexport function NewConversationIcon(): JSX.Element {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"19\"\n height=\"19\"\n viewBox=\"0 0 19 19\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M0.712717 3.38039C1.14249 2.95062 1.72538 2.70917 2.33317 2.70917H8.1665C8.51168 2.70917 8.7915 2.989 8.7915 3.33417C8.7915 3.67935 8.51168 3.95917 8.1665 3.95917H2.33317C2.0569 3.95917 1.79195 4.06892 1.5966 4.26427C1.40125 4.45962 1.2915 4.72457 1.2915 5.00084V16.6675C1.2915 16.9438 1.40125 17.2087 1.5966 17.4041C1.79195 17.5994 2.0569 17.7092 2.33317 17.7092H13.9998C14.2761 17.7092 14.5411 17.5994 14.7364 17.4041C14.9318 17.2087 15.0415 16.9438 15.0415 16.6675V10.8342C15.0415 10.489 15.3213 10.2092 15.6665 10.2092C16.0117 10.2092 16.2915 10.489 16.2915 10.8342V16.6675C16.2915 17.2753 16.0501 17.8582 15.6203 18.288C15.1905 18.7177 14.6076 18.9592 13.9998 18.9592H2.33317C1.72538 18.9592 1.14249 18.7177 0.712717 18.288C0.282947 17.8582 0.0415039 17.2753 0.0415039 16.6675V5.00084C0.0415039 4.39305 0.282947 3.81016 0.712717 3.38039Z\"\n fill=\"currentcolor\"\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M15.6665 2.19141C15.3634 2.19141 15.0728 2.3118 14.8584 2.52611L7.06419 10.3204L6.52548 12.4752L8.68031 11.9365L16.4746 4.14223C16.6889 3.92792 16.8093 3.63725 16.8093 3.33417C16.8093 3.03109 16.6889 2.74043 16.4746 2.52611C16.2603 2.3118 15.9696 2.19141 15.6665 2.19141ZM13.9746 1.64223C14.4233 1.1935 15.0319 0.941406 15.6665 0.941406C16.3011 0.941406 16.9097 1.1935 17.3584 1.64223C17.8072 2.09096 18.0593 2.69957 18.0593 3.33417C18.0593 3.96877 17.8072 4.57738 17.3584 5.02611L9.44178 12.9428C9.36168 13.0229 9.26132 13.0797 9.15142 13.1072L5.81809 13.9405C5.6051 13.9938 5.3798 13.9314 5.22456 13.7761C5.06932 13.6209 5.00692 13.3956 5.06016 13.1826L5.8935 9.84925C5.92097 9.73936 5.9778 9.639 6.0579 9.5589L13.9746 1.64223Z\"\n fill=\"currentcolor\"\n />\n </svg>\n );\n}\n","import React from 'react';\n\nexport function ToolIcon({ size = 20 }: { size?: number }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"DocSearch-Search-Icon\"\n >\n <path d=\"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z\" />\n </svg>\n );\n}\n","import React, { type JSX } from 'react';\n\nexport function MemoryIcon(): JSX.Element {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\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=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\" />\n <path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\" />\n </svg>\n );\n}\n","import React, { type JSX } from 'react';\n\ninterface BackIconProps {\n size?: number;\n color?: string;\n}\n\nexport function BackIcon({\n size = 20,\n color = 'currentColor',\n}: BackIconProps): JSX.Element {\n return (\n <svg\n width={size}\n height={size}\n className=\"DocSearch-Back-Icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={color}\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m12 19-7-7 7-7\" />\n <path d=\"M19 12H5\" />\n </svg>\n );\n}\n","import type { JSX } from 'react';\nimport React from 'react';\n\ninterface ConversationPromptSuggestionsProps {\n title: string;\n onSelectPromptSuggestion: (prompt: string) => void;\n suggestions: string[];\n}\nexport const ConversationPromptSuggestions = React.memo(\n function ConversationPromptSuggestions({\n title,\n suggestions,\n onSelectPromptSuggestion,\n }: ConversationPromptSuggestionsProps): JSX.Element {\n const titleId = React.useId();\n\n const handleSelectPromptSuggestion = React.useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n onSelectPromptSuggestion(e.currentTarget.value);\n },\n [onSelectPromptSuggestion]\n );\n\n return (\n <section\n className=\"DocSearch-PromptSuggestions\"\n aria-labelledby={titleId}\n >\n <h3 className=\"DocSearch-PromptSuggestions-Title\" id={titleId}>\n {title}\n </h3>\n <div className=\"DocSearch-PromptSuggestions-Content\">\n {suggestions.map((suggestion) => (\n <button\n key={suggestion}\n type=\"button\"\n className=\"DocSearch-PromptSuggestions-Action\"\n value={suggestion}\n onClick={handleSelectPromptSuggestion}\n >\n {suggestion}\n </button>\n ))}\n </div>\n </section>\n );\n }\n);\n","import React, { type JSX, useEffect, useState } from 'react';\n\nimport { LoadingIcon } from '../icons';\nimport type { StoredSearchPlugin } from '../stored-searches';\nimport type {\n AskAiFeedbackReason,\n OnAskAiFeedback,\n StoredAskAiState,\n} from '../types';\n\nexport type FeedbackActionsTranslations = Partial<{\n /**\n * Tooltip/aria-label for the button that copies the assistant's answer to the\n * clipboard.\n */\n copyButtonTitle: string;\n /**\n * Transient confirmation label shown on the copy button right after a\n * successful copy.\n */\n copyButtonCopiedText: string;\n /** Tooltip/aria-label for the thumbs-up (positive feedback) button. */\n likeButtonTitle: string;\n /**\n * Tooltip/aria-label for the thumbs-down (negative feedback) button that\n * opens the notes form.\n */\n dislikeButtonTitle: string;\n /** Confirmation message shown after feedback has been submitted. */\n thanksForFeedbackText: string;\n /**\n * Heading displayed at the top of the negative feedback form (e.g. \"What went\n * wrong?\").\n */\n feedbackPanelTitle: string;\n /**\n * Placeholder text for the free-form notes textarea in the negative feedback\n * form.\n */\n feedbackDetailsPlaceholder: string;\n /** Label for the button that submits the negative feedback form. */\n feedbackSubmitButtonText: string;\n /** Label for the button that cancels/dismisses the negative feedback form. */\n feedbackCancelButtonText: string;\n /**\n * Tooltip/aria-label for the button that closes/cancels the negative feedback\n * form.\n */\n feedbackCloseButtonTitle: string;\n /** Label for the \"Incorrect or incomplete\" tag. */\n feedbackTagIncorrect: string;\n /** Label for the \"Not what I asked for\" tag. */\n feedbackTagNotWhatIAsked: string;\n /** Label for the \"Slow or buggy\" tag. */\n feedbackTagSlowOrBuggy: string;\n /** Label for the \"Style or tone\" tag. */\n feedbackTagStyleOrTone: string;\n /** Label for the \"Safety or legal concern\" tag. */\n feedbackTagSafetyOrLegal: string;\n /** Label for the \"Other\" tag. */\n feedbackTagOther: string;\n}>;\n\ntype TagTranslationKey = Extract<\n keyof FeedbackActionsTranslations,\n `feedbackTag${string}`\n>;\n\ntype FeedbackReasonOption = {\n value: AskAiFeedbackReason;\n translationKey: TagTranslationKey;\n defaultLabel: string;\n};\n\n// Hoisted at module level so the array identity is stable across renders.\nconst FEEDBACK_REASONS: FeedbackReasonOption[] = [\n {\n value: 'incorrect',\n translationKey: 'feedbackTagIncorrect',\n defaultLabel: 'Incorrect or incomplete',\n },\n {\n value: 'not_what_i_asked',\n translationKey: 'feedbackTagNotWhatIAsked',\n defaultLabel: 'Not what I asked for',\n },\n {\n value: 'slow_or_buggy',\n translationKey: 'feedbackTagSlowOrBuggy',\n defaultLabel: 'Slow or buggy',\n },\n {\n value: 'style_or_tone',\n translationKey: 'feedbackTagStyleOrTone',\n defaultLabel: 'Style or tone',\n },\n {\n value: 'safety_or_legal',\n translationKey: 'feedbackTagSafetyOrLegal',\n defaultLabel: 'Safety or legal concern',\n },\n {\n value: 'other',\n translationKey: 'feedbackTagOther',\n defaultLabel: 'Other',\n },\n];\n\n// Maximum number of characters allowed in the feedback notes field.\nconst MAX_NOTES_LENGTH = 1000;\n\ntype FeedbackView = 'actions' | 'note' | 'thanks';\n\ninterface FeedbackActionsProps {\n id: string;\n showActions: boolean;\n latestAssistantMessageContent: string | null;\n translations: FeedbackActionsTranslations;\n conversations: StoredSearchPlugin<StoredAskAiState>;\n onFeedback?: OnAskAiFeedback;\n /** When rendered in the Sidepanel the copy button is ordered first. */\n isSidepanel?: boolean;\n}\n\nexport function FeedbackActions({\n id,\n showActions,\n latestAssistantMessageContent,\n translations,\n conversations,\n onFeedback,\n isSidepanel = false,\n}: FeedbackActionsProps): JSX.Element | null {\n // Derive the initial view during render (no effect needed): if feedback was\n // already recorded for this message, jump straight to the \"thanks\" state.\n const [view, setView] = useState<FeedbackView>(() => {\n const message = conversations.getOne?.(id);\n return message?.feedback ? 'thanks' : 'actions';\n });\n const [tags, setTags] = useState<AskAiFeedbackReason[]>([]);\n const [notes, setNotes] = useState('');\n const [saving, setSaving] = useState(false);\n const [savingError, setSavingError] = useState<Error | null>(null);\n\n const {\n likeButtonTitle = 'Like',\n dislikeButtonTitle = 'Dislike',\n thanksForFeedbackText = 'Thanks for your feedback!',\n } = translations;\n\n const handleLike = async (): Promise<void> => {\n if (saving) return;\n setSavingError(null);\n setSaving(true);\n try {\n await onFeedback?.(id, { thumbs: 1 });\n setView('thanks');\n } catch (error) {\n setSavingError(error as Error);\n } finally {\n setSaving(false);\n }\n };\n\n const handleDislike = (): void => {\n setSavingError(null);\n setView('note');\n };\n\n const handleToggleTag = (value: AskAiFeedbackReason): void => {\n setTags((prev) =>\n prev.includes(value)\n ? prev.filter((tag) => tag !== value)\n : [...prev, value]\n );\n };\n\n const handleSubmitNote = async (): Promise<void> => {\n if (saving) return;\n setSavingError(null);\n setSaving(true);\n try {\n await onFeedback?.(id, {\n thumbs: 0,\n tags: tags.length > 0 ? tags : undefined,\n notes: notes.trim() || undefined,\n });\n setView('thanks');\n } catch (error) {\n setSavingError(error as Error);\n } finally {\n setSaving(false);\n }\n };\n\n const handleCloseNote = (): void => {\n setTags([]);\n setNotes('');\n setSavingError(null);\n setView('actions');\n };\n\n if (!showActions || !latestAssistantMessageContent) {\n return null;\n }\n\n const copyButton = (\n <CopyButton\n translations={translations}\n onClick={() =>\n navigator.clipboard.writeText(latestAssistantMessageContent)\n }\n />\n );\n\n return (\n <>\n <div className=\"DocSearch-AskAiScreen-Actions-Controls\">\n {isSidepanel ? copyButton : null}\n\n {view === 'thanks' ? (\n <p className=\"DocSearch-AskAiScreen-FeedbackText DocSearch-AskAiScreen-FeedbackText--visible\">\n {thanksForFeedbackText}\n </p>\n ) : (\n <>\n {saving && view === 'actions' ? (\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n ) : (\n <>\n <LikeButton title={likeButtonTitle} onClick={handleLike} />\n <DislikeButton\n title={dislikeButtonTitle}\n onClick={handleDislike}\n />\n </>\n )}\n {savingError && view === 'actions' ? (\n <p className=\"DocSearch-AskAiScreen-FeedbackText\">\n {savingError.message || 'An error occured'}\n </p>\n ) : null}\n </>\n )}\n\n {isSidepanel ? null : copyButton}\n </div>\n\n {view === 'note' ? (\n <NegativeFeedbackPanel\n translations={translations}\n tags={tags}\n notes={notes}\n saving={saving}\n savingError={savingError}\n onToggleTag={handleToggleTag}\n onNotesChange={setNotes}\n onSubmit={handleSubmitNote}\n onClose={handleCloseNote}\n />\n ) : null}\n </>\n );\n}\n\ninterface NegativeFeedbackPanelProps {\n translations: FeedbackActionsTranslations;\n tags: AskAiFeedbackReason[];\n notes: string;\n saving: boolean;\n savingError: Error | null;\n onToggleTag: (tag: AskAiFeedbackReason) => void;\n onNotesChange: (notes: string) => void;\n onSubmit: () => void;\n onClose: () => void;\n}\n\nfunction NegativeFeedbackPanel({\n translations,\n tags,\n notes,\n saving,\n savingError,\n onToggleTag,\n onNotesChange,\n onSubmit,\n onClose,\n}: NegativeFeedbackPanelProps): JSX.Element {\n const feedbackTitleId = React.useId();\n const {\n feedbackPanelTitle = 'What went wrong? (optional)',\n feedbackDetailsPlaceholder = 'Share some details...',\n feedbackSubmitButtonText = 'Submit',\n feedbackCancelButtonText = 'Cancel',\n } = translations;\n\n return (\n <div\n className=\"DocSearch-Feedback-Panel\"\n role=\"group\"\n aria-labelledby={feedbackTitleId}\n >\n <div className=\"DocSearch-Feedback-Panel-Header\">\n <p className=\"DocSearch-Feedback-Panel-Title\" id={feedbackTitleId}>\n {feedbackPanelTitle}\n </p>\n </div>\n\n <div className=\"DocSearch-Feedback-Panel-Reasons\">\n {FEEDBACK_REASONS.map((reason) => {\n const isSelected = tags.includes(reason.value);\n return (\n <button\n key={reason.value}\n type=\"button\"\n className=\"DocSearch-Feedback-Panel-Reason\"\n aria-pressed={isSelected}\n onClick={() => onToggleTag(reason.value)}\n >\n <span>\n {translations[reason.translationKey] ?? reason.defaultLabel}\n </span>\n </button>\n );\n })}\n </div>\n\n <textarea\n className=\"DocSearch-Feedback-Panel-Textarea\"\n placeholder={feedbackDetailsPlaceholder}\n value={notes}\n rows={3}\n maxLength={MAX_NOTES_LENGTH}\n onChange={(event) =>\n onNotesChange(event.target.value.slice(0, MAX_NOTES_LENGTH))\n }\n />\n\n <p className=\"DocSearch-Feedback-Panel-CharCount\" aria-live=\"polite\">\n {notes.length}/{MAX_NOTES_LENGTH}\n </p>\n\n {savingError ? (\n <p className=\"DocSearch-Feedback-Panel-Error\">\n {savingError.message || 'An error occured'}\n </p>\n ) : null}\n\n <div className=\"DocSearch-Feedback-Panel-Actions\">\n <button\n type=\"button\"\n className=\"DocSearch-Feedback-Panel-Cancel\"\n onClick={onClose}\n >\n {feedbackCancelButtonText}\n </button>\n <button\n type=\"button\"\n className=\"DocSearch-Feedback-Panel-Submit\"\n disabled={saving}\n onClick={onSubmit}\n >\n {saving ? (\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n ) : (\n feedbackSubmitButtonText\n )}\n </button>\n </div>\n </div>\n );\n}\n\nexport function CopyButton({\n onClick,\n translations,\n}: {\n onClick: () => void;\n translations: FeedbackActionsTranslations;\n}): JSX.Element {\n const { copyButtonTitle = 'Copy', copyButtonCopiedText = 'Copied!' } =\n translations;\n\n const [isCopied, setIsCopied] = useState(false);\n\n useEffect(() => {\n if (isCopied) {\n const timer = setTimeout(() => {\n setIsCopied(false);\n }, 1500); // reset after 1.5 seconds\n return (): void => clearTimeout(timer);\n }\n return undefined;\n }, [isCopied]);\n\n const handleClick = (): void => {\n onClick();\n setIsCopied(true);\n };\n\n return (\n <button\n type=\"button\"\n className={`DocSearch-AskAiScreen-ActionButton DocSearch-AskAiScreen-CopyButton ${\n isCopied ? 'DocSearch-AskAiScreen-CopyButton--copied' : ''\n }`}\n disabled={isCopied} // disable button briefly after copy\n title={isCopied ? copyButtonCopiedText : copyButtonTitle}\n onClick={handleClick}\n >\n {isCopied ? (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n ) : (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n )}\n </button>\n );\n}\n\nexport function LikeButton({\n title,\n onClick,\n}: {\n title: string;\n onClick: () => void;\n}): JSX.Element {\n return (\n <button\n type=\"button\"\n className=\"DocSearch-AskAiScreen-ActionButton DocSearch-AskAiScreen-LikeButton\"\n title={title}\n onClick={onClick}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M7 10v12\" />\n <path d=\"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z\" />\n </svg>\n </button>\n );\n}\n\nexport function DislikeButton({\n title,\n onClick,\n}: {\n title: string;\n onClick: () => void;\n}): JSX.Element {\n return (\n <button\n type=\"button\"\n className=\"DocSearch-AskAiScreen-ActionButton DocSearch-AskAiScreen-DislikeButton\"\n title={title}\n onClick={onClick}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M17 14V2\" />\n <path d=\"M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z\" />\n </svg>\n </button>\n );\n}\n","import { Popover as PopoverPrimitive } from '@base-ui/react/popover';\nimport React from 'react';\nimport type { JSX } from 'react';\n\nimport { CloseIcon } from '../../icons';\n\nexport function Popover({ ...props }: PopoverPrimitive.Root.Props) {\n return <PopoverPrimitive.Root {...props} />;\n}\n\nconst PopoverTrigger = React.forwardRef<\n HTMLButtonElement,\n PopoverPrimitive.Trigger.Props\n>(({ className, ...props }, ref): JSX.Element => {\n const cn = `DocSearch-Popover-Trigger${className ? ` ${className}` : ''}`;\n return <PopoverPrimitive.Trigger className={cn} ref={ref} {...props} />;\n});\n\nPopover.Trigger = PopoverTrigger;\n\ntype PopoverPopupProps = Pick<\n PopoverPrimitive.Positioner.Props,\n 'align' | 'alignOffset' | 'collisionBoundary' | 'side' | 'sideOffset'\n> &\n Pick<PopoverPrimitive.Portal.Props, 'container'> &\n PopoverPrimitive.Popup.Props;\n\nfunction PopoverPopup({\n align = 'center',\n alignOffset = 0,\n side = 'bottom',\n sideOffset = 4,\n collisionBoundary = 'clipping-ancestors',\n container,\n children,\n ...props\n}: PopoverPopupProps) {\n return (\n <PopoverPrimitive.Portal container={container}>\n <PopoverPrimitive.Positioner\n className=\"DocSearch-Popover-Positioner\"\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n collisionBoundary={collisionBoundary}\n >\n <PopoverPrimitive.Popup className=\"DocSearch-Popover-Popup\" {...props}>\n <PopoverPrimitive.Arrow className=\"DocSearch-Popover-Arrow\" />\n <PopoverPrimitive.Close className=\"DocSearch-Popover-Close\">\n <CloseIcon />\n </PopoverPrimitive.Close>\n {children}\n </PopoverPrimitive.Popup>\n </PopoverPrimitive.Positioner>\n </PopoverPrimitive.Portal>\n );\n}\n\nPopover.Popup = PopoverPopup;\n\nfunction PopoverTitle({ ...props }: PopoverPrimitive.Title.Props) {\n return (\n <PopoverPrimitive.Title className=\"DocSearch-Popover-Title\" {...props} />\n );\n}\n\nPopover.Title = PopoverTitle;\n","import React, { type JSX, useEffect } from 'react';\n\nimport { ContentIcon } from '../icons';\nimport type { ExtractedLink } from '../utils/ai';\n\nimport { Popover } from './ui/Popover';\n\ninterface SourcesProps {\n links: ExtractedLink[];\n titleText?: string;\n pluralTitleText?: string;\n}\n\nexport function SourcesPanel({\n links,\n titleText = 'Source',\n pluralTitleText = 'Sources',\n}: SourcesProps): JSX.Element | null {\n const [open, setOpen] = React.useState(false);\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const [boundary, setBoundary] = React.useState<HTMLElement | null>(null);\n\n const sourcesTitle = links.length > 1 ? pluralTitleText : titleText;\n\n useEffect(() => {\n if (!open) {\n return undefined;\n }\n\n const trigger = triggerRef.current;\n const scrollContainer =\n trigger?.closest<HTMLElement>('.DocSearch-Sidepanel-Content') ??\n trigger?.closest<HTMLElement>('.DocSearch-Dropdown') ??\n null;\n\n setBoundary(scrollContainer);\n\n if (!scrollContainer) {\n return undefined;\n }\n\n const handleScroll = (): void => {\n if (!triggerRef.current) {\n return;\n }\n\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const containerRect = scrollContainer.getBoundingClientRect();\n\n const isOutOfView =\n triggerRect.bottom <= containerRect.top ||\n triggerRect.top >= containerRect.bottom;\n\n if (isOutOfView) {\n setOpen(false);\n }\n };\n\n scrollContainer.addEventListener('scroll', handleScroll, { passive: true });\n\n return () => {\n scrollContainer.removeEventListener('scroll', handleScroll);\n };\n }, [open]);\n\n if (links.length === 0) {\n return null;\n }\n\n return (\n <Popover open={open} modal=\"trap-focus\" onOpenChange={setOpen}>\n <Popover.Trigger\n ref={triggerRef}\n className=\"DocSearch-AskAiScreen-Sources-Action\"\n >\n <span className=\"DocSearch-AskAiScreen-Sources-Action-icon\">\n <ContentIcon />\n </span>\n <span className=\"DocSearch-AskAiScreen-Sources-Action-text\">\n {links.length} {sourcesTitle}\n </span>\n </Popover.Trigger>\n <Popover.Popup\n container={boundary}\n sideOffset={10}\n align=\"start\"\n alignOffset={-16}\n collisionBoundary={boundary ?? 'clipping-ancestors'}\n >\n <Popover.Title>{sourcesTitle}</Popover.Title>\n <ul className=\"DocSearch-AskAiScreen-Sources\">\n {links.map((l) => (\n <li key={l.url} className=\"DocSearch-AskAiScreen-Sources-source\">\n <a href={l.url} target=\"_blank\" rel=\"noopener noreferrer\">\n <ContentIcon />\n <span className=\"DocSearch-AskAiScreen-Sources-source-title\">\n {l.title || l.url}\n </span>\n </a>\n </li>\n ))}\n </ul>\n </Popover.Popup>\n </Popover>\n );\n}\n","interface BlockingMatchContext {\n message: string;\n messageLower: string;\n parsedJson: Record<string, unknown> | null;\n code: string | undefined;\n}\n\ninterface BlockingMatcher {\n matches: (context: BlockingMatchContext) => boolean;\n showNewConversationLink?: boolean;\n}\n\nconst PROMPT_BLOCKING_CODES = new Set(['AI-203', 'AI-205', 'AI-224', 'AI-225']);\n\nexport function readStringField(\n value: Record<string, unknown>,\n key: string\n): string | undefined {\n for (const [field, fieldValue] of Object.entries(value)) {\n if (\n field.toLowerCase() === key.toLowerCase() &&\n typeof fieldValue === 'string' &&\n fieldValue.trim() !== ''\n ) {\n return fieldValue.trim();\n }\n }\n\n return undefined;\n}\n\nfunction extractErrorCode(message: string): string | undefined {\n const directMatch = /\\b(AI-\\d{3})\\b/i.exec(message);\n\n if (directMatch) {\n return directMatch[1].toUpperCase();\n }\n\n return undefined;\n}\n\nfunction parseJson(message: string): Record<string, unknown> | null {\n try {\n const parsed: unknown = JSON.parse(message);\n\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Plain-text errors are handled by the other matchers.\n }\n\n return null;\n}\n\nfunction matchesDomainBlock(message: string): boolean {\n return (\n /\\brequest blocked for this domain\\b/.test(message) ||\n /\\bblocked for this domain\\b/.test(message)\n );\n}\n\nfunction matchesRateLimit(message: string): boolean {\n return (\n /\\b429\\b/.test(message) ||\n /\\brate\\s*limit/.test(message) ||\n /\\bretry\\s+after\\s+\\d+/.test(message) ||\n /\\btoo\\s+many\\s+attempts\\b/.test(message) ||\n /\\btoo_many_requests\\b/.test(message)\n );\n}\n\nfunction matchesTokenOutputLimit(message: string): boolean {\n return (\n /\\btokenoutputlimiterror\\b/.test(message) ||\n /could not complete response due to token output limits/.test(message)\n );\n}\n\nfunction matchesAccessOrLimit(message: string): boolean {\n return (\n /\\bwhitelist(?:ed)?\\b/.test(message) ||\n /\\bnot\\s+allowed\\s+for\\s+this\\s+domain\\b/.test(message) ||\n /\\bcontext\\s+length\\b/.test(message) ||\n /\\b(?:max|maximum)\\s+tokens?\\b/.test(message) ||\n /\\btoken\\s+limit\\b/.test(message) ||\n /\\btoken\\s+output\\b/.test(message) ||\n /\\boutput\\s+limits?\\b/.test(message) ||\n /\\bstep\\s+limit\\b/.test(message) ||\n /\\b(?:max|maximum)(?:\\s+agent)?\\s+steps?\\b/.test(message)\n );\n}\n\nfunction jsonImpliesCostControl(value: Record<string, unknown>): boolean {\n const type = readStringField(value, 'type') ?? '';\n const error = readStringField(value, 'error') ?? '';\n const message = readStringField(value, 'message') ?? '';\n\n return (\n /tokenoutput|outputlimit|steplimit|maxstep|ratelimit|domainnotallowed/i.test(\n type\n ) ||\n error.toUpperCase() === 'TOO_MANY_REQUESTS' ||\n matchesRateLimit(`${error} ${message}`.toLowerCase()) ||\n matchesAccessOrLimit(`${error} ${message}`.toLowerCase())\n );\n}\n\nconst BLOCKING_MATCHERS: BlockingMatcher[] = [\n {\n matches: ({ code }) => Boolean(code && PROMPT_BLOCKING_CODES.has(code)),\n },\n {\n matches: ({ parsedJson }) =>\n Boolean(\n parsedJson &&\n matchesDomainBlock(\n (readStringField(parsedJson, 'message') ?? '').toLowerCase()\n )\n ),\n showNewConversationLink: false,\n },\n {\n matches: ({ parsedJson }) =>\n Boolean(parsedJson && jsonImpliesCostControl(parsedJson)),\n },\n {\n matches: ({ messageLower }) => matchesTokenOutputLimit(messageLower),\n showNewConversationLink: false,\n },\n {\n matches: ({ messageLower }) => matchesRateLimit(messageLower),\n },\n {\n matches: ({ messageLower }) => matchesDomainBlock(messageLower),\n showNewConversationLink: false,\n },\n {\n matches: ({ messageLower }) => matchesAccessOrLimit(messageLower),\n },\n];\n\nexport function resolvePromptBlockingError(error: Error): {\n blocking: boolean;\n showNewConversationLink: boolean;\n} {\n const message = error.message ?? '';\n const context: BlockingMatchContext = {\n message,\n messageLower: message.toLowerCase(),\n parsedJson: parseJson(message),\n code: extractErrorCode(message),\n };\n const matches = BLOCKING_MATCHERS.filter((matcher) =>\n matcher.matches(context)\n );\n\n return {\n blocking: matches.length > 0,\n showNewConversationLink: matches.every(\n (matcher) => matcher.showNewConversationLink !== false\n ),\n };\n}\n\nexport function isTokenOutputLimitError(error?: Error): boolean {\n return Boolean(\n error && matchesTokenOutputLimit((error.message ?? '').toLowerCase())\n );\n}\n","/** Escapes HTML special characters for safe interpolation into HTML strings. */\nexport function escapeHtml(unsafe: string): string {\n return unsafe\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\n/** Strips HTML tags and escapes the remainder for plain-text React children. */\nexport function sanitizeUserInput(input: string): string {\n const withoutTags = input.replace(/<[^>]*>/g, '');\n return escapeHtml(withoutTags);\n}\n\nfunction decodeUrlForSchemeCheck(value: string): string {\n let current = value;\n for (let i = 0; i < 3; i += 1) {\n try {\n const decoded = decodeURIComponent(current);\n if (decoded === current) {\n break;\n }\n current = decoded;\n } catch {\n break;\n }\n }\n return current;\n}\n\nfunction stripControlsAndWhitespace(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i += 1) {\n const code = value.charCodeAt(i);\n if (code > 0x20 && code !== 0x7f) {\n result += value[i];\n }\n }\n return result;\n}\n\n/**\n * Returns a URL safe for href/src, or '' if unsafe. Does not HTML-escape —\n * callers building HTML strings must escape separately.\n */\nexport function sanitizeUrl(url: string | null | undefined): string {\n if (!url) {\n return '';\n }\n\n const trimmed = url.trim();\n if (!trimmed) {\n return '';\n }\n\n const normalized = stripControlsAndWhitespace(\n decodeUrlForSchemeCheck(trimmed)\n );\n if (!normalized) {\n return '';\n }\n\n if (normalized.startsWith('//')) {\n return '';\n }\n\n if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(normalized)) {\n return trimmed;\n }\n\n try {\n const parsed = new URL(normalized);\n if (\n parsed.protocol === 'http:' ||\n parsed.protocol === 'https:' ||\n parsed.protocol === 'mailto:'\n ) {\n return normalized;\n }\n } catch {\n return '';\n }\n\n return '';\n}\n","import type { TextUIPart } from 'ai';\n\nimport type { StoredAskAiState } from '../types';\nimport type {\n AggregatedToolCallPart,\n AIMessage,\n AIMessagePart,\n AIToolPart,\n AlgoliaMCPSearchOutputPart,\n SearchIndexOutputPart,\n SearchOutputPart,\n SearchToolPart,\n ToolCalls,\n} from '../types/AskiAi';\n\nimport {\n isTokenOutputLimitError,\n readStringField,\n resolvePromptBlockingError,\n} from './askAiBlockingMatchers';\nimport { sanitizeUrl, sanitizeUserInput } from './sanitize';\n\nexport interface ExtractedLink {\n url: string;\n title?: string;\n}\n\n// utility to extract links (markdown and bare urls) from a string\nexport function extractLinksFromMessage(\n message: AIMessage | null\n): ExtractedLink[] {\n const links: ExtractedLink[] = [];\n // Used to dedupe multiple urls\n const seen = new Set<string>();\n\n if (!message) {\n return [];\n }\n\n message.parts.forEach((part) => {\n if (part.type !== 'text') {\n return;\n }\n\n if (part.text.length === 0) {\n return;\n }\n\n const markdownLinkRegex = /\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\n const plainLinkRegex = /(?<!\\]\\()https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+/g;\n\n // Strip out all code blocks e.g. ```\n const textWithoutCodeBlocks = part.text.replace(/```[\\s\\S]*?```/g, '');\n\n // Strip out all inline code blocks e.g. `\n const cleanText = textWithoutCodeBlocks.replace(/`[^`]*`/g, '');\n\n // Get all markdown based links e.g. []()\n const markdownMatches = cleanText.matchAll(markdownLinkRegex);\n\n // Parses the title and url from the found links\n for (const match of markdownMatches) {\n const title = match[1].trim();\n const url = sanitizeUrl(match[2]);\n\n if (url && !seen.has(url)) {\n seen.add(url);\n links.push({ url, title: title || undefined });\n }\n }\n\n // Get all \"plain\" links e.g. https://algolia.com/doc\n const plainUrls = cleanText.matchAll(plainLinkRegex);\n\n for (const match of plainUrls) {\n // Strip any extra punctuation\n const cleanUrl = sanitizeUrl(match[0].replace(/[.,;:!?]+$/, ''));\n\n if (cleanUrl && !seen.has(cleanUrl)) {\n seen.add(cleanUrl);\n links.push({ url: cleanUrl });\n }\n }\n });\n\n return links;\n}\n\nexport const buildDummyAskAiHit = (\n query: string,\n messages: AIMessage[],\n chatId?: string\n): StoredAskAiState => {\n const textPart = messages[0].parts.find((part) => part.type === 'text');\n const sanitizedText = textPart?.text ? sanitizeUserInput(textPart.text) : '';\n\n return {\n query,\n objectID: sanitizedText,\n chatId,\n messages,\n type: 'askAI',\n anchor: 'stored',\n // dummy content to make it a valid hit\n // this is useful to show it among other hits\n content: null,\n hierarchy: {\n lvl0: 'askAI',\n lvl1: sanitizedText, // use first message as hit name (sanitized to prevent XSS)\n lvl2: new Date().toISOString(),\n lvl3: null,\n lvl4: null,\n lvl5: null,\n lvl6: null,\n },\n url: '',\n url_without_anchor: '',\n };\n};\n\n// answers can interleave text with tool calls, so join every text part\n// instead of stopping at the first one\n// see https://github.com/algolia/docsearch/issues/2782\nexport const getMessageContent = (message: AIMessage | null): string =>\n (message?.parts ?? [])\n .filter((part): part is TextUIPart => part.type === 'text')\n .map((part) => part.text)\n .join('\\n\\n');\n\n/** Helper function to check if an error reports the conversation depth limit. */\nexport function isThreadDepthError(error?: Error): boolean {\n if (!error) return false;\n\n return /(?:ai-217|conversation\\s+depth)/i.test(error.message ?? '');\n}\n\nexport function isAskAiPromptBlockingError(error?: Error): boolean {\n return Boolean(\n error &&\n (isThreadDepthError(error) || resolvePromptBlockingError(error).blocking)\n );\n}\n\nexport function isAgentStudioTokenOutputLimitError(error?: Error): boolean {\n return isTokenOutputLimitError(error);\n}\n\nexport function showAskAiBlockingBannerNewConversationLink(\n error?: Error\n): boolean {\n if (!error || isThreadDepthError(error)) {\n return true;\n }\n\n return resolvePromptBlockingError(error).showNewConversationLink;\n}\n\nfunction extractAgentStudioErrorFieldMessage(raw: string): string | undefined {\n let value = raw.trim();\n\n for (let iteration = 0; iteration < 10 && value; iteration++) {\n try {\n const parsed: unknown = JSON.parse(value);\n\n if (typeof parsed === 'string') {\n value = parsed.trim();\n continue;\n }\n\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n const record = parsed as Record<string, unknown>;\n const message = readStringField(record, 'message');\n const error = readStringField(record, 'error');\n\n if (message) {\n return message;\n }\n\n if (error) {\n return error;\n }\n }\n\n const fieldMatch =\n /\"message\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/.exec(value) ??\n /\"error\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/.exec(value);\n\n return fieldMatch?.[1]\n ?.replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, '\\\\')\n .trim();\n } catch {\n if (value.includes('\\\\\"')) {\n value = value.replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\').trim();\n continue;\n }\n\n return undefined;\n }\n }\n\n return undefined;\n}\n\nexport function getAskAiBlockingBannerMessage(\n error?: Error\n): string | undefined {\n if (!error) {\n return undefined;\n }\n\n const extracted = extractAgentStudioErrorFieldMessage(error.message ?? '');\n const isCodeOnlyThreadDepthError =\n isThreadDepthError(error) &&\n (/^\\s*AI-217\\s*$/i.test(error.message) ||\n (/^\\s*\\{.*\\}\\s*$/.test(error.message) && !extracted));\n\n if (isCodeOnlyThreadDepthError) {\n return undefined;\n }\n\n const message = (\n extracted ?? error.message.replace(/\\s*\\(AI-\\d{3}\\)\\s*$/i, '')\n ).trim();\n\n if (message && !(message.startsWith('{') && message.endsWith('}'))) {\n return message;\n }\n\n if (isAgentStudioTokenOutputLimitError(error)) {\n return 'Could not complete response due to token output limits';\n }\n\n return undefined;\n}\n\nexport const EMPTY_TOOLS: Readonly<ToolCalls> = Object.freeze({});\n\nexport function isAIToolPart(\n part: AggregatedToolCallPart | AIMessagePart\n): part is AIToolPart {\n return part.type.startsWith('tool-');\n}\n\nexport function isSearchToolPart(part: AIToolPart): part is SearchToolPart {\n return (\n part.type === 'tool-searchIndex' ||\n part.type === 'tool-algolia_search_index' ||\n part.type.startsWith('tool-algolia_search_index_')\n );\n}\n\nexport function isSearchIndexOutputPart(\n part: AIMessagePart\n): part is SearchIndexOutputPart {\n return part.type === 'tool-searchIndex' && part.state === 'output-available';\n}\n\nexport function isAlgoliaMCPSearchOutputPart(\n part: AIMessagePart\n): part is AlgoliaMCPSearchOutputPart {\n return (\n isAIToolPart(part) &&\n (part.type === 'tool-algolia_search_index' ||\n part.type.startsWith('tool-algolia_search_index_')) &&\n part.state === 'output-available'\n );\n}\n\nexport function isSearchOutputPart(\n part: AIMessagePart\n): part is SearchOutputPart {\n return (\n isAIToolPart(part) &&\n isSearchToolPart(part) &&\n part.state === 'output-available'\n );\n}\n\nexport function sanitizeMessagesForRequest(messages: AIMessage[]): AIMessage[] {\n let sanitizedMessages: AIMessage[] | undefined;\n\n messages.forEach((message, index) => {\n // Filter out `data-*` part types since Agent Studio does not currently support them on the request\n const parts = message.parts.filter(\n (part) => !part.type.startsWith('data-')\n );\n\n if (parts.length === message.parts.length) {\n sanitizedMessages?.push(message);\n return;\n }\n\n if (!sanitizedMessages) {\n sanitizedMessages = messages.slice(0, index);\n }\n\n sanitizedMessages.push({\n ...message,\n parts,\n });\n });\n\n return sanitizedMessages ?? messages;\n}\n\nexport function getAgentPromptSuggestions(parts: AIMessagePart[]): string[] {\n const suggestionsPart = parts.find(\n (part) => part.type === 'data-suggestions'\n );\n\n if (!suggestionsPart) return [];\n\n return suggestionsPart.data.suggestions;\n}\n\nexport function getSearchToolQueries(part: SearchToolPart): string[] {\n if (part.state !== 'input-available' && part.state !== 'output-available') {\n return [];\n }\n\n if (part.type === 'tool-searchIndex') {\n const query = (part.output?.query ?? part.input?.query ?? '').trim();\n return query ? [query] : [];\n }\n\n if ('queries' in part.input && Array.isArray(part.input.queries)) {\n return part.input.queries.map(({ query }) => query.trim()).filter(Boolean);\n }\n\n // There could be older stored MCP search tool calls,\n // we should parse it's input properly\n if ('query' in part.input && typeof part.input.query === 'string') {\n const query = part.input.query.trim();\n return query ? [query] : [];\n }\n\n return [];\n}\n","import React from 'react';\n\nexport interface ToolStateProps {\n variant: 'Call' | 'PartialCall' | 'Result';\n icon: React.ReactNode;\n shimmer?: boolean;\n children: React.ReactNode;\n}\n\nexport function ToolState({\n icon,\n shimmer = false,\n children,\n variant,\n}: ToolStateProps): React.JSX.Element {\n const className = `DocSearch-AskAiScreen-MessageContent-Tool Tool--${variant}${shimmer ? ' DocSearch-shimmer' : ''}`;\n\n return (\n <div className={className}>\n {icon}\n {children}\n </div>\n );\n}\n","import type { JSX } from 'react';\nimport React, { useMemo } from 'react';\n\nimport { LoadingIcon, MemoryIcon, SearchIcon, ToolIcon } from '../icons';\nimport type {\n AIToolPart,\n MemoryToolPart,\n SearchToolPart,\n ToolCalls,\n ToolDefinition,\n} from '../types/AskiAi';\nimport { getSearchToolQueries, isSearchToolPart } from '../utils/ai';\n\nimport { ToolState } from './ui/ToolState';\n\nexport type ToolCallTranslations = {\n /** Text shown while assistant is preparing tool call. */\n preToolCallText: string;\n /** Text shown while assistant is performing search tool call. */\n searchingText: string;\n /** Text shown while assistant is finished performing tool call. */\n toolCallResultText: string;\n /** Text shown when the agent saved related information to memory. */\n savedMemoryToolResultText: string;\n /** Text shown when the agent used the memory tool to enhance results. */\n memoryToolResultText: string;\n};\n\ninterface ToolCallProps {\n part: AIToolPart;\n translations: ToolCallTranslations;\n tools: ToolCalls;\n onSearchQueryClick?: (query: string) => void;\n memoryEnabled?: boolean;\n}\n\ninterface SearchToolProps {\n part: SearchToolPart;\n translations: ToolCallTranslations;\n onSearchQueryClick?: (query: string) => void;\n}\n\nfunction SearchTool({\n part,\n translations,\n onSearchQueryClick,\n}: SearchToolProps) {\n const { searchingText, preToolCallText, toolCallResultText } = translations;\n\n switch (part.state) {\n case 'input-streaming':\n return (\n <ToolState\n shimmer={true}\n icon={\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n }\n variant=\"PartialCall\"\n >\n <span>{searchingText}</span>\n </ToolState>\n );\n case 'input-available': {\n const queries = getSearchToolQueries(part);\n\n return (\n <>\n {queries.map((q, index) => (\n <ToolState\n // oxlint-disable-next-line react/no-array-index-key\n key={`${part.toolCallId}-call-${index}`}\n shimmer={true}\n icon={\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n }\n variant=\"Call\"\n >\n <span>\n {preToolCallText} {`\"${q}\" ...`}\n </span>\n </ToolState>\n ))}\n </>\n );\n }\n case 'output-available': {\n const queries = getSearchToolQueries(part);\n\n return (\n <>\n {queries.map((q, index) => (\n <ToolState\n // oxlint-disable-next-line react/no-array-index-key\n key={`${part.toolCallId}-result-${index}`}\n icon={<SearchIcon />}\n variant=\"Result\"\n >\n <span>\n {toolCallResultText}{' '}\n {onSearchQueryClick ? (\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 {' '}\n &quot;{q}&quot;\n </span>\n ) : (\n <span className=\"DocSearch-AskAiScreen-MessageContent-Tool-Query\">\n {' '}\n &quot;{q}&quot;\n </span>\n )}\n </span>\n </ToolState>\n ))}\n </>\n );\n }\n default:\n return null;\n }\n}\n\ninterface CustomToolProps {\n tool: ToolDefinition;\n part: AIToolPart;\n}\n\nfunction CustomTool({ tool, part }: CustomToolProps) {\n const toolOutput = useMemo(() => {\n if (part.state !== 'output-available') return null;\n\n return tool.render({ message: { input: part.input, output: part.output } });\n }, [part.input, part.output, tool, part.state]);\n\n if (part.state === 'output-error') {\n return null;\n }\n\n if (part.state !== 'output-available') {\n const { callingToolText = 'Loading tool' } = tool.translations || {};\n\n return (\n <ToolState shimmer={true} variant=\"PartialCall\" icon={<ToolIcon />}>\n <span>{callingToolText}</span>\n </ToolState>\n );\n }\n\n if (!toolOutput) return null;\n\n return (\n <ToolState icon={<ToolIcon />} variant=\"Result\">\n <span>{toolOutput}</span>\n </ToolState>\n );\n}\n\nfunction MemoryTool({\n part,\n translations,\n}: {\n part: MemoryToolPart;\n translations: ToolCallTranslations;\n}) {\n const { savedMemoryToolResultText, memoryToolResultText } = translations;\n\n if (part.state === 'output-error') return null;\n\n if (part.type === 'tool-algolia_memorize') {\n return (\n <ToolState variant=\"Result\" icon={<MemoryIcon />}>\n {savedMemoryToolResultText}\n </ToolState>\n );\n }\n\n return (\n <ToolState variant=\"Result\" icon={<MemoryIcon />}>\n {memoryToolResultText}\n </ToolState>\n );\n}\n\nfunction isMemoryToolPart(part: AIToolPart): part is MemoryToolPart {\n return (\n part.type === 'tool-algolia_ponder' ||\n part.type === 'tool-algolia_memorize' ||\n part.type === 'tool-algolia_memory_search'\n );\n}\n\nexport function ToolCall({\n part,\n translations,\n tools,\n onSearchQueryClick,\n memoryEnabled = false,\n}: ToolCallProps): JSX.Element | null {\n const normalizedToolName = part.type.replace('tool-', '');\n const customTool = tools[normalizedToolName];\n\n if (customTool) {\n return <CustomTool tool={customTool} part={part} />;\n }\n\n if (memoryEnabled && isMemoryToolPart(part)) {\n return <MemoryTool part={part} translations={translations} />;\n }\n\n if (isSearchToolPart(part)) {\n return (\n <SearchTool\n part={part}\n translations={translations}\n onSearchQueryClick={onSearchQueryClick}\n />\n );\n }\n\n return null;\n}\n","import { marked, type Tokens } from 'marked';\n\nimport { escapeHtml, sanitizeUrl } from './sanitize';\n\nconst renderer = new marked.Renderer();\n\nrenderer.code = ({ text, lang = '', escaped }: Tokens.Code): string => {\n const safeLang = /^[a-zA-Z0-9_-]+$/.test(lang) ? lang : '';\n const languageClass = safeLang ? `language-${safeLang}` : '';\n const safeCode = escaped ? text : escapeHtml(text);\n const encodedCode = encodeURIComponent(text);\n\n const copyIconSvg = `<svg class=\"DocSearch-CodeSnippet-CopyIcon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" /><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" /></svg>`;\n\n const checkIconSvg = `<svg class=\"DocSearch-CodeSnippet-CheckIcon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\" /></svg>`;\n\n return `\n <div class=\"DocSearch-CodeSnippet\">\n <button class=\"DocSearch-CodeSnippet-CopyButton\" data-code=\"${encodedCode}\" aria-label=\"copy code\">${copyIconSvg}${checkIconSvg}<span class=\"DocSearch-CodeSnippet-CopyButton-Label\"></span></button>\n <pre><code class=\"${languageClass}\">${safeCode}</code></pre>\n </div>\n `;\n};\n\nrenderer.link = ({ href, title, text }: Tokens.Link): string => {\n const safeHref = escapeHtml(sanitizeUrl(href));\n const textEscaped = escapeHtml(text);\n\n if (!safeHref) {\n return textEscaped;\n }\n\n const titleAttr = title ? ` title=\"${escapeHtml(title)}\"` : '';\n return `<a href=\"${safeHref}\"${titleAttr} target=\"_blank\" rel=\"noopener noreferrer\">${textEscaped}</a>`;\n};\n\nrenderer.image = ({ href, title, text }: Tokens.Image): string => {\n const safeHref = escapeHtml(sanitizeUrl(href));\n if (!safeHref) {\n return escapeHtml(text);\n }\n\n const titleAttr = title ? ` title=\"${escapeHtml(title)}\"` : '';\n return `<img src=\"${safeHref}\" alt=\"${escapeHtml(text)}\"${titleAttr} />`;\n};\n\nrenderer.html = ({ text }: Tokens.HTML | Tokens.Tag): string =>\n escapeHtml(text);\n\n/** Parses markdown into HTML safe for `dangerouslySetInnerHTML`. */\nexport function parseMarkdownToSafeHtml(content: string): string {\n return marked.parse(content, {\n gfm: true,\n breaks: true,\n renderer,\n }) as string;\n}\n","import React, { memo, useMemo, useEffect, useRef } from 'react';\n\nimport { parseMarkdownToSafeHtml } from './utils/markdown';\n\nexport const MemoizedMarkdown = memo(\n ({\n content,\n copyButtonText,\n copyButtonCopiedText,\n isStreaming,\n }: {\n content: string;\n copyButtonText: string;\n copyButtonCopiedText: string;\n isStreaming: boolean;\n }) => {\n const html = useMemo(() => parseMarkdownToSafeHtml(content), [content]);\n\n // container ref to scope dom queries and events\n const containerRef = useRef<HTMLDivElement>(null);\n\n // setup copy buttons whenever content or translations change\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const buttons = Array.from(\n container.querySelectorAll<HTMLButtonElement>(\n '.DocSearch-CodeSnippet-CopyButton'\n )\n );\n\n buttons.forEach((btn) => {\n const label = btn.querySelector<HTMLElement>(\n '.DocSearch-CodeSnippet-CopyButton-Label'\n );\n if (label) label.textContent = copyButtonText;\n\n // ensure icons initial visibility\n btn.classList.remove('DocSearch-CodeSnippet-CopyButton--copied');\n });\n\n function handleClick(event: MouseEvent): void {\n const targetEl = event.target as HTMLElement;\n const btn = targetEl.closest<HTMLButtonElement>(\n '.DocSearch-CodeSnippet-CopyButton'\n );\n if (!btn) return;\n\n const encoded = btn.getAttribute('data-code') ?? '';\n navigator.clipboard.writeText(decodeURIComponent(encoded)).catch(() => {\n /* noop */\n });\n\n const label = btn.querySelector<HTMLElement>(\n '.DocSearch-CodeSnippet-CopyButton-Label'\n );\n if (!label) return;\n\n btn.classList.add('DocSearch-CodeSnippet-CopyButton--copied');\n const original = copyButtonText;\n label.textContent = copyButtonCopiedText;\n\n setTimeout(() => {\n btn.classList.remove('DocSearch-CodeSnippet-CopyButton--copied');\n label.textContent = original;\n }, 1500);\n }\n\n container.addEventListener('click', handleClick);\n\n // eslint-disable-next-line consistent-return\n return (): void => {\n container.removeEventListener('click', handleClick);\n };\n }, [html, copyButtonText, copyButtonCopiedText]);\n\n return (\n <div\n ref={containerRef}\n className={`DocSearch-Markdown-Content ${isStreaming ? 'DocSearch-Markdown-Content--streaming' : ''}`}\n dangerouslySetInnerHTML={{ __html: html }}\n />\n );\n }\n);\nMemoizedMarkdown.displayName = 'MemoizedMarkdown';\n","import type {\n AIMessagePart,\n AggregatedToolCallPart,\n SearchOutputPart,\n} from '../types/AskiAi';\n\nimport { getSearchToolQueries, isSearchOutputPart } from './ai';\n\n/**\n * Groups consecutive search tool invocation result parts together. Both the\n * `searchIndex` tool and the Algolia MCP search tools (`algolia_search_index`\n * and `algolia_search_index_*`) are aggregated. Empty or falsy queries are\n * ignored.\n */\nexport function groupConsecutiveToolResults(\n parts: AIMessagePart[]\n): Array<AggregatedToolCallPart | AIMessagePart> {\n const aggregatedParts: Array<AggregatedToolCallPart | AIMessagePart> = [];\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n\n if (isSearchOutputPart(part)) {\n // build list of consecutive result queries\n const queries: string[] = [];\n let singleQueryPart: SearchOutputPart | undefined;\n let j = i;\n while (j < parts.length) {\n const candidate = parts[j];\n if (isSearchOutputPart(candidate)) {\n const queriesForPart = getSearchToolQueries(candidate);\n queries.push(...queriesForPart);\n\n // eslint-disable-next-line max-depth\n if (queriesForPart.length > 0) {\n singleQueryPart = candidate;\n }\n j++;\n } else {\n break;\n }\n }\n\n if (queries.length > 1) {\n aggregatedParts.push({ type: 'aggregated-tool-call', queries });\n } else if (queries.length === 1 && singleQueryPart) {\n // only one valid query, push the original part so rendering remains unchanged\n aggregatedParts.push(singleQueryPart);\n }\n\n i = j - 1; // skip processed items\n } else {\n aggregatedParts.push(part);\n }\n }\n\n return aggregatedParts;\n}\n","import type { PropsWithChildren, JSX, ButtonHTMLAttributes } from 'react';\nimport React from 'react';\n\nconst MenuContext = React.createContext({\n open: false,\n setOpen: (_open: boolean) => {},\n});\n\nexport function Menu({ children }: PropsWithChildren): JSX.Element {\n const [open, setOpen] = React.useState(false);\n const menuRef = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n function close(e): void {\n if (!menuRef.current?.contains(e.target)) {\n setOpen(false);\n }\n }\n\n if (open) {\n window.addEventListener('click', close);\n }\n\n return function removeListener(): void {\n window.removeEventListener('click', close);\n };\n }, [open]);\n\n return (\n <MenuContext.Provider value={{ open, setOpen }}>\n <div ref={menuRef} className=\"DocSearch-Menu\">\n {children}\n </div>\n </MenuContext.Provider>\n );\n}\n\ntype MenuTriggerProps = ButtonHTMLAttributes<HTMLButtonElement>;\n\nfunction MenuTrigger({\n children,\n className = '',\n disabled,\n}: PropsWithChildren<MenuTriggerProps>): JSX.Element {\n const { open, setOpen } = React.useContext(MenuContext);\n\n function toggleOpen(): void {\n if (disabled) return;\n\n setOpen(!open);\n }\n\n return (\n <button\n type=\"button\"\n className={`DocSearch-Menu-trigger ${className}${disabled ? ' disabled' : ''}`}\n aria-disabled={disabled}\n onClick={() => toggleOpen()}\n >\n {children}\n </button>\n );\n}\n\nMenu.Trigger = MenuTrigger;\n\nfunction MenuContent({ children }: PropsWithChildren): JSX.Element {\n const { open } = React.useContext(MenuContext);\n\n return (\n <div className={`DocSearch-Menu-content${open ? ' open' : ''}`}>\n {children}\n </div>\n );\n}\n\nMenu.Content = MenuContent;\n\ntype MenuItemProps = ButtonHTMLAttributes<HTMLButtonElement>;\n\nfunction MenuItem({\n children,\n className = '',\n onClick,\n ...props\n}: PropsWithChildren<MenuItemProps>): JSX.Element {\n const { setOpen } = React.useContext(MenuContext);\n\n const handleClick: React.MouseEventHandler<HTMLButtonElement> = (e): void => {\n if (onClick) {\n onClick(e);\n setOpen(false);\n }\n };\n return (\n <button\n type=\"button\"\n className={`DocSearch-Menu-item ${className}`}\n onClick={handleClick}\n {...props}\n >\n {children}\n </button>\n );\n}\n\nMenu.Item = MenuItem;\n","import { readStringField } from './utils/askAiBlockingMatchers';\n\nexport const agentStudioBaseUrl = (appId: string): string =>\n `https://${appId}.algolia.net/agent-studio/1`;\n\ninterface AgentStudioValidationError extends Error {\n name: 'ValidationError';\n detail?: Array<{ type: string; loc: string[]; msg: string }>;\n}\n\n// Parse Agent Studio errors as they are returned as JSON rather than Markdown/text\nexport const getAgentStudioErrorMessage = (error: Error): Error => {\n const raw = error.message;\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n return new Error(raw);\n }\n\n let iterations = 0;\n\n while (typeof parsed === 'string' && iterations < 10) {\n iterations += 1;\n const serializedError = parsed.trim();\n\n try {\n parsed = JSON.parse(serializedError);\n } catch {\n return new Error(serializedError);\n }\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return new Error(raw);\n }\n\n const parsedRecord = parsed as Record<string, unknown>;\n const parsedError = parsed as Error & {\n code?: string;\n errorCode?: string;\n error?: string;\n };\n let errorMessage = raw;\n\n if (parsedError.name === 'ValidationError') {\n const validationError = parsedError as AgentStudioValidationError;\n\n if (validationError.detail && validationError.detail.length > 0) {\n const { msg, loc } = validationError.detail[0];\n const field = loc.at(-1);\n\n errorMessage = `${msg}: ${field}`;\n }\n } else {\n errorMessage =\n readStringField(parsedRecord, 'message') ??\n readStringField(parsedRecord, 'error') ??\n raw;\n }\n\n const code = parsedError.code ?? parsedError.errorCode;\n\n if (\n typeof code === 'string' &&\n code.trim() &&\n !errorMessage.toUpperCase().includes(code.trim().toUpperCase())\n ) {\n errorMessage = `${errorMessage} (${code.trim()})`;\n }\n\n return new Error(errorMessage);\n};\n\nexport const postAgentStudioFeedback = ({\n agentId,\n vote,\n messageId,\n appId,\n apiKey,\n abortSignal,\n notes,\n tags,\n}: {\n agentId: string;\n vote: 0 | 1;\n messageId: string;\n appId: string;\n apiKey: string;\n abortSignal: AbortSignal;\n notes?: string;\n tags?: string[];\n}): Promise<Response> => {\n const headers = new Headers();\n headers.set('x-algolia-application-id', appId);\n headers.set('x-algolia-api-key', apiKey);\n headers.set('content-type', 'application/json');\n\n const baseUrl = `${agentStudioBaseUrl(appId)}/feedback`;\n\n return fetch(baseUrl, {\n method: 'POST',\n body: JSON.stringify({\n messageId,\n agentId,\n vote,\n ...(notes ? { notes } : {}),\n ...(tags && tags.length > 0 ? { tags } : {}),\n }),\n headers,\n signal: abortSignal,\n });\n};\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport { Chat, useChat } from '@ai-sdk/react';\nimport type { ChatOnToolCallCallback } from 'ai';\nimport {\n DefaultChatTransport,\n lastAssistantMessageIsCompleteWithToolCalls,\n generateId,\n} from 'ai';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n agentStudioBaseUrl,\n getAgentStudioErrorMessage,\n postAgentStudioFeedback,\n} from './askai';\nimport type { Exchange } from './AskAiScreen';\nimport type { StoredSearchPlugin } from './stored-searches';\nimport { createStoredConversations } from './stored-searches';\nimport { type AIMessage, type ToolCalls } from './types/AskiAi';\nimport type { OnAskAiFeedback } from './types/Feedback';\nimport { EMPTY_TOOLS, sanitizeMessagesForRequest } from './utils/ai';\n\nimport type { AgentStudioSearchParameters, Memory, StoredAskAiState } from '.';\n\ntype UseChat = UseChatHelpers<AIMessage>;\n\ntype UseAskAiParams = {\n agentId: string;\n apiKey: string;\n appId: string;\n searchParameters?: AgentStudioSearchParameters;\n tools: ToolCalls;\n memory?: Memory;\n indices?: string[];\n};\n\ntype UseAskAiReturn = {\n chatId: string;\n messages: AIMessage[];\n status: UseChat['status'];\n sendMessage: UseChat['sendMessage'];\n setMessages: UseChat['setMessages'];\n stopAskAiStreaming: UseChat['stop'];\n askAiError?: Error;\n isStreaming: boolean;\n exchanges: Exchange[];\n conversations: StoredSearchPlugin<StoredAskAiState>;\n sendFeedback: OnAskAiFeedback;\n /**\n * Create's a new chat instance, clearing existing messages and generating a\n * new conversation ID.\n */\n startNewConversation: () => void;\n /**\n * Create's a new chat instance, seeded with an existing conversation's ID and\n * its messages.\n */\n restoreConversation: (\n restored: AIMessage[],\n existingConversationId?: string\n ) => void;\n};\n\ntype UseAskAi = (params: UseAskAiParams) => UseAskAiReturn;\n\ntype AgentStudioTransportParams = Pick<\n UseAskAiParams,\n 'apiKey' | 'appId' | 'agentId'\n> & {\n searchParameters?: AgentStudioSearchParameters;\n userToken?: string;\n indices?: string[];\n};\n\nconst getAgentStudioTransport = ({\n appId,\n apiKey,\n agentId,\n searchParameters,\n userToken,\n indices,\n}: AgentStudioTransportParams): DefaultChatTransport<AIMessage> => {\n const algoliaParams: {\n searchParameters?: AgentStudioSearchParameters;\n indices?: string[];\n } = {};\n\n if (searchParameters) {\n algoliaParams.searchParameters = searchParameters;\n }\n\n if (indices && indices.length > 0) {\n algoliaParams.indices = indices;\n }\n\n return new DefaultChatTransport({\n api: `${agentStudioBaseUrl(appId)}/agents/${agentId}/completions?stream=true&compatibilityMode=ai-sdk-5`,\n headers: {\n 'x-algolia-application-id': appId,\n 'x-algolia-api-key': apiKey,\n ...(userToken ? { 'x-algolia-secure-user-token': userToken } : {}),\n },\n body: {\n algolia: algoliaParams,\n },\n prepareSendMessagesRequest({ id, messages, body, ...rest }) {\n // Filter out `data-*` part types since Agent Studio does not currently support them on the request\n const sanitizedMessages = sanitizeMessagesForRequest(messages);\n\n return {\n ...rest,\n body: {\n id,\n messages: sanitizedMessages,\n ...body,\n },\n };\n },\n });\n};\n\nexport const useAskAi: UseAskAi = ({\n agentId,\n apiKey,\n appId,\n tools = EMPTY_TOOLS,\n searchParameters,\n memory,\n indices,\n}) => {\n const abortControllerRef = useRef(new AbortController());\n\n const askAiTransport = useMemo(\n () =>\n getAgentStudioTransport({\n apiKey,\n appId,\n agentId,\n searchParameters,\n userToken: memory?.userToken,\n indices,\n }),\n [apiKey, appId, agentId, searchParameters, memory?.userToken, indices]\n );\n\n // Store transport in a ref since it is dependent on unstable dependencies:\n // - searchParameters, an object whose changed values trigger a new transport\n // - indices, an array whose changed values trigger a new transport\n const askAiTransportRef = useRef(askAiTransport);\n askAiTransportRef.current = askAiTransport;\n\n // Sync ref during render so the stable `handleToolCall` (registered once\n // by useChat) always sees the latest `tools` without re-creating itself.\n // Safe because tool calls only fire after a commit, and writes are idempotent.\n const toolsRef = useRef(tools);\n toolsRef.current = tools;\n\n const addToolOutputRef = useRef<UseChat['addToolOutput'] | null>(null);\n\n const handleToolCall: ChatOnToolCallCallback<AIMessage> = useCallback(\n ({ toolCall }) => {\n const tool = toolsRef.current[toolCall.toolName];\n if (!tool?.onToolCall) {\n return;\n }\n\n tool.onToolCall({\n ...toolCall,\n addToolOutput: async ({ output }) => {\n if (!addToolOutputRef.current) return;\n\n await addToolOutputRef.current({\n output,\n tool: toolCall.toolName,\n toolCallId: toolCall.toolCallId,\n });\n },\n });\n },\n []\n );\n\n const createChatInstance = useCallback(\n (messages?: AIMessage[], id = generateId()): Chat<AIMessage> =>\n new Chat<AIMessage>({\n id,\n messages,\n sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,\n transport: askAiTransportRef.current,\n onToolCall: handleToolCall,\n }),\n [handleToolCall]\n );\n\n const [chatInstance, setChatInstance] = useState(\n (): Chat<AIMessage> => createChatInstance()\n );\n // Keep a stable reference to the chat instance so reading messages are render safe\n const chatInstanceRef = useRef<Chat<AIMessage>>(chatInstance);\n chatInstanceRef.current = chatInstance;\n\n const { messages, status, setMessages, error, stop, addToolOutput } = useChat(\n {\n chat: chatInstance,\n }\n );\n\n useEffect(() => {\n addToolOutputRef.current = addToolOutput;\n }, [addToolOutput]);\n\n const conversations = useRef(\n createStoredConversations<StoredAskAiState>({\n key: `__DOCSEARCH_ASKAI_CONVERSATIONS__${appId}`,\n limit: 10,\n })\n ).current;\n\n const sendFeedback = useCallback<OnAskAiFeedback>(\n async (messageId, { thumbs, tags, notes }): Promise<void> => {\n if (!agentId) return;\n\n const res = await postAgentStudioFeedback({\n agentId,\n vote: thumbs,\n messageId,\n appId,\n apiKey,\n abortSignal: abortControllerRef.current.signal,\n notes,\n tags,\n });\n\n if (res.status >= 300) throw new Error('Failed, try again later.');\n conversations.addFeedback?.(\n messageId,\n thumbs === 1 ? 'like' : 'dislike',\n { tags, notes }\n );\n },\n [agentId, appId, apiKey, conversations]\n );\n\n const onStopStreaming = useCallback(async (): Promise<void> => {\n abortControllerRef.current.abort();\n await stop();\n }, [stop]);\n\n const exchanges = useMemo((): Exchange[] => {\n const grouped: Exchange[] = [];\n\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 isStreaming = status === 'streaming' || status === 'submitted';\n\n const askAiError = useMemo((): Error | undefined => {\n if (!error) return undefined;\n\n return getAgentStudioErrorMessage(error);\n }, [error]);\n\n const updateChatInstance = useCallback(\n (restored?: AIMessage[], existingConversationId?: string): void => {\n const newChatInstance = createChatInstance(\n restored,\n existingConversationId\n );\n chatInstanceRef.current = newChatInstance;\n setChatInstance(newChatInstance);\n },\n [createChatInstance]\n );\n\n const startNewConversation = useCallback((): void => {\n updateChatInstance();\n }, [updateChatInstance]);\n\n const restoreConversation = useCallback(\n (restored: AIMessage[], existingConversationId?: string): void => {\n updateChatInstance(restored, existingConversationId);\n },\n [updateChatInstance]\n );\n\n // This is so that the public `sendMessage` is always pointed to a stable reference of the chat instance\n const sendMessageSafe = useCallback<UseChat['sendMessage']>(\n (...args): Promise<void> => chatInstanceRef.current!.sendMessage(...args),\n []\n );\n\n return {\n chatId: chatInstance.id,\n messages,\n sendMessage: sendMessageSafe,\n status,\n setMessages,\n askAiError,\n stopAskAiStreaming: onStopStreaming,\n isStreaming,\n exchanges,\n conversations,\n sendFeedback,\n startNewConversation,\n restoreConversation,\n };\n};\n","import type { SearchResponse } from 'algoliasearch/lite';\nimport { useEffect, useState } from 'react';\n\nimport { SUGGESTED_QUETIONS_INDEX_NAME } from './constants';\n\nimport type {\n DocSearchTransformClient,\n SuggestedQuestion,\n SuggestedQuestionHit,\n} from '.';\n\ntype UseSuggestedQuestionsProps = {\n agentId: string | null;\n searchClient: DocSearchTransformClient;\n suggestedQuestionsEnabled?: boolean;\n};\n\nexport const useSuggestedQuestions = ({\n agentId,\n searchClient,\n suggestedQuestionsEnabled = false,\n}: UseSuggestedQuestionsProps): SuggestedQuestionHit[] => {\n const [suggestedQuestions, setSuggestedQuestions] = useState<\n SuggestedQuestionHit[]\n >([]);\n\n useEffect(() => {\n const getSuggestedQuestions = async (): Promise<void> => {\n const { results } = await searchClient.search<SuggestedQuestion>({\n requests: [\n {\n indexName: SUGGESTED_QUETIONS_INDEX_NAME,\n filters: `state:published AND assistantId:${agentId}`,\n hitsPerPage: 3,\n },\n ],\n });\n\n const result = results[0] as SearchResponse<SuggestedQuestion>;\n\n setSuggestedQuestions(result.hits);\n };\n\n if (suggestedQuestionsEnabled && agentId && agentId !== '') {\n getSuggestedQuestions();\n }\n }, [suggestedQuestionsEnabled, agentId, searchClient]);\n\n return suggestedQuestions;\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/version.d.ts
2
- declare const version = "5.0.0-beta.2";
2
+ declare const version = "5.0.0-beta.4";
3
3
  //#endregion
4
4
  export { version };
5
5
  //# sourceMappingURL=version.d.ts.map
@@ -1,5 +1,5 @@
1
1
  //#region src/version.ts
2
- const version = "5.0.0-beta.2";
2
+ const version = "5.0.0-beta.4";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","names":[],"sources":["../../src/version.ts"],"sourcesContent":["export const version = '5.0.0-beta.2';\n"],"mappings":";AAAA,MAAa,UAAU"}
1
+ {"version":3,"file":"version.js","names":[],"sources":["../../src/version.ts"],"sourcesContent":["export const version = '5.0.0-beta.4';\n"],"mappings":";AAAA,MAAa,UAAU"}