Chat History for LangGraph Cloud
Overview
assistant-cloud provides thread management and persistent chat history for applications built with LangGraph Cloud. This guide shows you how to integrate cloud persistence into your LangGraph application.
Prerequisites
You need an assistant-cloud account to follow this guide. Sign up here to get started.
Setup Guide
Create a Cloud Project
Create a new project in the assistant-cloud dashboard and from the settings page, copy:
- Frontend API URL:
https://proj-[ID].assistant-api.com
- API Key: For server-side operations
Configure Environment Variables
Add the following environment variables to your project:
# Frontend API URL from your cloud project settings
NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-[YOUR-ID].assistant-api.com
# API key for server-side operations
ASSISTANT_API_KEY=your-api-key-here
Install Dependencies
Install the required packages:
npm install @assistant-ui/react @assistant-ui/react-langgraph
Create the Runtime Provider
Create a runtime provider that integrates LangGraph with assistant-cloud. Choose between anonymous mode for demos/prototypes or authenticated mode for production:
"use client";
import {
AssistantCloud,
AssistantRuntimeProvider,
useCloudThreadListRuntime,
useThreadListItemRuntime,
} from "@assistant-ui/react";
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
import { createThread, getThreadState, sendMessage } from "@/lib/chatApi";
import { LangChainMessage } from "@assistant-ui/react-langgraph";
import { useMemo } from "react";
const useMyLangGraphRuntime = () => {
const threadListItemRuntime = useThreadListItemRuntime();
const runtime = useLangGraphRuntime({
stream: async function* (messages) {
const { externalId } = await threadListItemRuntime.initialize();
if (!externalId) throw new Error("Thread not found");
return sendMessage({
threadId: externalId,
messages,
});
},
onSwitchToThread: async (externalId) => {
const state = await getThreadState(externalId);
return {
messages:
(state.values as { messages?: LangChainMessage[] }).messages ?? [],
};
},
});
return runtime;
};
export function MyRuntimeProvider({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cloud = useMemo(
() =>
new AssistantCloud({
baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
anonymous: true, // Creates browser session-based user ID
}),
[],
);
const runtime = useCloudThreadListRuntime({
cloud,
runtimeHook: useMyLangGraphRuntime,
create: async () => {
const { thread_id } = await createThread();
return { externalId: thread_id };
},
});
return (
<AssistantRuntimeProvider runtime={runtime}>
{children}
</AssistantRuntimeProvider>
);
}
"use client";
import {
AssistantCloud,
AssistantRuntimeProvider,
useCloudThreadListRuntime,
useThreadListItemRuntime,
} from "@assistant-ui/react";
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
import { createThread, getThreadState, sendMessage } from "@/lib/chatApi";
import { LangChainMessage } from "@assistant-ui/react-langgraph";
import { useAuth } from "@clerk/nextjs";
import { useMemo } from "react";
const useMyLangGraphRuntime = () => {
const threadListItemRuntime = useThreadListItemRuntime();
const runtime = useLangGraphRuntime({
stream: async function* (messages) {
const { externalId } = await threadListItemRuntime.initialize();
if (!externalId) throw new Error("Thread not found");
return sendMessage({
threadId: externalId,
messages,
});
},
onSwitchToThread: async (externalId) => {
const state = await getThreadState(externalId);
return {
messages:
(state.values as { messages?: LangChainMessage[] }).messages ?? []
};
},
});
return runtime;
};
export function MyRuntimeProvider({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const { getToken } = useAuth();
const cloud = useMemo(
() =>
new AssistantCloud({
baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
authToken: async () => getToken({ template: "assistant-ui" }),
}),
[getToken],
);
const runtime = useCloudThreadListRuntime({
cloud,
runtimeHook: useMyLangGraphRuntime,
create: async () => {
const { thread_id } = await createThread();
return { externalId: thread_id };
},
});
return (
<AssistantRuntimeProvider runtime={runtime}>
{children}
</AssistantRuntimeProvider>
);
}
For Clerk authentication, configure the "assistant-ui"
token template in your Clerk dashboard.
The useMyLangGraphRuntime
hook is extracted into a separate function because it will be mounted multiple times, once per active thread.
Add Thread UI Components
Install the thread list component:
npx assistant-ui add thread-list
Then add it to your application layout:
import { Thread } from "@/components/assistant-ui/thread";
import { ThreadList } from "@/components/assistant-ui/thread-list";
export default function ChatPage() {
return (
<div className="grid h-dvh grid-cols-[250px_1fr] gap-x-2">
<ThreadList />
<Thread />
</div>
);
}
Authentication
The examples above show two authentication modes:
- Anonymous: Suitable for demos and prototypes. Creates a browser session-based user ID.
- Authenticated: For production use with user accounts. The authenticated example uses Clerk, but you can integrate any auth provider.
For other authentication providers or custom implementations, see the Cloud Authorization guide.
Next Steps
- Learn about LangGraph runtime setup for your application
- Explore ThreadListRuntime for advanced thread management
- Check out the LangGraph example on GitHub