> ## Documentation Index
> Fetch the complete documentation index at: https://www.algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate Agent Studio

> Integrate the Agent Studio with your application to deliver generative AI experiences powered by Algolia and large language models (LLMs).

export const ApplicationID = () => <Tooltip tip="A unique alphanumeric string that identifies an Algolia application." cta="Application ID (dashboard)" href="https://dashboard.algolia.com/account/api-keys">
    application ID
  </Tooltip>;

You can interact with your published agents using HTTP API or use the AI SDK UI for a seamless integration.

## Steps for integrating Agent Studio

<Steps>
  <Step title="Prepare your agent">
    Ensure that your agent is configured and published in the Algolia dashboard.
    To learn more, see [Get started with the Agent Studio dashboard](/doc/guides/algolia-ai/agent-studio/how-to/dashboard).
  </Step>

  <Step title="Get your agent ID">
    On the [**Agents**](https://dashboard.algolia.com/generativeAi/agent-studio/agents) page in the Agent Studio's dashboard,
    find your published agent's ID.
  </Step>

  <Step title="Choose how you want to integrate Agent Studio">
    * **HTTP API**: directly interact with your agent using HTTP requests.
    * **InstantSearch**: use the InstantSearch.js or React InstantSearch libraries to integrate search capabilities alongside your agent.
    * **AI SDK UI**: use the React-based SDK for a ready-to-use conversational UI.
  </Step>
</Steps>

## API integration

Interact with your GenAI agent directly using the Agent Studio API.

**Example curl request:**

```sh Command line icon=square-terminal theme={"system"}
curl "https://$ALGOLIA_APPLICATION_ID.algolia.net/agent-studio/1/agents/$AGENT_ID/completions?stream=false&compatibilityMode=ai-sdk-5" \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "x-algolia-application-id: $ALGOLIA_APPLICATION_ID" \
  -H "X-Algolia-API-Key: $ALGOLIA_SEARCH_API_KEY" \
  --data-raw '{
  "messages": [
        {
            "role": "user",
            "parts": [
                {
                    "text": "What is 1+1 ?"
                }
            ]
        }
    ]
}'
```

And the response would look like the following:

```json JSON icon=braces theme={"system"}
{
  "role": "assistant",
  "parts": [
    {
      "type": "step-start"
    },
    {
      "type": "text",
      "text": "1 + 1 = 2"
    }
  ]
}
```

To continue the conversation, include the previous messages in the request:

```diff JSON icon=braces theme={"system"}
{
    "messages": [
        {
            "role": "user",
            "content": "What is 1+1 ?"
        },
        {
            "role": "assistant",
            "content": "The sum of 1 + 1 is 2."
        },
+        {
+            "role": "user",
+            "content": "What is the sum of the previous value + 3"
+        }
    ]
}
```

To override Algolia search behavior for a single request, include `algolia.searchParameters` in the request body.
For supported fields and examples, see [Algolia Search tool](/doc/guides/algolia-ai/agent-studio/how-to/tools/algolia-search#query-time-search-parameter-overrides).
For the request schema for `POST /agent-studio/1/agents/{agentId}/completions`, see the [Agent Studio API reference](/doc/rest-api/agent-studio).

### Enable conversation persistence

To automatically save conversations server-side, include both a conversation ID and message IDs in your request:

```sh Command line icon=square-terminal theme={"system"}
curl "https://$ALGOLIA_APPLICATION_ID.algolia.net/agent-studio/1/agents/$AGENT_ID/completions?stream=false&compatibilityMode=ai-sdk-5" \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "x-algolia-application-id: $ALGOLIA_APPLICATION_ID" \
  -H "X-Algolia-API-Key: $ALGOLIA_SEARCH_API_KEY" \
  --data-raw '{
  "id": "alg_cnv_abc123",
  "messages": [
        {
            "id": "alg_msg_001",
            "role": "user",
            "parts": [
                {
                    "text": "What is 1+1 ?"
                }
            ]
        }
    ]
}'
```

Both fields are required:

* `id`: conversation identifier (prefix with `alg_cnv_` for consistency)
* `messages[].id`: unique ID for each message (prefix with `alg_msg_`)

You can then retrieve the conversation history using the conversations API.
For more information,
see [Conversations](/doc/guides/algolia-ai/agent-studio/how-to/conversations).

***

* Replace `{{ALGOLIA_APPLICATION_ID}}` with *your* Algolia <ApplicationID />.
* Replace `{{agentId}}` with *your* published agent ID.
* Use your application's [search-only API key](/doc/guides/security/api-keys#search-only-api-key) for authentication.
* The endpoint supports streaming responses and is compatible with [`ai-sdk`](https://ai-sdk.dev) v4 and v5.
* For streaming responses, set `stream=true` in the query parameters.
* For production, secure your API keys and restrict usage as needed.

## InstantSearch integration

Agent Studio is compatible with InstantSearch.js and React InstantSearch.
The InstantSearch integration only supports `ai-sdk` [v5](https://v5.ai-sdk.dev/).

The benefits of using InstantSearch are:

* Provides an out-of-the-box chat interface with multiple customization options.
* Integrates search results alongside your agent's responses.
* Handles custom tools with minimal setup.

For more information,
see [Get started with React InstantSearch](/doc/guides/building-search-ui/getting-started/react) and the [examples on GitHub](https://github.com/algolia/instantsearch/tree/master/examples/react/getting-started).

### Examples

The `Chat` widget renders the chat panel but doesn't render a way to open it.
Pair it with the [`ChatTrigger`](/doc/api-reference/widgets/chat-trigger/react) widget to add a floating button that opens the chat.

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  import { liteClient as algoliasearch } from 'algoliasearch/lite';
  import { InstantSearch, Chat, ChatTrigger } from 'react-instantsearch';
  import 'instantsearch.css/components/chat.css';

  const appID = "ALGOLIA_APPLICATION_ID";
  const apiKey = "ALGOLIA_API_KEY";
  const agentId = "AGENT_ID";

  const searchClient = algoliasearch(appID, apiKey);
  export function App() {
    return (
      <InstantSearch searchClient={searchClient}>
        <Chat
          agentId={agentId}
          itemComponent={({ item }) => (
            <div>
              <h3>{item.title}</h3>
              <p>{item.description}</p>
            </div>
          )}
        />
        <ChatTrigger />
      </InstantSearch>
    );
  }
  ```

  ```js Javascript icon=code theme={"system"}
  import { liteClient as algoliasearch } from 'algoliasearch/lite';
  import instantsearch from 'instantsearch.js';
  import { chat, chatTrigger } from 'instantsearch.js/es/widgets';
  import 'instantsearch.css/components/chat.css';

  const appID = "ALGOLIA_APPLICATION_ID";
  const apiKey = "ALGOLIA_API_KEY";
  const agentId = "AGENT_ID";

  const searchClient = algoliasearch(appID, apiKey);
  const search = instantsearch({ searchClient });

  search.addWidgets([
    chat({
      container: '#chat',
      agentId,
      templates: {
        item({ item }, { html }) {
          return html`
            <div>
              <h3>${item.title}</h3>
              <p>${item.description}</p>
            </div>
          `;
        },
      },
    }),
    chatTrigger({
      container: '#chat-trigger',
    }),
  ]);

  search.start();
  ```
</CodeGroup>

### Chat trigger

The [`Chat`](/doc/api-reference/widgets/chat/react) widget renders the chat panel but, on its own, doesn't give users a way to open it.
Add one of the following entry points to the same `InstantSearch` instance:

* The [`ChatTrigger`](/doc/api-reference/widgets/chat-trigger/react) widget, which renders a floating button that opens the chat overlay.
* [AI mode](/doc/guides/building-search-ui/going-further/chat-customization/ai-search-experience/react) on a `SearchBox` or autocomplete, which opens the chat with the user's query.
* An [inline layout](/doc/api-reference/widgets/chat/react#param-layout-component), which is always visible and doesn't need a trigger.

If the chat has none of these, the `Chat` widget logs a development warning.
To silence it (for example, when you open the chat programmatically), set `disableTriggerValidation` to `true` on the `Chat` widget.

By default, the trigger is a floating button anchored to the bottom-right of the viewport.
Set `floating` to `false` to render an inline button that flows with surrounding content.

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  import { Chat, ChatTrigger } from 'react-instantsearch';

  <Chat agentId={agentId} />
  {/* Floating button anchored to the bottom-right (default) */}
  <ChatTrigger />
  {/* Or an inline button that flows with surrounding content */}
  <ChatTrigger floating={false} />
  ```

  ```js Javascript icon=code theme={"system"}
  import { chat, chatTrigger } from 'instantsearch.js/es/widgets';

  chat({
    container: '#chat',
    agentId,
  });

  // Floating button anchored to the bottom-right (default)
  chatTrigger({
    container: '#chat-trigger',
  });

  // Or an inline button that flows with surrounding content
  chatTrigger({
    container: '#chat-trigger',
    floating: false,
  });
  ```
</CodeGroup>

### Rendering search results

If your agent uses a search tool, you must define item templates or components to control how search results appear in the chat interface.
Templates are required for search results.
They let you display product information, images, or other data in a format that fits your application.

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  <Chat
    // ...otherProps
    itemComponent={({ item }) => (
      <div>
        <h3>{item.title}</h3>
        <p>{item.description}</p>
        <img src={item.image} alt={item.title} />
      </div>
    )}
  />
  ```

  ```js Javascript icon=code theme={"system"}
  chat({
    // ...otherProps,
    templates: {
      item(item, { html }) {
        return html`
          <div>
            <h3>${item.title}</h3>
            <p>${item.description}</p>
            <img src="${item.image}" alt="${item.title}" />
          </div>
        `;
      },
    },
  }),
  ```
</CodeGroup>

The `itemComponent` (React) or `templates.item` (JavaScript) template renders each search result item with custom HTML and styling.
If your agent uses a search tool, you must define this template to display search results correctly in the chat interface.

### Insights events for agentic results

When you use the InstantSearch Chat widget with [events collection enabled](/doc/guides/sending-events/instantsearch/send-events#enable-events-collection), InstantSearch attributes events from agent-rendered results automatically.
This includes results rendered by the built-in Agent Studio search and display-results tools, and events sent with the `sendEvent` function passed to custom tool layouts.

Agentic results use an agentic `queryID`. Instead of using the Search API `queryID` from one underlying search request, InstantSearch attributes the event to the assistant message that presented the results:

```text theme={"system"}
message_<assistantMessageId>
```

This keeps all view, click, and conversion events from the same assistant message tied to the same agentic result set.

If you customize a tool layout, use the provided `sendEvent` function instead of calling the Insights API directly.
InstantSearch adds the required agentic `queryID` field for you.

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  <Chat
    agentId={agentId}
    tools={{
      custom_recommendations: {
        layoutComponent({ message, sendEvent }) {
          const items = message.output?.items ?? [];

          return (
            <ul>
              {items.map((item, index) => (
                <li key={item.objectID}>
                  <button
                    onClick={() =>
                      sendEvent(
                        'click',
                        {
                          ...item,
                          __position: index + 1,
                        },
                        'Agent Result Clicked'
                      )
                    }
                  >
                    {item.name}
                  </button>
                </li>
              ))}
            </ul>
          );
        },
      },
    }}
  />
  ```

  ```js Javascript icon=code theme={"system"}
  import { chat } from 'instantsearch.js/es/widgets';

  search.addWidgets([
    chat({
      container: '#chat',
      agentId,
      tools: {
        custom_recommendations: {
          templates: {
            layout({ message, sendEvent }, { html }) {
              const items = message.output?.items ?? [];

              return html`<ul>
                ${items.map(
                  (item, index) => html`<li>
                    <button
                      type="button"
                      onclick="${() =>
                        sendEvent(
                          'click',
                          {
                            ...item,
                            __position: index + 1,
                          },
                          'Agent Result Clicked'
                        )}"
                    >
                      ${item.name}
                    </button>
                  </li>`
                )}
              </ul>`;
            },
          },
        },
      },
    }),
  ]);
  ```
</CodeGroup>

Use this pattern when the event is caused by a result shown in an assistant message.
For events from a regular search results page, continue using the regular search `queryID`.

### Tools

InstantSearch Chat widgets let you integrate tools in your agent's responses.
Once a tool has been added to your agent in the dashboard, you can customize how it's rendered with InstantSearch.

For a complete guide to configuring tools in Agent Studio, see [Tools for Agent Studio](/doc/guides/algolia-ai/agent-studio/how-to/tools).

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  <Chat
    // ...otherProps
    tools={{
      weather: {
        layoutComponent: ({
          message,
          indexUiState,
          setIndexUiState,
          addToolResult,
        }) => <CustomWeatherComponent message={message} />,
        onToolCall: ({ addToolResult, input, ...rest }) =>
          addToolResult({ output: { temperature: 20 } }),
      },
    }}
  />
  ```

  ```js Javascript icon=code theme={"system"}
  chat({
    // ...otherProps,
    tools: {
      weather: {
        templates: {
          layout: (
            { message, indexUiState, setIndexUiState, addToolResult },
            { html }
          ) => html`<div>Custom weather component: ${message}</div>`,
        },
        onToolCall: ({ addToolResult, input, ...rest }) =>
          addToolResult({ output: { temperature: 20 } }),
      },
    },
  }),
  ```
</CodeGroup>

The `tools` prop is an object where the keys are the tool names defined in your agent configuration.
Each tool includes a `layoutComponent` (React) or `templates.layout` (JavaScript) to customize how tool calls appear in the chat interface, and an optional `onToolCall` handler to run custom logic when the tool is invoked.

For the full list of available props (including `applyFilters`, `sendEvent`, `onClose`, and `streamInput`), see the Chat widget reference for [React](/doc/api-reference/widgets/chat/react#param-tools) or [JavaScript](/doc/api-reference/widgets/chat/js#param-tools).

### Hidden context

Use the `context` prop (React) or `context` option (JavaScript) on the chat widget to send extra metadata with each user message—for example, the current page, locale, or session segment.
The widget serializes the value as JSON and adds it to the user message as a hidden text part of the form `<context>{"key":"value"}</context>`.
Users don't see it in the chat UI, but the agent does.

`context` can be a static object or a function that returns an object at send time.
Use a function when the context depends on the current state of the page.

<Warning>
  The widget sends `context` to the agent in plain text.
  Don't put secrets, access tokens, or personally identifiable information you don't intend to share with the model in this field.
</Warning>

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  <Chat
    // ...otherProps
    context={() => ({
      locale: navigator.language,
      currentPage: window.location.pathname,
    })}
  />
  ```

  ```js Javascript icon=code theme={"system"}
  chat({
    // ...otherProps,
    context: () => ({
      locale: navigator.language,
      currentPage: window.location.pathname,
    }),
  }),
  ```
</CodeGroup>

For more details, see the Chat widget reference for [React](/doc/api-reference/widgets/chat/react#param-context) or [JavaScript](/doc/api-reference/widgets/chat/js#param-context).

### Follow-up prompt suggestions

Follow-up prompt suggestions can be enabled in InstantSearch by enabling the suggestions feature in the [Agent Studio dashboard](/doc/guides/algolia-ai/agent-studio/how-to/dashboard#follow-up-prompt-suggestions) or [API](/doc/guides/algolia-ai/agent-studio/how-to/agent-configuration#follow-up-prompt-suggestions).

When enabled, the Chat widgets automatically handle and display suggestions after each agent response.
You can customize the suggestions layout using the `suggestions` component or template.

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  <Chat
    // ...otherProps
    suggestionsComponent={({ suggestions, onSuggestionClick }) => (
      <div>
        <h4>Suggestions:</h4>
        <ul>
          {suggestions.map((suggestion, index) => (
            <li key={index} onClick={() => onSuggestionClick(suggestion)}>
              {suggestion}
            </li>
          ))}
        </ul>
      </div>
    )}
  />
  ```

  ```js Javascript icon=code theme={"system"}
  chat({
    // ...
    templates: {
      // ...
      suggestions({ suggestions, onSuggestionClick }, { html }) {
        return html`
          <ul>
            ${suggestions.map(
              (suggestion) =>
                html`<li>
                  <button onClick=${() => onSuggestionClick(suggestion)}>
                    ${suggestion}
                  </button>
                </li>`,
            )}
          </ul>
        `;
      },
    },
  });
  ```
</CodeGroup>

### Prompt suggestions

To display AI-generated prompt suggestions outside the chat, for example on a search results or product detail page, use the `PromptSuggestions` widget.
It generates prompts from the current search context and hands them off to the chat widget when clicked.
To control how the agent generates suggestions, create a prompt configuration in the dashboard.
See [Generate prompt suggestions for your pages](/doc/guides/algolia-ai/agent-studio/how-to/prompt-suggestions).

For more details, see the `PromptSuggestions` widget reference for [React](/doc/api-reference/widgets/prompt-suggestions/react) or [JavaScript](/doc/api-reference/widgets/prompt-suggestions/js).

### Complete examples

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  import { liteClient as algoliasearch } from 'algoliasearch/lite';
  import { InstantSearch, Chat, ChatTrigger } from 'react-instantsearch';
  import 'instantsearch.css/components/chat.css';

  const appID = "ALGOLIA_APPLICATION_ID";
  const apiKey = "ALGOLIA_API_KEY";
  const agentId = "AGENT_ID";

  const searchClient = algoliasearch(appID, apiKey);

  export function App() {
    return (
      <InstantSearch searchClient={searchClient}>
        <Chat
          agentId={agentId}
          itemComponent={({ item }) => (
            <div>
              <h3>{item.title}</h3>
              <p>{item.description}</p>
            </div>
          )}
          tools={{
            weather: {
              layoutComponent: () => <div>Custom weather component</div>,
              onToolCall: ({ addToolResult }) =>
                addToolResult({ output: { temperature: 20 } }),
            },
          }}
        />
        <ChatTrigger />
      </InstantSearch>
    );
  }
  ```

  ```js Javascript icon=code theme={"system"}
  import { liteClient as algoliasearch } from 'algoliasearch/lite';
  import instantsearch from 'instantsearch.js';
  import { chat, chatTrigger } from 'instantsearch.js/es/widgets';
  import 'instantsearch.css/components/chat.css';

  const appID = "ALGOLIA_APPLICATION_ID";
  const apiKey = "ALGOLIA_API_KEY";
  const agentId = "AGENT_ID";

  const searchClient = algoliasearch(appID, apiKey);
  const search = instantsearch({ searchClient });

  search.addWidgets([
    chat({
      container: '#chat',
      agentId,
      templates: {
        item(item, { html }) {
          return html`
            <div>
              <h3>${item.title}</h3>
              <p>${item.description}</p>
            </div>
          `;
        },
      },
      tools: {
        weather: {
          template: {
            layout: (_, { html }) => html`<div>Custom weather component</div>`,
          },
          onToolCall: ({ addToolResult }) =>
            addToolResult({ output: { temperature: 20 } }),
        },
      },
    }),
    chatTrigger({
      container: '#chat-trigger',
    }),
  ]);

  search.start();
  ```
</CodeGroup>

## AI SDK UI integration

The Agent Studio is compatible with [AI SDK UI](https://ai-sdk.dev/docs/ai-sdk-ui/overview),
a React-based UI integration for building conversational interfaces.
Agent Studio supports both `ai-sdk` [v5](https://v5.ai-sdk.dev/) and [v4](https://v4.ai-sdk.dev/).

AI SDK UI isn't required to use Agent Studio, but it makes the integration process much easier by handling common tasks like UI rendering and state management.
The benefits of using the AI SDK UI are:

* Abstractions over low-level HTTP requests
* Built-in error handling, retries, and extensibility using middleware and plugins
* Fast setup for conversational user interfaces

It also allows for advanced use cases, such as:

* Custom tool handling
* UI state control

For more information, see the [AI SDK](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot) documentation.

### Installation

```sh Command line icon=square-terminal theme={"system"}
npm install ai @ai-sdk/react
```

### Example React integration

```jsx React icon=code theme={"system"}
import { useState } from 'react';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';

const App = () => {
  const [input, setInput] = useState('');

  const appID = "ALGOLIA_APPLICATION_ID";
  const apiKey = "ALGOLIA_SEARCH_API_KEY";
  const agentId = "AGENT_ID";

  const { messages, sendMessage } = useChat({
    transport: new DefaultChatTransport({
      api: `https://${appID}.algolia.net/agent-studio/1/agents/${agentId}/completions?stream=true&compatibilityMode=ai-sdk-5`,
      headers: {
        'x-algolia-application-id': appID,
        'x-algolia-api-key': apiKey,
      },
    }),
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    sendMessage({ text: input });
    setInput('');
  };

  return (
    <>
      {messages.map((message) => (
        <div key={message.id}>
          {message.role === 'user' ? 'User: ' : 'AI: '}
          {message.parts.map((part, index) =>
            part.type === 'text' ? <span key={index}>{part.text}</span> : null,
          )}
        </div>
      ))}

      <form onSubmit={handleSubmit}>
        <input value={input} onChange={(e) => setInput(e.target.value)} />
        <button type="submit">Submit</button>
      </form>
    </>
  );
};
```

## Send agentic Insights events manually

If you don't use InstantSearch Chat, use the ID of the assistant message that rendered the results.
With Agent Studio, this is the `id` from the assistant message returned by the completion response.
Store that assistant message, including its `id`, in your conversation state so later clicks and conversions can reuse the same `queryID`.

Build the event `queryID` from the assistant message ID:

```js theme={"system"}
const queryID = `message_${assistantMessage.id}`;
```

Positions should match the item's visible position in the assistant message, starting at `1`.

<CodeGroup>
  ```jsx React icon=code theme={"system"}
  function AgenticResults({
    assistantMessage,
    items,
    userToken,
    agentId,
    toolCallId,
  }) {
    const queryID = `message_${assistantMessage.id}`;

    React.useEffect(() => {
      if (items.length === 0) {
        return;
      }

      aa('viewedObjectIDs', {
        userToken,
        index: 'products',
        eventName: 'items_shown',
        objectIDs: items.map((item) => item.objectID),
        queryID,
      });
    }, [items, queryID, userToken]);

    return (
      <ul>
        {items.map((item, index) => {
          const position = index + 1;

          return (
            <li key={item.objectID}>
              <button
                type="button"
                onClick={() =>
                  aa('clickedObjectIDsAfterSearch', {
                    userToken,
                    index: 'products',
                    eventName: 'Agent Result Clicked',
                    objectIDs: [item.objectID],
                    positions: [position],
                    queryID,
                  })
                }
              >
                {item.name}
              </button>
            </li>
          );
        })}
      </ul>
    );
  }
  ```

  ```js JavaScript icon=code theme={"system"}
  const queryID = `message_${assistantMessage.id}`;
  const messageElement = document.querySelector(
    `[data-agentic-message-id="${assistantMessage.id}"]`
  );

  aa('viewedObjectIDs', {
    userToken,
    index: 'products',
    eventName: 'items_shown',
    objectIDs: items.map((item) => item.objectID),
    queryID,
  });

  messageElement
    ?.querySelectorAll('[data-agentic-result]')
    .forEach((resultElement, index) => {
      resultElement.addEventListener('click', () => {
        const objectID = resultElement.getAttribute('data-object-id');

        if (!objectID) {
          return;
        }

        aa('clickedObjectIDsAfterSearch', {
          userToken,
          index: 'products',
          eventName: 'Agent Result Clicked',
          objectIDs: [objectID],
          positions: [index + 1],
          queryID,
        });
      });
    });
  ```
</CodeGroup>

If the user converts later, reuse the same agentic `queryID` from the assistant message that showed the result.

```js JavaScript icon=code theme={"system"}
aa('convertedObjectIDsAfterSearch', {
  userToken,
  index: 'products',
  eventName: 'Agent Result Converted',
  objectIDs: [item.objectID],
  queryID,
});
```
