@docsearch/react 5.0.0-beta.0 → 5.0.0-beta.1

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 (28) hide show
  1. package/dist/esm/{AskAiScreenState-D0IZsCMJ.d.ts → AskAiScreenState-CRHicWbN.d.ts} +3 -3
  2. package/dist/esm/{DocSearch-Dq5Utfyb.d.ts → DocSearch-HJsNvtZr.d.ts} +3 -3
  3. package/dist/esm/{DocSearchAskAiModal-BwbMrrHv.d.ts → DocSearchAskAiModal-B7vpLudE.d.ts} +4 -4
  4. package/dist/esm/{DocSearchAskAiModal-CCrk6YLb.js → DocSearchAskAiModal-KaA6fBV4.js} +8 -8
  5. package/dist/esm/DocSearchAskAiModal-KaA6fBV4.js.map +1 -0
  6. package/dist/esm/{DocSearchButton-CRlNPf5k.d.ts → DocSearchButton-CZM_jACU.d.ts} +2 -2
  7. package/dist/esm/askaiModal.d.ts +1 -1
  8. package/dist/esm/askaiModal.js +1 -1
  9. package/dist/esm/button.d.ts +1 -1
  10. package/dist/esm/docsearchAi.d.ts +2 -2
  11. package/dist/esm/docsearchAi.js +1 -1
  12. package/dist/esm/{index-Dl8FMlR5.d.ts → index-Bqqv4HmN.d.ts} +19 -9
  13. package/dist/esm/index.d.ts +5 -5
  14. package/dist/esm/index.js +1 -1
  15. package/dist/esm/modal.d.ts +1 -1
  16. package/dist/esm/sidepanel.d.ts +4 -4
  17. package/dist/esm/sidepanel.js +4 -4
  18. package/dist/esm/sidepanel.js.map +1 -1
  19. package/dist/esm/{useDocSearchKeyboardEvents-68G8dw6c.d.ts → useDocSearchKeyboardEvents-u23fFhR9.d.ts} +2 -2
  20. package/dist/esm/useDocSearchKeyboardEvents.d.ts +1 -1
  21. package/dist/esm/{useSuggestedQuestions-D2TGVPsI.js → useSuggestedQuestions-CG2H3qm4.js} +34 -30
  22. package/dist/esm/useSuggestedQuestions-CG2H3qm4.js.map +1 -0
  23. package/dist/esm/useTheme.d.ts +1 -1
  24. package/dist/umd/index.js +15 -15
  25. package/dist/umd/index.js.map +1 -1
  26. package/package.json +4 -4
  27. package/dist/esm/DocSearchAskAiModal-CCrk6YLb.js.map +0 -1
  28. package/dist/esm/useSuggestedQuestions-D2TGVPsI.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sidepanel.js","names":[],"sources":["../../src/icons/SendIcon.tsx","../../src/icons/ExpandIcon.tsx","../../src/icons/FolderIcon.tsx","../../src/icons/EditIcon.tsx","../../src/useIsMobile.ts","../../src/Sidepanel/ConversationHistoryScreen.tsx","../../src/Sidepanel/AggregatedSearchBlock.tsx","../../src/Sidepanel/ConversationScreen.tsx","../../src/Sidepanel/NewConversationScreen.tsx","../../src/Sidepanel/PromptForm.tsx","../../src/Sidepanel/setSidepanelSearchClient.ts","../../src/Sidepanel/SidepanelHeader.tsx","../../src/Sidepanel/useManageSidepanelLayout.ts","../../src/Sidepanel/useSidepanelKeyboardEvents.ts","../../src/Sidepanel/useSidepanelWidth.ts","../../src/Sidepanel/Sidepanel.tsx","../../src/Sidepanel/SidepanelButton.tsx","../../src/Sidepanel.tsx"],"sourcesContent":["import type { JSX } from 'react';\nimport React from 'react';\n\nexport const SendIcon = (): 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=\"m5 12 7-7 7 7\" />\n <path d=\"M12 19V5\" />\n </svg>\n );\n};\n","import type { JSX } from 'react';\nimport React from 'react';\n\nexport const ExpandIcon = (): JSX.Element => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 13 13\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M8 0.5C8 0.223858 8.22386 0 8.5 0H12.5C12.7761 0 13 0.223858 13 0.5V4.5C13 4.77614 12.7761 5 12.5 5C12.2239 5 12 4.77614 12 4.5V1.70711L8.18689 5.52022C7.99162 5.71548 7.67504 5.71548 7.47978 5.52022C7.28452 5.32496 7.28452 5.00838 7.47978 4.81311L11.2929 1H8.5C8.22386 1 8 0.776142 8 0.5ZM5.52022 7.47978C5.71548 7.67504 5.71548 7.99162 5.52022 8.18689L1.70711 12H4.5C4.77614 12 5 12.2239 5 12.5C5 12.7761 4.77614 13 4.5 13H0.5C0.223858 13 0 12.7761 0 12.5V8.5C0 8.22386 0.223858 8 0.5 8C0.776142 8 1 8.22386 1 8.5V11.2929L4.81311 7.47978C5.00838 7.28452 5.32496 7.28452 5.52022 7.47978Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n};\n","import React from 'react';\nimport type { JSX } from 'react';\n\nexport const FolderIcon = (): JSX.Element => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\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=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n );\n};\n","import React from 'react';\nimport type { JSX } from 'react';\n\nexport const EditIcon = (): JSX.Element => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\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=\"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z\" />\n </svg>\n );\n};\n","import React from 'react';\n\nexport const useIsMobile = (): boolean => {\n const [isMobile, setIsMobile] = React.useState(false);\n\n React.useEffect(() => {\n const checkForMobile = (): void => {\n const isMobileMediaQuery = window.matchMedia('(max-width: 768px)');\n\n setIsMobile(isMobileMediaQuery.matches);\n };\n\n checkForMobile();\n\n window.addEventListener('resize', checkForMobile);\n\n return (): void => {\n window.removeEventListener('resize', checkForMobile);\n };\n }, []);\n\n return isMobile;\n};\n","/* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */\nimport React from 'react';\nimport type { JSX } from 'react';\n\nimport { CloseIcon, RecentIcon } from '../icons';\nimport type { StoredSearchPlugin } from '../stored-searches';\nimport type { StoredAskAiState } from '../types';\n\ntype ConversationHistoryScreenProps = {\n conversations: StoredSearchPlugin<StoredAskAiState>;\n selectConversation: (conversation: StoredAskAiState) => void;\n};\n\nexport const ConversationHistoryScreen = ({\n conversations,\n selectConversation,\n}: ConversationHistoryScreenProps): JSX.Element => {\n const [items, setItems] = React.useState(() => conversations.getAll());\n\n const handleRemoveConversation = (item: StoredAskAiState): void => {\n conversations.remove(item);\n setItems(conversations.getAll());\n };\n\n return (\n <div className=\"DocSearch-Sidepanel-ConversationHistoryScreen\">\n <ul>\n {items.map((item) => (\n <li\n key={item.objectID}\n className=\"DocSearch-Sidepanel-RecentConversation\"\n >\n <a\n href={item.url}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n\n selectConversation(item);\n }}\n >\n <div className=\"DocSearch-Sidepanel-RecentConversation-container\">\n <div className=\"DocSearch-Sidepanel-RecentConversation-icon\">\n <RecentIcon />\n </div>\n\n <div className=\"DocSearch-Sidepanel-RecentConversation-content\">\n <span className=\"DocSearch-Sidepanel-RecentConversation-title\">\n {item.hierarchy.lvl1}\n </span>\n </div>\n\n <div className=\"DocSearch-Hit-action\">\n <button\n className=\"DocSearch-Hit-action-button\"\n type=\"button\"\n title=\"Remove conversation from history\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n handleRemoveConversation(item);\n }}\n >\n <CloseIcon />\n </button>\n </div>\n </div>\n </a>\n </li>\n ))}\n </ul>\n </div>\n );\n};\n","import React, { Fragment } from 'react';\nimport type { JSX } from 'react';\n\nimport { SearchIcon } from '../icons';\n\ntype AggregatedSearchBlockProps = {\n queries: string[];\n};\n\nconst before = 'Searched for ';\nconst separator = ', ';\nconst lastSeparator = ' and ';\nconst after = '';\n\nexport function AggregatedSearchBlock({\n queries,\n}: AggregatedSearchBlockProps): JSX.Element {\n return (\n <div className=\"DocSearch-AskAiScreen-MessageContent-Tool Tool--AggregatedResult\">\n <SearchIcon size={18} />\n <span>\n {before && <span>{before}</span>}\n {queries.map((q, idx) => (\n // eslint-disable-next-line react/no-array-index-key\n <Fragment key={q + idx}>\n <span className=\"DocSearch-AskAiScreen-MessageContent-Tool-Query\">\n &quot;{q}&quot;\n </span>\n {idx < queries.length - 2 && separator}\n {idx === queries.length - 2 && lastSeparator}\n </Fragment>\n ))}\n {after && <span>{after}</span>}\n </span>\n </div>\n );\n}\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport type { JSX } from 'react';\nimport React, { memo, useMemo } from 'react';\n\nimport { type Exchange } from '../AskAiScreen';\nimport { ConversationPromptSuggestions } from '../components/ConversationPromptSuggestions';\nimport { FeedbackActions } from '../components/FeedbackActions';\nimport { SourcesPanel } from '../components/SourcesPanel';\nimport { ToolCall, type ToolCallTranslations } from '../components/ToolCall';\nimport { AlertIcon, LoadingIcon } from '../icons';\nimport { MemoizedMarkdown } from '../MemoizedMarkdown';\nimport type { StoredSearchPlugin } from '../stored-searches';\nimport type { OnAskAiFeedback, StoredAskAiState } from '../types';\nimport { type AIMessage, type ToolCalls } from '../types/AskiAi';\nimport {\n extractLinksFromMessage,\n getMessageContent,\n EMPTY_TOOLS,\n isAIToolPart,\n getAgentPromptSuggestions,\n} from '../utils/ai';\nimport { groupConsecutiveToolResults } from '../utils/groupConsecutiveToolResults';\n\nimport { AggregatedSearchBlock } from './AggregatedSearchBlock';\n\nexport type ConversationScreenTranslations = Partial<\n ToolCallTranslations & {\n /** Text shown as an LLM disclaimer. */\n conversationDisclaimer: string;\n /** Text shown while assistant is reasoning. */\n reasoningText: string;\n /** Text show while assistant is thinking. */\n thinkingText: string;\n /** Text shown describing related sources. */\n relatedSourcesText: string;\n /** Message that's shown when user has stopped the streaming of a message. */\n stoppedStreamingText: string;\n /** Text shown for copy button on code snippets. */\n copyButtonText: string;\n /** Message shown after clicking copy. */\n copyButtonCopiedText: string;\n /** Title for thumbs up feedback icon. */\n likeButtonTitle: string;\n /** Title for thumbs down feedback icon. */\n dislikeButtonTitle: string;\n /** Message displayed after feedback action. */\n thanksForFeedbackText: string;\n /** Title shown at the top of the negative feedback note panel. */\n feedbackPanelTitle: string;\n /** Placeholder for the negative feedback details textarea. */\n feedbackDetailsPlaceholder: string;\n /** Disclaimer shown inside the negative feedback note panel. */\n feedbackDisclaimerText: string;\n /** Submit button text for the negative feedback note panel. */\n feedbackSubmitButtonText: string;\n /** Accessible title for the negative feedback note panel close button. */\n feedbackCloseButtonTitle: string;\n /** Reason chip labels for the negative feedback note panel. */\n feedbackTagIncorrect: string;\n feedbackTagNotWhatIAsked: string;\n feedbackTagSlowOrBuggy: string;\n feedbackTagStyleOrTone: string;\n feedbackTagSafetyOrLegal: string;\n feedbackTagOther: string;\n /** Error title shown if there is an error while chatting. */\n errorTitleText;\n suggestedPromptsTitleText: string;\n }\n>;\n\nexport type ConversationScreenProps = {\n exchanges: Exchange[];\n conversations: StoredSearchPlugin<StoredAskAiState>;\n translations?: ConversationScreenTranslations;\n status: UseChatHelpers<AIMessage>['status'];\n handleFeedback?: OnAskAiFeedback;\n streamError?: Error;\n memoryEnabled?: boolean;\n tools?: ToolCalls;\n onSelectPromptSuggestion: (prompt: string) => void;\n};\n\ntype ConversationnExchangeProps = {\n exchange: Exchange;\n isLastExchange: boolean;\n status: ConversationScreenProps['status'];\n conversations: ConversationScreenProps['conversations'];\n translations?: ConversationScreenTranslations;\n onFeedback?: ConversationScreenProps['handleFeedback'];\n streamError?: ConversationScreenProps['streamError'];\n memoryEnabled?: boolean;\n tools: ToolCalls;\n onSelectPromptSuggestion: (prompt: string) => void;\n};\n\nconst ConversationExchange = React.forwardRef<\n HTMLDivElement,\n ConversationnExchangeProps\n>(\n (\n {\n exchange,\n translations = {},\n isLastExchange,\n conversations,\n onFeedback,\n status,\n streamError,\n memoryEnabled,\n tools,\n onSelectPromptSuggestion,\n },\n conversationRef\n ): JSX.Element => {\n const { userMessage, assistantMessage } = exchange;\n\n const {\n reasoningText = 'Reasoning...',\n thinkingText = 'Thinking...',\n searchingText = 'Searching...',\n relatedSourcesText,\n stoppedStreamingText = 'You stopped this response',\n preToolCallText = 'Searching...',\n toolCallResultText = 'Searched for',\n copyButtonText = 'Copy',\n copyButtonCopiedText = 'Copied!',\n errorTitleText = 'Chat error',\n savedMemoryToolResultText = 'Saved to memory',\n memoryToolResultText = 'Used memory to enhance results',\n suggestedPromptsTitleText = 'Suggested prompts',\n } = translations;\n\n const assistantContent = useMemo(\n () => getMessageContent(assistantMessage),\n [assistantMessage]\n );\n const userContent = useMemo(\n () => getMessageContent(userMessage),\n [userMessage]\n );\n\n const assistantParts = useMemo(\n () => groupConsecutiveToolResults(assistantMessage?.parts || []),\n [assistantMessage]\n );\n const urlsToDisplay = React.useMemo(\n () => extractLinksFromMessage(assistantMessage),\n [assistantMessage]\n );\n const suggestedPrompts = React.useMemo(() => {\n if (!isLastExchange) return [];\n return getAgentPromptSuggestions(assistantMessage?.parts || []);\n }, [assistantMessage, isLastExchange]);\n\n const wasStopped =\n userMessage.metadata?.stopped || assistantMessage?.metadata?.stopped;\n const isThinking =\n ['submitted', 'streaming'].includes(status) &&\n !assistantParts.some((part) => part.type !== 'step-start');\n const showActions =\n !wasStopped &&\n (!isLastExchange ||\n (isLastExchange && status === 'ready' && Boolean(assistantMessage)));\n\n const messageId = assistantMessage?.id || exchange.id;\n\n return (\n <div\n className=\"DocSearch-AskAiScreen-Response-Container\"\n ref={conversationRef}\n >\n <div className=\"DocSearch-AskAiScreen-Response\">\n <div className=\"DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user\">\n <p className=\"DocSearch-AskAiScreen-Query\">\n {userContent?.text ?? ''}\n </p>\n </div>\n <div className=\"DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant\">\n <div className=\"DocSearch-AskAiScreen-MessageContent\">\n {status === 'error' && streamError && isLastExchange && (\n <div className=\"DocSearch-AskAiScreen-Error\" role=\"alert\">\n <AlertIcon aria-hidden=\"true\" />\n <div className=\"DocSearch-AskAiScreen-Error-Content\">\n <h4 className=\"DocSearch-AskAiScreen-Error-Title\">\n {errorTitleText}\n </h4>\n <MemoizedMarkdown\n content={streamError.message}\n copyButtonText=\"\"\n copyButtonCopiedText=\"\"\n isStreaming={false}\n />\n </div>\n </div>\n )}\n\n {assistantParts.map((part, idx) => {\n const index = idx;\n\n if (part.type === 'reasoning' && part.state === 'streaming') {\n return (\n <div\n key={index}\n className=\"DocSearch-AskAiScreen-MessageContent-Reasoning shimmer\"\n >\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n <span className=\"shimmer\">{reasoningText}</span>\n </div>\n );\n }\n\n if (part.type === 'aggregated-tool-call') {\n return (\n <AggregatedSearchBlock key={index} queries={part.queries} />\n );\n }\n\n if (isAIToolPart(part)) {\n return (\n <ToolCall\n key={index}\n part={part}\n translations={{\n preToolCallText,\n searchingText,\n toolCallResultText,\n savedMemoryToolResultText,\n memoryToolResultText,\n }}\n tools={tools}\n memoryEnabled={memoryEnabled}\n />\n );\n }\n\n if (typeof part === 'string') {\n return (\n <MemoizedMarkdown\n key={index}\n content={part}\n copyButtonText={copyButtonText}\n copyButtonCopiedText={copyButtonCopiedText}\n isStreaming={false}\n />\n );\n }\n\n if (part.type === 'text') {\n return (\n <MemoizedMarkdown\n key={index}\n content={part.text}\n copyButtonText={copyButtonText}\n copyButtonCopiedText={copyButtonCopiedText}\n isStreaming={part.state === 'streaming'}\n />\n );\n }\n\n return null;\n })}\n\n {isThinking && isLastExchange && assistantParts.length === 0 && (\n <div\n className=\"DocSearch-AskAiScreen-MessageContent-Thinking\"\n role=\"status\"\n >\n <span className=\"shimmer\">{thinkingText}</span>\n <span className=\"DocSearch-AskAi-Thinking-Skeleton shimmer\" />\n <span className=\"DocSearch-AskAi-Thinking-Skeleton DocSearch-AskAi-Thinking-Skeleton--short shimmer\" />\n </div>\n )}\n </div>\n\n {wasStopped && (\n <p className=\"DocSearck-AskAiScreen-MessageContent-Stopped\">\n {stoppedStreamingText}\n </p>\n )}\n </div>\n\n <div className=\"DocSearch-AskAiScreen-Answer-Footer\">\n <SourcesPanel\n links={urlsToDisplay}\n titleText={relatedSourcesText}\n />\n <FeedbackActions\n isSidepanel={true}\n id={messageId}\n showActions={showActions}\n latestAssistantMessageContent={assistantContent?.text || null}\n translations={translations}\n conversations={conversations}\n onFeedback={onFeedback}\n />\n </div>\n\n {suggestedPrompts.length > 0 && (\n <ConversationPromptSuggestions\n title={suggestedPromptsTitleText}\n suggestions={suggestedPrompts}\n onSelectPromptSuggestion={onSelectPromptSuggestion}\n />\n )}\n </div>\n </div>\n );\n }\n);\n\nexport const ConversationScreen = memo(\n ({\n exchanges,\n translations = {},\n handleFeedback,\n tools = EMPTY_TOOLS,\n status,\n conversations,\n streamError,\n memoryEnabled,\n onSelectPromptSuggestion,\n }: ConversationScreenProps): JSX.Element => {\n const {\n conversationDisclaimer = 'Answers are generated with AI which can make mistakes. Verify responses.',\n } = translations;\n\n const mostRecentExchangeRef = React.useRef<HTMLDivElement>(null);\n const totalExchanges = exchanges.length;\n\n // Only scroll the most recent exchange into view when needed\n React.useEffect(() => {\n if (mostRecentExchangeRef.current) {\n mostRecentExchangeRef.current.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n });\n }\n }, [totalExchanges]);\n\n return (\n <div className=\"DocSearch-Sidepanel-ConversationScreen\">\n <p className=\"DocSearch-Sidepanel-ConversationScreen-disclaimer\">\n {conversationDisclaimer}\n </p>\n\n {exchanges.slice().map((exchange, idx) => {\n const isLastExchange = idx === exchanges.length - 1;\n return (\n <ConversationExchange\n key={exchange.id}\n exchange={exchange}\n translations={translations}\n isLastExchange={isLastExchange}\n ref={isLastExchange ? mostRecentExchangeRef : null}\n tools={tools}\n status={status}\n conversations={conversations}\n streamError={streamError}\n memoryEnabled={memoryEnabled}\n onFeedback={handleFeedback}\n onSelectPromptSuggestion={onSelectPromptSuggestion}\n />\n );\n })}\n </div>\n );\n }\n);\n","import type { JSX } from 'react';\nimport React from 'react';\n\nimport type { SuggestedQuestionHit } from '../types';\n\nexport type NewConversationScreenTranslations = Partial<{\n /** Title to be shown on the new conversation/starting screen. */\n titleText: string;\n /** Introduction text displayed on the new conversation/starting screen. */\n introductionText: string;\n}>;\n\ntype NewConversationScreenProps = {\n suggestedQuestions: SuggestedQuestionHit[];\n onSelectQuestion: (question: SuggestedQuestionHit) => void;\n translations?: NewConversationScreenTranslations;\n};\n\nexport const NewConversationScreen = ({\n suggestedQuestions,\n onSelectQuestion,\n translations = {},\n}: NewConversationScreenProps): JSX.Element => {\n const {\n titleText = 'How can I help you today?',\n introductionText = 'I search through your documentation to help you find setup guides, feature details and troubleshooting tips, fast.',\n } = translations;\n\n return (\n <div className=\"DocSearch-Sidepanel-NewConversationScreen\">\n <h4 className=\"DocSearch-Sidepanel-Screen--title\">{titleText}</h4>\n <p className=\"DocSearch-Sidepanel-Screen--introduction\">\n {introductionText}\n </p>\n\n <div className=\"DocSearch-Sidepanel-List\">\n {suggestedQuestions.map((q) => (\n <button\n key={q.objectID}\n type=\"button\"\n className=\"DocSearch-Sidepanel-SuggestedQuestion\"\n title=\"View conversation\"\n onClick={() => {\n onSelectQuestion(q);\n }}\n >\n <span>{q.question}</span>\n </button>\n ))}\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport type { JSX } from 'react';\n\nimport type { Exchange } from '../AskAiScreen';\nimport { SendIcon, StopIcon } from '../icons';\nimport { useIsMobile } from '../useIsMobile';\n\nexport type PromptFormTranslations = Partial<{\n /** Initial placeholder for the prompt input. */\n promptPlaceholderText: string;\n /** Placeholder text for wile a conversation is streaming. */\n promptAnsweringText: string;\n /** Placeholder text for after a question has already been asked. */\n promptAskAnotherQuestionText: string;\n /** Disclaimer text displayed beneath the prompt form. */\n promptDisclaimerText: string;\n promptLabelText: string;\n promptAriaLabelText: string;\n}>;\n\ntype Props = {\n exchanges: Exchange[];\n isStreaming: boolean;\n translations?: PromptFormTranslations;\n onSend: (prompt: string) => void;\n onStopStreaming: () => void;\n};\n\nconst MAX_PROMPT_ROWS = 8;\n\nexport const PromptForm = React.forwardRef<HTMLTextAreaElement, Props>(\n (\n { exchanges, isStreaming, translations = {}, onSend, onStopStreaming },\n ref\n ): JSX.Element => {\n const isMobile = useIsMobile();\n const [userPrompt, setUserPrompt] = React.useState('');\n const promptRef = React.useRef<HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(\n ref,\n () => promptRef.current as HTMLTextAreaElement\n );\n\n const {\n promptPlaceholderText = 'Ask a question',\n promptAnsweringText = 'Answering...',\n promptAskAnotherQuestionText = 'Ask another question',\n promptDisclaimerText = 'Answers are generated with AI which can make mistakes.',\n promptLabelText = 'Press Enter to send, or Shift and Enter for new line.',\n promptAriaLabelText = 'Prompt input',\n } = translations;\n\n const managePromptHeight = (): void => {\n if (!promptRef.current) return;\n\n const textArea = promptRef.current;\n const styles = getComputedStyle(textArea);\n\n const lineHeight = parseFloat(styles.lineHeight);\n const paddingTop = parseFloat(styles.paddingTop);\n const paddingBottom = parseFloat(styles.paddingBottom);\n const padding = paddingTop + paddingBottom;\n\n textArea.style.height = 'auto';\n\n const fullHeight = textArea.scrollHeight;\n const maxHeight = MAX_PROMPT_ROWS * lineHeight + padding;\n\n textArea.style.overflowY = fullHeight > maxHeight ? 'auto' : 'hidden';\n textArea.style.height = `${Math.min(fullHeight, maxHeight)}px`;\n };\n\n const handleSend = (): void => {\n if (isStreaming) return;\n\n const prompt = userPrompt.trim();\n\n if (prompt === '') return;\n\n onSend(prompt);\n\n setUserPrompt('');\n\n requestAnimationFrame(() => {\n promptRef.current?.focus();\n\n managePromptHeight();\n });\n };\n\n const handleKeyDown = (\n e: React.KeyboardEvent<HTMLTextAreaElement>\n ): void => {\n // Allow Enter to work normally (new line) when streaming\n if (isStreaming) return;\n\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n\n handleSend();\n }\n };\n\n React.useLayoutEffect(() => {\n managePromptHeight();\n }, [isMobile]);\n\n let promptPlaceholder = promptPlaceholderText;\n\n if (isStreaming) {\n promptPlaceholder = promptAnsweringText;\n } else if (exchanges.length > 0) {\n promptPlaceholder = promptAskAnotherQuestionText;\n }\n\n return (\n <div className=\"DocSearch-Sidepanel-Prompt\">\n <form\n className=\"DocSearch-Sidepanel-Prompt--form\"\n onSubmit={(e) => {\n e.preventDefault();\n\n if (isStreaming) return;\n\n handleSend();\n }}\n >\n <textarea\n ref={promptRef}\n placeholder={promptPlaceholder}\n className=\"DocSearch-Sidepanel-Prompt--textarea\"\n value={userPrompt}\n aria-label={promptAriaLabelText}\n aria-labelledby=\"prompt-label\"\n autoComplete=\"off\"\n translate=\"no\"\n rows={isMobile ? 1 : 2}\n onKeyDown={handleKeyDown}\n onInput={managePromptHeight}\n onChange={(e) => setUserPrompt(e.target.value)}\n />\n <span id=\"prompt-label\" className=\"sr-only\">\n {promptLabelText}\n </span>\n <div className=\"DocSearch-Sidepanel-Prompt--actions\">\n {isStreaming && (\n <button\n type=\"button\"\n title=\"Stop streaming\"\n className=\"DocSearch-Sidepanel-Prompt--stop\"\n onClick={onStopStreaming}\n >\n <StopIcon />\n </button>\n )}\n {!isStreaming && (\n <button\n type=\"submit\"\n aria-label=\"Send question\"\n title=\"Send question\"\n className=\"DocSearch-Sidepanel-Prompt--submit\"\n aria-disabled={userPrompt === ''}\n >\n <SendIcon />\n </button>\n )}\n </div>\n </form>\n <p className=\"DocSearch-Sidepanel-Prompt--disclaimer\">\n {promptDisclaimerText}\n </p>\n </div>\n );\n }\n);\n","import type { DocSearchTransformClient } from '..';\nimport { version } from '../version';\n\nexport const setSidepanelSearchClient = (\n client: DocSearchTransformClient\n): DocSearchTransformClient => {\n if (\n /docsearch-sidepanel.js \\(.*\\)/.test(\n client.transporter.algoliaAgent.value\n ) === false\n ) {\n client.addAlgoliaAgent('docsearch-sidepanel', version);\n }\n\n return client;\n};\n","import type { JSX } from 'react';\nimport React from 'react';\n\nimport type { Exchange } from '../AskAiScreen';\nimport {\n CloseIcon,\n ConversationHistoryIcon,\n EditIcon,\n ExpandIcon,\n FolderIcon,\n MoreVerticalIcon,\n NewConversationIcon,\n SparklesIcon,\n} from '../icons';\nimport { BackIcon } from '../icons/BackIcon';\nimport { Menu } from '../Menu';\nimport { useIsMobile } from '../useIsMobile';\n\nimport type { SidepanelState } from './types';\n\ntype BackButtonProps = {\n mobile?: boolean;\n onBack: () => void;\n disabled?: boolean;\n};\n\nconst BackButton = ({\n onBack,\n mobile = false,\n disabled = false,\n}: BackButtonProps): JSX.Element => {\n return (\n <button\n type=\"button\"\n className={`DocSearch-Action DocSearch-Sidepanel-Action-back${mobile ? ' mobile' : ''}`}\n title=\"Go back to previous screen\"\n aria-disabled={disabled}\n onClick={disabled ? undefined : onBack}\n >\n <BackIcon />\n </button>\n );\n};\n\nexport type HeaderTranslations = Partial<{\n /** The main title text shown on the header. */\n title: string;\n /** The title text shown on the conversation history screen. */\n conversationHistoryTitle: string;\n /** The text shown on the start a conversation button. */\n newConversationText: string;\n /** The text shown on the view conversation history button. */\n viewConversationHistoryText: string;\n}>;\n\ntype SidepanelHeaderProps = {\n sidepanelState: SidepanelState;\n exchanges: Exchange[];\n setSidepanelState: (state: SidepanelState) => void;\n onNewConversation: () => void;\n onToggleExpanded: () => void;\n onClose: () => void;\n translations?: HeaderTranslations;\n hasConversations: boolean;\n isStreaming: boolean;\n};\n\nexport const SidepanelHeader = React.memo(\n ({\n sidepanelState,\n exchanges,\n setSidepanelState,\n onNewConversation,\n onToggleExpanded,\n onClose,\n translations = {},\n hasConversations,\n isStreaming,\n }: SidepanelHeaderProps): JSX.Element => {\n const {\n title = 'Ask AI',\n conversationHistoryTitle = 'My conversation history',\n newConversationText = 'Start a new conversation',\n viewConversationHistoryText = 'Conversation history',\n } = translations;\n\n const isMobile = useIsMobile();\n\n const goToConversationHistory = (): void => {\n setSidepanelState('conversation-history');\n };\n\n const onBack = React.useCallback((): void => {\n if (exchanges.length > 0) {\n setSidepanelState('conversation');\n } else {\n setSidepanelState('new-conversation');\n }\n }, [exchanges, setSidepanelState]);\n\n const newConversationDisabled =\n sidepanelState === 'new-conversation' && exchanges.length < 1;\n\n let header = title;\n\n if (sidepanelState === 'conversation-history') {\n header = conversationHistoryTitle;\n }\n\n if (isMobile) {\n header = title;\n }\n\n return (\n <header className=\"DocSearch-Sidepanel-Header\">\n <div className=\"DocSearch-Sidepanel-Header--left\">\n <BackButton mobile={true} disabled={isStreaming} onBack={onBack} />\n\n {sidepanelState === 'conversation-history' && (\n <div className=\"DocSearch-Divider\" />\n )}\n\n <button\n type=\"button\"\n className=\"DocSearch-Action\"\n title={newConversationText}\n onClick={onNewConversation}\n >\n <EditIcon />\n </button>\n\n <div className=\"DocSearch-Divider\" />\n\n <button\n type=\"button\"\n className=\"DocSearch-Action\"\n title={viewConversationHistoryText}\n onClick={goToConversationHistory}\n >\n <FolderIcon />\n </button>\n </div>\n <div className=\"DocSearch-Sidepanel-Header--center\">\n <BackButton disabled={isStreaming} onBack={onBack} />\n <SparklesIcon className=\"DocSearch-Sidepanel-Header-TitleIcon\" />\n <h2 className=\"DocSearch-Sidepanel-Title\">{header}</h2>\n </div>\n <div className=\"DocSearch-Sidepanel-Header--right\">\n {sidepanelState !== 'conversation-history' &&\n (!newConversationDisabled || hasConversations) && (\n <Menu>\n <Menu.Trigger\n className=\"DocSearch-Action DocSearch-Sidepanel-Action-menu\"\n disabled={isStreaming}\n >\n <MoreVerticalIcon />\n </Menu.Trigger>\n <Menu.Content>\n {!newConversationDisabled && (\n <Menu.Item onClick={onNewConversation}>\n <NewConversationIcon />\n {newConversationText}\n </Menu.Item>\n )}\n {hasConversations && (\n <Menu.Item onClick={goToConversationHistory}>\n <ConversationHistoryIcon />\n {viewConversationHistoryText}\n </Menu.Item>\n )}\n </Menu.Content>\n </Menu>\n )}\n <button\n type=\"button\"\n className=\"DocSearch-Action DocSearch-Sidepanel-Action-expand\"\n title=\"Expand or collapse Sidepanel\"\n onClick={onToggleExpanded}\n >\n <ExpandIcon />\n </button>\n <button\n type=\"button\"\n className=\"DocSearch-Action DocSearch-Sidepanel-Action-close\"\n title=\"Close Sidepanel\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n </div>\n </header>\n );\n }\n);\n","import { useLayoutEffect, useRef } from 'react';\n\nimport { useIsMobile } from '../useIsMobile';\n\nimport type { PanelSide, PanelVariant } from './types';\n\ntype UseManageSidepanelLayoutProps = {\n variant: PanelVariant;\n side: PanelSide;\n selectors: string;\n isOpen: boolean;\n expectedWidth: string;\n};\n\nexport function useManageSidepanelLayout({\n variant,\n selectors,\n isOpen,\n expectedWidth,\n side,\n}: UseManageSidepanelLayoutProps): void {\n const targetRef = useRef<HTMLElement | null>(null);\n const lastSelectorRef = useRef<string | null>(null);\n const isMobile = useIsMobile();\n\n useLayoutEffect(() => {\n if (variant === 'floating' || isMobile) return;\n\n if (lastSelectorRef.current !== selectors) {\n if (targetRef.current) {\n if (side === 'left') {\n targetRef.current.style.marginLeft = '';\n } else {\n targetRef.current.style.marginRight = '';\n }\n targetRef.current.style.transition = '';\n }\n\n const candidates = Array.from(document.querySelectorAll(selectors));\n const nextTarget: HTMLElement | null =\n (candidates[0] as HTMLElement) || document.body;\n targetRef.current = nextTarget;\n lastSelectorRef.current = selectors;\n\n if (targetRef.current) {\n targetRef.current.style.transition = `margin-${side} 280ms cubic-bezier(0.22, 1, 0.36, 1)`;\n }\n }\n\n const target = targetRef.current;\n if (!target) return;\n\n const offset = isOpen ? expectedWidth : '0px';\n\n if (side === 'left') {\n target.style.marginLeft = offset;\n } else {\n target.style.marginRight = offset;\n }\n }, [isOpen, expectedWidth, variant, selectors, side, isMobile]);\n\n useLayoutEffect(() => {\n return (): void => {\n if (targetRef.current) {\n if (side === 'left') {\n targetRef.current.style.marginLeft = '';\n } else {\n targetRef.current.style.marginRight = '';\n }\n targetRef.current.style.transition = '';\n }\n };\n }, [side]);\n}\n","import type { SidepanelShortcuts } from '@docsearch/core';\nimport { useEffect } from 'react';\n\ntype UseSidepanelKeyboardEventsProps = {\n onClose: () => void;\n onOpen: () => void;\n isOpen: boolean;\n keyboardShortcuts?: SidepanelShortcuts;\n};\n\nexport function useSidepanelKeyboardEvents({\n onClose,\n onOpen,\n isOpen,\n keyboardShortcuts,\n}: UseSidepanelKeyboardEventsProps): void {\n useEffect(() => {\n function onKeyDown(e: KeyboardEvent): void {\n if (isOpen && e.code === 'Escape') {\n onClose();\n return;\n }\n\n const cmdIEnabled = keyboardShortcuts?.['Ctrl/Cmd+I'] !== false;\n\n if (!cmdIEnabled) return;\n\n const isCmdI = e.key?.toLowerCase() === 'i' && (e.metaKey || e.ctrlKey);\n\n if (isCmdI) {\n e.preventDefault();\n\n if (isOpen) {\n onClose();\n } else {\n onOpen();\n }\n }\n }\n\n window.addEventListener('keydown', onKeyDown);\n\n return (): void => {\n window.removeEventListener('keydown', onKeyDown);\n };\n }, [isOpen, onClose, onOpen, keyboardShortcuts]);\n}\n","import React from 'react';\n\nconst BASE_WIDTH = 360;\nconst EXPANDED_WIDTH = 580;\n\ntype UseSidepanelWidthProps = {\n isExpanded: boolean;\n width?: number | string;\n expandedWidth?: number | string;\n};\n\nexport const useSidepanelWidth = ({\n isExpanded,\n width,\n expandedWidth,\n}: UseSidepanelWidthProps): string => {\n const baseWidth = React.useMemo(() => {\n return typeof width === 'number'\n ? `${width}px`\n : (width ?? `${BASE_WIDTH}px`);\n }, [width]);\n\n const resolvedExpandedWidth = React.useMemo(() => {\n return typeof expandedWidth === 'number'\n ? `${expandedWidth}px`\n : (expandedWidth ?? `${EXPANDED_WIDTH}px`);\n }, [expandedWidth]);\n\n const expectedWidth = isExpanded ? resolvedExpandedWidth : baseWidth;\n\n return expectedWidth;\n};\n","import type { SidepanelShortcuts, InitialAskAiMessage } from '@docsearch/core';\nimport React, { useCallback } from 'react';\nimport type { JSX } from 'react';\n\nimport { AlgoliaLogo, type AlgoliaLogoTranslations } from '../AlgoliaLogo';\nimport type {\n DocSearchSidepanelProps,\n SidepanelSearchParameters,\n} from '../Sidepanel';\nimport type { StoredAskAiState, SuggestedQuestionHit } from '../types';\nimport { useAskAi } from '../useAskAi';\nimport { useIsMobile } from '../useIsMobile';\nimport { useSearchClient } from '../useSearchClient';\nimport { useSuggestedQuestions } from '../useSuggestedQuestions';\nimport { EMPTY_TOOLS, buildDummyAskAiHit } from '../utils/ai';\n\nimport { ConversationHistoryScreen } from './ConversationHistoryScreen';\nimport type { ConversationScreenTranslations } from './ConversationScreen';\nimport { ConversationScreen } from './ConversationScreen';\nimport type { NewConversationScreenTranslations } from './NewConversationScreen';\nimport { NewConversationScreen } from './NewConversationScreen';\nimport { PromptForm, type PromptFormTranslations } from './PromptForm';\nimport { setSidepanelSearchClient } from './setSidepanelSearchClient';\nimport type { HeaderTranslations } from './SidepanelHeader';\nimport { SidepanelHeader } from './SidepanelHeader';\nimport type { PanelSide, PanelVariant, SidepanelState } from './types';\nimport { useManageSidepanelLayout } from './useManageSidepanelLayout';\nimport { useSidepanelKeyboardEvents } from './useSidepanelKeyboardEvents';\nimport { useSidepanelWidth } from './useSidepanelWidth';\n\n/**\n * Imperative handle exposed by the Sidepanel component for programmatic\n * control.\n */\nexport interface SidepanelRef {\n /** Opens the sidepanel. */\n open: () => void;\n /** Closes the sidepanel. */\n close: () => void;\n /** Returns true once the component is mounted and ready. */\n readonly isReady: boolean;\n /** Returns true if the sidepanel is currently open. */\n readonly isOpen: boolean;\n}\n\nexport type SidepanelTranslations = Partial<{\n /** Translation texts for the Sidepanel header. */\n header: HeaderTranslations;\n /** Translation texts for the prompt form. */\n promptForm: PromptFormTranslations;\n /** Translation texts for the conversation screen. */\n conversationScreen: ConversationScreenTranslations;\n /** Translation texts for the new conversation/starting screen. */\n newConversationScreen: NewConversationScreenTranslations;\n /** Translation text for the Algolia logo. */\n logo: AlgoliaLogoTranslations;\n}>;\n\nexport type SidepanelProps = Pick<\n DocSearchSidepanelProps,\n 'indices' | 'memory' | 'tools'\n> & {\n /**\n * Variant of the Sidepanel positioning.\n *\n * - `inline` pushes page content when opened\n * - `floating` is positioned above all other content on page.\n *\n * @default 'floating'\n */\n variant?: PanelVariant;\n /**\n * Side of the page which the panel will originate from.\n *\n * @default 'right'\n */\n side?: PanelSide;\n /**\n * The selector of the element to push when Sidepanel opens with `inline`\n * variant.\n *\n * @default `'#root, main, .app, body'`\n */\n pushSelector?: string;\n /**\n * Width of the Sidepanel (px or any CSS width).\n *\n * @default `360px`\n */\n width?: number | string;\n /**\n * Width when expanded (px or any CSS width).\n *\n * @default `580px`\n */\n expandedWidth?: number | string;\n /**\n * The container element where the panel should be portaled to.\n *\n * @default `document.body`\n */\n portalContainer?: DocumentFragment | Element | null;\n /**\n * Enables displaying suggested questions on new conversation screen.\n *\n * @default false\n */\n suggestedQuestions?: boolean;\n /** Translations specific to the Sidepanel panel. */\n translations?: SidepanelTranslations;\n /**\n * Configuration for keyboard shortcuts. Allows enabling/disabling specific\n * shortcuts.\n *\n * @default `{ 'Ctrl/Cmd+I': true }`\n */\n keyboardShortcuts?: SidepanelShortcuts;\n};\n\ntype Props = Omit<\n DocSearchSidepanelProps,\n 'button' | 'indices' | 'memory' | 'panel' | 'tools'\n> &\n SidepanelProps &\n SidepanelSearchParameters & {\n isOpen?: boolean;\n onOpen: () => void;\n onClose: () => void;\n initialMessage?: InitialAskAiMessage;\n };\n\nfunction SidepanelInner(\n {\n isOpen = false,\n onOpen,\n onClose,\n assistantId,\n apiKey,\n appId,\n indexName,\n variant = 'floating',\n searchParameters,\n pushSelector,\n width,\n expandedWidth,\n suggestedQuestions: suggestedQuestionsEnabled = false,\n translations = {},\n keyboardShortcuts,\n side = 'right',\n initialMessage,\n tools = EMPTY_TOOLS,\n memory,\n indices,\n }: Props,\n ref: React.ForwardedRef<SidepanelRef>\n): JSX.Element {\n const [isExpanded, setIsExpanded] = React.useState(false);\n const [sidepanelState, setSidepanelState] =\n React.useState<SidepanelState>('new-conversation');\n const [stoppedStreaming, setStoppedStreaming] = React.useState(false);\n const sidepanelContainerRef = React.useRef<HTMLDivElement>(null);\n const promptInputRef = React.useRef<HTMLTextAreaElement>(null);\n const isMobile = useIsMobile();\n\n const expectedWidth = useSidepanelWidth({\n isExpanded,\n width,\n expandedWidth,\n });\n\n const selectors = React.useMemo(\n () => pushSelector ?? '#root, main, .app, body',\n [pushSelector]\n );\n\n const toggleIsExpanded = useCallback((): void => {\n setIsExpanded(!isExpanded);\n }, [isExpanded]);\n\n const searchClient = useSearchClient(appId, apiKey, setSidepanelSearchClient);\n\n const {\n chatId,\n status,\n sendMessage,\n stopAskAiStreaming,\n isStreaming,\n exchanges,\n conversations,\n messages,\n sendFeedback,\n askAiError,\n startNewConversation,\n restoreConversation,\n } = useAskAi({\n appId,\n indexName,\n assistantId,\n apiKey,\n searchParameters,\n tools,\n memory,\n indices,\n });\n\n const suggestedQuestions = useSuggestedQuestions({\n assistantId,\n suggestedQuestionsEnabled,\n searchClient,\n });\n\n const prevStatus = React.useRef(status);\n\n const handleSend = React.useCallback(\n (prompt: string): void => {\n setStoppedStreaming(false);\n\n sendMessage({ text: prompt });\n setSidepanelState('conversation');\n },\n [sendMessage]\n );\n\n const handleStartNewConversation = (): void => {\n startNewConversation();\n setSidepanelState('new-conversation');\n };\n\n const handleSelectQuestion = (question: SuggestedQuestionHit): void => {\n setStoppedStreaming(false);\n startNewConversation();\n sendMessage(\n { text: question.question },\n {\n body: {\n suggestedQuestionId: question.objectID,\n },\n }\n );\n setSidepanelState('conversation');\n };\n\n const handleStopStreaming = (): void => {\n setStoppedStreaming(true);\n stopAskAiStreaming();\n };\n\n const handleSelectConversation = React.useCallback(\n (conversation: StoredAskAiState): void => {\n if (conversation.messages) {\n restoreConversation(conversation.messages, conversation.chatId);\n } else if (conversation.query) {\n sendMessage({ text: conversation.query });\n }\n\n setSidepanelState('conversation');\n },\n [sendMessage, restoreConversation]\n );\n\n useManageSidepanelLayout({\n variant,\n expectedWidth,\n selectors,\n isOpen,\n side,\n });\n\n useSidepanelKeyboardEvents({\n onClose,\n onOpen,\n isOpen,\n keyboardShortcuts,\n });\n\n // Expose imperative handle for programmatic control\n React.useImperativeHandle(\n ref,\n () => ({\n open: onOpen,\n close: onClose,\n get isReady(): boolean {\n return true;\n },\n get isOpen(): boolean {\n return isOpen;\n },\n }),\n [onOpen, onClose, isOpen]\n );\n\n React.useEffect(() => {\n if (prevStatus.current === 'streaming' && status === 'ready') {\n if (stoppedStreaming && messages.at(-1)) {\n messages.at(-1)!.metadata = {\n stopped: true,\n };\n }\n\n for (const part of messages[0].parts) {\n if (part.type === 'text') {\n conversations.add(buildDummyAskAiHit(part.text, messages, chatId));\n }\n }\n }\n\n prevStatus.current = status;\n }, [conversations, status, messages, stoppedStreaming, chatId]);\n\n React.useEffect(() => {\n function setFullViewportHeight(): void {\n if (sidepanelContainerRef.current) {\n const vh = window.innerHeight * 0.01;\n sidepanelContainerRef.current.style.setProperty('--sp-vh', `${vh}px`);\n }\n }\n\n setFullViewportHeight();\n\n window.addEventListener('resize', setFullViewportHeight);\n\n return (): void => {\n window.removeEventListener('resize', setFullViewportHeight);\n };\n }, []);\n\n React.useEffect(() => {\n if (!initialMessage) return;\n\n let selectedConversation: StoredAskAiState | undefined;\n\n if (initialMessage.messageId) {\n selectedConversation = conversations.getConversation?.(\n initialMessage.messageId\n );\n }\n\n if (selectedConversation) {\n handleSelectConversation(selectedConversation);\n } else {\n startNewConversation();\n sendMessage(\n {\n text: initialMessage.query,\n },\n initialMessage.suggestedQuestionId\n ? {\n body: {\n suggestedQuestionId: initialMessage.suggestedQuestionId,\n },\n }\n : {}\n );\n setSidepanelState('conversation');\n }\n }, [\n initialMessage,\n sendMessage,\n conversations,\n handleSelectConversation,\n startNewConversation,\n ]);\n\n // Autofocus the prompt input when the sidepanel opens and blur it when\n // it closes. Disabled on mobile because focusing the textarea triggers the\n // virtual keyboard which disrupts the layout — this is a known issue that\n // has not been resolved yet.\n React.useEffect(() => {\n if (isOpen && !isMobile) {\n promptInputRef.current?.focus();\n }\n\n if (!isOpen) {\n promptInputRef.current?.blur();\n }\n }, [isOpen, isMobile]);\n\n return (\n <div\n className={`DocSearch-Sidepanel-Container ${variant} side-${side}${isOpen ? ' is-open' : ''}${isExpanded ? ' is-expanded' : ''}`}\n style={\n {\n '--sp-width': expectedWidth,\n } as React.CSSProperties\n }\n role=\"dialog\"\n tabIndex={-1}\n ref={sidepanelContainerRef}\n >\n <aside\n id=\"docsearch-sidepanel\"\n className={`DocSearch-Sidepanel ${sidepanelState}`}\n >\n <SidepanelHeader\n sidepanelState={sidepanelState}\n exchanges={exchanges}\n setSidepanelState={setSidepanelState}\n hasConversations={conversations.getAll().length > 0}\n isStreaming={isStreaming}\n onNewConversation={handleStartNewConversation}\n onToggleExpanded={toggleIsExpanded}\n onClose={onClose}\n />\n <div className=\"DocSearch-Sidepanel-Content\">\n {sidepanelState === 'new-conversation' && (\n <NewConversationScreen\n suggestedQuestions={suggestedQuestions}\n translations={translations.newConversationScreen}\n onSelectQuestion={handleSelectQuestion}\n />\n )}\n {sidepanelState === 'conversation' && (\n <ConversationScreen\n exchanges={exchanges}\n status={status}\n conversations={conversations}\n handleFeedback={sendFeedback}\n translations={translations.conversationScreen}\n streamError={askAiError}\n memoryEnabled={memory?.enabled ?? false}\n tools={tools}\n onSelectPromptSuggestion={handleSend}\n />\n )}\n {sidepanelState === 'conversation-history' && (\n <ConversationHistoryScreen\n conversations={conversations}\n selectConversation={handleSelectConversation}\n />\n )}\n </div>\n <PromptForm\n ref={promptInputRef}\n exchanges={exchanges}\n isStreaming={isStreaming}\n translations={translations.promptForm}\n onSend={handleSend}\n onStopStreaming={handleStopStreaming}\n />\n <footer className=\"DocSearch-Sidepanel-Footer\">\n <span className=\"DocSearch-Logo DocSearch-Sidepanel--powered-by\">\n <AlgoliaLogo translations={translations.logo} />\n </span>\n </footer>\n </aside>\n </div>\n );\n}\n\nexport const Sidepanel = React.forwardRef(SidepanelInner);\n","import type { SidepanelShortcuts } from '@docsearch/core';\nimport React, { useEffect, useState } from 'react';\nimport type { JSX } from 'react';\n\nimport { SparklesIcon } from '../icons';\nimport { ACTION_KEY_APPLE, ACTION_KEY_DEFAULT, isAppleDevice } from '../utils';\n\nexport type SidepanelButtonTranslations = Partial<{\n /**\n * Text to be displayed when button has variant: `inline`.\n *\n * @default 'Ask AI'\n */\n buttonText: string;\n /**\n * Aria label text for the button.\n *\n * @default 'Ask AI'\n */\n buttonAriaLabel: string;\n}>;\n\nexport type ButtonVariant = 'floating' | 'inline';\n\nexport type SidepanelButtonProps = {\n /**\n * Variant of the button positioning and styling.\n *\n * - `inline` displays the button inline where rendered, with extra text\n * - `floating` displays the button floating in bottom right of screen with just\n * icon.\n *\n * @default 'floating'\n */\n variant?: ButtonVariant;\n /** Translations specific to the Sidepanel button. */\n translations?: SidepanelButtonTranslations;\n /**\n * Configuration for keyboard shortcuts. Allows enabling/disabling specific\n * shortcuts.\n *\n * @default `{ 'Ctrl/Cmd+I': true }`\n */\n keyboardShortcuts?: SidepanelShortcuts;\n};\n\ntype Props = React.ComponentProps<'button'> & SidepanelButtonProps;\n\nexport const SidepanelButton = ({\n variant = 'floating',\n keyboardShortcuts,\n translations = {},\n ...props\n}: Props): JSX.Element => {\n const { buttonText = 'Ask AI', buttonAriaLabel = 'Ask AI' } = translations;\n const [key, setKey] = useState<\n typeof ACTION_KEY_APPLE | typeof ACTION_KEY_DEFAULT | null\n >(null);\n\n useEffect(() => {\n if (typeof navigator !== 'undefined') {\n isAppleDevice() ? setKey(ACTION_KEY_APPLE) : setKey(ACTION_KEY_DEFAULT);\n }\n }, []);\n\n const actionKeyAltText = key === ACTION_KEY_DEFAULT ? 'Control' : 'Meta';\n const isCtrlCmdIEnabled = keyboardShortcuts?.['Ctrl/Cmd+I'] !== false;\n const shortcut = `${actionKeyAltText}+i`;\n\n return (\n <button\n className={`DocSearch-SidepanelButton ${variant}`}\n type=\"button\"\n aria-label={\n isCtrlCmdIEnabled ? `${buttonAriaLabel} (${shortcut})` : buttonAriaLabel\n }\n aria-keyshortcuts={isCtrlCmdIEnabled ? shortcut : undefined}\n {...(variant === 'floating' ? { tabIndex: -1 } : {})}\n {...props}\n >\n <SparklesIcon />\n {variant !== 'floating' && buttonText}\n </button>\n );\n};\n","import { DocSearch, useDocSearch } from '@docsearch/core';\nimport type {\n DocSearchCallbacks,\n DocSearchRef,\n DocSearchTheme,\n SidepanelShortcuts,\n} from '@docsearch/core';\nimport type { JSX } from 'react';\nimport React from 'react';\nimport { createPortal } from 'react-dom';\n\nimport type {\n AgentStudioIndices,\n AgentStudioSearchParameters,\n Memory,\n} from './DocSearchAI';\nimport type {\n SidepanelButtonProps,\n SidepanelProps as SidepanelPanelProps,\n} from './Sidepanel/index';\nimport { SidepanelButton, Sidepanel } from './Sidepanel/index';\nimport type { ToolCalls } from './types/AskiAi';\n\nexport type { DocSearchRef, DocSearchCallbacks } from '@docsearch/core';\n\nexport type SidepanelSearchParameters = {\n /**\n * The search parameters to use for the ask AI feature. Keyed by the index\n * name.\n *\n * @example\n * {\n * \"INDEX_NAME\": { distinct: false }\n * }\n */\n searchParameters?: AgentStudioSearchParameters;\n};\n\nexport type DocSearchSidepanelProps = DocSearchCallbacks & {\n /** The assistant ID to use for the ask AI feature. */\n assistantId: string;\n /** Public api key with search permissions for the index. */\n apiKey: string;\n /** Algolia application id used by the search client. */\n appId: string;\n /**\n * The index name to use for the ask AI feature. Your assistant will search\n * this index for relevant documents.\n */\n indexName: string;\n /**\n * Configuration for keyboard shortcuts. Allows enabling/disabling specific\n * shortcuts.\n *\n * @default `{ 'Ctrl/Cmd+I': true }`\n */\n keyboardShortcuts?: SidepanelShortcuts;\n /**\n * Theme overrides applied to the Sidepanel button and panel.\n *\n * @default 'light'\n */\n theme?: DocSearchTheme;\n /** Props specific to the Sidepanel button. */\n button?: Omit<SidepanelButtonProps, 'keyboardShortcuts'>;\n /** Props specific to the Sidepanel panel. */\n panel?: Omit<SidepanelPanelProps, 'keyboardShortcuts'>;\n /**\n * Use custom tools driven by Agent Studio.\n *\n * For best performance, memoize this object with `useMemo` or define it\n * outside the component. Inline object literals will be recreated every\n * render but will not affect correctness.\n */\n tools?: ToolCalls;\n /**\n * Configuration for the Agent Studio memory feature.\n *\n * @example\n * { enabled: true, userToken: '{{SERVER_GENERATED_JWT_TOKEN}}' }\n *\n * @see https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/memory/overview\n */\n memory?: Memory;\n /** List of dynamic indices for the Agent Studio search tool to use. */\n indices?: AgentStudioIndices[];\n};\n\ntype SidepanelProps = DocSearchSidepanelProps & SidepanelSearchParameters;\n\nfunction DocSearchSidepanelComponent(\n {\n keyboardShortcuts,\n theme,\n onReady,\n onOpen,\n onClose,\n onSidepanelOpen,\n onSidepanelClose,\n ...props\n }: SidepanelProps,\n ref: React.ForwardedRef<DocSearchRef>\n): JSX.Element {\n return (\n <DocSearch\n keyboardShortcuts={keyboardShortcuts}\n theme={theme}\n ref={ref}\n onReady={onReady}\n onOpen={onOpen}\n onClose={onClose}\n onSidepanelOpen={onSidepanelOpen}\n onSidepanelClose={onSidepanelClose}\n >\n <DocSearchSidepanelComp {...props} />\n </DocSearch>\n );\n}\n\nexport const DocSearchSidepanel = React.forwardRef(DocSearchSidepanelComponent);\n\nfunction DocSearchSidepanelComp({\n button: buttonProps = {},\n panel: { portalContainer, ...panelProps } = {},\n ...rootProps\n}: DocSearchSidepanelProps): JSX.Element {\n const {\n docsearchState,\n setDocsearchState,\n keyboardShortcuts,\n registerView,\n initialAskAiMessage,\n } = useDocSearch();\n\n const toggleSidepanelState = React.useCallback(() => {\n setDocsearchState(docsearchState === 'sidepanel' ? 'ready' : 'sidepanel');\n }, [docsearchState, setDocsearchState]);\n\n const handleClose = (): void => {\n setDocsearchState('ready');\n };\n\n const handleOpen = (): void => {\n setDocsearchState('sidepanel');\n };\n\n const containerElement = React.useMemo(\n () => portalContainer ?? document.body,\n [portalContainer]\n );\n\n React.useEffect(() => {\n registerView('sidepanel');\n }, [registerView]);\n\n const ButtonComp = React.useMemo(\n () => (\n <SidepanelButton\n keyboardShortcuts={keyboardShortcuts}\n onClick={toggleSidepanelState}\n {...buttonProps}\n />\n ),\n [keyboardShortcuts, toggleSidepanelState, buttonProps]\n );\n\n return (\n <>\n {buttonProps.variant === 'inline'\n ? ButtonComp\n : createPortal(ButtonComp, containerElement)}\n {createPortal(\n <Sidepanel\n initialMessage={initialAskAiMessage}\n isOpen={docsearchState === 'sidepanel'}\n onClose={handleClose}\n onOpen={handleOpen}\n {...rootProps}\n {...panelProps}\n keyboardShortcuts={keyboardShortcuts}\n />,\n containerElement\n )}\n </>\n );\n}\n\nexport * from './Sidepanel/index';\n"],"mappings":"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"}
1
+ {"version":3,"file":"sidepanel.js","names":[],"sources":["../../src/icons/SendIcon.tsx","../../src/icons/ExpandIcon.tsx","../../src/icons/FolderIcon.tsx","../../src/icons/EditIcon.tsx","../../src/useIsMobile.ts","../../src/Sidepanel/ConversationHistoryScreen.tsx","../../src/Sidepanel/AggregatedSearchBlock.tsx","../../src/Sidepanel/ConversationScreen.tsx","../../src/Sidepanel/NewConversationScreen.tsx","../../src/Sidepanel/PromptForm.tsx","../../src/Sidepanel/setSidepanelSearchClient.ts","../../src/Sidepanel/SidepanelHeader.tsx","../../src/Sidepanel/useManageSidepanelLayout.ts","../../src/Sidepanel/useSidepanelKeyboardEvents.ts","../../src/Sidepanel/useSidepanelWidth.ts","../../src/Sidepanel/Sidepanel.tsx","../../src/Sidepanel/SidepanelButton.tsx","../../src/Sidepanel.tsx"],"sourcesContent":["import type { JSX } from 'react';\nimport React from 'react';\n\nexport const SendIcon = (): 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=\"m5 12 7-7 7 7\" />\n <path d=\"M12 19V5\" />\n </svg>\n );\n};\n","import type { JSX } from 'react';\nimport React from 'react';\n\nexport const ExpandIcon = (): JSX.Element => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 13 13\"\n fill=\"none\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M8 0.5C8 0.223858 8.22386 0 8.5 0H12.5C12.7761 0 13 0.223858 13 0.5V4.5C13 4.77614 12.7761 5 12.5 5C12.2239 5 12 4.77614 12 4.5V1.70711L8.18689 5.52022C7.99162 5.71548 7.67504 5.71548 7.47978 5.52022C7.28452 5.32496 7.28452 5.00838 7.47978 4.81311L11.2929 1H8.5C8.22386 1 8 0.776142 8 0.5ZM5.52022 7.47978C5.71548 7.67504 5.71548 7.99162 5.52022 8.18689L1.70711 12H4.5C4.77614 12 5 12.2239 5 12.5C5 12.7761 4.77614 13 4.5 13H0.5C0.223858 13 0 12.7761 0 12.5V8.5C0 8.22386 0.223858 8 0.5 8C0.776142 8 1 8.22386 1 8.5V11.2929L4.81311 7.47978C5.00838 7.28452 5.32496 7.28452 5.52022 7.47978Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n};\n","import React from 'react';\nimport type { JSX } from 'react';\n\nexport const FolderIcon = (): JSX.Element => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\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=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n );\n};\n","import React from 'react';\nimport type { JSX } from 'react';\n\nexport const EditIcon = (): JSX.Element => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\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=\"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z\" />\n </svg>\n );\n};\n","import React from 'react';\n\nexport const useIsMobile = (): boolean => {\n const [isMobile, setIsMobile] = React.useState(false);\n\n React.useEffect(() => {\n const checkForMobile = (): void => {\n const isMobileMediaQuery = window.matchMedia('(max-width: 768px)');\n\n setIsMobile(isMobileMediaQuery.matches);\n };\n\n checkForMobile();\n\n window.addEventListener('resize', checkForMobile);\n\n return (): void => {\n window.removeEventListener('resize', checkForMobile);\n };\n }, []);\n\n return isMobile;\n};\n","/* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */\nimport React from 'react';\nimport type { JSX } from 'react';\n\nimport { CloseIcon, RecentIcon } from '../icons';\nimport type { StoredSearchPlugin } from '../stored-searches';\nimport type { StoredAskAiState } from '../types';\n\ntype ConversationHistoryScreenProps = {\n conversations: StoredSearchPlugin<StoredAskAiState>;\n selectConversation: (conversation: StoredAskAiState) => void;\n};\n\nexport const ConversationHistoryScreen = ({\n conversations,\n selectConversation,\n}: ConversationHistoryScreenProps): JSX.Element => {\n const [items, setItems] = React.useState(() => conversations.getAll());\n\n const handleRemoveConversation = (item: StoredAskAiState): void => {\n conversations.remove(item);\n setItems(conversations.getAll());\n };\n\n return (\n <div className=\"DocSearch-Sidepanel-ConversationHistoryScreen\">\n <ul>\n {items.map((item) => (\n <li\n key={item.objectID}\n className=\"DocSearch-Sidepanel-RecentConversation\"\n >\n <a\n href={item.url}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n\n selectConversation(item);\n }}\n >\n <div className=\"DocSearch-Sidepanel-RecentConversation-container\">\n <div className=\"DocSearch-Sidepanel-RecentConversation-icon\">\n <RecentIcon />\n </div>\n\n <div className=\"DocSearch-Sidepanel-RecentConversation-content\">\n <span className=\"DocSearch-Sidepanel-RecentConversation-title\">\n {item.hierarchy.lvl1}\n </span>\n </div>\n\n <div className=\"DocSearch-Hit-action\">\n <button\n className=\"DocSearch-Hit-action-button\"\n type=\"button\"\n title=\"Remove conversation from history\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n handleRemoveConversation(item);\n }}\n >\n <CloseIcon />\n </button>\n </div>\n </div>\n </a>\n </li>\n ))}\n </ul>\n </div>\n );\n};\n","import React, { Fragment } from 'react';\nimport type { JSX } from 'react';\n\nimport { SearchIcon } from '../icons';\n\ntype AggregatedSearchBlockProps = {\n queries: string[];\n};\n\nconst before = 'Searched for ';\nconst separator = ', ';\nconst lastSeparator = ' and ';\nconst after = '';\n\nexport function AggregatedSearchBlock({\n queries,\n}: AggregatedSearchBlockProps): JSX.Element {\n return (\n <div className=\"DocSearch-AskAiScreen-MessageContent-Tool Tool--AggregatedResult\">\n <SearchIcon size={18} />\n <span>\n {before && <span>{before}</span>}\n {queries.map((q, idx) => (\n // eslint-disable-next-line react/no-array-index-key\n <Fragment key={q + idx}>\n <span className=\"DocSearch-AskAiScreen-MessageContent-Tool-Query\">\n &quot;{q}&quot;\n </span>\n {idx < queries.length - 2 && separator}\n {idx === queries.length - 2 && lastSeparator}\n </Fragment>\n ))}\n {after && <span>{after}</span>}\n </span>\n </div>\n );\n}\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport type { JSX } from 'react';\nimport React, { memo, useMemo } from 'react';\n\nimport { type Exchange } from '../AskAiScreen';\nimport { ConversationPromptSuggestions } from '../components/ConversationPromptSuggestions';\nimport { FeedbackActions } from '../components/FeedbackActions';\nimport { SourcesPanel } from '../components/SourcesPanel';\nimport { ToolCall, type ToolCallTranslations } from '../components/ToolCall';\nimport { AlertIcon, LoadingIcon } from '../icons';\nimport { MemoizedMarkdown } from '../MemoizedMarkdown';\nimport type { StoredSearchPlugin } from '../stored-searches';\nimport type { OnAskAiFeedback, StoredAskAiState } from '../types';\nimport { type AIMessage, type ToolCalls } from '../types/AskiAi';\nimport {\n extractLinksFromMessage,\n getMessageContent,\n EMPTY_TOOLS,\n isAIToolPart,\n getAgentPromptSuggestions,\n} from '../utils/ai';\nimport { groupConsecutiveToolResults } from '../utils/groupConsecutiveToolResults';\n\nimport { AggregatedSearchBlock } from './AggregatedSearchBlock';\n\nexport type ConversationScreenTranslations = Partial<\n ToolCallTranslations & {\n /** Text shown as an LLM disclaimer. */\n conversationDisclaimer: string;\n /** Text shown while assistant is reasoning. */\n reasoningText: string;\n /** Text show while assistant is thinking. */\n thinkingText: string;\n /** Text shown describing related sources. */\n relatedSourcesText: string;\n /** Message that's shown when user has stopped the streaming of a message. */\n stoppedStreamingText: string;\n /** Text shown for copy button on code snippets. */\n copyButtonText: string;\n /** Message shown after clicking copy. */\n copyButtonCopiedText: string;\n /** Title for thumbs up feedback icon. */\n likeButtonTitle: string;\n /** Title for thumbs down feedback icon. */\n dislikeButtonTitle: string;\n /** Message displayed after feedback action. */\n thanksForFeedbackText: string;\n /** Title shown at the top of the negative feedback note panel. */\n feedbackPanelTitle: string;\n /** Placeholder for the negative feedback details textarea. */\n feedbackDetailsPlaceholder: string;\n /** Disclaimer shown inside the negative feedback note panel. */\n feedbackDisclaimerText: string;\n /** Submit button text for the negative feedback note panel. */\n feedbackSubmitButtonText: string;\n /** Accessible title for the negative feedback note panel close button. */\n feedbackCloseButtonTitle: string;\n /** Reason chip labels for the negative feedback note panel. */\n feedbackTagIncorrect: string;\n feedbackTagNotWhatIAsked: string;\n feedbackTagSlowOrBuggy: string;\n feedbackTagStyleOrTone: string;\n feedbackTagSafetyOrLegal: string;\n feedbackTagOther: string;\n /** Error title shown if there is an error while chatting. */\n errorTitleText;\n suggestedPromptsTitleText: string;\n }\n>;\n\nexport type ConversationScreenProps = {\n exchanges: Exchange[];\n conversations: StoredSearchPlugin<StoredAskAiState>;\n translations?: ConversationScreenTranslations;\n status: UseChatHelpers<AIMessage>['status'];\n handleFeedback?: OnAskAiFeedback;\n streamError?: Error;\n memoryEnabled?: boolean;\n tools?: ToolCalls;\n onSelectPromptSuggestion: (prompt: string) => void;\n};\n\ntype ConversationnExchangeProps = {\n exchange: Exchange;\n isLastExchange: boolean;\n status: ConversationScreenProps['status'];\n conversations: ConversationScreenProps['conversations'];\n translations?: ConversationScreenTranslations;\n onFeedback?: ConversationScreenProps['handleFeedback'];\n streamError?: ConversationScreenProps['streamError'];\n memoryEnabled?: boolean;\n tools: ToolCalls;\n onSelectPromptSuggestion: (prompt: string) => void;\n};\n\nconst ConversationExchange = React.forwardRef<\n HTMLDivElement,\n ConversationnExchangeProps\n>(\n (\n {\n exchange,\n translations = {},\n isLastExchange,\n conversations,\n onFeedback,\n status,\n streamError,\n memoryEnabled,\n tools,\n onSelectPromptSuggestion,\n },\n conversationRef\n ): JSX.Element => {\n const { userMessage, assistantMessage } = exchange;\n\n const {\n reasoningText = 'Reasoning...',\n thinkingText = 'Thinking...',\n searchingText = 'Searching...',\n relatedSourcesText,\n stoppedStreamingText = 'You stopped this response',\n preToolCallText = 'Searching...',\n toolCallResultText = 'Searched for',\n copyButtonText = 'Copy',\n copyButtonCopiedText = 'Copied!',\n errorTitleText = 'Chat error',\n savedMemoryToolResultText = 'Saved to memory',\n memoryToolResultText = 'Used memory to enhance results',\n suggestedPromptsTitleText = 'Suggested prompts',\n } = translations;\n\n const assistantContent = useMemo(\n () => getMessageContent(assistantMessage),\n [assistantMessage]\n );\n const userContent = useMemo(\n () => getMessageContent(userMessage),\n [userMessage]\n );\n\n const assistantParts = useMemo(\n () => groupConsecutiveToolResults(assistantMessage?.parts || []),\n [assistantMessage]\n );\n const urlsToDisplay = React.useMemo(\n () => extractLinksFromMessage(assistantMessage),\n [assistantMessage]\n );\n const suggestedPrompts = React.useMemo(() => {\n if (!isLastExchange) return [];\n return getAgentPromptSuggestions(assistantMessage?.parts || []);\n }, [assistantMessage, isLastExchange]);\n\n const wasStopped =\n userMessage.metadata?.stopped || assistantMessage?.metadata?.stopped;\n const isThinking =\n ['submitted', 'streaming'].includes(status) &&\n !assistantParts.some((part) => part.type !== 'step-start');\n const showActions =\n !wasStopped &&\n (!isLastExchange ||\n (isLastExchange && status === 'ready' && Boolean(assistantMessage)));\n\n const messageId = assistantMessage?.id || exchange.id;\n\n return (\n <div\n className=\"DocSearch-AskAiScreen-Response-Container\"\n ref={conversationRef}\n >\n <div className=\"DocSearch-AskAiScreen-Response\">\n <div className=\"DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user\">\n <p className=\"DocSearch-AskAiScreen-Query\">\n {userContent?.text ?? ''}\n </p>\n </div>\n <div className=\"DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant\">\n <div className=\"DocSearch-AskAiScreen-MessageContent\">\n {status === 'error' && streamError && isLastExchange && (\n <div className=\"DocSearch-AskAiScreen-Error\" role=\"alert\">\n <AlertIcon aria-hidden=\"true\" />\n <div className=\"DocSearch-AskAiScreen-Error-Content\">\n <h4 className=\"DocSearch-AskAiScreen-Error-Title\">\n {errorTitleText}\n </h4>\n <MemoizedMarkdown\n content={streamError.message}\n copyButtonText=\"\"\n copyButtonCopiedText=\"\"\n isStreaming={false}\n />\n </div>\n </div>\n )}\n\n {assistantParts.map((part, idx) => {\n const index = idx;\n\n if (part.type === 'reasoning' && part.state === 'streaming') {\n return (\n <div\n key={index}\n className=\"DocSearch-AskAiScreen-MessageContent-Reasoning DocSearch-shimmer\"\n >\n <LoadingIcon className=\"DocSearch-AskAiScreen-SmallerLoadingIcon\" />\n <span className=\"DocSearch-shimmer\">{reasoningText}</span>\n </div>\n );\n }\n\n if (part.type === 'aggregated-tool-call') {\n return (\n <AggregatedSearchBlock key={index} queries={part.queries} />\n );\n }\n\n if (isAIToolPart(part)) {\n return (\n <ToolCall\n key={index}\n part={part}\n translations={{\n preToolCallText,\n searchingText,\n toolCallResultText,\n savedMemoryToolResultText,\n memoryToolResultText,\n }}\n tools={tools}\n memoryEnabled={memoryEnabled}\n />\n );\n }\n\n if (typeof part === 'string') {\n return (\n <MemoizedMarkdown\n key={index}\n content={part}\n copyButtonText={copyButtonText}\n copyButtonCopiedText={copyButtonCopiedText}\n isStreaming={false}\n />\n );\n }\n\n if (part.type === 'text') {\n return (\n <MemoizedMarkdown\n key={index}\n content={part.text}\n copyButtonText={copyButtonText}\n copyButtonCopiedText={copyButtonCopiedText}\n isStreaming={part.state === 'streaming'}\n />\n );\n }\n\n return null;\n })}\n\n {isThinking && isLastExchange && assistantParts.length === 0 && (\n <div\n className=\"DocSearch-AskAiScreen-MessageContent-Thinking\"\n role=\"status\"\n >\n <span className=\"DocSearch-shimmer\">{thinkingText}</span>\n <span className=\"DocSearch-AskAi-Thinking-Skeleton DocSearch-shimmer\" />\n <span className=\"DocSearch-AskAi-Thinking-Skeleton DocSearch-AskAi-Thinking-Skeleton--short DocSearch-shimmer\" />\n </div>\n )}\n </div>\n\n {wasStopped && (\n <p className=\"DocSearch-AskAiScreen-MessageContent-Stopped\">\n {stoppedStreamingText}\n </p>\n )}\n </div>\n\n <div className=\"DocSearch-AskAiScreen-Answer-Footer\">\n <SourcesPanel\n links={urlsToDisplay}\n titleText={relatedSourcesText}\n />\n <FeedbackActions\n isSidepanel={true}\n id={messageId}\n showActions={showActions}\n latestAssistantMessageContent={assistantContent?.text || null}\n translations={translations}\n conversations={conversations}\n onFeedback={onFeedback}\n />\n </div>\n\n {suggestedPrompts.length > 0 && (\n <ConversationPromptSuggestions\n title={suggestedPromptsTitleText}\n suggestions={suggestedPrompts}\n onSelectPromptSuggestion={onSelectPromptSuggestion}\n />\n )}\n </div>\n </div>\n );\n }\n);\n\nexport const ConversationScreen = memo(\n ({\n exchanges,\n translations = {},\n handleFeedback,\n tools = EMPTY_TOOLS,\n status,\n conversations,\n streamError,\n memoryEnabled,\n onSelectPromptSuggestion,\n }: ConversationScreenProps): JSX.Element => {\n const {\n conversationDisclaimer = 'Answers are generated with AI which can make mistakes. Verify responses.',\n } = translations;\n\n const mostRecentExchangeRef = React.useRef<HTMLDivElement>(null);\n const totalExchanges = exchanges.length;\n\n // Only scroll the most recent exchange into view when needed\n React.useEffect(() => {\n if (mostRecentExchangeRef.current) {\n mostRecentExchangeRef.current.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n });\n }\n }, [totalExchanges]);\n\n return (\n <div className=\"DocSearch-Sidepanel-ConversationScreen\">\n <p className=\"DocSearch-Sidepanel-ConversationScreen-disclaimer\">\n {conversationDisclaimer}\n </p>\n\n {exchanges.slice().map((exchange, idx) => {\n const isLastExchange = idx === exchanges.length - 1;\n return (\n <ConversationExchange\n key={exchange.id}\n exchange={exchange}\n translations={translations}\n isLastExchange={isLastExchange}\n ref={isLastExchange ? mostRecentExchangeRef : null}\n tools={tools}\n status={status}\n conversations={conversations}\n streamError={streamError}\n memoryEnabled={memoryEnabled}\n onFeedback={handleFeedback}\n onSelectPromptSuggestion={onSelectPromptSuggestion}\n />\n );\n })}\n </div>\n );\n }\n);\n","import type { JSX } from 'react';\nimport React from 'react';\n\nimport type { SuggestedQuestionHit } from '../types';\n\nexport type NewConversationScreenTranslations = Partial<{\n /** Title to be shown on the new conversation/starting screen. */\n titleText: string;\n /** Introduction text displayed on the new conversation/starting screen. */\n introductionText: string;\n}>;\n\ntype NewConversationScreenProps = {\n suggestedQuestions: SuggestedQuestionHit[];\n onSelectQuestion: (question: SuggestedQuestionHit) => void;\n translations?: NewConversationScreenTranslations;\n};\n\nexport const NewConversationScreen = ({\n suggestedQuestions,\n onSelectQuestion,\n translations = {},\n}: NewConversationScreenProps): JSX.Element => {\n const {\n titleText = 'How can I help you today?',\n introductionText = 'I search through your documentation to help you find setup guides, feature details and troubleshooting tips, fast.',\n } = translations;\n\n return (\n <div className=\"DocSearch-Sidepanel-NewConversationScreen\">\n <h4 className=\"DocSearch-Sidepanel-Screen--title\">{titleText}</h4>\n <p className=\"DocSearch-Sidepanel-Screen--introduction\">\n {introductionText}\n </p>\n\n <div className=\"DocSearch-Sidepanel-List\">\n {suggestedQuestions.map((q) => (\n <button\n key={q.objectID}\n type=\"button\"\n className=\"DocSearch-Sidepanel-SuggestedQuestion\"\n title=\"View conversation\"\n onClick={() => {\n onSelectQuestion(q);\n }}\n >\n <span>{q.question}</span>\n </button>\n ))}\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport type { JSX } from 'react';\n\nimport type { Exchange } from '../AskAiScreen';\nimport { SendIcon, StopIcon } from '../icons';\nimport { useIsMobile } from '../useIsMobile';\n\nexport type PromptFormTranslations = Partial<{\n /** Initial placeholder for the prompt input. */\n promptPlaceholderText: string;\n /** Placeholder text for wile a conversation is streaming. */\n promptAnsweringText: string;\n /** Placeholder text for after a question has already been asked. */\n promptAskAnotherQuestionText: string;\n /** Disclaimer text displayed beneath the prompt form. */\n promptDisclaimerText: string;\n promptLabelText: string;\n promptAriaLabelText: string;\n}>;\n\ntype Props = {\n exchanges: Exchange[];\n isStreaming: boolean;\n translations?: PromptFormTranslations;\n onSend: (prompt: string) => void;\n onStopStreaming: () => void;\n};\n\nconst MAX_PROMPT_ROWS = 8;\n\nexport const PromptForm = React.forwardRef<HTMLTextAreaElement, Props>(\n (\n { exchanges, isStreaming, translations = {}, onSend, onStopStreaming },\n ref\n ): JSX.Element => {\n const isMobile = useIsMobile();\n const [userPrompt, setUserPrompt] = React.useState('');\n const promptRef = React.useRef<HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(\n ref,\n () => promptRef.current as HTMLTextAreaElement\n );\n\n const {\n promptPlaceholderText = 'Ask a question',\n promptAnsweringText = 'Answering...',\n promptAskAnotherQuestionText = 'Ask another question',\n promptDisclaimerText = 'Answers are generated with AI which can make mistakes.',\n promptLabelText = 'Press Enter to send, or Shift and Enter for new line.',\n promptAriaLabelText = 'Prompt input',\n } = translations;\n\n const managePromptHeight = (): void => {\n if (!promptRef.current) return;\n\n const textArea = promptRef.current;\n const styles = getComputedStyle(textArea);\n\n const lineHeight = parseFloat(styles.lineHeight);\n const paddingTop = parseFloat(styles.paddingTop);\n const paddingBottom = parseFloat(styles.paddingBottom);\n const padding = paddingTop + paddingBottom;\n\n textArea.style.height = 'auto';\n\n const fullHeight = textArea.scrollHeight;\n const maxHeight = MAX_PROMPT_ROWS * lineHeight + padding;\n\n textArea.style.overflowY = fullHeight > maxHeight ? 'auto' : 'hidden';\n textArea.style.height = `${Math.min(fullHeight, maxHeight)}px`;\n };\n\n const handleSend = (): void => {\n if (isStreaming) return;\n\n const prompt = userPrompt.trim();\n\n if (prompt === '') return;\n\n onSend(prompt);\n\n setUserPrompt('');\n\n requestAnimationFrame(() => {\n promptRef.current?.focus();\n\n managePromptHeight();\n });\n };\n\n const handleKeyDown = (\n e: React.KeyboardEvent<HTMLTextAreaElement>\n ): void => {\n // Allow Enter to work normally (new line) when streaming\n if (isStreaming) return;\n\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n\n handleSend();\n }\n };\n\n React.useLayoutEffect(() => {\n managePromptHeight();\n }, [isMobile]);\n\n let promptPlaceholder = promptPlaceholderText;\n\n if (isStreaming) {\n promptPlaceholder = promptAnsweringText;\n } else if (exchanges.length > 0) {\n promptPlaceholder = promptAskAnotherQuestionText;\n }\n\n return (\n <div className=\"DocSearch-Sidepanel-Prompt\">\n <form\n className=\"DocSearch-Sidepanel-Prompt--form\"\n onSubmit={(e) => {\n e.preventDefault();\n\n if (isStreaming) return;\n\n handleSend();\n }}\n >\n <textarea\n ref={promptRef}\n placeholder={promptPlaceholder}\n className=\"DocSearch-Sidepanel-Prompt--textarea\"\n value={userPrompt}\n aria-label={promptAriaLabelText}\n aria-labelledby=\"prompt-label\"\n autoComplete=\"off\"\n translate=\"no\"\n rows={isMobile ? 1 : 2}\n onKeyDown={handleKeyDown}\n onInput={managePromptHeight}\n onChange={(e) => setUserPrompt(e.target.value)}\n />\n <span id=\"prompt-label\" className=\"sr-only\">\n {promptLabelText}\n </span>\n <div className=\"DocSearch-Sidepanel-Prompt--actions\">\n {isStreaming && (\n <button\n type=\"button\"\n title=\"Stop streaming\"\n className=\"DocSearch-Sidepanel-Prompt--stop\"\n onClick={onStopStreaming}\n >\n <StopIcon />\n </button>\n )}\n {!isStreaming && (\n <button\n type=\"submit\"\n aria-label=\"Send question\"\n title=\"Send question\"\n className=\"DocSearch-Sidepanel-Prompt--submit\"\n aria-disabled={userPrompt === ''}\n >\n <SendIcon />\n </button>\n )}\n </div>\n </form>\n <p className=\"DocSearch-Sidepanel-Prompt--disclaimer\">\n {promptDisclaimerText}\n </p>\n </div>\n );\n }\n);\n","import type { DocSearchTransformClient } from '..';\nimport { version } from '../version';\n\nexport const setSidepanelSearchClient = (\n client: DocSearchTransformClient\n): DocSearchTransformClient => {\n if (\n /docsearch-sidepanel.js \\(.*\\)/.test(\n client.transporter.algoliaAgent.value\n ) === false\n ) {\n client.addAlgoliaAgent('docsearch-sidepanel', version);\n }\n\n return client;\n};\n","import type { JSX } from 'react';\nimport React from 'react';\n\nimport type { Exchange } from '../AskAiScreen';\nimport {\n CloseIcon,\n ConversationHistoryIcon,\n EditIcon,\n ExpandIcon,\n FolderIcon,\n MoreVerticalIcon,\n NewConversationIcon,\n SparklesIcon,\n} from '../icons';\nimport { BackIcon } from '../icons/BackIcon';\nimport { Menu } from '../Menu';\nimport { useIsMobile } from '../useIsMobile';\n\nimport type { SidepanelState } from './types';\n\ntype BackButtonProps = {\n mobile?: boolean;\n onBack: () => void;\n disabled?: boolean;\n};\n\nconst BackButton = ({\n onBack,\n mobile = false,\n disabled = false,\n}: BackButtonProps): JSX.Element => {\n return (\n <button\n type=\"button\"\n className={`DocSearch-Action DocSearch-Sidepanel-Action-back${mobile ? ' mobile' : ''}`}\n title=\"Go back to previous screen\"\n aria-disabled={disabled}\n onClick={disabled ? undefined : onBack}\n >\n <BackIcon />\n </button>\n );\n};\n\nexport type HeaderTranslations = Partial<{\n /** The main title text shown on the header. */\n title: string;\n /** The title text shown on the conversation history screen. */\n conversationHistoryTitle: string;\n /** The text shown on the start a conversation button. */\n newConversationText: string;\n /** The text shown on the view conversation history button. */\n viewConversationHistoryText: string;\n}>;\n\ntype SidepanelHeaderProps = {\n sidepanelState: SidepanelState;\n exchanges: Exchange[];\n setSidepanelState: (state: SidepanelState) => void;\n onNewConversation: () => void;\n onToggleExpanded: () => void;\n onClose: () => void;\n translations?: HeaderTranslations;\n hasConversations: boolean;\n isStreaming: boolean;\n};\n\nexport const SidepanelHeader = React.memo(\n ({\n sidepanelState,\n exchanges,\n setSidepanelState,\n onNewConversation,\n onToggleExpanded,\n onClose,\n translations = {},\n hasConversations,\n isStreaming,\n }: SidepanelHeaderProps): JSX.Element => {\n const {\n title = 'Ask AI',\n conversationHistoryTitle = 'My conversation history',\n newConversationText = 'Start a new conversation',\n viewConversationHistoryText = 'Conversation history',\n } = translations;\n\n const isMobile = useIsMobile();\n\n const goToConversationHistory = (): void => {\n setSidepanelState('conversation-history');\n };\n\n const onBack = React.useCallback((): void => {\n if (exchanges.length > 0) {\n setSidepanelState('conversation');\n } else {\n setSidepanelState('new-conversation');\n }\n }, [exchanges, setSidepanelState]);\n\n const newConversationDisabled =\n sidepanelState === 'new-conversation' && exchanges.length < 1;\n\n let header = title;\n\n if (sidepanelState === 'conversation-history') {\n header = conversationHistoryTitle;\n }\n\n if (isMobile) {\n header = title;\n }\n\n return (\n <header className=\"DocSearch-Sidepanel-Header\">\n <div className=\"DocSearch-Sidepanel-Header--left\">\n <BackButton mobile={true} disabled={isStreaming} onBack={onBack} />\n\n {sidepanelState === 'conversation-history' && (\n <div className=\"DocSearch-Divider\" />\n )}\n\n <button\n type=\"button\"\n className=\"DocSearch-Action\"\n title={newConversationText}\n onClick={onNewConversation}\n >\n <EditIcon />\n </button>\n\n <div className=\"DocSearch-Divider\" />\n\n <button\n type=\"button\"\n className=\"DocSearch-Action\"\n title={viewConversationHistoryText}\n onClick={goToConversationHistory}\n >\n <FolderIcon />\n </button>\n </div>\n <div className=\"DocSearch-Sidepanel-Header--center\">\n <BackButton disabled={isStreaming} onBack={onBack} />\n <SparklesIcon className=\"DocSearch-Sidepanel-Header-TitleIcon\" />\n <h2 className=\"DocSearch-Sidepanel-Title\">{header}</h2>\n </div>\n <div className=\"DocSearch-Sidepanel-Header--right\">\n {sidepanelState !== 'conversation-history' &&\n (!newConversationDisabled || hasConversations) && (\n <Menu>\n <Menu.Trigger\n className=\"DocSearch-Action DocSearch-Sidepanel-Action-menu\"\n disabled={isStreaming}\n >\n <MoreVerticalIcon />\n </Menu.Trigger>\n <Menu.Content>\n {!newConversationDisabled && (\n <Menu.Item onClick={onNewConversation}>\n <NewConversationIcon />\n {newConversationText}\n </Menu.Item>\n )}\n {hasConversations && (\n <Menu.Item onClick={goToConversationHistory}>\n <ConversationHistoryIcon />\n {viewConversationHistoryText}\n </Menu.Item>\n )}\n </Menu.Content>\n </Menu>\n )}\n <button\n type=\"button\"\n className=\"DocSearch-Action DocSearch-Sidepanel-Action-expand\"\n title=\"Expand or collapse Sidepanel\"\n onClick={onToggleExpanded}\n >\n <ExpandIcon />\n </button>\n <button\n type=\"button\"\n className=\"DocSearch-Action DocSearch-Sidepanel-Action-close\"\n title=\"Close Sidepanel\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n </div>\n </header>\n );\n }\n);\n","import { useLayoutEffect, useRef } from 'react';\n\nimport { useIsMobile } from '../useIsMobile';\n\nimport type { PanelSide, PanelVariant } from './types';\n\ntype UseManageSidepanelLayoutProps = {\n variant: PanelVariant;\n side: PanelSide;\n selectors: string;\n isOpen: boolean;\n expectedWidth: string;\n};\n\nexport function useManageSidepanelLayout({\n variant,\n selectors,\n isOpen,\n expectedWidth,\n side,\n}: UseManageSidepanelLayoutProps): void {\n const targetRef = useRef<HTMLElement | null>(null);\n const lastSelectorRef = useRef<string | null>(null);\n const isMobile = useIsMobile();\n\n useLayoutEffect(() => {\n if (variant === 'floating' || isMobile) return;\n\n if (lastSelectorRef.current !== selectors) {\n if (targetRef.current) {\n if (side === 'left') {\n targetRef.current.style.marginLeft = '';\n } else {\n targetRef.current.style.marginRight = '';\n }\n targetRef.current.style.transition = '';\n }\n\n const candidates = Array.from(document.querySelectorAll(selectors));\n const nextTarget: HTMLElement | null =\n (candidates[0] as HTMLElement) || document.body;\n targetRef.current = nextTarget;\n lastSelectorRef.current = selectors;\n\n if (targetRef.current) {\n targetRef.current.style.transition = `margin-${side} 280ms cubic-bezier(0.22, 1, 0.36, 1)`;\n }\n }\n\n const target = targetRef.current;\n if (!target) return;\n\n const offset = isOpen ? expectedWidth : '0px';\n\n if (side === 'left') {\n target.style.marginLeft = offset;\n } else {\n target.style.marginRight = offset;\n }\n }, [isOpen, expectedWidth, variant, selectors, side, isMobile]);\n\n useLayoutEffect(() => {\n return (): void => {\n if (targetRef.current) {\n if (side === 'left') {\n targetRef.current.style.marginLeft = '';\n } else {\n targetRef.current.style.marginRight = '';\n }\n targetRef.current.style.transition = '';\n }\n };\n }, [side]);\n}\n","import type { SidepanelShortcuts } from '@docsearch/core';\nimport { useEffect } from 'react';\n\ntype UseSidepanelKeyboardEventsProps = {\n onClose: () => void;\n onOpen: () => void;\n isOpen: boolean;\n keyboardShortcuts?: SidepanelShortcuts;\n};\n\nexport function useSidepanelKeyboardEvents({\n onClose,\n onOpen,\n isOpen,\n keyboardShortcuts,\n}: UseSidepanelKeyboardEventsProps): void {\n useEffect(() => {\n function onKeyDown(e: KeyboardEvent): void {\n if (isOpen && e.code === 'Escape') {\n onClose();\n return;\n }\n\n const cmdIEnabled = keyboardShortcuts?.['Ctrl/Cmd+I'] !== false;\n\n if (!cmdIEnabled) return;\n\n const isCmdI = e.key?.toLowerCase() === 'i' && (e.metaKey || e.ctrlKey);\n\n if (isCmdI) {\n e.preventDefault();\n\n if (isOpen) {\n onClose();\n } else {\n onOpen();\n }\n }\n }\n\n window.addEventListener('keydown', onKeyDown);\n\n return (): void => {\n window.removeEventListener('keydown', onKeyDown);\n };\n }, [isOpen, onClose, onOpen, keyboardShortcuts]);\n}\n","import React from 'react';\n\nconst BASE_WIDTH = 360;\nconst EXPANDED_WIDTH = 580;\n\ntype UseSidepanelWidthProps = {\n isExpanded: boolean;\n width?: number | string;\n expandedWidth?: number | string;\n};\n\nexport const useSidepanelWidth = ({\n isExpanded,\n width,\n expandedWidth,\n}: UseSidepanelWidthProps): string => {\n const baseWidth = React.useMemo(() => {\n return typeof width === 'number'\n ? `${width}px`\n : (width ?? `${BASE_WIDTH}px`);\n }, [width]);\n\n const resolvedExpandedWidth = React.useMemo(() => {\n return typeof expandedWidth === 'number'\n ? `${expandedWidth}px`\n : (expandedWidth ?? `${EXPANDED_WIDTH}px`);\n }, [expandedWidth]);\n\n const expectedWidth = isExpanded ? resolvedExpandedWidth : baseWidth;\n\n return expectedWidth;\n};\n","import type { SidepanelShortcuts, InitialAskAiMessage } from '@docsearch/core';\nimport React, { useCallback } from 'react';\nimport type { JSX } from 'react';\n\nimport { AlgoliaLogo, type AlgoliaLogoTranslations } from '../AlgoliaLogo';\nimport type {\n DocSearchSidepanelProps,\n SidepanelSearchParameters,\n} from '../Sidepanel';\nimport type { StoredAskAiState, SuggestedQuestionHit } from '../types';\nimport { useAskAi } from '../useAskAi';\nimport { useIsMobile } from '../useIsMobile';\nimport { useSearchClient } from '../useSearchClient';\nimport { useSuggestedQuestions } from '../useSuggestedQuestions';\nimport { EMPTY_TOOLS, buildDummyAskAiHit } from '../utils/ai';\n\nimport { ConversationHistoryScreen } from './ConversationHistoryScreen';\nimport type { ConversationScreenTranslations } from './ConversationScreen';\nimport { ConversationScreen } from './ConversationScreen';\nimport type { NewConversationScreenTranslations } from './NewConversationScreen';\nimport { NewConversationScreen } from './NewConversationScreen';\nimport { PromptForm, type PromptFormTranslations } from './PromptForm';\nimport { setSidepanelSearchClient } from './setSidepanelSearchClient';\nimport type { HeaderTranslations } from './SidepanelHeader';\nimport { SidepanelHeader } from './SidepanelHeader';\nimport type { PanelSide, PanelVariant, SidepanelState } from './types';\nimport { useManageSidepanelLayout } from './useManageSidepanelLayout';\nimport { useSidepanelKeyboardEvents } from './useSidepanelKeyboardEvents';\nimport { useSidepanelWidth } from './useSidepanelWidth';\n\n/**\n * Imperative handle exposed by the Sidepanel component for programmatic\n * control.\n */\nexport interface SidepanelRef {\n /** Opens the sidepanel. */\n open: () => void;\n /** Closes the sidepanel. */\n close: () => void;\n /** Returns true once the component is mounted and ready. */\n readonly isReady: boolean;\n /** Returns true if the sidepanel is currently open. */\n readonly isOpen: boolean;\n}\n\nexport type SidepanelTranslations = Partial<{\n /** Translation texts for the Sidepanel header. */\n header: HeaderTranslations;\n /** Translation texts for the prompt form. */\n promptForm: PromptFormTranslations;\n /** Translation texts for the conversation screen. */\n conversationScreen: ConversationScreenTranslations;\n /** Translation texts for the new conversation/starting screen. */\n newConversationScreen: NewConversationScreenTranslations;\n /** Translation text for the Algolia logo. */\n logo: AlgoliaLogoTranslations;\n}>;\n\nexport type SidepanelProps = Pick<\n DocSearchSidepanelProps,\n 'indices' | 'memory' | 'tools'\n> & {\n /**\n * Variant of the Sidepanel positioning.\n *\n * - `inline` pushes page content when opened\n * - `floating` is positioned above all other content on page.\n *\n * @default 'floating'\n */\n variant?: PanelVariant;\n /**\n * Side of the page which the panel will originate from.\n *\n * @default 'right'\n */\n side?: PanelSide;\n /**\n * The selector of the element to push when Sidepanel opens with `inline`\n * variant.\n *\n * @default `'#root, main, .app, body'`\n */\n pushSelector?: string;\n /**\n * Width of the Sidepanel (px or any CSS width).\n *\n * @default `360px`\n */\n width?: number | string;\n /**\n * Width when expanded (px or any CSS width).\n *\n * @default `580px`\n */\n expandedWidth?: number | string;\n /**\n * The container element where the panel should be portaled to.\n *\n * @default `document.body`\n */\n portalContainer?: DocumentFragment | Element | null;\n /**\n * Enables displaying suggested questions on new conversation screen.\n *\n * @default false\n */\n suggestedQuestions?: boolean;\n /** Translations specific to the Sidepanel panel. */\n translations?: SidepanelTranslations;\n /**\n * Configuration for keyboard shortcuts. Allows enabling/disabling specific\n * shortcuts.\n *\n * @default `{ 'Ctrl/Cmd+I': true }`\n */\n keyboardShortcuts?: SidepanelShortcuts;\n};\n\ntype Props = Omit<\n DocSearchSidepanelProps,\n 'button' | 'indices' | 'memory' | 'panel' | 'tools'\n> &\n SidepanelProps &\n SidepanelSearchParameters & {\n isOpen?: boolean;\n onOpen: () => void;\n onClose: () => void;\n initialMessage?: InitialAskAiMessage;\n };\n\nfunction SidepanelInner(\n {\n isOpen = false,\n onOpen,\n onClose,\n assistantId,\n apiKey,\n appId,\n indexName,\n variant = 'floating',\n searchParameters,\n pushSelector,\n width,\n expandedWidth,\n suggestedQuestions: suggestedQuestionsEnabled = false,\n translations = {},\n keyboardShortcuts,\n side = 'right',\n initialMessage,\n tools = EMPTY_TOOLS,\n memory,\n indices,\n }: Props,\n ref: React.ForwardedRef<SidepanelRef>\n): JSX.Element {\n const [isExpanded, setIsExpanded] = React.useState(false);\n const [sidepanelState, setSidepanelState] =\n React.useState<SidepanelState>('new-conversation');\n const [stoppedStreaming, setStoppedStreaming] = React.useState(false);\n const sidepanelContainerRef = React.useRef<HTMLDivElement>(null);\n const promptInputRef = React.useRef<HTMLTextAreaElement>(null);\n const isMobile = useIsMobile();\n\n const expectedWidth = useSidepanelWidth({\n isExpanded,\n width,\n expandedWidth,\n });\n\n const selectors = React.useMemo(\n () => pushSelector ?? '#root, main, .app, body',\n [pushSelector]\n );\n\n const toggleIsExpanded = useCallback((): void => {\n setIsExpanded(!isExpanded);\n }, [isExpanded]);\n\n const searchClient = useSearchClient(appId, apiKey, setSidepanelSearchClient);\n\n const {\n chatId,\n status,\n sendMessage,\n stopAskAiStreaming,\n isStreaming,\n exchanges,\n conversations,\n messages,\n sendFeedback,\n askAiError,\n startNewConversation,\n restoreConversation,\n } = useAskAi({\n appId,\n indexName,\n assistantId,\n apiKey,\n searchParameters,\n tools,\n memory,\n indices,\n });\n\n const suggestedQuestions = useSuggestedQuestions({\n assistantId,\n suggestedQuestionsEnabled,\n searchClient,\n });\n\n const prevStatus = React.useRef(status);\n\n const handleSend = React.useCallback(\n (prompt: string): void => {\n setStoppedStreaming(false);\n\n sendMessage({ text: prompt });\n setSidepanelState('conversation');\n },\n [sendMessage]\n );\n\n const handleStartNewConversation = (): void => {\n startNewConversation();\n setSidepanelState('new-conversation');\n };\n\n const handleSelectQuestion = (question: SuggestedQuestionHit): void => {\n setStoppedStreaming(false);\n startNewConversation();\n sendMessage(\n { text: question.question },\n {\n body: {\n suggestedQuestionId: question.objectID,\n },\n }\n );\n setSidepanelState('conversation');\n };\n\n const handleStopStreaming = (): void => {\n setStoppedStreaming(true);\n stopAskAiStreaming();\n };\n\n const handleSelectConversation = React.useCallback(\n (conversation: StoredAskAiState): void => {\n if (conversation.messages) {\n restoreConversation(conversation.messages, conversation.chatId);\n } else if (conversation.query) {\n sendMessage({ text: conversation.query });\n }\n\n setSidepanelState('conversation');\n },\n [sendMessage, restoreConversation]\n );\n\n useManageSidepanelLayout({\n variant,\n expectedWidth,\n selectors,\n isOpen,\n side,\n });\n\n useSidepanelKeyboardEvents({\n onClose,\n onOpen,\n isOpen,\n keyboardShortcuts,\n });\n\n // Expose imperative handle for programmatic control\n React.useImperativeHandle(\n ref,\n () => ({\n open: onOpen,\n close: onClose,\n get isReady(): boolean {\n return true;\n },\n get isOpen(): boolean {\n return isOpen;\n },\n }),\n [onOpen, onClose, isOpen]\n );\n\n React.useEffect(() => {\n if (prevStatus.current === 'streaming' && status === 'ready') {\n if (stoppedStreaming && messages.at(-1)) {\n messages.at(-1)!.metadata = {\n stopped: true,\n };\n }\n\n for (const part of messages[0].parts) {\n if (part.type === 'text') {\n conversations.add(buildDummyAskAiHit(part.text, messages, chatId));\n }\n }\n }\n\n prevStatus.current = status;\n }, [conversations, status, messages, stoppedStreaming, chatId]);\n\n React.useEffect(() => {\n function setFullViewportHeight(): void {\n if (sidepanelContainerRef.current) {\n const vh = window.innerHeight * 0.01;\n sidepanelContainerRef.current.style.setProperty('--sp-vh', `${vh}px`);\n }\n }\n\n setFullViewportHeight();\n\n window.addEventListener('resize', setFullViewportHeight);\n\n return (): void => {\n window.removeEventListener('resize', setFullViewportHeight);\n };\n }, []);\n\n React.useEffect(() => {\n if (!initialMessage) return;\n\n let selectedConversation: StoredAskAiState | undefined;\n\n if (initialMessage.messageId) {\n selectedConversation = conversations.getConversation?.(\n initialMessage.messageId\n );\n }\n\n if (selectedConversation) {\n handleSelectConversation(selectedConversation);\n } else {\n startNewConversation();\n sendMessage(\n {\n text: initialMessage.query,\n },\n initialMessage.suggestedQuestionId\n ? {\n body: {\n suggestedQuestionId: initialMessage.suggestedQuestionId,\n },\n }\n : {}\n );\n setSidepanelState('conversation');\n }\n }, [\n initialMessage,\n sendMessage,\n conversations,\n handleSelectConversation,\n startNewConversation,\n ]);\n\n // Autofocus the prompt input when the sidepanel opens and blur it when\n // it closes. Disabled on mobile because focusing the textarea triggers the\n // virtual keyboard which disrupts the layout — this is a known issue that\n // has not been resolved yet.\n React.useEffect(() => {\n if (isOpen && !isMobile) {\n promptInputRef.current?.focus();\n }\n\n if (!isOpen) {\n promptInputRef.current?.blur();\n }\n }, [isOpen, isMobile]);\n\n return (\n <div\n className={`DocSearch-Sidepanel-Container ${variant} side-${side}${isOpen ? ' is-open' : ''}${isExpanded ? ' is-expanded' : ''}`}\n style={\n {\n '--sp-width': expectedWidth,\n } as React.CSSProperties\n }\n role=\"dialog\"\n tabIndex={-1}\n ref={sidepanelContainerRef}\n >\n <aside\n id=\"docsearch-sidepanel\"\n className={`DocSearch-Sidepanel ${sidepanelState}`}\n >\n <SidepanelHeader\n sidepanelState={sidepanelState}\n exchanges={exchanges}\n setSidepanelState={setSidepanelState}\n hasConversations={conversations.getAll().length > 0}\n isStreaming={isStreaming}\n onNewConversation={handleStartNewConversation}\n onToggleExpanded={toggleIsExpanded}\n onClose={onClose}\n />\n <div className=\"DocSearch-Sidepanel-Content\">\n {sidepanelState === 'new-conversation' && (\n <NewConversationScreen\n suggestedQuestions={suggestedQuestions}\n translations={translations.newConversationScreen}\n onSelectQuestion={handleSelectQuestion}\n />\n )}\n {sidepanelState === 'conversation' && (\n <ConversationScreen\n exchanges={exchanges}\n status={status}\n conversations={conversations}\n handleFeedback={sendFeedback}\n translations={translations.conversationScreen}\n streamError={askAiError}\n memoryEnabled={memory?.enabled ?? false}\n tools={tools}\n onSelectPromptSuggestion={handleSend}\n />\n )}\n {sidepanelState === 'conversation-history' && (\n <ConversationHistoryScreen\n conversations={conversations}\n selectConversation={handleSelectConversation}\n />\n )}\n </div>\n <PromptForm\n ref={promptInputRef}\n exchanges={exchanges}\n isStreaming={isStreaming}\n translations={translations.promptForm}\n onSend={handleSend}\n onStopStreaming={handleStopStreaming}\n />\n <footer className=\"DocSearch-Sidepanel-Footer\">\n <span className=\"DocSearch-Logo DocSearch-Sidepanel--powered-by\">\n <AlgoliaLogo translations={translations.logo} />\n </span>\n </footer>\n </aside>\n </div>\n );\n}\n\nexport const Sidepanel = React.forwardRef(SidepanelInner);\n","import type { SidepanelShortcuts } from '@docsearch/core';\nimport React, { useEffect, useState } from 'react';\nimport type { JSX } from 'react';\n\nimport { SparklesIcon } from '../icons';\nimport { ACTION_KEY_APPLE, ACTION_KEY_DEFAULT, isAppleDevice } from '../utils';\n\nexport type SidepanelButtonTranslations = Partial<{\n /**\n * Text to be displayed when button has variant: `inline`.\n *\n * @default 'Ask AI'\n */\n buttonText: string;\n /**\n * Aria label text for the button.\n *\n * @default 'Ask AI'\n */\n buttonAriaLabel: string;\n}>;\n\nexport type ButtonVariant = 'floating' | 'inline';\n\nexport type SidepanelButtonProps = {\n /**\n * Variant of the button positioning and styling.\n *\n * - `inline` displays the button inline where rendered, with extra text\n * - `floating` displays the button floating in bottom right of screen with just\n * icon.\n *\n * @default 'floating'\n */\n variant?: ButtonVariant;\n /** Translations specific to the Sidepanel button. */\n translations?: SidepanelButtonTranslations;\n /**\n * Configuration for keyboard shortcuts. Allows enabling/disabling specific\n * shortcuts.\n *\n * @default `{ 'Ctrl/Cmd+I': true }`\n */\n keyboardShortcuts?: SidepanelShortcuts;\n};\n\ntype Props = React.ComponentProps<'button'> & SidepanelButtonProps;\n\nexport const SidepanelButton = ({\n variant = 'floating',\n keyboardShortcuts,\n translations = {},\n ...props\n}: Props): JSX.Element => {\n const { buttonText = 'Ask AI', buttonAriaLabel = 'Ask AI' } = translations;\n const [key, setKey] = useState<\n typeof ACTION_KEY_APPLE | typeof ACTION_KEY_DEFAULT | null\n >(null);\n\n useEffect(() => {\n if (typeof navigator !== 'undefined') {\n isAppleDevice() ? setKey(ACTION_KEY_APPLE) : setKey(ACTION_KEY_DEFAULT);\n }\n }, []);\n\n const actionKeyAltText = key === ACTION_KEY_DEFAULT ? 'Control' : 'Meta';\n const isCtrlCmdIEnabled = keyboardShortcuts?.['Ctrl/Cmd+I'] !== false;\n const shortcut = `${actionKeyAltText}+i`;\n\n return (\n <button\n className={`DocSearch-SidepanelButton ${variant}`}\n type=\"button\"\n aria-label={\n isCtrlCmdIEnabled ? `${buttonAriaLabel} (${shortcut})` : buttonAriaLabel\n }\n aria-keyshortcuts={isCtrlCmdIEnabled ? shortcut : undefined}\n {...(variant === 'floating' ? { tabIndex: -1 } : {})}\n {...props}\n >\n <SparklesIcon />\n {variant !== 'floating' && buttonText}\n </button>\n );\n};\n","import { DocSearch, useDocSearch } from '@docsearch/core';\nimport type {\n DocSearchCallbacks,\n DocSearchRef,\n DocSearchTheme,\n SidepanelShortcuts,\n} from '@docsearch/core';\nimport type { JSX } from 'react';\nimport React from 'react';\nimport { createPortal } from 'react-dom';\n\nimport type {\n AgentStudioIndices,\n AgentStudioSearchParameters,\n Memory,\n} from './DocSearchAI';\nimport type {\n SidepanelButtonProps,\n SidepanelProps as SidepanelPanelProps,\n} from './Sidepanel/index';\nimport { SidepanelButton, Sidepanel } from './Sidepanel/index';\nimport type { ToolCalls } from './types/AskiAi';\n\nexport type { DocSearchRef, DocSearchCallbacks } from '@docsearch/core';\n\nexport type SidepanelSearchParameters = {\n /**\n * The search parameters to use for the ask AI feature. Keyed by the index\n * name.\n *\n * @example\n * {\n * \"INDEX_NAME\": { distinct: false }\n * }\n */\n searchParameters?: AgentStudioSearchParameters;\n};\n\nexport type DocSearchSidepanelProps = DocSearchCallbacks & {\n /** The assistant ID to use for the ask AI feature. */\n assistantId: string;\n /** Public api key with search permissions for the index. */\n apiKey: string;\n /** Algolia application id used by the search client. */\n appId: string;\n /**\n * The index name to use for the ask AI feature. Your assistant will search\n * this index for relevant documents.\n */\n indexName: string;\n /**\n * Configuration for keyboard shortcuts. Allows enabling/disabling specific\n * shortcuts.\n *\n * @default `{ 'Ctrl/Cmd+I': true }`\n */\n keyboardShortcuts?: SidepanelShortcuts;\n /**\n * Theme overrides applied to the Sidepanel button and panel.\n *\n * @default 'light'\n */\n theme?: DocSearchTheme;\n /** Props specific to the Sidepanel button. */\n button?: Omit<SidepanelButtonProps, 'keyboardShortcuts'>;\n /** Props specific to the Sidepanel panel. */\n panel?: Omit<SidepanelPanelProps, 'keyboardShortcuts'>;\n /**\n * Use custom tools driven by Agent Studio.\n *\n * For best performance, memoize this object with `useMemo` or define it\n * outside the component. Inline object literals will be recreated every\n * render but will not affect correctness.\n */\n tools?: ToolCalls;\n /**\n * Configuration for the Agent Studio memory feature.\n *\n * @example\n * { enabled: true, userToken: '{{SERVER_GENERATED_JWT_TOKEN}}' }\n *\n * @see https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/memory/overview\n */\n memory?: Memory;\n /** List of dynamic indices for the Agent Studio search tool to use. */\n indices?: AgentStudioIndices[];\n};\n\ntype SidepanelProps = DocSearchSidepanelProps & SidepanelSearchParameters;\n\nfunction DocSearchSidepanelComponent(\n {\n keyboardShortcuts,\n theme,\n onReady,\n onOpen,\n onClose,\n onSidepanelOpen,\n onSidepanelClose,\n ...props\n }: SidepanelProps,\n ref: React.ForwardedRef<DocSearchRef>\n): JSX.Element {\n return (\n <DocSearch\n keyboardShortcuts={keyboardShortcuts}\n theme={theme}\n ref={ref}\n onReady={onReady}\n onOpen={onOpen}\n onClose={onClose}\n onSidepanelOpen={onSidepanelOpen}\n onSidepanelClose={onSidepanelClose}\n >\n <DocSearchSidepanelComp {...props} />\n </DocSearch>\n );\n}\n\nexport const DocSearchSidepanel = React.forwardRef(DocSearchSidepanelComponent);\n\nfunction DocSearchSidepanelComp({\n button: buttonProps = {},\n panel: { portalContainer, ...panelProps } = {},\n ...rootProps\n}: DocSearchSidepanelProps): JSX.Element {\n const {\n docsearchState,\n setDocsearchState,\n keyboardShortcuts,\n registerView,\n initialAskAiMessage,\n } = useDocSearch();\n\n const toggleSidepanelState = React.useCallback(() => {\n setDocsearchState(docsearchState === 'sidepanel' ? 'ready' : 'sidepanel');\n }, [docsearchState, setDocsearchState]);\n\n const handleClose = (): void => {\n setDocsearchState('ready');\n };\n\n const handleOpen = (): void => {\n setDocsearchState('sidepanel');\n };\n\n const containerElement = React.useMemo(\n () => portalContainer ?? document.body,\n [portalContainer]\n );\n\n React.useEffect(() => {\n registerView('sidepanel');\n }, [registerView]);\n\n const ButtonComp = React.useMemo(\n () => (\n <SidepanelButton\n keyboardShortcuts={keyboardShortcuts}\n onClick={toggleSidepanelState}\n {...buttonProps}\n />\n ),\n [keyboardShortcuts, toggleSidepanelState, buttonProps]\n );\n\n return (\n <>\n {buttonProps.variant === 'inline'\n ? ButtonComp\n : createPortal(ButtonComp, containerElement)}\n {createPortal(\n <Sidepanel\n initialMessage={initialAskAiMessage}\n isOpen={docsearchState === 'sidepanel'}\n onClose={handleClose}\n onOpen={handleOpen}\n {...rootProps}\n {...panelProps}\n keyboardShortcuts={keyboardShortcuts}\n />,\n containerElement\n )}\n </>\n );\n}\n\nexport * from './Sidepanel/index';\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import "./index-Dl8FMlR5.js";
1
+ import "./index-Bqqv4HmN.js";
2
2
  import React from "react";
3
3
  //#region src/types/KeyboardShortcuts.d.ts
4
4
  interface KeyboardShortcuts {
@@ -40,4 +40,4 @@ interface UseDocSearchKeyboardEventsProps {
40
40
  declare function useDocSearchKeyboardEvents({ isOpen, onOpen, onClose, isAskAiActive, onAskAiToggle, keyboardShortcuts }: UseDocSearchKeyboardEventsProps): void;
41
41
  //#endregion
42
42
  export { useDocSearchKeyboardEvents as n, KeyboardShortcuts as r, UseDocSearchKeyboardEventsProps as t };
43
- //# sourceMappingURL=useDocSearchKeyboardEvents-68G8dw6c.d.ts.map
43
+ //# sourceMappingURL=useDocSearchKeyboardEvents-u23fFhR9.d.ts.map
@@ -1,2 +1,2 @@
1
- import { n as useDocSearchKeyboardEvents, t as UseDocSearchKeyboardEventsProps } from "./useDocSearchKeyboardEvents-68G8dw6c.js";
1
+ import { n as useDocSearchKeyboardEvents, t as UseDocSearchKeyboardEventsProps } from "./useDocSearchKeyboardEvents-u23fFhR9.js";
2
2
  export { UseDocSearchKeyboardEventsProps, useDocSearchKeyboardEvents };
@@ -579,9 +579,6 @@ function isAIToolPart(part) {
579
579
  function isSearchToolPart(part) {
580
580
  return part.type === "tool-searchIndex" || part.type === "tool-algolia_search_index" || part.type.startsWith("tool-algolia_search_index_");
581
581
  }
582
- function isSearchIndexOutputPart(part) {
583
- return part.type === "tool-searchIndex" && part.state === "output-available";
584
- }
585
582
  function isSearchOutputPart(part) {
586
583
  return isAIToolPart(part) && isSearchToolPart(part) && part.state === "output-available";
587
584
  }
@@ -604,11 +601,25 @@ function getAgentPromptSuggestions(parts) {
604
601
  if (!suggestionsPart) return [];
605
602
  return suggestionsPart.data.suggestions;
606
603
  }
604
+ function getSearchToolQueries(part) {
605
+ if (part.state !== "input-available" && part.state !== "output-available") return [];
606
+ if (part.type === "tool-searchIndex") {
607
+ var _ref, _part$output$query, _part$output, _part$input;
608
+ const query = ((_ref = (_part$output$query = (_part$output = part.output) === null || _part$output === void 0 ? void 0 : _part$output.query) !== null && _part$output$query !== void 0 ? _part$output$query : (_part$input = part.input) === null || _part$input === void 0 ? void 0 : _part$input.query) !== null && _ref !== void 0 ? _ref : "").trim();
609
+ return query ? [query] : [];
610
+ }
611
+ if ("queries" in part.input && Array.isArray(part.input.queries)) return part.input.queries.map(({ query }) => query.trim()).filter(Boolean);
612
+ if ("query" in part.input && typeof part.input.query === "string") {
613
+ const query = part.input.query.trim();
614
+ return query ? [query] : [];
615
+ }
616
+ return [];
617
+ }
607
618
 
608
619
  //#endregion
609
620
  //#region src/components/ui/ToolState.tsx
610
621
  function ToolState({ icon, shimmer = false, children, variant }) {
611
- const className = `DocSearch-AskAiScreen-MessageContent-Tool Tool--${variant}${shimmer ? " shimmer" : ""}`;
622
+ const className = `DocSearch-AskAiScreen-MessageContent-Tool Tool--${variant}${shimmer ? " DocSearch-shimmer" : ""}`;
612
623
  return /* @__PURE__ */ React.createElement("div", { className }, icon, children);
613
624
  }
614
625
 
@@ -622,14 +633,19 @@ function SearchTool({ part, translations, onSearchQueryClick }) {
622
633
  icon: /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }),
623
634
  variant: "PartialCall"
624
635
  }, /* @__PURE__ */ React.createElement("span", null, searchingText));
625
- case "input-available": return /* @__PURE__ */ React.createElement(ToolState, {
626
- shimmer: true,
627
- icon: /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }),
628
- variant: "Call"
629
- }, /* @__PURE__ */ React.createElement("span", null, preToolCallText, " ", `"${part.input.query || ""}" ...`));
636
+ case "input-available": {
637
+ const queries = getSearchToolQueries(part);
638
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, queries.map((q, index) => /* @__PURE__ */ React.createElement(ToolState, {
639
+ key: `${part.toolCallId}-call-${index}`,
640
+ shimmer: true,
641
+ icon: /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }),
642
+ variant: "Call"
643
+ }, /* @__PURE__ */ React.createElement("span", null, preToolCallText, " ", `"${q}" ...`))));
644
+ }
630
645
  case "output-available": {
631
- const query = part.type === "tool-searchIndex" ? part.output.query : part.input.query;
632
- return /* @__PURE__ */ React.createElement(ToolState, {
646
+ const queries = getSearchToolQueries(part);
647
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, queries.map((q, index) => /* @__PURE__ */ React.createElement(ToolState, {
648
+ key: `${part.toolCallId}-result-${index}`,
633
649
  icon: /* @__PURE__ */ React.createElement(SearchIcon, null),
634
650
  variant: "Result"
635
651
  }, /* @__PURE__ */ React.createElement("span", null, toolCallResultText, " ", onSearchQueryClick ? /* @__PURE__ */ React.createElement("span", {
@@ -639,11 +655,11 @@ function SearchTool({ part, translations, onSearchQueryClick }) {
639
655
  onKeyDown: (e) => {
640
656
  if (e.key === "Enter" || e.key === " ") {
641
657
  e.preventDefault();
642
- onSearchQueryClick(query || "");
658
+ onSearchQueryClick(q);
643
659
  }
644
660
  },
645
- onClick: () => onSearchQueryClick(query || "")
646
- }, " ", "\"", query || "", "\"") : /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-MessageContent-Tool-Query" }, " ", "\"", query || "", "\"")));
661
+ onClick: () => onSearchQueryClick(q)
662
+ }, " ", "\"", q, "\"") : /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-MessageContent-Tool-Query" }, " ", "\"", q, "\"")))));
647
663
  }
648
664
  default: return null;
649
665
  }
@@ -780,16 +796,6 @@ MemoizedMarkdown.displayName = "MemoizedMarkdown";
780
796
  //#endregion
781
797
  //#region src/utils/groupConsecutiveToolResults.ts
782
798
  /**
783
- * Extracts the search query from a search tool result part. `searchIndex`
784
- * exposes the query on its output, while the Algolia MCP search tools expose it
785
- * on their input.
786
- */
787
- function getSearchQuery(part) {
788
- var _part$output, _part$input;
789
- const query = isSearchIndexOutputPart(part) ? (_part$output = part.output) === null || _part$output === void 0 ? void 0 : _part$output.query : (_part$input = part.input) === null || _part$input === void 0 ? void 0 : _part$input.query;
790
- return (query !== null && query !== void 0 ? query : "").trim();
791
- }
792
- /**
793
799
  * Groups consecutive search tool invocation result parts together. Both the
794
800
  * `searchIndex` tool and the Algolia MCP search tools (`algolia_search_index`
795
801
  * and `algolia_search_index_*`) are aggregated. Empty or falsy queries are
@@ -806,11 +812,9 @@ function groupConsecutiveToolResults(parts) {
806
812
  while (j < parts.length) {
807
813
  const candidate = parts[j];
808
814
  if (isSearchOutputPart(candidate)) {
809
- const q = getSearchQuery(candidate);
810
- if (q && q.length > 0) {
811
- queries.push(q);
812
- singleQueryPart = candidate;
813
- }
815
+ const queriesForPart = getSearchToolQueries(candidate);
816
+ queries.push(...queriesForPart);
817
+ if (queriesForPart.length > 0) singleQueryPart = candidate;
814
818
  j++;
815
819
  } else break;
816
820
  }
@@ -1109,4 +1113,4 @@ const useSuggestedQuestions = ({ assistantId, searchClient, suggestedQuestionsEn
1109
1113
 
1110
1114
  //#endregion
1111
1115
  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 };
1112
- //# sourceMappingURL=useSuggestedQuestions-D2TGVPsI.js.map
1116
+ //# sourceMappingURL=useSuggestedQuestions-CG2H3qm4.js.map