Copilot
Render AI suggestions ghost text as you type.
Features
- Renders ghost text suggestions as you type
- Two trigger modes:
- Shortcut (
Ctrl+Space
). Press again for alternative suggestions. - Debounce mode: automatically triggers after a space at paragraph ends
- Shortcut (
- Accept suggestions with Tab or word-by-word with
Cmd+→
- Built-in support for Vercel AI SDK completion API
Installation
npm install @udecode/plate-ai @udecode/plate-markdown
Usage
import { CopilotPlugin } from '@udecode/plate-ai/react';
import {
MarkdownPlugin,
serializeMdNodes,
stripMarkdown,
} from '@udecode/plate-markdown';
const plugins = [
// ...otherPlugins,
MarkdownPlugin.configure({ options: { indentList: true } }),
CopilotPlugin.configure(({ api }) => ({
options: {
completeOptions: {
api: '/api/your-api-endpoint',
body: {
system: `You are an advanced AI writing assistant, similar to VSCode Copilot but for general text. Your task is to predict and generate the next part of the text based on the given context.
Rules:
- Continue the text naturally up to the next punctuation mark (., ,, ;, :, ?, or !).
- Maintain style and tone. Don't repeat given text.
- For unclear context, provide the most likely continuation.
- Handle code snippets, lists, or structured text if needed.
- Don't include """ in your response.
- CRITICAL: Always end with a punctuation mark.
- CRITICAL: Avoid starting a new block. Do not use block formatting like >, #, 1., 2., -, etc. The suggestion should continue in the same block as the context.
- If no context is provided or you can't generate a continuation, return "0" without explanation.`,
},
onFinish: (_, completion) => {
if (completion === '0') return;
api.copilot.setBlockSuggestion({
//stripMarkdownBlocks in plus GhostText
text: stripMarkdown(completion),
});
},
},
debounceDelay: 500,
getPrompt: ({ editor }) => {
const contextEntry = getAncestorNode(editor);
if (!contextEntry) return '';
const prompt = serializeMdNodes([contextEntry[0] as TElement]);
return `Continue the text up to the next punctuation mark:
"""
${prompt}
"""`;
},
renderGhostText: GhostText,
},
}));
Tab Key Handling
The Copilot plugin uses the Tab key to accept suggestions. To avoid conflicts with other plugins that use Tab (like IndentPlugin
or TabbablePlugin
), ensure CopilotPlugin
is placed before them in your plugin configuration. This allows Copilot to handle Tab key events first when suggestions are present.
const plugins = [
// ...otherPlugins,
CopilotPlugin,
// Place tab-using plugins after Copilot
IndentPlugin,
TabbablePlugin,
];
Examples
Plate UI
Refer to the preview above.
Plate Plus
Keyboard Shortcuts
Key | Description |
---|---|
Ctrl + Space | Trigger suggestion. Press again for alternative suggestions. |
Tab | Accept the entire suggestion. |
Cmd + → | Accept the next word of the suggestion. |
Escape | Dismiss the current suggestion. |
Plugins
CopilotPlugin
Options
- Block above is not empty
- Block above ends with a space
- No existing suggestion
- Selection is not expanded
- Selection is at block end
Additional conditions to auto trigger copilot. Default checks:
AI completion configuration options. See AI SDK useCompletion Parameters.
Delay for debouncing auto-triggered suggestions. Default: 0
Function to extract the next word from suggestion text.
Function to generate the prompt for AI completion. Default: Uses markdown serialization of ancestor node
Component to render ghost text suggestions.
Conditions to trigger copilot. Default checks:
API
editor.api.copilot.accept()
Accepts the current suggestion.
editor.api.copilot.acceptNextWord()
Accepts the next word of the suggestion.
editor.api.copilot.reset()
Resets the plugin state:
- Aborts any ongoing API request
- Clears the current completion
- Clears suggestion node ID and text
editor.api.copilot.setBlockSuggestion()
Sets suggestion text for a block.
Parameters
editor.api.copilot.stop()
Stops ongoing suggestion requests:
- Cancels debounced trigger calls
- Aborts current API request
- Resets abort controller
editor.api.copilot.triggerSuggestion()
Triggers a new suggestion request. Can be debounced based on plugin configuration.