suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
  • AI
GitHubCreate
DocsComponentsPatternsInteractionsChartsBlocksAICreate
AI21
  • Overview
Conversation
  • Chat
  • Message
  • Prompt Input
  • Suggestion
  • Model Selector
  • Context
  • Checkpoint
  • Inline Citation
Agent steps
  • Chain of Thought
  • Reasoning
  • Tool
  • Confirmation
  • Task
  • Plan
  • Queue
  • Subagent
  • Sources
Output
  • Terminal
  • Stack Trace
  • Test Results
  • File Tree

suiss/ui · AI

Checkpoint

Marks a point in the conversation that you can return to, dropping every message after it.

"use client"

import * as React from "react"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Button } from "@/components/ui/button"
import { Marker, MarkerContent } from "@/components/ui/marker"
import { Message, MessageContent } from "@/components/ui/message"

type Turn = {
  id: string
  role: "user" | "assistant"
  text: string
  checkpoint?: string
}

const transcript: Turn[] = [

Checkpoint is a point in the conversation you can return to. It is a Marker after a turn, with a Restore button. Restore keeps that turn and drops every message after it.

Installation

Checkpoint is built with the Marker and Button components.

$ pnpm dlx shadcn@latest add @esuiss/marker @esuiss/button

Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add marker button

Usage

Render a marker after the turn, with a button that restores it.

<Marker variant="separator">
  <MarkerContent className="inline-flex items-center gap-2">
    {label}
    <Button size="xs" variant="outline" onClick={restore}>
      Restore
    </Button>
  </MarkerContent>
</Marker>
<Marker variant="separator">
  <MarkerContent className="inline-flex items-center gap-2">
    {label}
    <Button size="xs" variant="outline" onPress={restore}>
      Restore
    </Button>
  </MarkerContent>
</Marker>

Show the button only on checkpoints that have turns after them.

AI SDK

Restore replaces the thread with the messages up to and including that turn. Every later turn is removed. Send a new message to continue from there.

const index = messages.findIndex((message) => message.id === messageId)
setMessages(messages.slice(0, index + 1))

Write the checkpoint as a data part on the agent's turn. Send the same id again only when you mean to update that checkpoint.

app/api/chat/route.ts
writer.write({
  type: "data-checkpoint",
  id: "rename",
  data: { label: "Button renamed" },
})

API Reference

See Marker and Button.

Accessibility

  • Name each Restore button after its checkpoint with aria-label, such as "Restore to Button renamed", so several buttons can be told apart.
import { ArrowCounterClockwiseIcon } from "phosphor-react-native"
import * as React from "react"
import { View } from "react-native"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Button } from "@/components/ui/button"
import { Icon } from "@/components/ui/icon"
import { Marker, MarkerContent } from "@/components/ui/marker"
import { Message, MessageContent } from "@/components/ui/message"
import { Text } from "@/components/ui/text"

const turns = [
  {
    ask: "Rename the button component to action.",
    reply: "Renamed Button to Action in components/ui/button.tsx.",
  },
  {
import EsuissUI
import SwiftUI

struct CheckpointExample: View {
  @State private var restored = false

  var body: some View {
    VStack(alignment: .leading, spacing: 16) {
      CheckpointTurn(ask: "Rename the button component to action.", reply: "Renamed Button to Action in components/ui/button.tsx.")
      Marker(.separator) { MarkerContent("Checkpoint") }
      if !restored {
        CheckpointTurn(ask: "Update the docs to match.", reply: "Updated the Button page to say Action.")
      }
      Button(restored ? "Reset" : "Restore checkpoint") { restored.toggle() }
        .buttonStyle(.variant(.outline, size: .sm))
    }
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Bubble
import com.esuiss.ui.components.BubbleContent
import com.esuiss.ui.components.BubbleVariant
import com.esuiss.ui.components.Button
import com.esuiss.ui.components.ButtonSize
import com.esuiss.ui.components.ButtonVariant

Checkpoint on mobile is built from the same parts as on the web: Message, Bubble, Marker, Button. The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

Installation

$ pnpm dlx @esuiss/ui@latest add message bubble marker button
$ pnpm dlx @esuiss/ui@latest add message bubble marker button --platform swift
$ pnpm dlx @esuiss/ui@latest add message bubble marker button --platform kotlin

API Reference

See Message, Bubble, Marker, Button.

NextInline CitationPreviousContext

On this page

  1. 01Installation
  2. 02Usage
  3. 03AI SDK
  4. 04API Reference
  5. 05Accessibility
  6. 06Installation
  7. 07API Reference