1
0
Fork 0

fix(agentStudio): agents dynamic mode enabled (#2959)

* fix(agentStudio): agents dynamic mode enabled

* fix(askai): use string[] for dynamic agentStudio indices
This commit is contained in:
Felipe Bermudez 2026-08-05 16:37:25 -05:00 committed by GitHub
parent 3f74c33d45
commit fe4d0c29f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 146 additions and 517 deletions

View file

@ -0,0 +1,6 @@
---
"@docsearch/react": patch
"@docsearch/docusaurus-adapter": patch
---
Align Ask AI dynamic indices with Agent Studio completions: `askAi.indices` is now `string[]` (index names only). Use `askAi.searchParameters` for per-index runtime overrides.

View file

@ -28,12 +28,7 @@ const minimalAskAiConfig = {
const askAiConfigWithIndices = { const askAiConfigWithIndices = {
...minimalAskAiConfig, ...minimalAskAiConfig,
indices: [ indices: ['markdown-index'],
{
index: 'markdown-index',
description: 'Documentation content.',
},
],
} satisfies NonNullable<DocSearchInput>['askAi']; } satisfies NonNullable<DocSearchInput>['askAi'];
function testValidateThemeConfigWithUserThemeConfig( function testValidateThemeConfigWithUserThemeConfig(
@ -240,20 +235,16 @@ describe('validateThemeConfig', () => {
}); });
}); });
it('accepts Agent Studio index searchParameters', () => { it('accepts Agent Studio searchParameters keyed by index', () => {
const docsearch: DocSearchInput = { const docsearch: DocSearchInput = {
...minimalDocSearchConfig, ...minimalDocSearchConfig,
askAi: { askAi: {
...askAiConfigWithIndices, ...askAiConfigWithIndices,
indices: [ searchParameters: {
{ 'markdown-index': {
index: 'markdown-index', filters: 'language:en AND version:1.0',
description: 'Documentation content.',
searchParameters: {
facetFilters: ['language:en', 'version:1.0'],
},
}, },
], },
}, },
}; };
@ -310,12 +301,7 @@ describe('validateThemeConfig', () => {
...minimalDocSearchConfig, ...minimalDocSearchConfig,
askAi: minimalAskAiConfig, askAi: minimalAskAiConfig,
sidePanel: { sidePanel: {
indices: [ indices: ['sidepanel-markdown-index'],
{
index: 'sidepanel-markdown-index',
description: 'Documentation content for the side panel.',
},
],
}, },
}; };
@ -342,7 +328,7 @@ describe('validateThemeConfig', () => {
); );
}); });
it('rejects incomplete sidePanel Agent Studio indices', () => { it('rejects non-string sidePanel Agent Studio indices', () => {
const docsearch = { const docsearch = {
...minimalDocSearchConfig, ...minimalDocSearchConfig,
askAi: minimalAskAiConfig, askAi: minimalAskAiConfig,
@ -353,7 +339,7 @@ describe('validateThemeConfig', () => {
expectThrowMessage( expectThrowMessage(
() => testValidateThemeConfig(docsearch), () => testValidateThemeConfig(docsearch),
'"docsearch.sidePanel.indices[0].description" is required' '"docsearch.sidePanel.indices[0]" must be a string'
); );
}); });

View file

@ -6,16 +6,11 @@
*/ */
import type { AskAiConfig } from '@docsearch/docusaurus-adapter'; import type { AskAiConfig } from '@docsearch/docusaurus-adapter';
import type { import type { DocSearchAskAi, DocSearchProps } from '@docsearch/react';
AgentStudioIndices,
DocSearchAskAi,
DocSearchProps,
} from '@docsearch/react';
import type { FacetFilters } from 'algoliasearch/lite'; import type { FacetFilters } from 'algoliasearch/lite';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useAlgoliaContextualFacetFiltersIfEnabled } from './useAlgoliaContextualFacetFilters'; import { useAlgoliaContextualFacetFiltersIfEnabled } from './useAlgoliaContextualFacetFilters';
import { mergeFacetFilters } from './utils';
type AskAiOptions = AskAiConfig & Pick<DocSearchAskAi, 'tools'>; type AskAiOptions = AskAiConfig & Pick<DocSearchAskAi, 'tools'>;
// The minimal props the hook needs from DocSearch // The minimal props the hook needs from DocSearch
@ -45,44 +40,49 @@ function getAskAiIndexName(
askAi: AskAiConfig, askAi: AskAiConfig,
indices: NonNullable<DocSearchProps['indices']> indices: NonNullable<DocSearchProps['indices']>
): string { ): string {
return askAi.indices?.[0]?.index ?? getIndexName(indices[0]!); return askAi.indices?.[0] ?? getIndexName(indices[0]!);
} }
function applyContextualSearchToAgentStudioIndex( function facetFiltersToFilterString(facetFilters: FacetFilters): string {
index: AgentStudioIndices, const items = Array.isArray(facetFilters) ? facetFilters : [facetFilters];
contextualSearchFilters: FacetFilters
): AgentStudioIndices { return items
return { .map((item) =>
...index, Array.isArray(item) ? `(${item.join(' OR ')})` : String(item)
searchParameters: { )
...index.searchParameters, .join(' AND ');
facetFilters: mergeFacetFilters( }
index.searchParameters?.facetFilters,
contextualSearchFilters function mergeFilters(existing: string | undefined, added: string): string {
), return existing ? `(${existing}) AND (${added})` : added;
},
};
} }
// We need to apply contextualSearch facetFilters to AskAI filters // We need to apply contextualSearch facetFilters to AskAI filters
// This can't be done at config normalization time because contextual filters // This can't be done at config normalization time because contextual filters
// can only be determined at runtime // can only be determined at runtime. Agent Studio accepts them via
// askAi.searchParameters[index].filters, keyed by dynamic index names.
function applyAskAiContextualSearch( function applyAskAiContextualSearch(
askAi: AskAiOptions | undefined, askAi: AskAiOptions | undefined,
contextualSearchFilters: FacetFilters | undefined contextualSearchFilters: FacetFilters | undefined
): AskAiOptions | undefined { ): AskAiOptions | undefined {
if (!askAi) { if (!askAi || !contextualSearchFilters || !askAi.indices?.length) {
return undefined;
}
if (!contextualSearchFilters) {
return askAi; return askAi;
} }
const contextualFilters = facetFiltersToFilterString(contextualSearchFilters);
const searchParameters = { ...askAi.searchParameters };
for (const indexName of askAi.indices) {
const current = searchParameters[indexName] ?? {};
searchParameters[indexName] = {
...current,
filters: mergeFilters(current.filters, contextualFilters),
};
}
return { return {
...askAi, ...askAi,
indices: askAi.indices?.map((index) => searchParameters,
applyContextualSearchToAgentStudioIndex(index, contextualSearchFilters)
),
}; };
} }

View file

@ -7,7 +7,6 @@
declare module '@docsearch/docusaurus-adapter' { declare module '@docsearch/docusaurus-adapter' {
import type { import type {
AgentStudioIndices,
AgentStudioSearchParameters, AgentStudioSearchParameters,
DocSearchAskAi, DocSearchAskAi,
DocSearchProps, DocSearchProps,
@ -50,7 +49,7 @@ declare module '@docsearch/docusaurus-adapter' {
agentId: DocSearchAskAi['agentId']; agentId: DocSearchAskAi['agentId'];
suggestedQuestions?: DocSearchAskAi['suggestedQuestions']; suggestedQuestions?: DocSearchAskAi['suggestedQuestions'];
searchParameters?: AgentStudioSearchParameters; searchParameters?: AgentStudioSearchParameters;
indices?: AgentStudioIndices[]; indices?: string[];
memory?: DocSearchAskAi['memory']; memory?: DocSearchAskAi['memory'];
promptSuggestions?: DocSearchAskAi['promptSuggestions']; promptSuggestions?: DocSearchAskAi['promptSuggestions'];
}; };

View file

@ -37,56 +37,6 @@ const SearchParametersSchema = Joi.object({
.optional(), .optional(),
}).unknown(); }).unknown();
const SearchControlTextParamSchema = Joi.object({
exposed: Joi.boolean().required(),
default: Joi.string().optional(),
}).unknown(false);
const SearchControlNumberParamSchema = Joi.object({
exposed: Joi.boolean().required(),
default: Joi.number().optional(),
constraint: Joi.object({
min: Joi.number().optional(),
max: Joi.number().optional(),
})
.unknown(false)
.optional(),
}).unknown(false);
const SearchControlStringArrayParamSchema = Joi.object({
exposed: Joi.boolean().required(),
default: Joi.array().items(Joi.string()).optional(),
constraint: Joi.object({
values: Joi.array().items(Joi.string()).optional(),
})
.unknown(false)
.optional(),
merge: Joi.boolean().optional(),
}).unknown(false);
const SearchControlFacetParamSchema = Joi.object({
exposed: Joi.boolean().valid(false).required(),
default: Joi.array().items(Joi.string()).optional(),
}).unknown(false);
const AgentStudioSearchControlsSchema = Joi.object({
query: SearchControlTextParamSchema.optional(),
hits_per_page: SearchControlNumberParamSchema.optional(),
page: SearchControlNumberParamSchema.optional(),
attributesToRetrieve: SearchControlStringArrayParamSchema.optional(),
responseFields: SearchControlStringArrayParamSchema.optional(),
facets: SearchControlFacetParamSchema.optional(),
custom: Joi.object().unknown().optional(),
}).unknown(false);
const AskAiIndexSchema = Joi.object({
index: Joi.string().required(),
description: Joi.string().required(),
enhancedDescription: Joi.string().optional(),
searchParameters: SearchParametersSchema.optional(),
searchControls: AgentStudioSearchControlsSchema.optional(),
}).unknown(false);
const AskAiMemorySchema = Joi.object({ const AskAiMemorySchema = Joi.object({
enabled: Joi.bool().optional().default(false), enabled: Joi.bool().optional().default(false),
userToken: Joi.string().optional(), userToken: Joi.string().optional(),
@ -107,7 +57,7 @@ const SidePanelSchema = Joi.object({
translations: Joi.object().optional().unknown(), translations: Joi.object().optional().unknown(),
hideButton: Joi.boolean().optional(), hideButton: Joi.boolean().optional(),
portalContainer: Joi.object().optional().unknown(), portalContainer: Joi.object().optional().unknown(),
indices: Joi.array().items(AskAiIndexSchema).min(1).optional(), indices: Joi.array().items(Joi.string().min(1)).min(1).optional(),
memory: AskAiMemorySchema.optional(), memory: AskAiMemorySchema.optional(),
}).unknown(false); }).unknown(false);
@ -136,7 +86,7 @@ const AskAiSchema = Joi.object({
searchParameters: Joi.object() searchParameters: Joi.object()
.pattern(Joi.string(), SearchParametersSchema) .pattern(Joi.string(), SearchParametersSchema)
.optional(), .optional(),
indices: Joi.array().items(AskAiIndexSchema).min(1).optional(), indices: Joi.array().items(Joi.string().min(1)).min(1).optional(),
memory: AskAiMemorySchema.optional(), memory: AskAiMemorySchema.optional(),
promptSuggestions: AskAiPromptSuggestionsSchema.optional(), promptSuggestions: AskAiPromptSuggestionsSchema.optional(),
}).unknown(false); }).unknown(false);

View file

@ -1,6 +1,5 @@
import { DocSearch as DocSearchProvider, useDocSearch } from '@docsearch/core'; import { DocSearch as DocSearchProvider, useDocSearch } from '@docsearch/core';
import type { DocSearchRef, InitialAskAiMessage } from '@docsearch/core'; import type { DocSearchRef, InitialAskAiMessage } from '@docsearch/core';
import type { SearchParamsObject } from 'algoliasearch/lite';
import React, { type JSX } from 'react'; import React, { type JSX } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
@ -22,111 +21,6 @@ export type AgentStudioSearchParameters = Record<
Omit<AskAiSearchParameters, 'facetFilters'> Omit<AskAiSearchParameters, 'facetFilters'>
>; >;
interface IndexTextParam {
exposed: boolean;
default?: string;
}
interface NumberConstraint {
min?: number;
max?: number;
}
interface IndexNumberParam {
exposed: boolean;
default?: number;
constraint?: NumberConstraint;
}
interface StringArrayConstraints {
values?: string[];
}
interface IndexStringArrayParam {
exposed: boolean;
default?: string[];
constraint?: StringArrayConstraints;
merge?: boolean;
}
interface IndexFacetParam {
exposed: false;
default?: string[];
}
export interface AgentStudioSearchControls {
/**
* Augmented query for the MCP search tool to use.
*
* @default undefined
*/
query?: IndexTextParam;
/**
* Number of hits for the MCP to return per page.
*
* @default { exposed: false, default: 7 }
*/
hits_per_page?: IndexNumberParam;
/**
* The page number the MCP should pull results from.
*
* @default { exposed: false, default: 0 }
*/
page?: IndexNumberParam;
/**
* List of attributes that the MCP can retrieve from the index.
*
* @default { exposed: false, default: ['*'] }
*/
attributesToRetrieve?: IndexStringArrayParam;
/**
* List of fields that the MCP will return to the Agent.
*
* @default { exposed: false, default: ["hits", "nbHits", "page", "nbPages", "hitsPerPage", "facets"] }
*/
responseFields?: IndexStringArrayParam;
/**
* Defined facets the MCP will use when querying the index.
*
* @default undefined
*/
facets?: IndexFacetParam;
/**
* Any other custom properties the MCP should send when querying the index.
*
* @default undefined
*/
custom?: Record<string, unknown>;
}
export interface AgentStudioIndices {
/** The name of the index used by the search tool. */
index: string;
/** A brief description for the search tool. */
description: string;
/**
* A description used to steer the agent on how/when to use the search tool.
*
* @default ''
*/
enhancedDescription?: string;
/**
* Default search parameters for the internal (non-MCP) search tool path.
*
* @default undefined
*/
searchParameters?: SearchParamsObject;
/**
* Structured search parameters for the MCP-based search tool path.
*
* Each parameter controls whether it is exposed to the LLM and it's default
* value.
*
* @default undefined
*/
searchControls?: AgentStudioSearchControls;
}
export interface Memory { export interface Memory {
/** /**
* Determines whether or not to display the memory based tool calls. * Determines whether or not to display the memory based tool calls.
@ -182,8 +76,14 @@ export interface DocSearchAskAi {
* } * }
*/ */
searchParameters?: AgentStudioSearchParameters; searchParameters?: AgentStudioSearchParameters;
/** List of dynamic indices for the Agent Studio search tool to use. */ /**
indices?: AgentStudioIndices[]; * Index names for the Agent Studio search tool on this request.
*
* Agent Studio expects names only. Put descriptions and tool defaults on the
* agent configuration. Put per-index runtime overrides in
* `searchParameters`.
*/
indices?: string[];
/** /**
* Use custom tools driven by Agent Studio. * Use custom tools driven by Agent Studio.
* *
@ -235,12 +135,7 @@ function DocSearchAIComponent(
ref: React.ForwardedRef<DocSearchRef> ref: React.ForwardedRef<DocSearchRef>
): JSX.Element { ): JSX.Element {
return ( return (
<DocSearchProvider <DocSearchProvider {...props} appId={appId} apiKey={apiKey} ref={ref}>
{...props}
appId={appId}
apiKey={apiKey}
ref={ref}
>
<DocSearchAIInner {...props} /> <DocSearchAIInner {...props} />
</DocSearchProvider> </DocSearchProvider>
); );

View file

@ -9,11 +9,7 @@ import type { JSX } from 'react';
import React from 'react'; import React from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import type { import type { AgentStudioSearchParameters, Memory } from './DocSearchAI';
AgentStudioIndices,
AgentStudioSearchParameters,
Memory,
} from './DocSearchAI';
import type { import type {
SidepanelButtonProps, SidepanelButtonProps,
SidepanelProps as SidepanelPanelProps, SidepanelProps as SidepanelPanelProps,
@ -77,8 +73,14 @@ export type DocSearchSidepanelProps = DocSearchCallbacks & {
* @see https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/memory/overview * @see https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/memory/overview
*/ */
memory?: Memory; memory?: Memory;
/** List of dynamic indices for the Agent Studio search tool to use. */ /**
indices?: AgentStudioIndices[]; * Index names for the Agent Studio search tool on this request.
*
* Agent Studio expects names only. Put descriptions and tool defaults on the
* agent configuration. Put per-index runtime overrides in
* `searchParameters`.
*/
indices?: string[];
}; };
type SidepanelProps = DocSearchSidepanelProps & SidepanelSearchParameters; type SidepanelProps = DocSearchSidepanelProps & SidepanelSearchParameters;

View file

@ -291,12 +291,7 @@ describe('useAskAi', () => {
}); });
it('includes indices under the algolia body when provided', () => { it('includes indices under the algolia body when provided', () => {
const indices = [ const indices = ['docsearch-markdown'];
{
index: 'docsearch-markdown',
description: 'Use this to gather specific results.',
},
];
renderHook(() => renderHook(() =>
useAskAi({ useAskAi({
@ -317,12 +312,7 @@ describe('useAskAi', () => {
const searchParameters = { const searchParameters = {
'index-name': { distinct: false }, 'index-name': { distinct: false },
}; };
const indices = [ const indices = ['docsearch-markdown'];
{
index: 'docsearch-markdown',
description: 'Use this to gather specific results.',
},
];
renderHook(() => renderHook(() =>
useAskAi({ useAskAi({
@ -571,7 +561,7 @@ describe('useAskAi', () => {
searchParameters: { searchParameters: {
'index-name': { distinct: false }, 'index-name': { distinct: false },
}, },
indices: [{ index: 'index-name', description: 'Test index' }], indices: ['index-name'],
}, },
} }
); );
@ -583,7 +573,7 @@ describe('useAskAi', () => {
searchParameters: { searchParameters: {
'index-name': { distinct: false }, 'index-name': { distinct: false },
}, },
indices: [{ index: 'index-name', description: 'Test index' }], indices: ['index-name'],
}); });
expect(result.current.startNewConversation).toBe(startNewConversation); expect(result.current.startNewConversation).toBe(startNewConversation);

View file

@ -20,12 +20,7 @@ import { type AIMessage, type ToolCalls } from './types/AskiAi';
import type { OnAskAiFeedback } from './types/Feedback'; import type { OnAskAiFeedback } from './types/Feedback';
import { EMPTY_TOOLS, sanitizeMessagesForRequest } from './utils/ai'; import { EMPTY_TOOLS, sanitizeMessagesForRequest } from './utils/ai';
import type { import type { AgentStudioSearchParameters, Memory, StoredAskAiState } from '.';
AgentStudioIndices,
AgentStudioSearchParameters,
Memory,
StoredAskAiState,
} from '.';
type UseChat = UseChatHelpers<AIMessage>; type UseChat = UseChatHelpers<AIMessage>;
@ -36,7 +31,7 @@ type UseAskAiParams = {
searchParameters?: AgentStudioSearchParameters; searchParameters?: AgentStudioSearchParameters;
tools: ToolCalls; tools: ToolCalls;
memory?: Memory; memory?: Memory;
indices?: AgentStudioIndices[]; indices?: string[];
}; };
type UseAskAiReturn = { type UseAskAiReturn = {
@ -74,7 +69,7 @@ type AgentStudioTransportParams = Pick<
> & { > & {
searchParameters?: AgentStudioSearchParameters; searchParameters?: AgentStudioSearchParameters;
userToken?: string; userToken?: string;
indices?: AgentStudioIndices[]; indices?: string[];
}; };
const getAgentStudioTransport = ({ const getAgentStudioTransport = ({
@ -87,7 +82,7 @@ const getAgentStudioTransport = ({
}: AgentStudioTransportParams): DefaultChatTransport<AIMessage> => { }: AgentStudioTransportParams): DefaultChatTransport<AIMessage> => {
const algoliaParams: { const algoliaParams: {
searchParameters?: AgentStudioSearchParameters; searchParameters?: AgentStudioSearchParameters;
indices?: AgentStudioIndices[]; indices?: string[];
} = {}; } = {};
if (searchParameters) { if (searchParameters) {

View file

@ -3,14 +3,18 @@ title: Configure dynamic indices
description: Select Agent Studio search indices dynamically at runtime. description: Select Agent Studio search indices dynamically at runtime.
--- ---
Pass `askAi.indices` when the Agent Studio search tool needs index definitions at request time. This lets your application choose indices, descriptions, fixed search parameters, and model-controlled parameters for each DocSearch instance. Pass `askAi.indices` when Agent Studio should search a specific set of indices for this request. This lets each DocSearch instance choose which indices the agent can use.
This property isn't the same as the top-level `indices` property: This property isn't the same as the top-level `indices` property:
- Top-level `indices` configures DocSearch keyword search. Entries are index names or objects with a `name` property. - Top-level `indices` configures DocSearch keyword search. Entries are index names or objects with a `name` property.
- `askAi.indices` configures Agent Studio search. Entries use an `index` property and require a `description`. - `askAi.indices` configures Agent Studio search. Entries are index name strings.
## Define an index Agent Studio completions accept index names only. Put index descriptions and tool defaults on the agent configuration in Agent Studio. Put per-index runtime overrides in `askAi.searchParameters`.
The agent's Algolia Search tool must use `mode: "dynamic"`. If the tool's static index list is empty, also enable `allowUnlistedIndices`.
## Select indices
```tsx title="Search.tsx" ```tsx title="Search.tsx"
<DocSearchAI <DocSearchAI
@ -18,123 +22,26 @@ This property isn't the same as the top-level `indices` property:
apiKey="YOUR_SEARCH_API_KEY" apiKey="YOUR_SEARCH_API_KEY"
indices={['docs']} indices={['docs']}
askAi={{ askAi={{
assistantId: 'YOUR_AGENT_ID', agentId: 'YOUR_AGENT_ID',
indices: [ indices: ['docs_markdown', 'api_reference'],
{ searchParameters: {
index: 'docs_markdown', docs_markdown: {
description: 'Published product documentation.', filters: 'visibility:public',
enhancedDescription: attributesToRetrieve: ['title', 'content', 'url'],
'Use this index for installation, configuration, and API questions.',
searchParameters: {
filters: 'visibility:public',
attributesToRetrieve: ['title', 'content', 'url'],
},
searchControls: {
query: { exposed: true },
hits_per_page: {
exposed: false,
default: 7,
constraint: { min: 1, max: 10 },
},
attributesToRetrieve: {
exposed: false,
default: ['title', 'content', 'url'],
constraint: {
values: ['title', 'content', 'url'],
},
},
facets: {
exposed: false,
default: ['language', 'version'],
},
},
}, },
], api_reference: {
distinct: false,
},
},
}} }}
/> />
``` ```
Each index accepts these properties: ### `indices`
### `index` > `type: string[]` | **optional**
> `type: string` | **required** Index names available to the Agent Studio search tool for this request. When omitted, Agent Studio uses the indices configured on the agent tool.
Names the Algolia index.
### `description`
> `type: string` | **required**
Tells the agent what the index contains.
### `enhancedDescription`
> `type: string` | **optional**
Gives the agent more guidance about when and how to use the index.
### `searchParameters`
> `type: SearchParamsObject` | **optional**
Sets defaults for the internal, non-MCP search path. It accepts Algolia search parameters.
### `searchControls`
> `type: AgentStudioSearchControls` | **optional**
Configures parameters for the MCP-based search path.
Write specific descriptions. Agent Studio uses them to select an index and plan a search. See [Algolia Search tool configuration](https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/tools/algolia-search) for guidance.
## Configure search controls
A search control describes whether the model can provide a value and which default or constraints apply.
### `query`
> `type: { exposed, default? }` | **optional**
Sets the search query control. It has no DocSearch default when omitted.
### `hits_per_page`
> `type: { exposed, default?, constraint?: { min?, max? } }` | **optional**
Sets the number of results per page. When omitted, DocSearch uses `{ exposed: false, default: 7 }`.
### `page`
> `type: { exposed, default?, constraint?: { min?, max? } }` | **optional**
Sets the requested page. When omitted, DocSearch uses `{ exposed: false, default: 0 }`.
### `attributesToRetrieve`
> `type: { exposed, default?, constraint?: { values? }, merge? }` | **optional**
Sets the attributes returned for each hit. When omitted, DocSearch uses `{ exposed: false, default: ['*'] }`.
### `responseFields`
> `type: { exposed, default?, constraint?: { values? }, merge? }` | **optional**
Sets the fields returned in the search response. When omitted, DocSearch uses `{ exposed: false, default: ['hits', 'nbHits', 'page', 'nbPages', 'hitsPerPage', 'facets'] }`.
### `facets`
> `type: { exposed: false, default? }` | **optional**
Sets the facets requested with the search. It has no DocSearch default when omitted.
### `custom`
> `type: Record<string, unknown>` | **optional**
Sets extra tool parameters. It has no DocSearch default when omitted.
Use `exposed: true` only for values the model should choose from conversation context. Use fixed defaults for business rules and response limits. For the distinction between runtime and predefined parameters, see [Agent Studio tools](https://www.algolia.com/doc/guides/algolia-ai/agent-studio/how-to/tools/overview#configure-runtime-parameters-for-dynamic-tool-execution).
## Set request-wide search parameters ## Set request-wide search parameters
@ -142,7 +49,8 @@ Use `exposed: true` only for values the model should choose from conversation co
```js title="docsearch.js" ```js title="docsearch.js"
askAi: { askAi: {
assistantId: 'YOUR_AGENT_ID', agentId: 'YOUR_AGENT_ID',
indices: ['docs_markdown'],
searchParameters: { searchParameters: {
docs_markdown: { docs_markdown: {
filters: 'visibility:public', filters: 'visibility:public',
@ -153,10 +61,12 @@ askAi: {
} }
``` ```
Supported override fields are `filters`, `attributesToRetrieve`, `restrictSearchableAttributes`, `distinct`, `userToken`, `enablePersonalization`, `personalizationImpact`, and `optionalFilters`.
Don't use the flat search-parameter shape from earlier DocSearch AI integrations. Don't use the flat search-parameter shape from earlier DocSearch AI integrations.
## Docusaurus validation ## Docusaurus validation
The v5 Docusaurus adapter requires at least one entry when you set `askAi.indices`. Every entry must include `index` and `description`. It rejects unknown `searchControls` properties, except values nested under `custom`. The v5 Docusaurus adapter requires at least one string when you set `askAi.indices`. Contextual search merges version/language filters into `askAi.searchParameters[index].filters` for each dynamic index name.
See the [React package reference](/docs/packages/react/api-reference) and [Docusaurus adapter guide](/docs/packages/docusaurus-adapter/getting-started) for the complete types. See the [React package reference](/docs/packages/react/api-reference) and [Docusaurus adapter guide](/docs/packages/docusaurus-adapter/getting-started) for the complete types.

View file

@ -196,7 +196,7 @@ The modal queries every index in array order. The search page queries only the f
Keep `contextualSearch: true` to limit results to the current locale and Docusaurus docs versions. The adapter merges these conditions into each index's `facetFilters` instead of replacing your filters. Keep `contextualSearch: true` to limit results to the current locale and Docusaurus docs versions. The adapter merges these conditions into each index's `facetFilters` instead of replacing your filters.
Contextual search also applies to each `askAi.indices` item. Define dynamic Agent Studio indices if Ask AI must receive these facet filters. Contextual search also applies to Ask AI when you set `askAi.indices`. The adapter merges version and language filters into `askAi.searchParameters[index].filters` for each dynamic index name.
Set `contextualSearch: false` when your records don't contain Docusaurus `language` and `docusaurus_tag` attributes: Set `contextualSearch: false` when your records don't contain Docusaurus `language` and `docusaurus_tag` attributes:
@ -322,30 +322,22 @@ Search parameters keyed by index name. Root `askAi.searchParameters` supports `f
### `indices` ### `indices`
> `type: AgentStudioIndex[]` | **optional** > `type: string[]` | **optional**
Dynamic indices available to Agent Studio search tools. See [dynamic indices][1]. Index names available to Agent Studio search tools. See [dynamic indices][1].
Use `askAi.indices` to describe dynamic indices:
```js title="docusaurus.config.mjs" ```js title="docusaurus.config.mjs"
askAi: { askAi: {
assistantId: 'YOUR_ASSISTANT_ID', agentId: 'YOUR_ASSISTANT_ID',
indices: [ indices: ['docs_markdown'],
{ searchParameters: {
index: 'docs_markdown', docs_markdown: {
description: 'Product documentation.', filters: 'language:en',
enhancedDescription: 'Use for setup and API questions.',
searchParameters: {
facetFilters: ['language:en'],
},
}, },
], },
}, },
``` ```
Each item requires `index` and `description`. It can also include `enhancedDescription`, `searchParameters`, and `searchControls`. Search controls can configure `query`, `hits_per_page`, `page`, `attributesToRetrieve`, `responseFields`, `facets`, and custom properties.
### `memory` ### `memory`
> `type: { enabled?: boolean, userToken?: string }` | **optional** > `type: { enabled?: boolean, userToken?: string }` | **optional**
@ -441,7 +433,7 @@ Enable or disable the panel shortcut. The shortcut is enabled by default.
### `indices` ### `indices`
> `type: AgentStudioIndex[]` | **optional** > `type: string[]` | **optional**
Override Agent Studio indices for the panel. Defaults to `askAi.indices`. See [dynamic indices][1]. Override Agent Studio indices for the panel. Defaults to `askAi.indices`. See [dynamic indices][1].
@ -607,9 +599,9 @@ The schema also reports these messages for missing or invalid required configura
"docsearch.indices" must contain at least 1 items "docsearch.indices" must contain at least 1 items
"docsearch.unknownKey" is not allowed "docsearch.unknownKey" is not allowed
"docsearch.askAi.indices" must contain at least 1 items "docsearch.askAi.indices" must contain at least 1 items
"docsearch.askAi.indices[0].description" is required "docsearch.askAi.indices[0]" must be a string
"docsearch.sidePanel.indices" must contain at least 1 items "docsearch.sidePanel.indices" must contain at least 1 items
"docsearch.sidePanel.indices[0].description" is required "docsearch.sidePanel.indices[0]" must be a string
``` ```
Replace `unknownKey` with the rejected option name. Other invalid nested values use the same Joi path format. Replace `unknownKey` with the rejected option name. Other invalid nested values use the same Joi path format.

View file

@ -192,13 +192,8 @@ askAi: 'YOUR_ASSISTANT_ID',
```js title="docusaurus.config.mjs" ```js title="docusaurus.config.mjs"
askAi: { askAi: {
assistantId: 'YOUR_ASSISTANT_ID', agentId: 'YOUR_ASSISTANT_ID',
indices: [ indices: ['docs_markdown'],
{
index: 'docs_markdown',
description: 'Product documentation.',
},
],
}, },
``` ```
@ -240,7 +235,7 @@ askAi: {
</TabItem> </TabItem>
</Tabs> </Tabs>
Root `askAi.searchParameters` supports `filters`, `attributesToRetrieve`, `restrictSearchableAttributes`, and `distinct`. Put `facetFilters` on a dynamic `askAi.indices` item's `searchParameters` instead. Root `askAi.searchParameters` supports `filters`, `attributesToRetrieve`, `restrictSearchableAttributes`, and `distinct`.
## 7. Move the Sidepanel to the root ## 7. Move the Sidepanel to the root

View file

@ -387,35 +387,21 @@ askAi: {
#### `indices` #### `indices`
> `type: AgentStudioIndices[]` | **optional** > `type: string[]` | **optional**
Dynamic indices available to the Agent Studio search tool. There's no default. Index names for the Agent Studio search tool on this request. There's no default.
Each `AgentStudioIndices` item requires `index` and `description`. It can also define `enhancedDescription`, `searchParameters`, and `searchControls`. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in `searchParameters`.
`searchControls` supports `query`, `hits_per_page`, `page`, `attributesToRetrieve`, `responseFields`, `facets`, and `custom`. The `exposed` flag controls whether the model can set a value. Constraints set allowed numeric ranges or string-array values.
```js title="docsearch-options.js" ```js title="docsearch-options.js"
askAi: { askAi: {
assistantId: 'YOUR_ASSISTANT_ID', agentId: 'YOUR_ASSISTANT_ID',
indices: [ indices: ['api_reference', 'docs_markdown'],
{ searchParameters: {
index: 'api_reference', api_reference: {
description: 'API symbols and parameter reference', filters: 'version:latest',
enhancedDescription: 'Use for questions about methods and options.',
searchControls: {
hits_per_page: {
exposed: true,
default: 7,
constraint: { min: 1, max: 10 },
},
facets: {
exposed: false,
default: ['version'],
},
},
}, },
], },
} }
``` ```

View file

@ -251,9 +251,9 @@ Sends search parameters keyed by index name. `AgentStudioIndexSearchParameters`
### `indices` ### `indices`
> `type: AgentStudioIndices[]` | **optional** > `type: string[]` | **optional**
Defines dynamic indices available to Agent Studio search tools. Index names available to Agent Studio search tools. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in `searchParameters`.
### `tools` ### `tools`
@ -273,40 +273,6 @@ Displays memory tool activity and sends a secure user token.
Configures prompt suggestions in keyword search. `hitsPerPage` defaults to `3`. Configures prompt suggestions in keyword search. `hitsPerPage` defaults to `3`.
## Dynamic indices
Each dynamic index accepts the following fields:
### `index`
> `type: string` | **required**
Index available to Agent Studio search tools.
### `description`
> `type: string` | **required**
Describes the index contents to Agent Studio.
### `enhancedDescription`
> `type: string` | **optional**
Provides more context about the index contents.
### `searchParameters`
> `type: SearchParamsObject` | **optional**
Sets search parameters for the dynamic index.
### `searchControls`
> `type: AgentStudioSearchControls` | **optional**
Configures `query`, `hits_per_page`, `page`, `attributesToRetrieve`, `responseFields`, `facets`, and `custom` controls. Text, number, and string-array controls use an `exposed` flag and can define defaults or constraints.
## Custom tools ## Custom tools
Each `ToolDefinition` accepts the following fields: Each `ToolDefinition` accepts the following fields:

View file

@ -310,11 +310,9 @@ Search parameters keyed by index name. Each value supports `filters`, `attribute
#### `indices` #### `indices`
> `type: AgentStudioIndices[]` | **optional** > `type: string[]` | **optional**
Dynamic indices for Agent Studio. Each item requires `index` and `description`. It can also define `enhancedDescription`, `searchParameters`, and `searchControls`. Index names for the Agent Studio search tool on this request. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in `searchParameters`.
`searchControls` supports `query`, `hits_per_page`, `page`, `attributesToRetrieve`, `responseFields`, `facets`, and `custom`.
#### `tools` #### `tools`

View file

@ -195,28 +195,17 @@ See [Get started with Agent Studio](/docs/agent-studio/getting-started) before c
## Add dynamic Agent Studio indices ## Add dynamic Agent Studio indices
Describe each index so the agent can select the right source: Pass the index names Agent Studio should search for this request:
```jsx title="DynamicIndicesSearch.jsx" ```jsx title="DynamicIndicesSearch.jsx"
const askAi = { const askAi = {
assistantId: 'YOUR_ASSISTANT_ID', agentId: 'YOUR_ASSISTANT_ID',
indices: [ indices: ['product_docs', 'api_reference'],
{ searchParameters: {
index: 'product_docs', product_docs: {
description: 'Product guides and conceptual documentation', filters: 'language:en',
searchControls: {
hits_per_page: {
exposed: true,
default: 7,
constraint: { min: 1, max: 10 },
},
},
}, },
{ },
index: 'api_reference',
description: 'API symbols, options, and return values',
},
],
}; };
<DocSearchAI <DocSearchAI

View file

@ -124,9 +124,9 @@ Configures memory-tool rendering and authentication.
### `indices` ### `indices`
> `type: AgentStudioIndices[]` | **optional** > `type: string[]` | **optional**
Defines dynamic indices available to Agent Studio. Index names available to Agent Studio. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in `searchParameters`.
These fields are root props: These fields are root props:
@ -141,16 +141,11 @@ const assistant = sidepanel({
enabled: true, enabled: true,
userToken: userMemoryToken, userToken: userMemoryToken,
}, },
indices: [ indices: ['docs', 'support_articles'],
{ searchParameters: {
index: 'docs', docs: { filters: 'version:v5' },
description: 'Product documentation and API references.', support_articles: { filters: 'visibility:public' },
}, },
{
index: 'support_articles',
description: 'Troubleshooting and support articles.',
},
],
tools: { tools: {
getReleaseChannel: { getReleaseChannel: {
async onToolCall({ input, addToolOutput }) { async onToolCall({ input, addToolOutput }) {
@ -165,8 +160,6 @@ const assistant = sidepanel({
}); });
``` ```
`AgentStudioIndices` requires `index` and `description`. It also accepts `enhancedDescription`, `searchParameters`, and `searchControls`.
`ToolDefinition` requires `render({ message: { input, output } })`, which returns a string. It can also define `onToolCall` and `translations.callingToolText`. If you handle a client-side tool, call `addToolOutput`. `ToolDefinition` requires `render({ message: { input, output } })`, which returns a string. It can also define `onToolCall` and `translations.callingToolText`. If you handle a client-side tool, call `addToolOutput`.
Generate `memory.userToken` on your server. The package sends it as `x-algolia-secure-user-token`. Generate `memory.userToken` on your server. The package sends it as `x-algolia-secure-user-token`.

View file

@ -133,7 +133,7 @@ Don't generate or sign the token in the browser.
## Provide dynamic indices ## Provide dynamic indices
Use `indices` to describe the indices Agent Studio can select at request time. This list is separate from the required `indexName`, which remains the Sidepanel's primary index. Use `indices` to select the indices Agent Studio can search at request time. This list is separate from the required `indexName`, which remains the Sidepanel's primary index.
```tsx title="DynamicIndices.tsx" ```tsx title="DynamicIndices.tsx"
<Sidepanel <Sidepanel
@ -145,17 +145,7 @@ Use `indices` to describe the indices Agent Studio can select at request time. T
docs: { filters: 'version:v5' }, docs: { filters: 'version:v5' },
support_articles: { filters: 'visibility:public' }, support_articles: { filters: 'visibility:public' },
}} }}
indices={[ indices={['docs', 'support_articles']}
{
index: 'docs',
description: 'Product documentation and API references.',
},
{
index: 'support_articles',
description: 'Troubleshooting and support articles.',
enhancedDescription: 'Use for errors and operational incidents.',
},
]}
/> />
``` ```

View file

@ -116,9 +116,9 @@ Configures Agent Studio memory rendering and authentication.
#### `indices` #### `indices`
> `type: AgentStudioIndices[]` | **optional** > `type: string[]` | **optional**
Defines dynamic indices available to Agent Studio. Index names available to Agent Studio. Put descriptions and tool defaults on the agent configuration. Put per-index runtime overrides in `searchParameters`.
### Translation groups ### Translation groups
@ -134,20 +134,6 @@ Defines dynamic indices available to Agent Studio.
V5 uses Agent Studio for Sidepanel conversations. It doesn't expose an `agentStudio` prop. V5 uses Agent Studio for Sidepanel conversations. It doesn't expose an `agentStudio` prop.
### `AgentStudioIndices`
```ts
interface AgentStudioIndices {
index: string;
description: string;
enhancedDescription?: string;
searchParameters?: SearchParamsObject;
searchControls?: AgentStudioSearchControls;
}
```
`searchControls` accepts `query`, `hits_per_page`, `page`, `attributesToRetrieve`, `responseFields`, `facets`, and `custom`. Controls specify whether Agent Studio may expose a value to the model and can include defaults and constraints.
### `ToolDefinition` ### `ToolDefinition`
```ts ```ts

View file

@ -228,7 +228,8 @@ These additions aren't breaking by themselves, but they replace common v4 custom
- `facets` and `DocSearchFacet` for keyword filters. - `facets` and `DocSearchFacet` for keyword filters.
- `resultBadgeKey` for hit metadata. - `resultBadgeKey` for hit metadata.
- `DocSearchAI` and `DocSearchAskAiModal` for AI-capable React views. - `DocSearchAI` and `DocSearchAskAiModal` for AI-capable React views.
- `AgentStudioIndices` and `AgentStudioSearchControls` for dynamic search tools. - `askAi.indices` (`string[]`) for dynamic Agent Studio search indices.
- `askAi.searchParameters` for per-index runtime search overrides.
- `ToolCalls` and `ToolDefinition` for custom Agent Studio tools. - `ToolCalls` and `ToolDefinition` for custom Agent Studio tools.
- `Memory` for user-scoped Agent Studio memory. - `Memory` for user-scoped Agent Studio memory.
- `PromptSuggestions` for keyword-query prompt suggestions. - `PromptSuggestions` for keyword-query prompt suggestions.