# Checkpoint

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

Source: https://suiss.app/ui/docs/ai/checkpoint

**React**

**Example**

```tsx
"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[] = [
  { id: "1", role: "user", text: "Rename the button component to action." },
  {
    id: "2",
    role: "assistant",
    text: "Renamed Button to Action in components/ui/button.tsx.",
    checkpoint: "Button renamed",
  },
  { id: "3", role: "user", text: "Update the docs to match." },
  {
    id: "4",
    role: "assistant",
    text: "Updated the Button page to say Action.",
  },
]

export default function CheckpointDemo() {
  const [turns, setTurns] = React.useState(transcript)

  return (
    <div className="flex min-h-72 w-full max-w-sm flex-col gap-4 py-6 text-sm">
      {turns.map((turn, index) => (
        <React.Fragment key={turn.id}>
          {turn.role === "user" ? (
            <Message align="end">
              <MessageContent>
                <Bubble align="end" variant="muted">
                  <BubbleContent>{turn.text}</BubbleContent>
                </Bubble>
              </MessageContent>
            </Message>
          ) : (
            <Message>
              <MessageContent>
                <p>{turn.text}</p>
              </MessageContent>
            </Message>
          )}
          {turn.checkpoint && (
            <Marker variant="separator">
              <MarkerContent className="inline-flex items-center gap-2">
                {turn.checkpoint}
                {index < turns.length - 1 && (
                  <Button
                    size="xs"
                    variant="outline"
                    aria-label={`Restore to ${turn.checkpoint}`}
                    onClick={() => setTurns(turns.slice(0, index + 1))}
                  >
                    Restore
                  </Button>
                )}
              </MarkerContent>
            </Marker>
          )}
        </React.Fragment>
      ))}
      {turns.length < transcript.length && (
        <Button
          variant="outline"
          size="sm"
          className="mt-auto self-start"
          onClick={() => setTurns(transcript)}
        >
          Reset
        </Button>
      )}
    </div>
  )
}
```

Checkpoint is a point in the conversation you can return to. It is a [Marker](https://suiss.app/ui/docs/components/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](https://suiss.app/ui/docs/components/marker) and [Button](https://suiss.app/ui/docs/components/button) components.

```bash title="Terminal"
npx shadcn@latest add @esuiss/marker @esuiss/button
```

Or use the [suiss/ui CLI](https://suiss.app/ui/docs/cli):

```bash title="Terminal"
npx @esuiss/ui@latest add marker button
```

## Usage

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

```tsx
<Marker variant="separator">
  <MarkerContent className="inline-flex items-center gap-2">
    {label}
    <Button size="xs" variant="outline" onClick={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.

```tsx
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.

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

## API Reference

See [Marker](https://suiss.app/ui/docs/components/marker#api-reference) and [Button](https://suiss.app/ui/docs/components/button#api-reference).

## Accessibility

- Name each Restore button after its checkpoint with `aria-label`, such as "Restore to Button renamed", so several buttons can be told apart.

**React Native, SwiftUI, Jetpack Compose**

```tsx
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.",
  },
  {
    ask: "Update the docs to match.",
    reply: "Updated the Button page to say Action.",
  },
]

function CheckpointExample() {
  const [restored, setRestored] = React.useState(false)
  const shown = restored ? turns.slice(0, 1) : turns
  return (
    <View className="w-full gap-4">
      {shown.map((turn, index) => (
        <View key={turn.ask} className="gap-3">
          <Message align="end">
            <MessageContent>
              <Bubble variant="muted">
                <BubbleContent>{turn.ask}</BubbleContent>
              </Bubble>
            </MessageContent>
          </Message>
          <Text>{turn.reply}</Text>
          {index === 0 ? (
            <Marker variant="separator">
              <MarkerContent>Checkpoint</MarkerContent>
            </Marker>
          ) : null}
        </View>
      ))}
      <View className="items-start">
        <Button
          variant="outline"
          size="sm"
          onPress={() => setRestored(!restored)}
        >
          <Icon as={ArrowCounterClockwiseIcon} />
          <Text>{restored ? "Reset" : "Restore checkpoint"}</Text>
        </Button>
      </View>
    </View>
  )
}

export function AiCheckpointExample() {
  return (
    <CheckpointExample />
  )
}
```

```swift
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))
    }
  }
}

struct CheckpointTurn: View {
  let ask: String
  let reply: String

  var body: some View {
    VStack(alignment: .leading, spacing: 12) {
      Message(align: .end) {
        MessageContent {
          Bubble(variant: .muted, align: .end) { BubbleContent(verbatim: ask) }
        }
      }
      Text(verbatim: reply).textStyle(.base).foregroundStyle(EsuissColor.foreground)
    }
  }
}
```

```kotlin
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
import com.esuiss.ui.components.Marker
import com.esuiss.ui.components.MarkerContent
import com.esuiss.ui.components.MarkerVariant
import com.esuiss.ui.components.Message
import com.esuiss.ui.components.MessageAlign
import com.esuiss.ui.components.MessageContent
import com.esuiss.ui.components.Text

@Composable
fun CheckpointAIDefault() {
    var restored by rememberSaveable { mutableStateOf(false) }
    Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp)) {
        Turn("Rename the button component to action.", "Renamed Button to Action in components/ui/button.tsx.")
        Marker(variant = MarkerVariant.Separator) { MarkerContent("Checkpoint") }
        if (!restored) Turn("Update the docs to match.", "Updated the Button page to say Action.")
        Button(if (restored) "Reset" else "Restore checkpoint", onClick = { restored = !restored }, variant = ButtonVariant.Outline, size = ButtonSize.Sm)
    }
}

@Composable
fun Turn(ask: String, reply: String) {
    Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp)) {
        Message(Modifier.fillMaxWidth(), align = MessageAlign.End) {
            MessageContent {
                Bubble(variant = BubbleVariant.Muted) { BubbleContent(ask) }
            }
        }
        Text(reply)
    }
}
```

Checkpoint on mobile is built from the same parts as on the web: [Message](https://suiss.app/ui/docs/components/message), [Bubble](https://suiss.app/ui/docs/components/bubble), [Marker](https://suiss.app/ui/docs/components/marker), [Button](https://suiss.app/ui/docs/components/button). The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

## Installation

**React Native**

```bash title="Terminal"
npx @esuiss/ui@latest add message bubble marker button
```

**SwiftUI**

```bash title="Terminal"
npx @esuiss/ui@latest add message bubble marker button --platform swift
```

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add message bubble marker button --platform kotlin
```

## API Reference

See [Message](https://suiss.app/ui/docs/components/message), [Bubble](https://suiss.app/ui/docs/components/bubble), [Marker](https://suiss.app/ui/docs/components/marker), [Button](https://suiss.app/ui/docs/components/button).

