Knowledge/AgentStudio/08-frontend-integration.md
08 — Frontend Integration
How Agent Studio agents reach the user. Three integration paths exist; production agents use them in different combinations.
Three integration paths
| Path | What it is | When to use |
|---|---|---|
| HTTP API direct | POST to /agent-studio/1/agents/{agentId}/completions with custom transport |
Custom UIs, non-React apps, full control over UX |
| Native widgets | <Chat>, <FilterSuggestions> from react-instantsearch or instantsearch.js |
Standard chat or filter-suggestion UIs, fastest path to production |
| AI SDK UI | useChat hook from @ai-sdk/react (which <Chat> is built on) |
Custom React components with managed message state and streaming |
Path 1: HTTP API direct
Lowest level. Full control. What we use today.
const response = await fetch(
`https://${appId}.algolia.net/agent-studio/1/agents/${agentId}/completions?compatibilityMode=ai-sdk-4&stream=true`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Algolia-Application-Id": appId,
"X-Algolia-API-Key": apiKey,
"X-Algolia-Secure-User-Token": jwt // optional
},
body: JSON.stringify({
id: "alg_cnv_abc123",
messages: [{ id: "alg_msg_1", role: "user", content: query }]
})
}
);
// Process SSE stream
SSE event types (compatibilityMode=ai-sdk-4):
- Text deltas
- Tool call requests (9: prefix in v4 stream)
- Tool result sends back (client → server)
- Reasoning chunks (if sendReasoning: true)
- e: and d: finish reasons (tool-approval-required, stop, etc.)
Compatibility mode ai-sdk-5 uses data: prefix and named event types (data-tool-approval, finish-step, finish). We currently use v4. v5 maps better to AI SDK React patterns.
Path 2: Native widgets
<Chat> widget (react-instantsearch)
Per 04-frontend-widgets.md §1.
import { liteClient as algoliasearch } from 'algoliasearch/lite';
import { InstantSearch, Chat } from 'react-instantsearch';
const searchClient = algoliasearch(APP_ID, API_KEY);
<InstantSearch indexName="instant_search" searchClient={searchClient}>
<Chat agentId="..." />
</InstantSearch>
Required (one of): agentId OR transport (custom HTTP config).
Key optional props:
- feedback (boolean) — thumbs up/down on assistant messages (only with agentId)
- tools (Record<string, Tool>) — client-side tool definitions:
jsx
tools={{
suggest_searches: {
onToolCall: async ({ input, addToolResult, indexUiState, setIndexUiState }) => {
// Execute the tool's intent
await addToolResult({ output: { success: true, ... } });
},
layoutComponent: ({ message }) => (
// Render the tool call/result as a UI component
<SearchSuggestionsCard suggestions={message.input.suggestions} />
)
}
}}
- getSearchPageURL: (uiState) => string — for "View all" navigation
- layoutComponent — ChatInlineLayout or ChatOverlayLayout
- classNames — CSS class overrides
- translations — UI text dictionary
- itemComponent, assistantMessageLeadingComponent, userMessageLeadingComponent, promptFooterComponent, etc. — slot overrides
Notable: Works with Vercel AI SDK 5 transport. NO UMD/CDN — ES modules only.
<FilterSuggestions> widget
For agents created with the "Filter suggestions" template. Renders AI-suggested facet filters.
<FilterSuggestions
agentId="..."
attributes={['brand', 'category']} // restrict to specific facets
maxSuggestions={3} // default 3, max 5
debounceMs={300} // delay before fetching
hitsToSample={5} // # search results sent as context
/>
Frontend renders clickable suggestion chips. Each click applies the filter to the active InstantSearch state.
Vanilla JS variants
instantsearch.js/es/widgets exports chat() and filterSuggestions():
import { chat, filterSuggestions } from 'instantsearch.js/es/widgets';
instantsearch.addWidgets([
chat({ container: '#chat', agentId: '...' }),
filterSuggestions({ container: '#filters', agentId: '...', attributes: ['brand'] })
]);
Same prop surface as React, slight syntax difference. NO UMD/CDN — ES modules only. Requires instantsearch.js 4.46.0+.
Path 3: AI SDK UI
For custom React UIs without the full <Chat> shell.
import { useChat } from '@ai-sdk/react';
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
api: `https://${appId}.algolia.net/agent-studio/1/agents/${agentId}/completions?compatibilityMode=ai-sdk-5&stream=true`,
headers: {
'X-Algolia-Application-Id': appId,
'X-Algolia-API-Key': apiKey
}
});
<Chat> is built on top of useChat (per 04-frontend-widgets.md). Use useChat directly when you want managed message state + streaming but custom layout.
Tool integration: the round-trip
Critical pattern (per 02-tools.md §3.2 and 04-frontend-widgets.md §1):
- Agent decides to call
client_sidetoolXwith arguments{ ... } - Streaming response includes a tool-call request event
<Chat>(or youruseChathandler) invokes the tool'sonToolCall({ input, addToolResult, ... })- Your code:
- Performs the action (mutate UI state, call backend, fetch user data, etc.)
- Calls
await addToolResult({ output: <result> }) - The result is sent back to the agent, which uses it to continue its response
- Optionally, your tool's
layoutComponent({ message })renders the call+result as a UI element in the chat
The <Chat> widget handles the round-trip wiring automatically. With raw useChat, you wire onToolCall yourself.
Component slots and customization
<Chat> exposes many slots for customization:
| Slot | Purpose |
|---|---|
itemComponent |
Custom search result item renderer (when search tool returns hits) |
headerCloseIconComponent, headerMaximizeIconComponent, etc. |
Header icon customization |
messagesErrorComponent |
Error state for messages |
messagesLoaderComponent |
Loader animation |
assistantMessageLeadingComponent / Trailing / Footer |
Avatar / metadata / disclaimer slots |
userMessageLeadingComponent / Trailing / Footer |
User-side equivalents |
promptHeaderComponent / promptFooterComponent |
Above/below the input |
toggleButtonIconComponent |
For overlay layout, the toggle icon |
suggestionsComponent |
Custom suggestions renderer (when suggestions.enabled: true) |
Per-tool customization via tools[toolName].layoutComponent (and tools[toolName].onToolCall).
CSS classes
Standard .ais-Chat class hierarchy. Override via classNames prop. Major sub-elements:
| Area | Classes |
|---|---|
| Root | root, container |
| Header | root, clear, close, maximize, title, titleIcon |
| Messages | root, content, scroll |
| Message | root, container, leading, content, actions |
| Prompt | root, textarea, submit, body, footer |
| Toggle | toggleButton |
Translations / i18n
Customizable text across header, messages, message, prompt sections via the translations prop. See 04-frontend-widgets.md §1 "Translation Keys" for the full key list.
Vercel AI SDK 5 compatibility
The widget transport must be Vercel AI SDK 5 compatible. The compatibilityMode=ai-sdk-4 query parameter exists for older clients; ai-sdk-5 is the current default. Migration from v4 to v5 is mainly stream event format — text deltas and tool calls keep similar semantics.
For RC3 Phoenix: standardize on ai-sdk-5 for new code; migrate v4 code over time.
Beta status caveats
All four widgets (Chat React, Chat JS, FilterSuggestions React, FilterSuggestions JS) are BETA. Breaking changes possible in minor versions. Pin versions in package.json and read changelogs before upgrading.
What this section does NOT cover
- Detailed migration plan from our current frontend to native widgets — see 12-ui-and-instantsearch
- Tool schema design — see 02-tool-types
- Output shape decisions for tool design — see 05-output-shape-decision