Integrate AI Autocomplete in Monaco Editor

Welcome to the Monaco Editor AI Autocomplete Guide - your complete tutorial for adding AI-powered autocomplete to the Monaco editor. You’ll learn how to integrate intelligent code completion, improve editor productivity, and deliver real-time AI suggestions using FrontLLM and the monacopilot completion plugin.
See the live demo of AI Autocomplete in Monaco Editor here.
Setup
Install the required dependencies:
"dependencies": {
"monaco-editor": "0.52.2",
"monacopilot": "1.2.7",
"frontllm": "^0.2.0"
}
Before continuing, ensure you have a FrontLLM gateway. You can create one from your FrontLLM dashboard and obtain a gateway ID.
import { frontLLM } from 'frontllm';
const gateway = frontLLM('<YOUR_GATEWAY_ID>');
Initialize the Monaco Editor
Below is a minimal setup that creates a Monaco instance on the page:
import * as monaco from 'monaco-editor';
const placeholder = document.getElementById('placeholder');
const editor = monaco.editor.create(placeholder, {
value: START_TEXT,
language: 'markdown'
});
Now we need to integrate the monacopilot completion provider into our Monaco editor instance.
registerCompletion(monaco, editor, {
language: 'markdown',
requestHandler: myRequestHandler // Autocomplete request handler
});
As you can see, we need to implement the requestHandler function, which is responsible for fetching AI-generated autocomplete suggestions.
Implement the Request Handler
The requestHandler accepts a params argument, which contains the current editor state. We can extract the content before and after the cursor position to provide context for the AI model.
async function myRequestHandler(params) {
const beforeCursor = params.body.completionMetadata.textBeforeCursor;
const afterCursor = params.body.completionMetadata.textAfterCursor;
// ...
}
For example, if the state of the document is as follows:
I like█ apples.
Then beforeCursor will be I like and afterCursor will be apples..
This allows us to build a prompt that instructs the AI model to provide suggestions only after the cursor position. We can use the following system prompt:
You are a code completion assistant. Your job is to rewrite the marked region of user content, respecting the cursor location.
# 🔍 Markers:
- Editable content is wrapped in:
`<|USER_CONTENT_START|>`
...
`<|USER_CONTENT_END|>`
- The cursor is marked using the **exact token**:
`<|user_cursor_is_here|>`
# 🚫 Forbidden actions (do **NOT** do these):
1. ❌ **Do NOT move, delete, replace, or duplicate** the `<|user_cursor_is_here|>` token.
2. ❌ Do NOT add any text **before or on the same line as** the cursor.
3. ❌ Do NOT change or reformat any text **before** the cursor.
If any of these are violated: **return the content exactly as-is**, unchanged.
# ✅ What you MUST do:
- Add code suggestions *only after* the `<|user_cursor_is_here|>` token.
- Preserve all formatting, indentation, line breaks, and spacing.
- Return only the content between `<|USER_CONTENT_START|>` and `<|USER_CONTENT_END|>` with your changes.
# 🧱 Example:
User input:
```
<|USER_CONTENT_START|>hello<|user_cursor_is_here|><|USER_CONTENT_END|>
```
Correct response:
```
<|USER_CONTENT_START|>hello<|user_cursor_is_here|>world!<|USER_CONTENT_END|>
```
As you can see, we wrap the beforeCursor and afterCursor content with special markers to instruct the AI model where the cursor is located and what content is editable.
Our previous example will then look like this:
<|USER_CONTENT_START|>I like<|user_cursor_is_here|> apples.<|USER_CONTENT_END|>
To build the final prompt, we can use the following code:
const prompt = `Please complete this text:\n' +
'<|USER_CONTENT_START|>${beforeCursor}<|user_cursor_is_here|>${afterCursor}<|USER_CONTENT_END|>`;
Now we can send the final request to the FrontLLM gateway:
const response = await gateway.complete({
model: 'smart',
messages: [
{
role: 'system',
content: `You are a code completion assistant...`
},
{
role: 'user',
content: prompt
}
]
});
If you want to exclude the system prompt from your code, you can use pre prompts supported by FrontLLM.
Result Extraction
Next, we extract the AI suggestions from the response. We only need the content between the <|user_cursor_is_here|> and <|USER_CONTENT_END|> markers.
Here’s a simple function that does that:
function extract(response: CreateNonStreamingChatCompletionResponse): string | null {
const content = response.choices[0].message.content;
const cursorPos = content.indexOf('<|user_cursor_is_here|>');
const endPos = content.indexOf('<|USER_CONTENT_END|>');
if (cursorPos === -1 || endPos === -1 || endPos <= cursorPos) {
return null;
}
return content.substring(cursorPos + '<|user_cursor_is_here|>'.length, endPos);
}
The final implementation of the myFetchFunction will look like this:
async function myRequestHandler(params) {
const beforeCursor = params.body.completionMetadata.textBeforeCursor;
const afterCursor = params.body.completionMetadata.textAfterCursor;
const response = await gateway.complete({
/* ... */
});
const completion = extract(response);
return {
completion
};
}
You now have a fully working AI-powered autocomplete system inside your Monaco Editor!
From here, you can enhance the implementation by adding abort signal support, improving error handling, and refining the prompt to match your specific needs. For larger documents, consider trimming the amount of context you send to the AI model for better performance.
Summary
In this guide, we walked through the essential steps for adding AI-powered autocomplete to a Monaco Editor using FrontLLM.
Enjoy coding with intelligent assistance!
You can view the source code here or check out the 🇲🇨 live demo.