Tracked changes

Experimental

The Tracked Changes extension is currently in Alpha phase.

Continuation from the AI agent chatbot guide

This guide continues the AI agent chatbot guide. Read it first.

Display AI-generated changes as tracked changes, so your users can review and accept or reject them individually. This integrates the AI Toolkit with the Tracked Changes extension.

See the source code on GitHub.

Show tracked changes

To display AI edits as tracked changes, set reviewOptions.mode to 'trackedChanges' when executing a tool.

API endpoint

The API endpoint is the same as in the AI agent chatbot guide. No changes are needed on the server side to enable tracked changes.

// app/api/tracked-changes/route.ts
import { openai } from '@ai-sdk/openai'
import { toolDefinitions } from '@tiptap-pro/ai-toolkit-ai-sdk'
import { createAgentUIStreamResponse, ToolLoopAgent, type UIMessage } from 'ai'

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json()

  const agent = new ToolLoopAgent({
    model: openai('gpt-5.4-mini'),
    instructions:
      'You are an assistant that can edit rich text documents. Use tiptapRead before tiptapEdit.',
    tools: toolDefinitions(),
  })

  return createAgentUIStreamResponse({
    agent,
    uiMessages: messages,
  })
}

Client-side setup

On the client, add the TrackedChanges extension and pass reviewOptions with mode 'trackedChanges' to the executeTool method.

The TrackedChanges extension must be configured with enabled: false — the AI Toolkit enables it automatically when needed.

import { useChat } from '@ai-sdk/react'
import { EditorContent, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { AiToolkit, getAiToolkit } from '@tiptap-pro/ai-toolkit'
import { TrackedChanges } from '@tiptap-pro/extension-tracked-changes'
import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai'

export default function Page() {
  const editor = useEditor({
    immediatelyRender: false,
    extensions: [
      StarterKit,
      TrackedChanges.configure({
        enabled: false,
      }),
      AiToolkit,
    ],
    content: `<p>Ask the AI to improve this document.</p>`,
  })

  const { messages, sendMessage, addToolOutput } = useChat({
    transport: new DefaultChatTransport({ api: '/api/tracked-changes' }),
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
    async onToolCall({ toolCall }) {
      if (!editor) return

      const toolkit = getAiToolkit(editor)
      const result = toolkit.executeTool({
        toolName: toolCall.toolName,
        input: toolCall.input,
        reviewOptions: {
          mode: 'trackedChanges',
          trackedChangesOptions: {
            userId: 'ai-assistant',
            userMetadata: {
              name: 'AI',
            },
          },
        },
      })

      addToolOutput({
        tool: toolCall.toolName,
        toolCallId: toolCall.toolCallId,
        output: result.output,
      })
    },
  })

  // ... render editor and chat UI
}

After the AI edits the document, the changes appear as tracked changes. Users can accept or reject them using the acceptSuggestion, rejectSuggestion, acceptAllSuggestions, and rejectAllSuggestions commands from the Tracked Changes extension.

End result

See the source code on GitHub.

Next steps