Comments workflow
Build a workflow that allows the AI to manage comments and threads in your Tiptap documents.
See the source code on GitHub.
Tech stack
- React + Next.js
- AI SDK by Vercel + OpenAI models
- Tiptap AI Toolkit
- Tiptap Comments extension
Project overview
This demo uses the AI Toolkit's Comments workflow to manage threads and comments in the document. The AI can create new threads, add comments, update comments, remove comments, and manage thread status.
Installation
Create a Next.js project:
npx create-next-app@latest comments-workflowInstall the core Tiptap packages and the Vercel AI SDK for OpenAI:
npm install @tiptap/react @tiptap/starter-kit ai @ai-sdk/react @ai-sdk/openai zod uuidInstall the Tiptap AI Toolkit and Comments extension:
Pro package
The AI Toolkit is a pro package. Before installation, set up access to the private NPM registry by following the private registry guide.
npm install @tiptap-pro/ai-toolkit @tiptap-pro/ai-toolkit-tool-definitions @tiptap-pro/extension-commentsServer setup
Create an API endpoint that uses the Vercel AI SDK to call the OpenAI model.
Inside the API endpoint, create and configure the Comments workflow using the createEditThreadsWorkflow function. The workflow includes a ready-to-use system prompt that instructs the AI model on how to manage comments.
The user message should include:
nodes: The nodes of the document (obtained fromtiptapRead)threads: The existing threads in the document (obtained fromgetThreads)task: The task to be performed by the AI. For example,Add a comment suggesting improvements to the introduction.
// app/api/comments-workflow/route.ts
import { openai } from '@ai-sdk/openai'
import { createEditThreadsWorkflow } from '@tiptap-pro/ai-toolkit-tool-definitions'
import { Output, streamText } from 'ai'
export async function POST(req: Request) {
const { nodes, threads, task } = await req.json()
// Create and configure the Comments workflow (with the default settings).
// It includes the ready-to-use system prompt and the output schema.
const workflow = createEditThreadsWorkflow()
const result = streamText({
model: openai('gpt-5-mini'),
// System prompt
system: workflow.systemPrompt,
// User message
prompt: JSON.stringify({
nodes,
threads,
task,
}),
output: Output.object({ schema: workflow.zodOutputSchema }),
// If you use gpt-5-mini, set the reasoning effort to minimal to improve the
// response time.
providerOptions: {
openai: {
reasoningEffort: 'minimal',
},
},
})
return result.toTextStreamResponse()
}Client setup
Create a React component that renders the editor with the Comments extension and applies comment operations.
First, when the workflow starts, call the tiptapRead method to get the document content and getThreads method to get existing threads.
Then, call the API endpoint to start the workflow. Use the editThreadsWorkflow method to apply the comment operations.
// app/comments-workflow/page.tsx
'use client'
import { experimental_useObject as useObject } from '@ai-sdk/react'
import { EditorContent, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { AiToolkit, getAiToolkit, editThreadsWorkflowOutputSchema } from '@tiptap-pro/ai-toolkit'
import { Comments } from '@tiptap-pro/extension-comments'
import { useEffect, useState } from 'react'
// Create a simple comments provider
const commentsProvider = {
threads: [],
getThreads: () => commentsProvider.threads,
createThread: (thread) => {
commentsProvider.threads.push(thread)
return thread
},
updateThread: (id, data) => {
const index = commentsProvider.threads.findIndex((t) => t.id === id)
if (index !== -1) {
commentsProvider.threads[index] = { ...commentsProvider.threads[index], ...data }
}
},
deleteThread: (id) => {
commentsProvider.threads = commentsProvider.threads.filter((t) => t.id !== id)
},
}
export default function Page() {
const editor = useEditor({
immediatelyRender: false,
extensions: [
StarterKit,
AiToolkit,
Comments.configure({
provider: commentsProvider,
}),
],
content: `<h1>Document with Comments</h1><p>This is a sample document where AI can add and manage comments.</p>`,
})
const [task, setTask] = useState('Add a comment suggesting improvements to this document')
const { submit, isLoading, object } = useObject({
api: '/api/comments-workflow',
schema: editThreadsWorkflowOutputSchema,
})
const operations = object?.operations ?? []
// Apply operations as they arrive
useEffect(() => {
if (!editor || operations.length === 0) return
const toolkit = getAiToolkit(editor)
toolkit.editThreadsWorkflow({
operations,
})
}, [operations, editor])
if (!editor) return null
const manageComments = () => {
const toolkit = getAiToolkit(editor)
// Get the document content and existing threads
const { nodes } = toolkit.tiptapRead()
const { threads } = toolkit.getThreads()
// Call the API endpoint to start the workflow
submit({ nodes, threads, task })
}
return (
<div>
<EditorContent editor={editor} />
<input
type="text"
value={task}
onChange={(e) => setTask(e.target.value)}
placeholder="Enter task for comments..."
/>
<button onClick={manageComments} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Manage Comments with AI'}
</button>
</div>
)
}Available operations
The Comments workflow supports the following operations:
| Operation | Format | Description |
|---|---|---|
| Create thread | ['createThread', nodeHash, htmlContent] | Creates a new thread at a specific location |
| Create comment | ['createComment', threadId, content] | Adds a comment to an existing thread |
| Update comment | ['updateComment', threadId, commentId, content] | Updates an existing comment |
| Remove comment | ['removeComment', threadId, commentId] | Removes a comment from a thread |
| Remove thread | ['removeThread', threadId] | Removes an entire thread |
| Resolve thread | ['resolveThread', threadId] | Marks a thread as resolved |
| Unresolve thread | ['unresolveThread', threadId] | Marks a thread as unresolved |
End result
With additional CSS styles, the result is a polished comments management application:
See the source code on GitHub.
Related guides
- API reference of the
tiptapReadmethod - API reference of the
getThreadsmethod - API reference of the
editThreadsWorkflowmethod - Comments extension: Learn more about the Comments extension.