The prompt sent to the FIM LLM follows this structure:
'(:template (:prompt minuet--default-fim-prompt-function
:suffix minuet--default-fim-suffix-function))This template utilizes two default functions that generate the following:
:prompt: Returns the programming language, indentation style, and the verbatim content of the context before the cursor.:suffix: Returns the verbatim content of the context after cursor.
Both :prompt and :suffix are implemented as functions, each accepting a
plist ctx with these attributes and returning a string:
:before-cursor: The text before the cursor.:after-cursor: The text after the cursor.:language-and-tab: The programming language and indentation style.is_incomplete_before: A boolean indicating whether the content before the cursor was truncated.is_incomplete_after: A boolean indicating whether the content after the cursor was truncated.
These functions are customizable to provide additional context to the LLM. The
:suffix function can be disabled by setting its value to nil using
plist-put, resulting in a request containing only the :prompt content.
Note: for Ollama users: Do not include special tokens (e.g., <|fim_begin|>)
within the prompt or suffix functions, as these will be automatically populated
by Ollama. If your use case requires special tokens not covered by Ollama's
default template, disable the :suffix function by setting it to nil and
incorporate the necessary special tokens within the prompt function.
We utilize two distinct strategies when constructing prompts:
-
Prefix First Style: This involves including the code preceding the cursor initially, followed by the code succeeding the cursor. This approach is used for the OpenAI and Gemini providers.
-
Suffix First Style: This method involves including the code following the cursor initially, and then the code preceding the cursor. It is employed for OpenAI-Compatible and Claude providers.
The counterpart variables are:
minuet-default-promptandminuet-default-prompt-prefix-first.minuet-default-fewshotsandminuet-default-fewshots-prefix-first.minuet-default-chat-input-templateandminuet-default-chat-input-template-prefix-first.
{{{:prompt}}}\n{{{:guidelines}}}\n{{{:n_completion_template}}}
Prefix First Style:
You are an AI code completion engine. Provide contextually appropriate completions:
- Code completions in code context
- Comment/documentation text in comments
- String content in string literals
- Prose in markdown/documentation files
Input markers:
<contextAfterCursor>: Context after cursor<cursorPosition>: Current cursor location<contextBeforeCursor>: Context before cursor
Suffix First Style:
You are an AI code completion engine. Provide contextually appropriate completions:
- Code completions in code context
- Comment/documentation text in comments
- String content in string literals
- Prose in markdown/documentation files
Input markers:
<contextAfterCursor>: Context after cursor<cursorPosition>: Current cursor location<contextBeforeCursor>: Context before cursor
Note that the user input will be provided in reverse order: first the context after cursor, followed by the context before cursor.
Guidelines:
- Offer completions after the
<cursorPosition>marker. - Make sure you have maintained the user's existing whitespace and indentation. This is REALLY IMPORTANT!
- Provide multiple completion options when possible.
- Return completions separated by the marker
<endCompletion>. - The returned message will be further parsed and processed. DO NOT include additional comments or markdown code block fences. Return the result directly.
- Keep each completion option concise, limiting it to a single line or a few lines.
- Create entirely new code completion that DO NOT REPEAT OR COPY any user's
existing code around
<cursorPosition>.
- Provide at most %d completion items.
;; suffix-first style
(defvar minuet-default-fewshots
`((:role "user"
:content "# language: javascript
<contextAfterCursor>
return result;
}
const processedData = transformData(rawData, {
uppercase: true,
removeSpaces: false
});
<contextBeforeCursor>
function transformData(data, options) {
const result = [];
for (let item of data) {
<cursorPosition>")
(:role "assistant"
:content "let processed = item;
if (options.uppercase) {
processed = processed.toUpperCase();
}
if (options.removeSpaces) {
processed = processed.replace(/\s+/g, '');
}
result.push(processed);
}
<endCompletion>
if (typeof item === 'string') {
let processed = item;
if (options.uppercase) {
processed = processed.toUpperCase();
}
if (options.removeSpaces) {
processed = processed.replace(/\s+/g, '');
}
result.push(processed);
} else {
result.push(item);
}
}
<endCompletion>
")))
(defvar minuet-default-fewshots-prefix-first
`((:role "user"
:content "# language: javascript
<contextBeforeCursor>
function transformData(data, options) {
const result = [];
for (let item of data) {
<cursorPosition>
<contextAfterCursor>
return result;
}
const processedData = transformData(rawData, {
uppercase: true,
removeSpaces: false
});")
,(cadr minuet-default-fewshots)))The chat input represents the final prompt delivered to the LLM for completion.
The chat input template follows a structure similar to the system prompt and can be customized using the following format:
Suffix First Style:
{{{:language-and-tab}}}
<contextAfterCursor>
{{{:context_after_cursor}}}
<contextBeforeCursor>
{{{:context_before_cursor}}}<cursorPosition>
Prefix First Style:
{{{:language-and-tab}}}
<contextBeforeCursor>
{{{:context_before_cursor}}}<cursorPosition>
<contextAfterCursor>
{{{:context_after_cursor}}}
The chat input template can be provided either as a single string or as a list
of strings. If supplied as a list, each string will be expanded using the
template and its components. The resulting list will then be transformed into a
multi-turn conversation, with roles alternating between user and assistant.
Components:
:language-and-tab: Specifies the programming language and indentation style utilized by the user:context-before-cursor: Contains the text content preceding the cursor position:context-after-cursor: Contains the text content following the cursor position
Implementation requires each component to be defined by a function that accepts
a single parameter context and returns a string. This context parameter is a
plist containing the following values:
:before-cursor: The text before the cursor.:after-cursor: The text after the cursor.:language-and-tab: The programming language and indentation style.is_incomplete_before: A boolean indicating whether the content before the cursor was truncated.is_incomplete_after: A boolean indicating whether the content after the cursor was truncated.
You can customize the :template by encoding placeholders within triple braces.
These placeholders will be interpolated using the corresponding key-value pairs
from the table. The value can be a function that takes no argument and returns a
string, or a symbol whose value is a string.
Here's a simplified example for illustrative purposes (not intended for actual configuration):
(setq my-minuet-simple-template "{{{:assistant}}}\n{{{:role}}}")
(setq my-minuet-simple-role "you are also a computer scientist")
(defun my-simple-assistant-prompt () "" "you are a helpful assistant.")
(plist-put
minuet-openai-options
:system
'(:template my-minuet-simple-template ; note: you do not need the comma , for interpolation
:assistant my-simple-assistant-prompt
:role my-minuet-simple-role))Note that :n_completion_template is a special placeholder as it contains one
%d which will be encoded with minuet-n-completions, if you want to customize
this template, make sure your prompt also contains only one %d.
Similarly, :fewshots can be a plist in the following form or a function that
takes no argument and returns a plist.
Below is an example to configure the prompt based on major mode:
(defun my-minuet-few-shots ()
(if (derived-mode-p 'js-mode)
(list '(:role "user"
:content "// language: javascript
<contextAfterCursor>
fib(5)
<contextBeforeCursor>
function fibonacci(n) {
<cursorPosition>")
'(:role "assistant"
:content " // Recursive Fibonacci implementation
if (n < 2) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
<endCompletion>
// Iterative Fibonacci implementation
let a = 0, b = 1;
for (let i = 0; i < n; i++) {
[a, b] = [b, a + b];
}
return a;
<endCompletion>
"))
minuet-default-fewshots))
(plist-put minuet-openai-options :fewshots #'my-minuet-few-shots)Here, we present a practical example for configuring the prompt for Gemini, aiming to reuse existing components of the default prompt wherever possible.
Please note that you should not copy-paste this into your configuration, as it represents the default setting applied to Gemini.
(use-package minuet
:config
(setq minuet-provider 'gemini)
(defvar my-minuet-gemini-prompt minuet-default-prompt-prefix-first)
(defvar my-minuet-gemini-chat-input-template
"{{{:language-and-tab}}}
<contextBeforeCursor>
{{{:context-before-cursor}}}<cursorPosition>
<contextAfterCursor>
{{{:context-after-cursor}}}")
(defvar my-minuet-gemini-fewshots
`((:role "user"
:content "# language: javascript
<contextBeforeCursor>
function transformData(data, options) {
const result = [];
for (let item of data) {
<cursorPosition>
<contextAfterCursor>
return result;
}
const processedData = transformData(rawData, {
uppercase: true,
removeSpaces: false
});")
,(cadr minuet-default-fewshots)))
(minuet-set-optional-options minuet-gemini-options
:prompt 'my-minuet-gemini-prompt
:system)
(minuet-set-optional-options minuet-gemini-options
:template 'my-minuet-gemini-chat-input-template
:chat-input)
(plist-put minuet-gemini-options :fewshots 'my-minuet-gemini-fewshots)
)