From 3b1e20b81968ce35a3ffcd50b7a4c80749bf1c49 Mon Sep 17 00:00:00 2001 From: Chris Nicholas Date: Wed, 27 May 2026 10:29:57 +0100 Subject: [PATCH] New AI get started guides (#3489) Co-authored-by: Cursor Agent Co-authored-by: Chris Nicholas Co-authored-by: Marc Bouchenoire --- .../get-started/nextjs-ai-notifications.mdx | 378 ++++++++++++++++++ docs/pages/get-started/nextjs-ai-presence.mdx | 343 ++++++++++++++++ .../get-started/nextjs-ai-react-flow.mdx | 273 +++++++++++++ .../nextjs-notifications-custom-in-app.mdx | 61 ++- .../nextjs-notifications-in-app.mdx | 61 ++- docs/pages/get-started/nextjs-presence.mdx | 4 +- docs/routes.json | 15 + 7 files changed, 1123 insertions(+), 12 deletions(-) create mode 100644 docs/pages/get-started/nextjs-ai-notifications.mdx create mode 100644 docs/pages/get-started/nextjs-ai-presence.mdx create mode 100644 docs/pages/get-started/nextjs-ai-react-flow.mdx diff --git a/docs/pages/get-started/nextjs-ai-notifications.mdx b/docs/pages/get-started/nextjs-ai-notifications.mdx new file mode 100644 index 00000000000..5d1ff69b680 --- /dev/null +++ b/docs/pages/get-started/nextjs-ai-notifications.mdx @@ -0,0 +1,378 @@ +--- +meta: + title: "Get started with AI agent notifications using Liveblocks and Next.js" + parentTitle: "Quickstart" + description: + "Learn how to notify users when an AI agent has completed its work using + Liveblocks notifications and Next.js" +--- + +Liveblocks is a realtime collaboration infrastructure for building performant +collaborative experiences. Follow this guide to create an inbox notification +system in your app, and notify users when an AI agent has completed its work. +This uses a Next.js `/app` directory application, with the hooks from +[`@liveblocks/react`](/docs/api-reference/liveblocks-react), the components from +[`@liveblocks/react-ui`](/docs/api-reference/liveblocks-react-ui), and +[`@liveblocks/node`](/docs/api-reference/liveblocks-node) on the server. + +## Quickstart + + + + + + Install Liveblocks + + + Every package should use the same version. + + ```bash trackEvent="install_liveblocks" + npm install @liveblocks/client @liveblocks/react @liveblocks/react-ui @liveblocks/node + ``` + + + + + + Initialize the `liveblocks.config.ts` file + + + We can use this file later to [define types for our application](/docs/api-reference/liveblocks-react#Typing-your-data). + + ```bash + npx create-liveblocks-app@latest --init --framework react + ``` + + + + + + Add your secret key + + + Create a `.env.local` file and add your Liveblocks secret key from the + [dashboard](/dashboard/apikeys). + + ```env file=".env.local" + LIVEBLOCKS_SECRET_KEY="{{SECRET_KEY}}" + ``` + + + + + + Set up authentication + + + Create an [authentication](/docs/authentication) API route with + [`identifyUser`](/docs/api-reference/liveblocks-node#id-tokens), + passing a unique user ID. + + ```ts file="app/api/liveblocks-auth/route.ts" + import { Liveblocks } from "@liveblocks/node"; + + const liveblocks = new Liveblocks({ + secret: process.env.LIVEBLOCKS_SECRET_KEY!, + }); + + export async function POST(request: Request) { + // Get the current user from your database + const user = __getUserFromDB__(request); + + // Identify the user and return the result + const { status, body } = await liveblocks.identifyUser( + { userId: user.id }, + { + userInfo: { + name: user.name, + avatar: user.avatar, + }, + }, + ); + + return new Response(body, { status }); + } + ``` + + + + + + Create a Liveblocks provider + + + Liveblocks Notifications uses the concept of projects, which relate to + projects in [your dashboard](/dashboard). Notifications are sent between + users in the same project. To connect and receive notifications, you must + add [`LiveblocksProvider`](/docs/api-reference/liveblocks-react#LiveblocksProvider) + to a client component in your app. + + ```tsx file="app/Providers.tsx" highlight="8-10" + "use client"; + + import { ReactNode } from "react"; + import { LiveblocksProvider } from "@liveblocks/react"; + + export function Providers({ children }: { children: ReactNode }) { + return ( + + {children} + + ); + } + ``` + + + + + + Add the provider to your layout + + + After creating your provider file, it’s time to use it. Import + your room into your `layout.tsx` file. + + ```tsx file="app/layout.tsx" + import { Providers } from "./Providers"; + + export default function Layout({ children }) { + return ( + + + // +++ + + {children} + + // +++ + + + ); + } + ``` + + + + + + Use the Liveblocks hooks and components + + + Now that we’ve set up the provider, we can start using the Liveblocks hooks and components. + We’ll add [`useInboxNotifications`](/docs/api-reference/liveblocks-react#useInboxNotifications) + to get the current project’s notifications, then we’ll + use [`InboxNotification`](/docs/api-reference/liveblocks-react-ui#InboxNotification) and [`InboxNotificationList`](/docs/api-reference/liveblocks-react-ui#InboxNotificationList) to render them. + + ```tsx file="app/page.tsx" highlight="10,13-20" + "use client"; + + import { useInboxNotifications } from "@liveblocks/react/suspense"; + import { + InboxNotification, + InboxNotificationList, + } from "@liveblocks/react-ui"; + + export default function Page() { + const { inboxNotifications } = useInboxNotifications(); + + return ( + + {inboxNotifications.map((inboxNotification) => ( + + ))} + + ); + } + ``` + + + + + + Import default styles + + + The default components come with default styles, you can import them into the + root layout of your app or directly into a CSS file with `@import`. + + ```tsx file="app/layout.tsx" + import "@liveblocks/react-ui/styles.css"; + ``` + + + + + + + Notify the user when your agent completes + + + Trigger a notification with + [`triggerInboxNotification`](/docs/api-reference/liveblocks-node#post-inbox-notifications-trigger) + from a server action or route handler at the end of your agent’s work. In + this example, a custom `$agentCompleted` notification is sent once the + agent has finished a task. + + ```ts file="app/run-agent.ts" + "use server"; + + import { Liveblocks } from "@liveblocks/node"; + + const liveblocks = new Liveblocks({ + secret: process.env.LIVEBLOCKS_SECRET_KEY!, + }); + + export async function runAgent({ + userId, + task, + }: { + userId: string; + task: string; + }) { + const startedAt = Date.now(); + + // Run your AI agent here, e.g. generateText, mutateFlow, … + await __runYourAgent__({ task }); + + // +++ + // Notify the user that the agent has finished + await liveblocks.triggerInboxNotification({ + userId, + kind: "$agentCompleted", + subjectId: `agent-${task}`, + activityData: { + task, + status: "complete", + durationMs: Date.now() - startedAt, + }, + }); + // +++ + } + ``` + + + + + + + + Render the agent notification + + + After triggering the custom notification, modify `InboxNotification` to + [render `$agentCompleted` with custom UI](/docs/api-reference/liveblocks-react-ui#Rendering-notification-kinds-differently). + + ```tsx file="app/page.tsx" + "use client"; + + import { useInboxNotifications } from "@liveblocks/react/suspense"; + import { + InboxNotification, + InboxNotificationList, + } from "@liveblocks/react-ui"; + + export default function Page() { + const { inboxNotifications } = useInboxNotifications(); + + return ( + + {inboxNotifications.map((inboxNotification) => ( + ( + ✨} + > + Your agent finished working on{" "} + {props.inboxNotification.activities[0].data.task}. + + ), + }} + // +++ + /> + ))} + + ); + } + ``` + + + + + + + Next: add your users + + + Notifications is set up and working now, but the auth route is using a placeholder + user—the next step is to connect it to your real users, and attach their name and avatar to their notifications. + + + + + + + +## What to read next + +Congratulations! You’ve set up notifications that fire when your AI agent +finishes its work. + +- [API reference](/docs/api-reference/liveblocks-react#Notifications) +- [Component reference](/docs/api-reference/liveblocks-react-ui#Notifications) +- [`triggerInboxNotification` reference](/docs/api-reference/liveblocks-node#post-inbox-notifications-trigger) +- [AI Presence quickstart](/docs/get-started/nextjs-ai-presence) + +--- + +## Examples using Notifications + + + + + + + diff --git a/docs/pages/get-started/nextjs-ai-presence.mdx b/docs/pages/get-started/nextjs-ai-presence.mdx new file mode 100644 index 00000000000..fb34d1b0a67 --- /dev/null +++ b/docs/pages/get-started/nextjs-ai-presence.mdx @@ -0,0 +1,343 @@ +--- +meta: + title: "Get started with AI Presence using Liveblocks and Next.js" + parentTitle: "Quickstart" + description: + "Learn how to show AI agents in your avatar stack and highlight what they’re + editing using Liveblocks Presence and Next.js" +--- + +Liveblocks is a realtime collaboration infrastructure for building performant +collaborative experiences. Follow the following steps to show an AI agent as a +real user inside your Next.js `/app` directory application: in the avatar stack, +and as a highlighted box around the form field or cell it’s currently editing, +using +[`setPresence`](/docs/api-reference/liveblocks-node#post-rooms-roomId-presence) +from [`@liveblocks/node`](/docs/api-reference/liveblocks-node) and the +[`useOthers`](/docs/api-reference/liveblocks-react#useOthers) hook from +[`@liveblocks/react`](/docs/api-reference/liveblocks-react). + +## Quickstart + + + + + + Have a Presence app ready + + + To add AI Presence on top of your existing app, you first need a Liveblocks + Presence setup with [`AvatarStack`](/docs/api-reference/liveblocks-react-ui#AvatarStack) + and authenticated users. Open up your app, or set up presence if you + haven’t already. + + + + + + + + Install `@liveblocks/node` + + + We’ll set the AI agent’s presence from the server, so install + [`@liveblocks/node`](/docs/api-reference/liveblocks-node). + + ```bash trackEvent="install_liveblocks" + npm install @liveblocks/node + ``` + + + + + + Add your secret key + + + Create a `.env.local` file and add your Liveblocks secret key from the + [dashboard](/dashboard/apikeys). + + ```env file=".env.local" + LIVEBLOCKS_SECRET_KEY="{{SECRET_KEY}}" + ``` + + + + + + Add an AI user to your database + + + The AI agent appears in the room like any other user, so it needs an ID, + name, and avatar. Add a dedicated user for your agent alongside your real + users, and return it from + [`resolveUsers`](/docs/api-reference/liveblocks-react#LiveblocksProviderResolveUsers) + so it can be rendered in + [`AvatarStack`](/docs/api-reference/liveblocks-react-ui#AvatarStack). + + ```tsx title="Find where you fetch data in your resolver functions…" + { + // +++ + const users = await fetchUsers(userIds); + // +++ + // ... + }} + > + {children} + + ``` + + ```ts title="…and modify the return values to include an AI user" + // +++ + export const AI_USER_INFO = { + id: "__AI_AGENT", + info: { + name: "AI Assistant", + avatar: "https://liveblocks.io/api/avatar?u=__AI_AGENT&agent=true", + color: "#6366f1", + }, + }; + // +++ + + async function fetchUsers(userIds: string[]) { + const users = []; + + for (const userId of userIds) { + // +++ + if (userId === AI_USER_INFO.id) { + users.push(AI_USER_INFO); + continue; + } + // +++ + + const user = await __getUserFromDb__(userId); + users.push(user ? { id: userId, info: user.info } : undefined); + } + + return users; + } + ``` + + + + + Show the AI in your avatar stack + + + To make the AI appear in + [`AvatarStack`](/docs/api-reference/liveblocks-react-ui#AvatarStack) and [`useOthers`](/docs/api-reference/liveblocks-react#useOthers) + from the server, call [`setPresence`](/docs/api-reference/liveblocks-node#post-rooms-roomId-presence). + Use this to signify your agent is running a task in the room. + + ```ts file="app/agent-presence.ts" highlight="11-16" + "use server"; + + import { Liveblocks } from "@liveblocks/node"; + import { AI_USER_INFO } from "./database"; + + const liveblocks = new Liveblocks({ + secret: process.env.LIVEBLOCKS_SECRET_KEY!, + }); + + export async function runAgentTask(roomId: string) { + // +++ + await liveblocks.setPresence(roomId, { + userId: AI_USER_INFO.id, + userInfo: AI_USER_INFO.info, + data: {}, + ttl: 30, // How many seconds it should appear + }); + // +++ + + // Run your AI task or workflow + // ... + } + ``` + + The agent will now appear in presence alongside real users. + + + + + + Show AI presence in custom UI + + + With [`useOthers`](/docs/api-reference/liveblocks-react#useOthers) you can create + custom AI presence within any UI. An example of this is showing a highlighted box + around the part of the interface that the AI is editing. + + To set this up, first set presence types in your app. An `editingId` string can represent + an element that the AI is currently editing, such as a form field, and a value `null` can signify that + the AI is not editing anything. + + ```ts file="liveblocks.config.ts" + declare global { + interface Liveblocks { + Presence: { + editingId: string | null; + }; + } + } + + export {}; + ``` + + Next, when using [`setPresence`](/docs/api-reference/liveblocks-node#post-rooms-roomId-presence) on the server, + set the `editingId` property to the ID of the element that the AI is currently editing. + + ```ts file="app/agent-presence.ts" highlight="11-16" + "use server"; + + import { Liveblocks } from "@liveblocks/node"; + import { AI_USER_INFO } from "./database"; + + const liveblocks = new Liveblocks({ + secret: process.env.LIVEBLOCKS_SECRET_KEY!, + }); + + export async function runAgentTask(roomId: string) { + await liveblocks.setPresence(roomId, { + userId: AI_USER_INFO.id, + userInfo: AI_USER_INFO.info, + // +++ + data: { + editingId: "title-1", + }, + // +++ + ttl: 30, + }); + + // Edit the input field with AI + // ... + } + ``` + + On the client, use [`useOthers`](/docs/api-reference/liveblocks-react#useOthers) + to create a small component that draws a highlighted box around the targeted element + when the AI is editing it. + + + ```tsx file="app/AiPresenceEditFrame.tsx" + "use client"; + + import { useOthers, shallow } from "@liveblocks/react"; + import { AI_USER_INFO } from "./database"; + import { shallow } from "@liveblocks/react"; + + export function AiPresenceEditFrame({ editingId }: { editingId: string }) { + // Check if the AI user is online AND editing the current ID + const aiIsEditing = useOthers(((others) => { + const ai = others.find((o) => o.id === AI_USER_INFO.id); + return ai && ai.presence.editingId === editingId; + }), shallow); + + if (!aiIsEditing) { + return children; + } + + return ( +
+
+ {children} +
+
+ ); + } + ``` + + You can then wrap any part of your your UI with `AiPresenceEditFrame`, give each one a unique `editingId`, + and if the AI is editing that ID, a highlighted box will appear around it. + + ```tsx file="app/Form.tsx" + "use client"; + + import { AiPresenceEditFrame } from "./AiPresenceEditFrame"; + + export function Form() { + return ( +
+ // +++ + + + + // +++ + +