Manage and review AI responses
The AI extension stores the current state in its extension storage under editor.storage.ai
. It keeps track of the current state of the AI response, as well as any past responses.
key | type | definition |
---|---|---|
state | 'loading' | 'error' | 'idle' | While the AI is generating a response, the state is set to loading . After the response is generated, the state is set to idle . When there is an error, the state is set to error |
response | string | undefined | The most recent message generated by the AI. When idle , if this is a string, it is the previous generated message, if undefined , no message has been generated. When loading , this will be a string of the HTML or text the AI has generated so far (if streaming the response). When error , this is undefined |
error | Error | undefined | The error generated, only ever set in the error state |
generatedWith | { action: TextAction; options: TextOptions; range: undefined | Range; } | undefined | The options that describe what the last generated response was generated with range is only ever set if inserting the content into the editor |
pastResponses | string[] | Stores previously generated responses (on success), most recent first. Cleared when the response is accepted/rejected. |
initialContent | Slice | null | The content of the editor before the AI response was inserted. Used to undo the AI response with the aiReject command. |
Accessing AI storage
You can use the extension storage to access the current state of the AI generation.
const aiStorage = editor.storage.ai
if (aiStorage.response.state === 'error') {
// The error that occurred
aiStorage.response.error
}
if (aiStorage.response.state === 'loading') {
// The response of the AI model as it is being generated
aiStorage.response
}
if (aiStorage.response.state === 'idle') {
if (aiStorage.response) {
// The successful response
aiStorage.response
} else {
// No response has been requested yet
}
}
Review AI-generated content
The AI extension provides commands to review the AI-generated content after it has been inserted into the editor.
aiAccept
Marks the AI response as accepted. This will clear the pastResponses
array and set the initialContent
to null
.
editor.commands.aiAccept()
aiReject
Resets the editor content to the previous value.
editor.commands.aiReject()
Resetting to the initial value after multiple AI requests
If you call multiple AI commands in a row, the initialContent
property will be set to the content of the
immediately previous command. So when you call aiReject
, the editor content will be reset to the
state before the previous AI command was executed. To reset the editor content to the state before
all AI commands were executed, you can call commands with the regenerate
option set to true
.
For example: editor.commands.aiSummarize({ regenerate: true })
.
aiRegenerate
Retries the AI response with the same parameters as the previous request.
editor.commands.aiRegenerate()
Preview AI responses before inserting them
Want to preview AI responses before they are inserted into the editor? You can use insert: false
on any AI TextOption. The result will be stored in the extension storage but not inserted into the editor's content.
editor.commands.aiTextPrompt({
text: 'Re-write this text to make it more formal',
stream: true,
insert: false,
format: 'rich-text',
})
From there, you can use the aiAccept
, aiReject
, and aiRegenerate
commands
aiAccept
This command is meant to be ran when the user has accepted the AI response, it will insert the response into the editor by default and it’s behavior changes depending on the provided options.
key | type | definition |
---|---|---|
insertAt | number | { from: number, to: number } | When a number , accept the response and insert it into the start of the editor. When { from: number, to: number } , accept the response and replace the content from position from to position to with the AI response |
append | boolean | If true , instead of replacing the current selection, append to it |
The default behavior with no provided options is to accept the response and insert it into the editor, replacing the current selection
// Accept the response and insert it into the editor
editor.commands.aiAccept()
// Accept the response and insert it into the editor at the start
editor.commands.aiAccept({ insertAt: 0 })
// Accept the response and insert it into the editor at the end
editor.commands.aiAccept({ insertAt: editor.state.doc.content.size })
// Accept the response and append it to the current selection
editor.commands.aiAccept({ append: true })
aiRegenerate
This command is meant to be ran when the user wants the to retry the AI response, it will use all the same options as the previous AI text operation and add to the editor.storage.ai.pastResponses
array
key | type | definition |
---|---|---|
insert | boolean | Whether to insert the regenerated response into the editor |
insertAt | number | { from: number, to: number } | If not specified,the regenerated response will be inserted where the previous response was. When a number , regenerate the response and insert it into the start of the editor. When { from: number, to: number } , regenerate the response and replace the content from position from to position to with the AI response |
The default behavior with no provided options is to, regenerate the response and insert it into the editor, replacing the current selection
// Regenerate the response and insert it into the editor
editor.commands.aiRegenerate()
// Regenerate the response and insert it into the editor at the start
editor.commands.aiRegenerate({ insertAt: 0 })
// Regenerate the response and insert it into the editor at the end
editor.commands.aiRegenerate({ insertAt: editor.state.doc.content.size })
// Regenerate the response and append it to the current selection
editor.commands.aiRegenerate({ append: true })
aiReject
This command is meant to be ran when the user has rejected the AI response, it will reset the extension’s state to the initial idle state and clear all editor.storage.ai.pastResponses
key | type | definition |
---|---|---|
type | 'reset' | 'pause' | Whether to reset the AI to the idle state. Or just pause the current response. Default is 'reset' |
editor.commands.aiReject()
// Will not clear out editor.storage.ai, useful for keeping current response in the editor storage
editor.commands.aiReject({ type: 'pause' })
Advanced example (preview AI responses)
One use case of the extension storage is to render a preview of the AI generated content. The tryParseToTiptapHTML
function leverages your editor's schema to generate a HTML preview of the AI response.
// Display the response as HTML
import { tryParseToTiptapHTML } from '@tiptap-pro/extension-ai'
// try to parse the current message as HTML, and null if it could not be parsed
tryParseToTiptapHTML(editor.storage.ai.response, editor)
// try to parse a previous response as HTML, and null if it could not be parsed
tryParseToTiptapHTML(editor.storage.ai.pastResponses[0], editor)
// For example in React
function PreviewComponent({ editor }) {
const htmlResponse = tryParseToTiptapHTML(editor.storage.ai.response, editor)
/* This is safe since we've parsed the content with prose-mirror first */
return <div dangerouslySetInnerHTML={{ __html: htmlResponse }}></div>
}
See our demo below for a full example.