From ee9fddb152d7180f81e2d21875208925b3d1abd0 Mon Sep 17 00:00:00 2001 From: Paul Jankowski <8bittitan@gmail.com> Date: Thu, 6 Aug 2026 14:40:33 -0400 Subject: [PATCH] feat(v5): Back port cost control errors (#2965) --- .changeset/bright-errors-block.md | 6 + bundlesize.config.json | 2 +- packages/docsearch-css/src/_askai.css | 12 +- packages/docsearch-css/src/sidepanel.css | 22 +++ packages/docsearch-react/src/AskAiScreen.tsx | 79 ++++---- .../docsearch-react/src/AskAiScreenState.tsx | 1 + .../src/DocSearchAskAiModal.tsx | 33 +++- .../src/Sidepanel/ConversationScreen.tsx | 34 ++-- .../src/Sidepanel/PromptForm.tsx | 52 +++++- .../src/Sidepanel/Sidepanel.tsx | 21 ++- .../src/__tests__/askai.test.tsx | 125 ++++++++++++- .../src/__tests__/searchbox.test.tsx | 27 ++- packages/docsearch-react/src/askai.ts | 74 ++++++-- .../src/components/AskAiSearchBox.tsx | 45 +++-- .../src/utils/__tests__/ai.test.ts | 99 ++++++++++ packages/docsearch-react/src/utils/ai.ts | 105 +++++++++++ .../src/utils/askAiBlockingMatchers.ts | 170 ++++++++++++++++++ 17 files changed, 810 insertions(+), 97 deletions(-) create mode 100644 .changeset/bright-errors-block.md create mode 100644 packages/docsearch-react/src/utils/askAiBlockingMatchers.ts diff --git a/.changeset/bright-errors-block.md b/.changeset/bright-errors-block.md new file mode 100644 index 00000000..3299281f --- /dev/null +++ b/.changeset/bright-errors-block.md @@ -0,0 +1,6 @@ +--- +'@docsearch/css': patch +'@docsearch/react': patch +--- + +Surface Agent Studio cost-control errors and block prompts until the user can recover. [#2878](https://github.com/algolia/docsearch/pull/2878) diff --git a/bundlesize.config.json b/bundlesize.config.json index 3b4562c1..6e456483 100644 --- a/bundlesize.config.json +++ b/bundlesize.config.json @@ -2,7 +2,7 @@ "files": [ { "path": "packages/docsearch-css/dist/style.css", - "maxSize": "8.1 kB" + "maxSize": "8.2 kB" }, { "path": "packages/docsearch-react/dist/umd/index.js", diff --git a/packages/docsearch-css/src/_askai.css b/packages/docsearch-css/src/_askai.css index 3db890ac..ad4d6f7f 100644 --- a/packages/docsearch-css/src/_askai.css +++ b/packages/docsearch-css/src/_askai.css @@ -537,10 +537,15 @@ color: var(--docsearch-text-color); font-size: 12px; border: 1px solid var(--docsearch-error-soft-color); - animation: slide-down 0.3s ease-out; width: 100%; } +@media (prefers-reduced-motion: no-preference) { + .DocSearch-AskAiScreen-Error--ThreadDepth { + animation: slide-down 0.3s ease-out; + } +} + @keyframes slide-down { from { opacity: 0; @@ -572,6 +577,11 @@ color: rgb(153 27 27); } +.DocSearch-ThreadDepthError-Link:focus-visible { + outline: 2px solid var(--docsearch-focus-color); + outline-offset: 2px; +} + .DocSearch-AskAiScreen-FeedbackText { font-size: 0.7em; font-weight: 400; diff --git a/packages/docsearch-css/src/sidepanel.css b/packages/docsearch-css/src/sidepanel.css index 1a03b8f2..13d3094c 100644 --- a/packages/docsearch-css/src/sidepanel.css +++ b/packages/docsearch-css/src/sidepanel.css @@ -405,6 +405,28 @@ gap: 0.5rem; } +.DocSearch-Sidepanel-PromptBlockingBanner { + padding: 0.75rem; + color: var(--docsearch-sidepanel-text-base); + font-size: 0.75rem; + border: 1px solid var(--docsearch-error-soft-color); + border-radius: 0.25rem; + background: var(--docsearch-sidepanel-background); +} + +.DocSearch-Sidepanel-PromptBlockingBanner p { + margin: 0; +} + +.DocSearch-Sidepanel-PromptBlockingBanner p + p { + margin-top: 0.5rem; +} + +.DocSearch-Sidepanel-PromptBlockingBanner .DocSearch-ThreadDepthError-Link:focus-visible { + outline: 2px solid var(--docsearch-sidepanel-primary); + outline-offset: 2px; +} + .DocSearch-Sidepanel-Prompt--form:focus-within { border-color: var(--docsearch-sidepanel-primary); } diff --git a/packages/docsearch-react/src/AskAiScreen.tsx b/packages/docsearch-react/src/AskAiScreen.tsx index b2f7e858..3e3bda2a 100644 --- a/packages/docsearch-react/src/AskAiScreen.tsx +++ b/packages/docsearch-react/src/AskAiScreen.tsx @@ -18,8 +18,11 @@ import type { import { type AIMessage, type ToolCalls } from './types/AskiAi'; import { extractLinksFromMessage, + getAskAiBlockingBannerMessage, getMessageContent, + isAskAiPromptBlockingError, isThreadDepthError, + showAskAiBlockingBannerNewConversationLink, isAIToolPart, getAgentPromptSuggestions, } from './utils/ai'; @@ -199,7 +202,7 @@ function AskAiExchangeCard({ [translations] ); - const isThreadDepth = isThreadDepthError(askAiError); + const isPromptBlockingError = isAskAiPromptBlockingError(askAiError); const assistantContent = useMemo( () => getMessageContent(assistantMessage), @@ -252,7 +255,7 @@ function AskAiExchangeCard({ {loadingStatus === 'error' && askAiError && isLastExchange && - !isThreadDepth && ( + !isPromptBlockingError && (
- {threadDepthExceededMessage}{' '} - {' '} - to continue. -
++ {blockingMessage ?? + (isThreadDepthError(askAiError) + ? threadDepthExceededMessage + : 'This conversation cannot continue.')} +
+ {showNewConversationLink && ( ++ {' '} + to continue. +
+ )} +{blockingErrorMessage ?? blockingErrorFallbackText}
+ {showNewConversationLink && ( ++ {' '} + {blockingErrorContinueText} +
+ )} +