Checkpoint
A simple component for marking conversation history points and restoring the chat to a previous state.
The Checkpoint component provides a way to mark specific points in a conversation history and restore the chat to that state. Inspired by VSCode's Copilot checkpoint feature, it allows users to revert to an earlier conversation state while maintaining a clear visual separation between different conversation segments.
"use client";import { Checkpoint, CheckpointIcon, CheckpointTrigger,} from "@/components/ai-elements/checkpoint";import { Conversation, ConversationContent } from "@/components/ai-elements/conversation";import { Message, MessageContent, MessageResponse,} from "@/components/ai-elements/message";import { nanoid } from "nanoid";import { Fragment, useState } from "react";type MessageType = { id: string; role: "user" | "assistant"; content: string;};const initialMessages: MessageType[] = [ { id: nanoid(), role: "user", content: "What is React?", }, { id: nanoid(), role: "assistant", content: "React is a JavaScript library for building user interfaces. It was developed by Facebook and is now maintained by Meta and a community of developers.", }, { id: nanoid(), role: "user", content: "How does component state work?", },];const Example = () => { const [messages, setMessages] = useState<MessageType[]>(initialMessages); const [checkpoints] = useState([ { messageCount: 2, timestamp: new Date(Date.now() - 3_600_000) }, ]); const handleRestore = (messageCount: number) => { setMessages(initialMessages.slice(0, messageCount)); }; return ( <div className="flex size-full flex-col rounded-lg border p-6"> <Conversation> <ConversationContent> {messages.map((message, index) => { const checkpoint = checkpoints.find( (cp) => cp.messageCount === index + 1 ); return ( <Fragment key={message.id}> <Message from={message.role}> <MessageContent> <MessageResponse>{message.content}</MessageResponse> </MessageContent> </Message> {checkpoint && ( <Checkpoint> <CheckpointIcon /> <CheckpointTrigger onClick={() => handleRestore(checkpoint.messageCount)} tooltip="Restores workspace and chat to this point" > Restore checkpoint </CheckpointTrigger> </Checkpoint> )} </Fragment> ); })} </ConversationContent> </Conversation> </div> );};export default Example;Installation
npx ai-elements@latest add checkpointnpx shadcn@latest add @ai-elements/checkpoint"use client";import { Button } from "@repo/shadcn-ui/components/ui/button";import { Separator } from "@repo/shadcn-ui/components/ui/separator";import { Tooltip, TooltipContent, TooltipTrigger,} from "@repo/shadcn-ui/components/ui/tooltip";import { cn } from "@repo/shadcn-ui/lib/utils";import { BookmarkIcon, type LucideProps } from "lucide-react";import type { ComponentProps, HTMLAttributes } from "react";export type CheckpointProps = HTMLAttributes<HTMLDivElement>;export const Checkpoint = ({ className, children, ...props}: CheckpointProps) => ( <div className={cn("flex items-center gap-0.5 text-muted-foreground", className)} {...props} > {children} <Separator /> </div>);export type CheckpointIconProps = LucideProps;export const CheckpointIcon = ({ className, children, ...props}: CheckpointIconProps) => children ?? ( <BookmarkIcon className={cn("size-4 shrink-0", className)} {...props} /> );export type CheckpointTriggerProps = ComponentProps<typeof Button> & { tooltip?: string;};export const CheckpointTrigger = ({ children, className, variant = "ghost", size = "sm", tooltip, ...props}: CheckpointTriggerProps) => tooltip ? ( <Tooltip> <TooltipTrigger asChild> <Button size={size} type="button" variant={variant} {...props}> {children} </Button> </TooltipTrigger> <TooltipContent align="start" side="bottom"> {tooltip} </TooltipContent> </Tooltip> ) : ( <Button size={size} type="button" variant={variant} {...props}> {children} </Button> );Features
- Simple flex layout with icon, trigger, and separator
- Visual separator line for clear conversation breaks
- Clickable restore button for reverting to checkpoint
- Customizable icon (defaults to BookmarkIcon)
- Keyboard accessible with proper ARIA labels
- Responsive design that adapts to different screen sizes
- Seamless light/dark theme integration
Usage with AI SDK
Build a chat interface with conversation checkpoints that allow users to restore to previous states.
Add the following component to your frontend:
'use client';
import { useState, Fragment } from 'react';
import { useChat } from '@ai-sdk/react';
import {
Checkpoint,
CheckpointIcon,
CheckpointTrigger,
} from '@/components/ai-elements/checkpoint';
import { Message, MessageContent, MessageResponse } from '@/components/ai-elements/message';
import { Conversation, ConversationContent } from '@/components/ai-elements/conversation';
type CheckpointType = {
id: string;
messageIndex: number;
timestamp: Date;
messageCount: number;
};
const CheckpointDemo = () => {
const { messages, setMessages } = useChat();
const [checkpoints, setCheckpoints] = useState<CheckpointType[]>([]);
const createCheckpoint = (messageIndex: number) => {
const checkpoint: CheckpointType = {
id: nanoid(),
messageIndex,
timestamp: new Date(),
messageCount: messageIndex + 1,
};
setCheckpoints([...checkpoints, checkpoint]);
};
const restoreToCheckpoint = (messageIndex: number) => {
// Restore messages to checkpoint state
setMessages(messages.slice(0, messageIndex + 1));
// Remove checkpoints after this point
setCheckpoints(checkpoints.filter(cp => cp.messageIndex <= messageIndex));
};
return (
<div className="max-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px]">
<Conversation>
<ConversationContent>
{messages.map((message, index) => {
const checkpoint = checkpoints.find(cp => cp.messageIndex === index);
return (
<Fragment key={message.id}>
<Message from={message.role}>
<MessageContent>
<MessageResponse>{message.content}</MessageResponse>
</MessageContent>
</Message>
{checkpoint && (
<Checkpoint>
<CheckpointIcon />
<CheckpointTrigger
onClick={() => restoreToCheckpoint(checkpoint.messageIndex)}
>
Restore checkpoint
</CheckpointTrigger>
</Checkpoint>
)}
</Fragment>
);
})}
</ConversationContent>
</Conversation>
</div>
);
};
export default CheckpointDemo;Use Cases
Manual Checkpoints
Allow users to manually create checkpoints at important conversation points:
<Button onClick={() => createCheckpoint(messages.length - 1)}>
Create Checkpoint
</Button>Automatic Checkpoints
Create checkpoints automatically after significant conversation milestones:
useEffect(() => {
// Create checkpoint every 5 messages
if (messages.length > 0 && messages.length % 5 === 0) {
createCheckpoint(messages.length - 1);
}
}, [messages.length]);Branching Conversations
Use checkpoints to enable conversation branching where users can explore different conversation paths:
const restoreAndBranch = (messageIndex: number) => {
// Save current branch
const currentBranch = messages.slice(messageIndex + 1);
saveBranch(currentBranch);
// Restore to checkpoint
restoreToCheckpoint(messageIndex);
};Props
<Checkpoint />
Prop
Type
<CheckpointIcon />
Prop
Type
<CheckpointTrigger />
Prop
Type