Skip to content

Commit f83f5a9

Browse files
feat: agent studio feedback integration (#2868)
Cherry-picked from v5 branch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e20d30d commit f83f5a9

File tree

9 files changed

+171
-117
lines changed

9 files changed

+171
-117
lines changed

examples/demo-react/src/App.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import './App.css';
77
import '@docsearch/css/dist/style.css';
88
import '@docsearch/css/dist/sidepanel.css';
99

10-
import { AgentStudioExample } from './examples/agent-studio';
10+
import AgentStudio from './examples/agent-studio';
11+
import AgentStudioSidepanel from './examples/agent-studio-sidepanel';
1112
import Basic from './examples/basic';
1213
import BasicAskAI from './examples/basic-askai';
1314
import Composable from './examples/composable';
@@ -102,7 +103,14 @@ function App(): JSX.Element {
102103
<section className="demo-section">
103104
<p className="section-description">Agent Studio</p>
104105
<div className="search-wrapper column">
105-
<AgentStudioExample />
106+
<AgentStudio />
107+
</div>
108+
</section>
109+
110+
<section className="demo-section">
111+
<p className="section-description">Agent Studio sidepanel</p>
112+
<div className="search-wrapper column">
113+
<AgentStudioSidepanel />
106114
</div>
107115
</section>
108116
</main>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* eslint-disable react/react-in-jsx-scope */
2+
import { DocSearch } from '@docsearch/core';
3+
import { SidepanelButton } from '@docsearch/sidepanel/button';
4+
import { Sidepanel } from '@docsearch/sidepanel/sidepanel';
5+
import type { JSX } from 'react';
6+
7+
export default function AgentStudioSidepanel(): JSX.Element {
8+
return (
9+
<DocSearch>
10+
<SidepanelButton
11+
variant="inline"
12+
translations={{
13+
buttonText: 'Agent Studio',
14+
}}
15+
/>
16+
<Sidepanel
17+
indexName="docsearch-markdown"
18+
appId="PMZUYBQDAK"
19+
apiKey="a00716d83c64f6c61905c078b7d5ab66"
20+
assistantId="ccdec697-e3fe-465b-a1c3-657e7bf18aef"
21+
agentStudio={true}
22+
/>
23+
</DocSearch>
24+
);
25+
}

examples/demo-react/src/examples/agent-studio.tsx

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,25 @@
22
import { DocSearch } from '@docsearch/core';
33
import { DocSearchButton } from '@docsearch/modal/button';
44
import { DocSearchModal } from '@docsearch/modal/modal';
5-
import { SidepanelButton } from '@docsearch/sidepanel/button';
6-
import { Sidepanel } from '@docsearch/sidepanel/sidepanel';
75
import type { JSX } from 'react';
86

9-
export function AgentStudioExample(): JSX.Element {
7+
export default function AgentStudio(): JSX.Element {
108
return (
11-
<>
12-
<DocSearch>
13-
<DocSearchButton
14-
translations={{
15-
buttonText: 'Ask AI with Agent Studio',
16-
}}
17-
/>
18-
<DocSearchModal
19-
indexName="docsearch"
20-
appId="PMZUYBQDAK"
21-
apiKey="a00716d83c64f6c61905c078b7d5ab66"
22-
askAi={{
23-
assistantId: 'ccdec697-e3fe-465b-a1c3-657e7bf18aef',
24-
agentStudio: true,
25-
}}
26-
/>
27-
</DocSearch>
28-
29-
<DocSearch>
30-
<SidepanelButton
31-
variant="inline"
32-
translations={{
33-
buttonText: 'Agent Studio',
34-
}}
35-
/>
36-
<Sidepanel
37-
indexName="docsearch-markdown"
38-
appId="PMZUYBQDAK"
39-
apiKey="a00716d83c64f6c61905c078b7d5ab66"
40-
assistantId="ccdec697-e3fe-465b-a1c3-657e7bf18aef"
41-
agentStudio={true}
42-
/>
43-
</DocSearch>
44-
</>
9+
<DocSearch>
10+
<DocSearchButton
11+
translations={{
12+
buttonText: 'Ask AI with Agent Studio',
13+
}}
14+
/>
15+
<DocSearchModal
16+
indexName="docsearch"
17+
appId="PMZUYBQDAK"
18+
apiKey="a00716d83c64f6c61905c078b7d5ab66"
19+
askAi={{
20+
assistantId: 'ccdec697-e3fe-465b-a1c3-657e7bf18aef',
21+
agentStudio: true,
22+
}}
23+
/>
24+
</DocSearch>
4525
);
4626
}

packages/docsearch-react/src/AskAiScreen.tsx

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ function AskAiExchangeCard({
140140
isLastExchange &&
141141
!displayParts.some((part) => part.type !== 'step-start');
142142

143+
const messageId = agentStudio ? assistantMessage?.id || exchange.id : userMessage?.id || exchange.id;
144+
143145
return (
144146
<div className="DocSearch-AskAiScreen-Response-Container">
145147
<div className="DocSearch-AskAiScreen-Response">
@@ -236,12 +238,11 @@ function AskAiExchangeCard({
236238
</div>
237239
<div className="DocSearch-AskAiScreen-Answer-Footer">
238240
<AskAiScreenFooterActions
239-
id={userMessage?.id || exchange.id}
241+
id={messageId}
240242
showActions={showActions}
241243
latestAssistantMessageContent={assistantContent?.text || null}
242244
translations={translations}
243245
conversations={conversations}
244-
agentStudio={agentStudio}
245246
onFeedback={onFeedback}
246247
/>
247248
</div>
@@ -262,7 +263,6 @@ interface AskAiScreenFooterActionsProps {
262263
translations: AskAiScreenTranslations;
263264
conversations: StoredSearchPlugin<StoredAskAiState>;
264265
onFeedback?: (messageId: string, thumbs: 0 | 1) => Promise<void>;
265-
agentStudio?: boolean;
266266
}
267267

268268
export function AskAiScreenFooterActions({
@@ -272,7 +272,6 @@ export function AskAiScreenFooterActions({
272272
translations,
273273
conversations,
274274
onFeedback,
275-
agentStudio,
276275
}: AskAiScreenFooterActionsProps): JSX.Element | null {
277276
// local state for feedback, initialised from stored conversations
278277
const initialFeedback = React.useMemo(() => {
@@ -310,26 +309,25 @@ export function AskAiScreenFooterActions({
310309

311310
return (
312311
<div className="DocSearch-AskAiScreen-Actions">
313-
{!agentStudio &&
314-
(feedback === null ? (
315-
<>
316-
{saving ? (
317-
<LoadingIcon className="DocSearch-AskAiScreen-SmallerLoadingIcon" />
318-
) : (
319-
<>
320-
<LikeButton title={likeButtonTitle} onClick={() => handleFeedback('like')} />
321-
<DislikeButton title={dislikeButtonTitle} onClick={() => handleFeedback('dislike')} />
322-
</>
323-
)}
324-
{savingError && (
325-
<p className="DocSearch-AskAiScreen-FeedbackText">{savingError.message || 'An error occured'}</p>
326-
)}
327-
</>
328-
) : (
329-
<p className="DocSearch-AskAiScreen-FeedbackText DocSearch-AskAiScreen-FeedbackText--visible">
330-
{thanksForFeedbackText}
331-
</p>
332-
))}
312+
{feedback === null ? (
313+
<>
314+
{saving ? (
315+
<LoadingIcon className="DocSearch-AskAiScreen-SmallerLoadingIcon" />
316+
) : (
317+
<>
318+
<LikeButton title={likeButtonTitle} onClick={() => handleFeedback('like')} />
319+
<DislikeButton title={dislikeButtonTitle} onClick={() => handleFeedback('dislike')} />
320+
</>
321+
)}
322+
{savingError && (
323+
<p className="DocSearch-AskAiScreen-FeedbackText">{savingError.message || 'An error occured'}</p>
324+
)}
325+
</>
326+
) : (
327+
<p className="DocSearch-AskAiScreen-FeedbackText DocSearch-AskAiScreen-FeedbackText--visible">
328+
{thanksForFeedbackText}
329+
</p>
330+
)}
333331
<CopyButton
334332
translations={translations}
335333
onClick={() => navigator.clipboard.writeText(latestAssistantMessageContent)}
@@ -373,7 +371,7 @@ export function AskAiScreen({ translations = {}, ...props }: AskAiScreenProps):
373371
startNewConversationButtonText = 'Start a new conversation',
374372
} = translations;
375373

376-
const { messages, askAiError, status } = props;
374+
const { messages, askAiError, status, agentStudio } = props;
377375

378376
// Check if there's a thread depth error
379377
const hasThreadDepthError = useMemo(() => {
@@ -448,7 +446,7 @@ export function AskAiScreen({ translations = {}, ...props }: AskAiScreenProps):
448446
loadingStatus={props.status}
449447
translations={translations}
450448
conversations={props.conversations}
451-
agentStudio={props.agentStudio}
449+
agentStudio={agentStudio}
452450
onSearchQueryClick={handleSearchQueryClick}
453451
onFeedback={props.onFeedback}
454452
/>

packages/docsearch-react/src/DocSearchModal.tsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@ import type { ScreenStateTranslations } from './ScreenState';
2020
import { ScreenState } from './ScreenState';
2121
import type { SearchBoxTranslations } from './SearchBox';
2222
import { SearchBox } from './SearchBox';
23-
import { createStoredConversations, createStoredSearches } from './stored-searches';
23+
import { createStoredSearches } from './stored-searches';
2424
import type {
2525
DocSearchHit,
2626
DocSearchState,
2727
InternalDocSearchHit,
2828
StoredAskAiMessage,
29-
StoredAskAiState,
3029
StoredDocSearchHit,
3130
SuggestedQuestionHit,
3231
} from './types';
@@ -384,12 +383,6 @@ export function DocSearchModal({
384383
const defaultIndexName = indexes[0].name;
385384

386385
// storage
387-
const conversations = React.useRef(
388-
createStoredConversations<StoredAskAiState>({
389-
key: `__DOCSEARCH_ASKAI_CONVERSATIONS__${askAiConfig?.indexName || defaultIndexName}`,
390-
limit: 10,
391-
}),
392-
).current;
393386
const favoriteSearches = React.useRef(
394387
createStoredSearches<StoredDocSearchHit>({
395388
key: `__DOCSEARCH_FAVORITE_SEARCHES__${defaultIndexName}`,
@@ -405,15 +398,16 @@ export function DocSearchModal({
405398

406399
const [stoppedStream, setStoppedStream] = React.useState(false);
407400

408-
const { messages, status, setMessages, sendMessage, stopAskAiStreaming, askAiError, sendFeedback } = useAskAi({
409-
assistantId: askAiConfigurationId,
410-
apiKey: askAiConfig?.apiKey || apiKey,
411-
appId: askAiConfig?.appId || appId,
412-
indexName: askAiConfig?.indexName || defaultIndexName,
413-
searchParameters: askAiSearchParameters,
414-
useStagingEnv: askAiUseStagingEnv,
415-
agentStudio,
416-
});
401+
const { messages, status, setMessages, sendMessage, stopAskAiStreaming, askAiError, sendFeedback, conversations } =
402+
useAskAi({
403+
assistantId: askAiConfigurationId,
404+
apiKey: askAiConfig?.apiKey || apiKey,
405+
appId: askAiConfig?.appId || appId,
406+
indexName: askAiConfig?.indexName || defaultIndexName,
407+
searchParameters: askAiSearchParameters,
408+
useStagingEnv: askAiUseStagingEnv,
409+
agentStudio,
410+
});
417411

418412
const prevStatus = React.useRef(status);
419413
React.useEffect(() => {

packages/docsearch-react/src/Sidepanel/ConversationActions.tsx

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ interface ConversationActionsProps {
1414
conversations: StoredSearchPlugin<StoredAskAiState>;
1515
onFeedback?: (messageId: string, thumbs: 0 | 1) => Promise<void>;
1616
isSidepanel?: boolean;
17-
agentStudio?: boolean;
1817
}
1918

2019
export function ConversationActions({
@@ -24,7 +23,6 @@ export function ConversationActions({
2423
onFeedback,
2524
latestAssistantMessageContent,
2625
showActions,
27-
agentStudio,
2826
}: ConversationActionsProps): JSX.Element | null {
2927
const initialFeedback = React.useMemo(() => {
3028
const message = conversations.getOne?.(id);
@@ -65,26 +63,25 @@ export function ConversationActions({
6563
translations={translations}
6664
onClick={() => navigator.clipboard.writeText(latestAssistantMessageContent)}
6765
/>
68-
{!agentStudio &&
69-
(feedback === null ? (
70-
<>
71-
{saving ? (
72-
<LoadingIcon className="DocSearch-AskAiScreen-SmallerLoadingIcon" />
73-
) : (
74-
<>
75-
<LikeButton title={likeButtonTitle} onClick={() => handleFeedback('like')} />
76-
<DislikeButton title={dislikeButtonTitle} onClick={() => handleFeedback('dislike')} />
77-
</>
78-
)}
79-
{savingError && (
80-
<p className="DocSearch-AskAiScreen-FeedbackText">{savingError.message || 'An error occured'}</p>
81-
)}
82-
</>
83-
) : (
84-
<p className="DocSearch-AskAiScreen-FeedbackText DocSearch-AskAiScreen-FeedbackText--visible">
85-
{thanksForFeedbackText}
86-
</p>
87-
))}
66+
{feedback === null ? (
67+
<>
68+
{saving ? (
69+
<LoadingIcon className="DocSearch-AskAiScreen-SmallerLoadingIcon" />
70+
) : (
71+
<>
72+
<LikeButton title={likeButtonTitle} onClick={() => handleFeedback('like')} />
73+
<DislikeButton title={dislikeButtonTitle} onClick={() => handleFeedback('dislike')} />
74+
</>
75+
)}
76+
{savingError && (
77+
<p className="DocSearch-AskAiScreen-FeedbackText">{savingError.message || 'An error occured'}</p>
78+
)}
79+
</>
80+
) : (
81+
<p className="DocSearch-AskAiScreen-FeedbackText DocSearch-AskAiScreen-FeedbackText--visible">
82+
{thanksForFeedbackText}
83+
</p>
84+
)}
8885
</div>
8986
);
9087
}

packages/docsearch-react/src/Sidepanel/ConversationScreen.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ const ConversationExchange = React.forwardRef<HTMLDivElement, ConversationnExcha
120120
const showActions =
121121
!wasStopped && (!isLastExchange || (isLastExchange && status === 'ready' && Boolean(assistantMessage)));
122122

123+
const messageId = agentStudio ? assistantMessage?.id || exchange.id : userMessage?.id || exchange.id;
124+
123125
return (
124126
<div className="DocSearch-AskAiScreen-Response-Container" ref={conversationRef}>
125127
<div className="DocSearch-AskAiScreen-Response">
@@ -212,12 +214,11 @@ const ConversationExchange = React.forwardRef<HTMLDivElement, ConversationnExcha
212214

213215
<div className="DocSearch-AskAiScreen-Answer-Footer">
214216
<ConversationActions
215-
id={userMessage?.id || exchange.id}
217+
id={messageId}
216218
showActions={showActions}
217219
latestAssistantMessageContent={assistantContent?.text || null}
218220
translations={translations}
219221
conversations={conversations}
220-
agentStudio={agentStudio}
221222
onFeedback={onFeedback}
222223
/>
223224
</div>

0 commit comments

Comments
 (0)