Vercel AI SDK integration
This page covers the Vercel-specific adapter that connects Document Authoring AI to Vercel AI SDK(opens in a new tab). For the conceptual model, see agentic tools; for the Edit/Review/View policy, see review and approval.
Before you start
This guide assumes:
- A Document Authoring editor is already running in the browser.
- Your app uses Vercel AI SDK for the chat transport and the model loop.
- Your server can reach your model provider.
- The browser can grab the live
DocAuthEditorinstance when tool calls arrive.
The examples use OpenAI through Vercel AI SDK, but any Vercel-supported provider works the same way; the toolkit doesn’t care which model is on the other side.
Server route for agentic tools
The toolkit ships framework-neutral helpers in @nutrient-sdk/document-authoring-ai. The Vercel adapter in @nutrient-sdk/document-authoring-ai/vercel converts those definitions into an AI SDK tool set before you hand them to streamText(opens in a new tab).
import { openai } from "@ai-sdk/openai";import { convertToModelMessages, stepCountIs, streamText,} from "ai";import { getAiPromptGuide, getAiToolDefinitions,} from "@nutrient-sdk/document-authoring-ai";import { toVercelAiTools } from "@nutrient-sdk/document-authoring-ai/vercel";
const tools = toVercelAiTools(getAiToolDefinitions());const system = `${getAiPromptGuide()}
When the user asks for motivation or justification, include a concise reviewComment on each write tool call.`;
export async function POST(req: Request) { const body = await req.json();
const result = streamText({ model: openai("gpt-4o-mini"), system, messages: await convertToModelMessages(body.messages), stopWhen: stepCountIs(20), temperature: 0.1, tools, });
return result.toUIMessageStreamResponse();}The adapter returns tools with no execute handlers, so the route exposes the tools to the model but doesn’t run them. The browser does. getAiPromptGuide is the system prompt designed for these tools; using it as your base system prompt tells the model how the toolkit handles element IDs, read-before-write ordering, and the rest of the rules.
Browser chat loop
The useChat(opens in a new tab) hook is where the model’s tool calls land in the browser. The toolkit work inside onToolCall is the same execution loop described in agentic tools. The Vercel-specific part is feeding the result back through addToolOutput(opens in a new tab).
import { useChat } from "@ai-sdk/react";import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls,} from "ai";import { isAiWriteToolName,} from "@nutrient-sdk/document-authoring-ai";import { getAiToolkit } from "@nutrient-sdk/document-authoring-ai/editor";
const toolkit = getAiToolkit(editor);
const { addToolOutput } = useChat({ transport: new DefaultChatTransport({ api: "/api/chat" }), sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls, async onToolCall({ toolCall }) { // Skip Vercel dynamic tools; they aren't part of this route's tool set. if ("dynamic" in toolCall && toolCall.dynamic) { return; }
const editorMode = editor.getEditorMode(); const isWriteTool = isAiWriteToolName(toolCall.toolName);
if (isWriteTool && editorMode === "view") { addToolOutput({ tool: toolCall.toolName, toolCallId: toolCall.toolCallId, state: "output-error", errorText: "The document is in View mode. Switch to Edit or Review mode before editing.", }); return; }
const executed = await toolkit.executeTool( { id: toolCall.toolCallId, name: toolCall.toolName, args: toolCall.input, }, { writeMode: isWriteTool && editorMode === "review" ? "track_changes" : "apply", reviewComments: isWriteTool ? "create" : "disabled", }, );
addToolOutput({ tool: toolCall.toolName, toolCallId: toolCall.toolCallId, output: executed, }); },});lastAssistantMessageIsCompleteWithToolCalls(opens in a new tab) lets Vercel’s chat loop pick the conversation back up once you’ve submitted every tool output.
The reviewComments option is a host policy, not a model decision. The model can supply reviewComment on write tool calls because the tool schema exposes it, but the browser decides whether to create comment threads when it executes the call.
Server route for workflows
Workflows use Vercel’s structured-output API instead of tool calls. The route receives workflow input from the browser and returns one validated output object with generateText(opens in a new tab) and Output.object(opens in a new tab).
import { openai } from "@ai-sdk/openai";import { generateText, Output } from "ai";import { getBuiltInWorkflow } from "@nutrient-sdk/document-authoring-ai";import { toVercelAiWorkflowOutputSchema } from "@nutrient-sdk/document-authoring-ai/vercel";
export async function POST(req: Request) { const body = await req.json(); const workflow = getBuiltInWorkflow("proofreading");
const result = await generateText({ model: openai("gpt-4o-mini"), system: workflow.systemPrompt, prompt: JSON.stringify({ task: body.task ?? workflow.defaultTask, input: body.workflowInput, }), output: Output.object(toVercelAiWorkflowOutputSchema(workflow)), temperature: 0.1, });
return Response.json({ output: result.output });}On the browser side, call toolkit.readWorkflowInput to build the request body, hit this route, and apply the result with toolkit.applyWorkflowOutput. The full browser flow is in workflows.