@@ -405,7 +402,7 @@ export function AskAiScreen({ translations = {}, ...props }: AskAiScreenProps):
startNewConversationButtonText = 'Start a new conversation',
} = translations;
- const { messages, tools, askAiError, status, agentStudio, memoryEnabled } = props;
+ const { messages, tools, askAiError, status, memoryEnabled } = props;
// Check if there's a thread depth error
const hasThreadDepthError = useMemo(() => {
@@ -481,7 +478,6 @@ export function AskAiScreen({ translations = {}, ...props }: AskAiScreenProps):
translations={translations}
tools={tools}
conversations={props.conversations}
- agentStudio={agentStudio}
memoryEnabled={memoryEnabled}
onSearchQueryClick={handleSearchQueryClick}
onFeedback={props.onFeedback}
diff --git a/packages/docsearch-react/src/AskAiScreenState.tsx b/packages/docsearch-react/src/AskAiScreenState.tsx
index 0d07fe6f..df358a6c 100644
--- a/packages/docsearch-react/src/AskAiScreenState.tsx
+++ b/packages/docsearch-react/src/AskAiScreenState.tsx
@@ -57,7 +57,6 @@ export interface AskAiScreenStateProps
suggestedQuestions: SuggestedQuestionHit[];
selectSuggestedQuestion: (question: SuggestedQuestionHit) => void;
onNewConversation: () => void;
- agentStudio?: boolean;
memoryEnabled?: boolean;
}
@@ -86,7 +85,6 @@ export const AskAiScreenState = React.memo(
status={props.status}
askAiError={props.askAiError}
translations={translations?.askAiScreen}
- agentStudio={props.agentStudio}
memoryEnabled={props.memoryEnabled}
/>
);
diff --git a/packages/docsearch-react/src/DocSearch.tsx b/packages/docsearch-react/src/DocSearch.tsx
index 8482eff9..55773215 100644
--- a/packages/docsearch-react/src/DocSearch.tsx
+++ b/packages/docsearch-react/src/DocSearch.tsx
@@ -63,45 +63,17 @@ export type DocSearchAskAi = {
* @default false
*/
suggestedQuestions?: boolean;
- // HACK: This is a hack for testing staging, remove before releasing
- useStagingEnv?: boolean;
-} & (
- | {
- /**
- * **Experimental:** Whether to use Agent Studio as the chat backend.
- *
- * This is an experimental feature and its API may change without notice in future releases.
- * Use with caution in production environments.
- *
- * @default false
- */
- agentStudio?: never;
- /**
- * The search parameters to use for the ask AI feature.
- *
- * **NOTE**: If using `agentStudio = true`, the `searchParameters` object is
- * keyed by the index name.
- */
- searchParameters?: AskAiSearchParameters;
- }
- | {
- agentStudio: false;
- searchParameters?: AskAiSearchParameters;
- }
- | {
- agentStudio: true;
- /**
- * The search parameters to use for the ask AI feature.
- * Keyed by the index name.
- *
- * @example
- * {
- * "INDEX_NAME": { distinct: false }
- * }
- */
- searchParameters?: AgentStudioSearchParameters;
- }
-);
+ /**
+ * The search parameters to use for the ask AI feature.
+ * Keyed by the index name.
+ *
+ * @example
+ * {
+ * "INDEX_NAME": { distinct: false }
+ * }
+ */
+ searchParameters?: AgentStudioSearchParameters;
+};
export interface DocSearchIndex {
name: string;
diff --git a/packages/docsearch-react/src/DocSearchAskAiModal.tsx b/packages/docsearch-react/src/DocSearchAskAiModal.tsx
index 771876d4..686327c0 100644
--- a/packages/docsearch-react/src/DocSearchAskAiModal.tsx
+++ b/packages/docsearch-react/src/DocSearchAskAiModal.tsx
@@ -109,14 +109,12 @@ export function DocSearchAskAiModal({
const askAiConfig = typeof askAi === 'object' ? askAi : null;
const askAiConfigurationId = typeof askAi === 'string' ? askAi : askAiConfig?.assistantId || null;
const askAiSearchParameters = askAiConfig?.searchParameters;
- const askAiUseStagingEnv = askAiConfig?.useStagingEnv || false;
const [askAiState, setAskAiState] = React.useState('initial');
const suggestedQuestions = useSuggestedQuestions({
assistantId: askAiConfigurationId,
searchClient,
suggestedQuestionsEnabled: askAiConfig?.suggestedQuestions,
});
- const agentStudio = askAiConfig?.agentStudio ?? false;
const memoryEnabled = props.memory?.enabled ?? false;
const indexes = normalizeDocSearchIndexes({
@@ -141,8 +139,6 @@ export function DocSearchAskAiModal({
appId: askAiConfig?.appId || appId,
indexName: askAiConfig?.indexName || defaultIndexName,
searchParameters: askAiSearchParameters,
- useStagingEnv: askAiUseStagingEnv,
- agentStudio,
tools,
memory: props.memory,
});
@@ -465,7 +461,6 @@ export function DocSearchAskAiModal({
selectAskAiQuestion={handleSelectAskAiQuestion}
suggestedQuestions={suggestedQuestions}
selectSuggestedQuestion={selectSuggestedQuestion}
- agentStudio={agentStudio}
memoryEnabled={memoryEnabled}
onAskAiToggle={onAskAiToggle}
onNewConversation={handleNewConversation}
diff --git a/packages/docsearch-react/src/Sidepanel.tsx b/packages/docsearch-react/src/Sidepanel.tsx
index 34c0cb0d..a09d8db4 100644
--- a/packages/docsearch-react/src/Sidepanel.tsx
+++ b/packages/docsearch-react/src/Sidepanel.tsx
@@ -4,49 +4,25 @@ import type { JSX } from 'react';
import React from 'react';
import { createPortal } from 'react-dom';
-import type { AgentStudioSearchParameters, AskAiSearchParameters, Memory } from './DocSearch';
+import type { AgentStudioSearchParameters, Memory } from './DocSearch';
import type { SidepanelButtonProps, SidepanelProps as SidepanelPanelProps } from './Sidepanel/index';
import { SidepanelButton, Sidepanel } from './Sidepanel/index';
import type { ToolCalls } from './types/AskiAi';
export type { DocSearchRef, DocSearchCallbacks } from '@docsearch/core';
-export type SidepanelSearchParameters =
- | {
- /**
- * **Experimental:** Whether to use Agent Studio as the chat backend.
- *
- * This is an experimental feature and its API may change without notice in future releases.
- * Use with caution in production environments.
- *
- * @default false
- */
- agentStudio?: never;
- /**
- * The search parameters to use for the ask AI feature.
- *
- * **NOTE**: If using `agentStudio = true`, the `searchParameters` object is
- * keyed by the index name.
- */
- searchParameters?: AskAiSearchParameters;
- }
- | {
- agentStudio: false;
- searchParameters?: AskAiSearchParameters;
- }
- | {
- agentStudio: true;
- /**
- * The search parameters to use for the ask AI feature.
- * Keyed by the index name.
- *
- * @example
- * {
- * "INDEX_NAME": { distinct: false }
- * }
- */
- searchParameters?: AgentStudioSearchParameters;
- };
+export type SidepanelSearchParameters = {
+ /**
+ * The search parameters to use for the ask AI feature.
+ * Keyed by the index name.
+ *
+ * @example
+ * {
+ * "INDEX_NAME": { distinct: false }
+ * }
+ */
+ searchParameters?: AgentStudioSearchParameters;
+};
export type DocSearchSidepanelProps = DocSearchCallbacks & {
/**
diff --git a/packages/docsearch-react/src/Sidepanel/ConversationScreen.tsx b/packages/docsearch-react/src/Sidepanel/ConversationScreen.tsx
index bff280be..b5218105 100644
--- a/packages/docsearch-react/src/Sidepanel/ConversationScreen.tsx
+++ b/packages/docsearch-react/src/Sidepanel/ConversationScreen.tsx
@@ -71,7 +71,6 @@ export type ConversationScreenProps = {
status: UseChatHelpers['status'];
handleFeedback?: (messageId: string, thumbs: 0 | 1) => Promise;
streamError?: Error;
- agentStudio?: boolean;
memoryEnabled?: boolean;
tools?: ToolCalls;
};
@@ -84,7 +83,6 @@ type ConversationnExchangeProps = {
translations?: ConversationScreenTranslations;
onFeedback?: ConversationScreenProps['handleFeedback'];
streamError?: ConversationScreenProps['streamError'];
- agentStudio?: boolean;
memoryEnabled?: boolean;
tools: ToolCalls;
};
@@ -99,7 +97,6 @@ const ConversationExchange = React.forwardRef
diff --git a/packages/docsearch-react/src/Sidepanel/Sidepanel.tsx b/packages/docsearch-react/src/Sidepanel/Sidepanel.tsx
index 3d3694bd..26ecd339 100644
--- a/packages/docsearch-react/src/Sidepanel/Sidepanel.tsx
+++ b/packages/docsearch-react/src/Sidepanel/Sidepanel.tsx
@@ -118,8 +118,6 @@ export type SidepanelProps = {
* @default `{ 'Ctrl/Cmd+I': true }`
*/
keyboardShortcuts?: SidepanelShortcuts;
- // HACK: This is a hack for testing staging, remove before releasing
- useStagingEnv?: boolean;
};
type Props = Omit &
@@ -150,8 +148,6 @@ function SidepanelInner(
keyboardShortcuts,
side = 'right',
initialMessage,
- useStagingEnv = false,
- agentStudio = false,
tools = EMPTY_TOOLS,
memory,
}: Props,
@@ -195,8 +191,6 @@ function SidepanelInner(
assistantId,
apiKey,
searchParameters,
- useStagingEnv,
- agentStudio,
tools,
memory,
});
@@ -401,7 +395,6 @@ function SidepanelInner(
handleFeedback={sendFeedback}
translations={translations.conversationScreen}
streamError={askAiError}
- agentStudio={agentStudio}
memoryEnabled={memory?.enabled ?? false}
tools={tools}
/>
diff --git a/packages/docsearch-react/src/__tests__/useAskAi.test.tsx b/packages/docsearch-react/src/__tests__/useAskAi.test.tsx
index a3549a69..9f99a8a7 100644
--- a/packages/docsearch-react/src/__tests__/useAskAi.test.tsx
+++ b/packages/docsearch-react/src/__tests__/useAskAi.test.tsx
@@ -84,7 +84,6 @@ describe('useAskAi', () => {
renderHook(() =>
useAskAi({
- agentStudio: false,
apiKey: 'api-key',
appId: 'app-id',
assistantId: 'assistant-id',
@@ -133,7 +132,6 @@ describe('useAskAi', () => {
renderHook(() =>
useAskAi({
- agentStudio: false,
apiKey: 'api-key',
appId: 'app-id',
assistantId: 'assistant-id',
@@ -159,10 +157,9 @@ describe('useAskAi', () => {
expect(result).toBeUndefined();
});
- it('sends the secure user token header when memory.userToken is provided in Agent Studio mode', () => {
+ it('sends the secure user token header when memory.userToken is provided', () => {
renderHook(() =>
useAskAi({
- agentStudio: true,
apiKey: 'api-key',
appId: 'app-id',
assistantId: 'assistant-id',
@@ -180,7 +177,6 @@ describe('useAskAi', () => {
it('omits the secure user token header when no memory token is provided', () => {
renderHook(() =>
useAskAi({
- agentStudio: true,
apiKey: 'api-key',
appId: 'app-id',
assistantId: 'assistant-id',
diff --git a/packages/docsearch-react/src/askai.ts b/packages/docsearch-react/src/askai.ts
index 693c0d0f..4f9f6bc5 100644
--- a/packages/docsearch-react/src/askai.ts
+++ b/packages/docsearch-react/src/askai.ts
@@ -1,110 +1,5 @@
-import { ASK_AI_API_URL, BETA_ASK_AI_API_URL } from './constants';
-
-// ... existing imports ...
-const TOKEN_KEY = 'askai_token';
-
export const agentStudioBaseUrl = (appId: string): string => `https://${appId}.algolia.net/agent-studio/1`;
-type TokenPayload = { exp: number };
-
-const decode = (token: string): TokenPayload => {
- const [b64] = token.split('.');
- return JSON.parse(atob(b64));
-};
-
-const isExpired = (token?: string | null): boolean => {
- if (!token) return true;
- try {
- const { exp } = decode(token);
- // refresh 30 s before the backend rejects it
- return Date.now() / 1000 > exp - 30;
- } catch {
- return true;
- }
-};
-
-let inflight: Promise | null = null;
-
-// call /token once, cache the promise while it’s running
-export const getValidToken = async ({
- assistantId,
- abortSignal,
- useStagingEnv = false,
-}: {
- assistantId: string;
- abortSignal: AbortSignal;
- useStagingEnv?: boolean;
- // eslint-disable-next-line require-await
-}): Promise => {
- const cached = sessionStorage.getItem(TOKEN_KEY);
- if (!isExpired(cached)) return cached!;
-
- const baseUrl = useStagingEnv ? BETA_ASK_AI_API_URL : ASK_AI_API_URL;
-
- if (!inflight) {
- inflight = fetch(`${baseUrl}/token`, {
- method: 'POST',
- headers: {
- 'x-algolia-assistant-id': assistantId,
- 'content-type': 'application/json',
- },
- signal: abortSignal,
- })
- .then((r) => r.json())
- .then(({ token, success, message }) => {
- // If request was unsuccessful, throw an error to prevent calling `/chat` without a token
- if (!success && message) {
- throw new Error(message);
- }
-
- sessionStorage.setItem(TOKEN_KEY, token);
- return token;
- })
- .finally(() => (inflight = null));
- }
-
- return inflight;
-};
-
-export const postFeedback = async ({
- assistantId,
- thumbs,
- messageId,
- appId,
- abortSignal,
- useStagingEnv = false,
-}: {
- assistantId: string;
- thumbs: 0 | 1;
- messageId: string;
- appId: string;
- abortSignal: AbortSignal;
- useStagingEnv?: boolean;
-}): Promise => {
- const headers = new Headers();
- headers.set('x-algolia-assistant-id', assistantId);
- headers.set('content-type', 'application/json');
-
- const token = await getValidToken({
- assistantId,
- abortSignal,
- useStagingEnv,
- });
- headers.set('authorization', `TOKEN ${token}`);
-
- const baseUrl = useStagingEnv ? BETA_ASK_AI_API_URL : ASK_AI_API_URL;
-
- return fetch(`${baseUrl}/feedback`, {
- method: 'POST',
- body: JSON.stringify({
- appId,
- messageId,
- thumbs,
- }),
- headers,
- });
-};
-
interface AgentStudioValidationError extends Error {
name: 'ValidationError';
detail?: Array<{ type: string; loc: string[]; msg: string }>;
diff --git a/packages/docsearch-react/src/constants.ts b/packages/docsearch-react/src/constants.ts
index 00feb8ff..93fb7ef9 100644
--- a/packages/docsearch-react/src/constants.ts
+++ b/packages/docsearch-react/src/constants.ts
@@ -1,4 +1,2 @@
export const MAX_QUERY_SIZE = 512;
-export const ASK_AI_API_URL = 'https://askai.algolia.com/chat';
-export const BETA_ASK_AI_API_URL = 'https://beta-chat-askai.algolia.com';
export const SUGGESTED_QUETIONS_INDEX_NAME = 'algolia_ask_ai_suggested_questions';
diff --git a/packages/docsearch-react/src/useAskAi.ts b/packages/docsearch-react/src/useAskAi.ts
index b581e16b..d57092b9 100644
--- a/packages/docsearch-react/src/useAskAi.ts
+++ b/packages/docsearch-react/src/useAskAi.ts
@@ -4,21 +4,14 @@ import type { ChatOnToolCallCallback } from 'ai';
import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
import { useCallback, useEffect, useMemo, useRef } from 'react';
-import {
- agentStudioBaseUrl,
- getAgentStudioErrorMessage,
- getValidToken,
- postAgentStudioFeedback,
- postFeedback,
-} from './askai';
+import { agentStudioBaseUrl, getAgentStudioErrorMessage, postAgentStudioFeedback } from './askai';
import type { Exchange } from './AskAiScreen';
-import { ASK_AI_API_URL, BETA_ASK_AI_API_URL } from './constants';
import type { StoredSearchPlugin } from './stored-searches';
import { createStoredConversations } from './stored-searches';
import { type AIMessage, type ToolCalls } from './types/AskiAi';
import { EMPTY_TOOLS } from './utils/ai';
-import type { AgentStudioSearchParameters, AskAiSearchParameters, Memory, StoredAskAiState } from '.';
+import type { AgentStudioSearchParameters, Memory, StoredAskAiState } from '.';
type UseChat = UseChatHelpers;
@@ -27,21 +20,10 @@ type UseAskAiParams = {
apiKey: string;
appId: string;
indexName: string;
- useStagingEnv?: boolean;
- searchParameters?: AskAiSearchParameters;
+ searchParameters?: AgentStudioSearchParameters;
tools: ToolCalls;
- agentStudio: boolean;
memory?: Memory;
-} & (
- | {
- agentStudio: false;
- searchParameters?: AskAiSearchParameters;
- }
- | {
- agentStudio: true;
- searchParameters?: AgentStudioSearchParameters;
- }
-);
+};
type UseAskAiReturn = {
messages: AIMessage[];
@@ -81,51 +63,12 @@ const getAgentStudioTransport = ({
});
};
-const getAskAiTransport = ({
- assistantId,
- apiKey,
- indexName,
- searchParameters,
- appId,
- abortController,
- useStagingEnv,
-}: Pick & {
- abortController: AbortController;
-}): DefaultChatTransport => {
- return new DefaultChatTransport({
- api: useStagingEnv ? BETA_ASK_AI_API_URL : ASK_AI_API_URL,
- headers: async (): Promise> => {
- if (!assistantId) {
- throw new Error('Ask AI assistant ID is required');
- }
-
- const token = await getValidToken({
- assistantId,
- abortSignal: abortController.signal,
- useStagingEnv,
- });
-
- return {
- ...(token ? { authorization: `TOKEN ${token}` } : {}),
- 'X-Algolia-API-Key': apiKey,
- 'X-Algolia-Application-Id': appId,
- 'X-Algolia-Index-Name': indexName,
- 'X-Algolia-Assistant-Id': assistantId || '',
- 'X-AI-SDK-Version': 'v5',
- };
- },
- body: searchParameters ? { searchParameters } : {},
- });
-};
-
export const useAskAi: UseAskAi = ({
assistantId,
apiKey,
appId,
indexName,
- useStagingEnv = false,
tools = EMPTY_TOOLS,
- agentStudio,
searchParameters,
memory,
}) => {
@@ -133,24 +76,14 @@ export const useAskAi: UseAskAi = ({
const askAiTransport = useMemo(
() =>
- agentStudio
- ? getAgentStudioTransport({
- apiKey,
- appId,
- assistantId: assistantId ?? '',
- searchParameters,
- userToken: memory?.userToken,
- })
- : getAskAiTransport({
- assistantId: assistantId ?? '',
- apiKey,
- appId,
- indexName,
- searchParameters,
- abortController: abortControllerRef.current,
- useStagingEnv,
- }),
- [apiKey, appId, assistantId, indexName, useStagingEnv, agentStudio, searchParameters, memory?.userToken],
+ getAgentStudioTransport({
+ apiKey,
+ appId,
+ assistantId: assistantId ?? '',
+ searchParameters,
+ userToken: memory?.userToken,
+ }),
+ [apiKey, appId, assistantId, searchParameters, memory?.userToken],
);
// Sync ref during render so the stable `handleToolCall` (registered once
@@ -202,28 +135,19 @@ export const useAskAi: UseAskAi = ({
async (messageId: string, thumbs: 0 | 1): Promise => {
if (!assistantId) return;
- const res = await (agentStudio
- ? postAgentStudioFeedback({
- agentId: assistantId,
- vote: thumbs,
- messageId,
- appId,
- apiKey,
- abortSignal: abortControllerRef.current.signal,
- })
- : postFeedback({
- assistantId,
- thumbs,
- messageId,
- appId,
- abortSignal: abortControllerRef.current.signal,
- useStagingEnv,
- }));
+ const res = await postAgentStudioFeedback({
+ agentId: assistantId,
+ vote: thumbs,
+ messageId,
+ appId,
+ apiKey,
+ abortSignal: abortControllerRef.current.signal,
+ });
if (res.status >= 300) throw new Error('Failed, try again later.');
conversations.addFeedback?.(messageId, thumbs === 1 ? 'like' : 'dislike');
},
- [assistantId, agentStudio, appId, apiKey, useStagingEnv, conversations],
+ [assistantId, appId, apiKey, conversations],
);
const onStopStreaming = async (): Promise => {
@@ -253,10 +177,8 @@ export const useAskAi: UseAskAi = ({
const askAiError = useMemo((): Error | undefined => {
if (!error) return undefined;
- if (!agentStudio) return error;
-
return getAgentStudioErrorMessage(error);
- }, [error, agentStudio]);
+ }, [error]);
return {
messages,