This June we’ve released a new way to add advanced AI chats to your product.

- [AI Copilots](#ai-copilots): Ready-made customizable React components for AI
  chats.
  - [Chat listings](#chat-listings): Create a dynamic chat switcher with
    permanent chats.
  - [Knowledge](#knowledge): Pass front and back-end contextual information to
    your AI.
  - [Copilots](#copilots): Set up your chosen OpenAI, Anthropic, and Gemini
    models.
  - [Tools](#tools): AI actions, custom components, human-in-the-loop
    interactions.
  - [Examples](#examples): An advanced dashboard integration, and two basic
    setups.

## Upgrade now

To use the latest features, update your packages with the following command.

```bash
npx create-liveblocks-app@latest --upgrade
```

If you were previously on Liveblocks 2.24 or below, make sure to follow our
[upgrade guides](/docs/platform/upgrading) before updating.

<MarketingCallout
  title="Try AI Copilots"
  buttonText="Book a demo"
  href="/contact/sales"
>
  Book a demo with our team to start building with AI Copilots.
</MarketingCallout>

## AI Copilots

It’s easier than ever to deeply integrate advanced AI into your app with
[Liveblocks AI Copilots](/ai-copilots). Start with our pre-built chat components
for React, and add knowledge, tools, and custom components.

<Figure
  caption={
    <>
      Our{" "}
      <Link href="/examples/ai-dashboard-reports">
        AI Dashboard Reports example
      </Link>{" "}
      highlights many different features.
    </>
  }
>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/liveblocks-3-0/many-features.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

Our ready-made [`AiChat`](/docs/api-reference/liveblocks-react-ui#AiChat)
component is all you need to get started. Each chat has a unique ID which you
must set.

```tsx
import { AiChat } from "@liveblocks/react-ui";

function App() {
  return <AiChat chatId="my-chat-id" />;
}
```

Chats are powered by our WebSocket collaboration layer, and update in real-time,
even with multiple browser tabs open. If you close the page, the chat will keep
streaming in, and you can re-open it to continue the conversation.

### Chat listings

Each chat in your app is tied to an authenticated user, and each user can have
multiple chats, and their chats are stored permanently. Replies can stream into
multiple chats at once, and switching between chats will never cause
interruptions.

<Figure
  caption={
    <>
      <Link href="/examples/ai-chats">AI Chats example</Link>.
    </>
  }
>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-june-25/switch-chats.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

It’s straightforward to create an interface that lets you switch between chats
with [`useAiChats`](/docs/api-reference/liveblocks-react#useAiChats).

```tsx highlight="6,12-16"
import { useState } from "react";
import { AiChat } from "@liveblocks/react-ui";
import { useAiChats } from "@liveblocks/react/suspense";

function Chats() {
  const { chats, error, isLoading } = useAiChats();
  const [chatId, setChatId] = useState();

  return (
    <>
      <ul>
        {chats.map((chat) => (
          <li key={chat.id} onClick={() => setChatId(chat.id)}>
            {chat.title || "Untitled"}
          </li>
        ))}
      </ul>
      <AiChat chatId={chatId} />
    </>
  );
}
```

Additionally you can create and delete new chats with
[`useCreateAiChat`](/docs/api-reference/liveblocks-react#useCreateAiChat) and
[`useDeleteAiChat`](/docs/api-reference/liveblocks-react#useDeleteAiChat).

### Knowledge

Knowledge is a way to pass information to your AI, so that it can understand
context and provide intelligent answers. There’s two ways to add it, on the
front-end and on the back-end.

#### Front-end knowledge

Front-end knowledge is ideal for passing relatively small amounts of data that’s
relevant to the current user or page. For example, you could pass the user’s
payment plan, the user’s information, or the current document’s text. Here’s how
to add it with
[`RegisterAiKnowledge`](/docs/api-reference/liveblocks-react#RegisterAiKnowledge).

```tsx
<RegisterAiKnowledge
  description="The current user's payment plan"
  value="Enterprise"
/>

<RegisterAiKnowledge
  description="The current user's info"
  value={{
    name: "Jody Hekla",
    email: "jody.hekla@example.com",
    teams: ["Engineering", "Product"],
  }}
/>

<RegisterAiKnowledge
  description="The current document's content"
  value={`
    # Untitled

    This is an untitled document.
  `}
/>
```

The AI will have access to this information when it’s generating a response. For
example, if you ask “Which plan am I on?” it’ll reply with “You're on the
_Enterprise_ plan”.

#### Back-end knowledge

Back-end knowledge is ideal for passing large amounts of data, for example
documentation and manuals. The AI will be able to read your knowledge base, and
accurately answer questions using your information. You can import PDF files,
images, and web pages, when managing your copilot from the dashboard.

### Copilots

By default, Liveblocks has an AI model set up, but you can also choose to create
a copilot with your chosen AI model from the Liveblocks dashboard. You can
define AI prompts, back-end knowledge sources (e.g. PDFs, websites), and a
number of different settings for your copilot.

<Figure>
  <Image
    src="/images/blog/whats-new-in-liveblocks-june-25/dashboard-manage-copilot.webp"
    alt="Manage your copilots in the Liveblocks dashboard"
    width={768}
    height={512}
    quality={90}
  />
</Figure>

OpenAI, Anthropic, and Gemini models are supported. Copy the `copilotId` from
the dashboard to use it with your chat.

```tsx highlight="7"
import { AiChat } from "@liveblocks/react-ui";

function App() {
  return (
    <AiChat
      chatId="my-chat-id"
      copilotId="co_MxwUN5Ah94wAAQEFo80U8" // ←
    />
  );
}
```

### Tools

Tools allow you to add complex interactions into your AI chat, for example
allowing AI to autonomously take actions, interact with your front-end, and
render custom components. Tools are implemented with
[`RegisterAiTool`](/docs/api-reference/liveblocks-react#RegisterAiTool).

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/liveblocks-3-0/invite-member.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

Above is an example of a human-in-the-loop action that allows AI to invite
members to a project. When confirm is clicked, a member is added to the page and
a toast is triggered.

#### Actions

By defining a tool with an `execute` function, AI can call a function in your
front-end, when it think it’s relevant. A simple example is a tool that shows
toast notification on the screen. Whenever you say “Show me a toast”, AI will
call the `execute` function, and render it.

```tsx highlight="4,6-13"
<RegisterAiTool
  name="send-toast-notification"
  tool={defineAiTool()({
    description: "Send a toast notification",

    execute: async () => {
      __toast__("Here's a toast!");

      return {
        data: {},
        description: "You sent a toast",
      };
    },
  })}
/>
```

You can take this a step further by adding parameters to the tool, in this case
a `message`, allowing the AI to decide what to write in the toast. You can show
UI in the chat, letting the user know a toast was sent, using `render`.

```tsx highlight="6-14,16-17,25"
<RegisterAiTool
  name="send-toast-notification"
  tool={defineAiTool()({
    description: "Send a toast notification",

    parameters: {
      type: "object",
      properties: {
        message: {
          type: "string",
          description: "The message to display in the toast",
        },
      },
    },

    execute: async ({ message }) => {
      __toast__(message);

      return {
        data: {},
        description: "You sent a toast",
      };
    },

    render: () => <AiTool title="Toast sent" icon="🍞" />,
  })}
/>
```

The [`AiTool`](/docs/api-reference/liveblocks-react-ui#AiTool) component renders
pre-built UI that matches the chat.

#### Human-in-the-loop actions

You can create human-in-the-loop actions, where the AI asks the user to confirm
an action, before it’s executed. This is useful for actions that are destructive
or irreversible, for example deleting a file. To implement this, don’t define
`execute`, and instead use
[`AiTool.Confirmation`](/docs/api-reference/liveblocks-react-ui#AiTool.Confirmation)
inside `render`.

```tsx highlight="19-30"
<RegisterAiTool
  name="delete-file"
  tool={defineAiTool()({
    description: "Delete a file from the user's workspace",

    parameters: {
      type: "object",
      properties: {
        fileName: { type: "string", description: "Name of the file" },
      },
    },

    render: ({ stage, args, result, types }) => {
      return (
        <AiTool
          title={stage === "executing" ? "Delete file?" : "File deleted"}
          icon="🗑️"
        >
          <AiTool.Confirmation
            types={types}
            confirm={async ({ fileName }) => {
              await __deleteFile__(fileName);
              return {
                data: { deletedFileName: fileName },
              };
            }}
            cancel={() => {}}
          >
            Are you sure you want to delete {args.fileName}?
          </AiTool.Confirmation>
        </AiTool>
      );
    },
  })}
/>
```

The example above will show a confirm/cancel box in the chat, and the `confirm`
function will be triggered when the user clicks the button.

#### Custom components

You can render fully custom components inside the chat, for example, below I’m
adding a button that creates a new project. Whenever AI hears “Create project”,
it’ll render the button below its message.

```tsx
<RegisterAiTool
  name="create-project"
  tool={defineAiTool()({
    description: "Create a new project",

    render: () => (
      <button
        className="bg-blue-500 rounded-md p-2 text-white"
        onClick={() => {
          __newProject__();
        }}
      >
        Create project
      </button>
    ),
  })}
/>
```

You also can create custom confirm/dialog boxes using `render`.

### Examples

We’ve created a number of examples to help you get started with AI Copilots.

#### AI Dashboard Reports

Our [AI Dashboard Reports](/examples/ai-dashboard-reports) example contains an
AI pop-up chat that allows you to ask questions about the transactions and
invoices represented on the page. Additionally, it can navigate you to different
pages, invite new users, send unpaid invoice reminders, and share how many seats
are left on your plan.

<div className="my-8 hidden sm:block md:my-10">
  <div className="relative rounded-xl bg-marketing-surface-faded-subtle p-2 after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
    <div className="relative aspect-4/3 w-full overflow-hidden rounded-md after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
      <Embed
        src="https://nextjs-ai-dashboard-reports.liveblocks.app/"
        className="absolute origin-top-left"
        style={{
          width: `${1.62 * 100}%`,
          height: `${1.62 * 100}%`,
          transform: `scale(${1 / 1.62})`,
        }}
      />
    </div>
  </div>
</div>

#### AI Chats

Our [AI Chats](/examples/ai-chats) example demonstrates how to create a chat
switcher and listing page.

<div className="my-8 hidden sm:block md:my-10">
  <div className="relative rounded-xl bg-marketing-surface-faded-subtle p-2 after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
    <div className="relative aspect-4/3 w-full overflow-hidden rounded-md after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
      <Embed
        src="https://nextjs-ai-chats.liveblocks.app/"
        className="absolute origin-top-left"
        style={{
          width: `${1.5 * 100}%`,
          height: `${1.5 * 100}%`,
          transform: `scale(${1 / 1.5})`,
        }}
      />
    </div>
  </div>
</div>

#### AI Popup Chat

Our [AI Popup Chat](/examples/ai-popup) example demonstrates how to create a
floating pop-up chat in the corner of your application. It has a panel for
switching between different chats, and a button to open a new chat.

<div className="my-8 hidden sm:block md:my-10">
  <div className="relative rounded-xl bg-marketing-surface-faded-subtle p-2 after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
    <div className="relative aspect-4/3 w-full overflow-hidden rounded-md after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-marketing-divider-subtle">
      <Embed
        src="https://nextjs-ai-popup.liveblocks.app/"
        className="absolute origin-top-left"
        style={{
          width: `${1.4 * 100}%`,
          height: `${1.4 * 100}%`,
          transform: `scale(${1 / 1.4})`,
        }}
      />
    </div>
  </div>
</div>

## Minor improvements

Here’s a list of other improvements in [our changelog](/changelog) since our
last update:

- TypeScript 5.0 is now the minimum supported version.
- Remove deprecated APIs, see
  [the deprecated section](/docs/platform/upgrading/3.0#deprecated) in the
  upgrade guide to learn more.
- Rename `UPDATE_USER_NOTIFICATION_SETTINGS_ERROR` to
  `UPDATE_NOTIFICATION_SETTINGS_ERROR` when using `useNotificationSettings` or
  `useUpdateNotificationSettings`.
- The `onMentionClick` prop on `Thread` and `Comment` now receives a
  `MentionData` object instead of a `userId` string.
- The `Mention` component on the `Comment.Body` and `Composer.Editor` primitives
  now receives a `mention` prop instead of a `userId` one.
- The `MentionSuggestions` component on the `Composer.Editor` primitive now
  receives a `mentions` prop instead of a `userIds` one, and the
  `selectedUserId` prop has been renamed to `selectedMentionId`.
- Rename `LiveblocksUIConfig` to `LiveblocksUiConfig` for consistency with other
  Liveblocks APIs.
- Remove deprecated `htmlBody`/`reactBody` properties from
  `prepareThreadNotificationEmailAsHtml` /
  `prepareThreadNotificationEmailAsReact`, use `body` instead.
- Remove `htmlContent`/`reactContent` properties from
  `prepareTextMentionNotificationEmailAsHtml` /
  `prepareTextMentionNotificationEmailAsReact`, use `content` instead.
- The `prepareTextMentionNotificationEmailAsReact` and
  `prepareTextMentionNotificationEmailAsHtml` functions’ returned data changed
  slightly:
  - The `id` property is now named `textMentionId`, it refers to the mention’s
    Text Mention ID, not the user ID used for the mention
  - The `id` property now refers to the mention’s ID, as in the user ID used for
    the mention
- The `element` prop received by the `Mention` component in
  `prepareTextMentionNotificationEmailAsReact` now contains an `id` property
  instead of `userId`, and a new `kind` property to indicate the mention’s kind.
- The `getMentionedIdsFromCommentBody` utility has been replaced by
  `getMentionsFromCommentBody`.
- Add `InboxNotification.Inspector` component to help debugging custom inbox
  notifications.
- Add support for Redux v5.
- Fix default `z-index` of collaboration cursors, and make them inherit their
  font family instead of always using Arial.
- Add `lb-lexical-cursors` class to the collaboration cursors’ container.
- Improve URL sanitization in comments.
- Improve mentions’ serialization.
- Adds experimental setting `LiveObject.detectLargeObjects`, which can be
  enabled globally using `LiveObject.detectLargeObjects = true` (default is
  false). With this setting enabled, calls to `LiveObject.set()` or
  `LiveObject.update()` will throw as soon as you add a value that would make
  the total size of the LiveObject exceed the platform limit of 128 kB. The
  benefit is that you get an early error instead of a silent failure, but the
  downside is that this adds significant runtime overhead if your application
  makes many LiveObject mutations.
- Fix: also display errors in production builds when they happen in `render`
  methods defined with `defineAiTool()`. Previously, these errors would only be
  shown during development.
- Fix an issue with the render component of tool calls not being displayed
  correctly when the tool call signal was read before it was registered.
- Fix caching issue when editing notification settings.

Find the complete information [in our changelog](/changelog).

### Upgrade

To use these latest features, update your packages with:

```bash
npx create-liveblocks-app@latest --upgrade
```

## Contributors

<Contributors
  gitHubUsernames={[
    "adigau",
    "ctnicholas",
    "flowflorent",
    "jrowny",
    "marcbouchenoire",
    "nimeshnayaju",
    "nvie",
    "ofoucherot",
    "pierrelevaillant",
    "stevenfabre",
    "sugardarius",
  ]}
/>