Proofreader
Build a proofreader that reads a document on the server, generates corrections, and applies them on the server.
See the source code on GitHub.
Proofreader format
The Server AI Toolkit proofreader workflow currently uses format: 'shorthand'.
Reuse the same session across read and execute
The read step returns a sessionId. Send that same sessionId with the execute request so the
server can reject stale edits when the document changed after the AI read it.
1. Read the document content from the AI Server
Start by reading the document in shorthand format. Call:
POST /v3/ai/toolkit/read/read-document
const readResponse = await fetch(`${apiBaseUrl}/toolkit/read/read-document`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwtToken}`,
'X-App-Id': appId,
},
body: JSON.stringify({
schemaAwarenessData,
sessionId,
format: 'shorthand',
reviewOptions: {
mode: 'disabled',
},
experimental_documentOptions: {
documentId,
userId: 'ai-assistant',
},
}),
})
const readResult = await readResponse.json()2. Generate proofreader operations
Get the workflow definition from the AI Server, combine it with the schema awareness prompt, and ask the model to return proofreader operations.
const workflowResponse = await fetch(`${apiBaseUrl}/toolkit/workflows/proofreader`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwtToken}`,
'X-App-Id': appId,
},
body: JSON.stringify({
format: 'shorthand',
}),
})
const workflow = await workflowResponse.json()
const schemaResponse = await fetch(`${apiBaseUrl}/toolkit/schema-awareness-prompt`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwtToken}`,
'X-App-Id': appId,
},
body: JSON.stringify({
schemaAwarenessData,
}),
})
const { prompt: schemaAwarenessPrompt } = await schemaResponse.json()
const result = streamText({
model,
system: `${workflow.systemPrompt}\n\n${schemaAwarenessPrompt}`,
prompt: JSON.stringify({
content: readResult.output.content,
task: 'Correct all grammar and spelling mistakes',
}),
output: Output.object({ schema: z.fromJSONSchema(workflow.outputSchema) }),
})
const output = await result.output3. Execute the workflow
Execute the workflow directly to apply the corrections to the document. Call:
POST /v3/ai/toolkit/execute-workflow/proofreader
const executeResponse = await fetch(`${apiBaseUrl}/toolkit/execute-workflow/proofreader`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwtToken}`,
'X-App-Id': appId,
},
body: JSON.stringify({
schemaAwarenessData,
format: 'shorthand',
input: output,
sessionId: readResult.sessionId,
reviewOptions: {
mode: 'disabled',
},
experimental_documentOptions: {
documentId,
userId: 'ai-assistant',
},
}),
})
const executeResult = await executeResponse.json()4. Trigger the workflow from the editor UI
The client sends the document ID and current session ID, then stores the updated session ID from the response.
const runProofreader = async () => {
const response = await fetch('/api/server-proofreader-workflow', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
documentId,
schemaAwarenessData: getSchemaAwarenessData(editor),
sessionId,
}),
})
const result: { sessionId: string } = await response.json()
setSessionId(result.sessionId)
}Tracked changes
To make the proofreader work with tracked changes instead of direct edits, keep the same setup and change only the execute call and the client UI.
In the POST /v3/ai/toolkit/execute-workflow/proofreader request shown in step 3, replace this:
reviewOptions: {
mode: 'disabled',
}with this:
reviewOptions: {
mode: 'trackedChanges',
trackedChangesOptions: {
userId: 'ai-assistant',
},
}Then render tracked-changes controls in the editor so users can review the suggestions:
editor.commands.acceptAllSuggestions()
editor.commands.rejectAllSuggestions()End result
The result is a collaborative proofreader workflow for server-side grammar and spelling fixes:
See the source code on GitHub.
Next steps
- Review review options
- See the REST API request details