From 7df6c787d4687ff56377ee16d89e282edb17783f Mon Sep 17 00:00:00 2001 From: Jonathan Clement Date: Fri, 7 Nov 2025 08:40:57 -0600 Subject: [PATCH] Added Pseudo FIM Feature -Added Pseudo FIM feature which provides in line completion for use with models not specifically designed for FIM. This allows for in line completions with models such as gpt-oss-20b/120b. -Added Pseudo FIM system prompt preference which is used when Pseudo FIM is enabled in the models preferences. -This feature works well in LM Studio/OpenAI and Ollama. Implemented, but untested for Mistral. -When Pseudo FIM is not enabled, the behavior should be identical to the original FIM implementation (requiring a FIM enabled model). Notes: Interestingly, Pseudo FIM mode still works well with the qwen2.5-coder models. It works reasonably well with meta-llama-3.1-8b-instruct, gemma-3-12b. It works very well with gpt-oss-20b. Future possibilities: This new feature uses a system prompt to instruct the model to behave like a FIM model. Future work should be done to appropriately automatically supply more context with this system prompt (or the user prompt) so the Pseudo FIM model may consider fuller context in its completions. --- .../aicoder/llm/LlmPromptTemplates.java | 112 ++++++ .../hetzge/eclipse/aicoder/llm/LlmUtils.java | 333 ++++++++++-------- .../preferences/AiCoderPreferences.java | 16 +- .../preferences/LlmPreferencePage.java | 6 + .../preferences/PromptsPreferencePage.java | 1 + 5 files changed, 325 insertions(+), 143 deletions(-) diff --git a/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmPromptTemplates.java b/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmPromptTemplates.java index 8268094..9d0575b 100644 --- a/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmPromptTemplates.java +++ b/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmPromptTemplates.java @@ -21,6 +21,118 @@ public static String changeCodeSystemPrompt() { """.trim(); } + public static String pseudoFimCodeSystemPrompt() { + return """ + You are an expert code completion AI. + Complete the code. + - The user will provide a code snippet formatted as a "Fill in the Middle" (FIM) request with <|fim_prefix|>, <|fim_suffix|>, and <|fim_middle|> tags. + - You must strictly complete the code, starting immediately after the <|fim_middle|> tag, and return **ONLY** the generated completion code, without any surrounding explanation or text. + - Do not include the prefix or suffix in your response. + - Do not repeat any of the provided context in the response. + - Partial code snippets are expected. + - Apply the following examples returning multiple lines unless instructed to return only a single line assuming the user will complete subsequent lines. + - Provide the completion that fills in the missing code. + + :::Example prompts and responses::: + + Example 1: + ``` + <|fim_prefix|># Current edit location: [path]; + + public class Main { + + public static void main(String[] args) { + // TODO: add a for loop count from 1 to 10 + for (<|fim_suffix|> + } + } + <|fim_middle|> + ``` + Correct response: + ``` + int i = 1; i <= 10; i++) { + System.out.println(i); + } + ``` + + Example 2: + ``` + <|fim_prefix|># Current edit location: [path]; + + public class Main { + + public static void main(String[] args) { + // TODO: add a for loop count from 1 to 10 + for(<|fim_suffix|>) + } + } + <|fim_middle|> + ``` + Correct response: + ```int i = 1; i <= 10; i++``` + + Example 3: "<|fim_prefix|># Current edit location: [path]; + ``` + public class Main { + + public static void main(String[] args) { + int j = 100; + while(j<|fim_suffix|> + } + } + <|fim_middle|> + ``` + Correct response: + ``` + > 0) { + System.out.println(j); + j--; + } + ``` + Example 4: + ``` + <|fim_prefix|># Current edit location: [path]; + + public class Main { + + public static void main(String[] args) { + int j = 100; + while(j<|fim_suffix|>) + } + } + <|fim_middle|> + ``` + Correct response: + is: + ``` > 0``` + + Example 5: + ``` + <|fim_prefix|># Current edit location: [path]; + + public class Main { + + public static void main(String[] args) { + String title = "A FIM example."; + System.out + } + } + <|fim_middle|> + ``` + Correct response: + ```.println(title);``` + + ## Additional information ## + - Use Java 21 syntax + - Use the correct variables based on the context + - If a comment precedes the line to you be completed, implement it + - Focus on short, high confidence completions + - Do not generate extraneous code that does not logically fill in the completion + - When the completion is combined with the context code, it should be logically and syntactically correct and compliable + - Pay attention to opening and closing characters such as braces and parentheses + """.trim(); + } + public static String generateCodeSystemPrompt() { return """ You are a software developer assistant. diff --git a/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmUtils.java b/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmUtils.java index 8ac8260..eee9960 100644 --- a/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmUtils.java +++ b/plugin/src/de/hetzge/eclipse/aicoder/llm/LlmUtils.java @@ -54,153 +54,204 @@ private static LlmResponse execute(LlmOption llmModelOption, String systemPrompt } private static LlmResponse executeOllama(LlmOption llmModelOption, String systemPrompt, String prompt, String suffix) throws IOException { - final boolean isFillInTheMiddle = suffix != null; - final String urlString = AiCoderPreferences.getOllamaBaseUrl(); - final boolean multilineEnabled = AiCoderPreferences.isMultilineEnabled(); - final Json json = Json.object() - .set("model", llmModelOption.modelKey()) - .set("prompt", prompt) - .set("stream", false) - .set("options", Json.object() - .set("temperature", 0)); - if (systemPrompt != null) { - json.set("system", systemPrompt); - } - if (isFillInTheMiddle) { - json.set("suffix", suffix); - json.at("options") - .set("num_predict", AiCoderPreferences.getMaxTokens()) - .set("stop", createStop(multilineEnabled)); - } - final URL url = URI.create(urlString).resolve("/api/generate").toURL(); - final long beforeTimestamp = System.currentTimeMillis(); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("Accept", "application/json"); - connection.setDoOutput(true); - HttpUtils.writeRequestBody(connection, json); - final int responseCode = connection.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - final String responseBody = HttpUtils.readResponseBody(connection); - final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); - final Json responseJson = Json.read(responseBody); - final String content = responseJson.at("response").asString(); - final int inputTokens = responseJson.at("prompt_eval_count").asInteger(); - final int outputTokens = responseJson.at("eval_count").asInteger(); - return new LlmResponse(llmModelOption, content, responseBody, inputTokens, outputTokens, duration, false); - } else { - AiCoderActivator.log().log(new Status(IStatus.WARNING, AiCoderActivator.PLUGIN_ID, String.format("Error: %s (%s)", connection.getResponseMessage(), responseCode))); - final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); - final String responseBody = HttpUtils.readErrorResponseBody(connection); - return new LlmResponse(llmModelOption, "", responseBody, 0, 0, duration, true); - } + final boolean isFillInTheMiddle = suffix != null; + final boolean isPseudoFim = isFillInTheMiddle && AiCoderPreferences.isEnablePseduoFim(); + + final String urlString = AiCoderPreferences.getOllamaBaseUrl(); + final boolean multilineEnabled = AiCoderPreferences.isMultilineEnabled(); + String currentSystemPrompt = systemPrompt; + String currentPrompt = prompt; + if (isPseudoFim) { + String fimPayload = JinjaUtils.applyTemplate(AiCoderPreferences.getOpenAiFimTemplate(), Map.ofEntries( + Map.entry("prefix", prompt), + Map.entry("suffix", suffix))); + currentSystemPrompt = getPseduoFIMSystemPrompt(AiCoderPreferences.getPseudoFimSystemPrompt(), multilineEnabled); + currentPrompt = fimPayload; + } + final Json json = Json.object() + .set("model", llmModelOption.modelKey()) + .set("prompt", currentPrompt) + .set("stream", false) + .set("options", Json.object() + .set("temperature", 0)); + if (currentSystemPrompt != null) { + json.set("system", currentSystemPrompt); + } + if (isFillInTheMiddle) { + json.at("options").set("num_predict", AiCoderPreferences.getMaxTokens()); + if (!isPseudoFim) { + json.set("suffix", suffix); + json.at("options").set("stop", createStop(multilineEnabled)); + } + } + + final URL url = URI.create(urlString).resolve("/api/generate").toURL(); + final long beforeTimestamp = System.currentTimeMillis(); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/json"); + connection.setDoOutput(true); + HttpUtils.writeRequestBody(connection, json); + final int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + final String responseBody = HttpUtils.readResponseBody(connection); + final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); + final Json responseJson = Json.read(responseBody); + String content = responseJson.at("response").asString(); + if (isPseudoFim) + content = content.trim(); + final int inputTokens = responseJson.at("prompt_eval_count").asInteger(); + final int outputTokens = responseJson.at("eval_count").asInteger(); + return new LlmResponse(llmModelOption, content, responseBody, inputTokens, outputTokens, duration, false); + } else { + AiCoderActivator.log().log(new Status(IStatus.WARNING, AiCoderActivator.PLUGIN_ID, String.format("Error: %s (%s)", connection.getResponseMessage(), responseCode))); + final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); + final String responseBody = HttpUtils.readErrorResponseBody(connection); + return new LlmResponse(llmModelOption, "", responseBody, 0, 0, duration, true); + } } private static LlmResponse executeMistral(LlmOption llmModelOption, String systemPrompt, String prompt, String suffix) throws IOException { - final boolean isFillInTheMiddle = suffix != null; - final String urlString = "https://codestral.mistral.ai"; - final String codestralApiKey = AiCoderPreferences.getCodestralApiKey(); - final boolean multilineEnabled = AiCoderPreferences.isMultilineEnabled(); - final Json json = Json.object() - .set("model", llmModelOption.modelKey()) - .set("temperature", 0); - if (isFillInTheMiddle) { - json.set("prompt", prompt) - .set("suffix", suffix) - .set("max_tokens", AiCoderPreferences.getMaxTokens()) - .set("stop", createStop(multilineEnabled)); - } else { - final Json messagesJson = Json.array(); - if (systemPrompt != null) { - messagesJson.add(Json.object() - .set("role", "system") - .set("content", systemPrompt)); - } - messagesJson.add(Json.object() - .set("role", "user") - .set("content", prompt)); - json.set("messages", messagesJson); - } - final String path = isFillInTheMiddle ? "/v1/fim/completions" : "/v1/chat/completions"; - final URL url = URI.create(urlString).resolve(path).toURL(); - final long beforeTimestamp = System.currentTimeMillis(); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("Accept", "application/json"); - connection.setRequestProperty("Authorization", "Bearer " + codestralApiKey); - connection.setDoOutput(true); - HttpUtils.writeRequestBody(connection, json); - final int responseCode = connection.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - final String responseBody = HttpUtils.readResponseBody(connection); - final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); - final Json responseJson = Json.read(responseBody); - final String content = responseJson.at("choices").at(0).at("message").at("content").asString(); - final int inputTokens = responseJson.at("usage").at("prompt_tokens").asInteger(); - final int outputTokens = responseJson.at("usage").at("completion_tokens").asInteger(); - return new LlmResponse(llmModelOption, content, responseBody, inputTokens, outputTokens, duration, false); - } else { - AiCoderActivator.log().log(new Status(IStatus.WARNING, AiCoderActivator.PLUGIN_ID, String.format("Error: %s (%s)", connection.getResponseMessage(), responseCode))); - final String responseBody = HttpUtils.readErrorResponseBody(connection); - final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); - return new LlmResponse(llmModelOption, "", responseBody, 0, 0, duration, true); - } + final boolean isFillInTheMiddle = suffix != null; + final boolean isPseudoFim = isFillInTheMiddle && AiCoderPreferences.isEnablePseduoFim(); + final String urlString = "https://codestral.mistral.ai"; + final String codestralApiKey = AiCoderPreferences.getCodestralApiKey(); + final boolean multilineEnabled = AiCoderPreferences.isMultilineEnabled(); + final Json json = Json.object() + .set("model", llmModelOption.modelKey()) + .set("temperature", 0); + String currentSystemPrompt = systemPrompt; + String currentPrompt = prompt; + if (isFillInTheMiddle && !isPseudoFim) { + json.set("prompt", currentPrompt) + .set("suffix", suffix) + .set("max_tokens", AiCoderPreferences.getMaxTokens()) + .set("stop", createStop(multilineEnabled)); + } else { + final Json messagesJson = Json.array(); + if (isPseudoFim) { + currentPrompt = JinjaUtils.applyTemplate(AiCoderPreferences.getOpenAiFimTemplate(), Map.ofEntries( + Map.entry("prefix", prompt), + Map.entry("suffix", suffix))); + currentSystemPrompt = getPseduoFIMSystemPrompt(AiCoderPreferences.getPseudoFimSystemPrompt(), multilineEnabled); // APPLY MULTILINE INSTRUCTION + json.set("max_tokens", AiCoderPreferences.getMaxTokens()); + } + if (currentSystemPrompt != null) { + messagesJson.add(Json.object() + .set("role", "system") + .set("content", currentSystemPrompt)); + } + messagesJson.add(Json.object() + .set("role", "user") + .set("content", currentPrompt)); + + json.set("messages", messagesJson); + } + final String path = isFillInTheMiddle && !isPseudoFim ? "/v1/fim/completions" : "/v1/chat/completions"; + final URL url = URI.create(urlString).resolve(path).toURL(); + final long beforeTimestamp = System.currentTimeMillis(); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/json"); + connection.setRequestProperty("Authorization", "Bearer " + codestralApiKey); + connection.setDoOutput(true); + HttpUtils.writeRequestBody(connection, json); + + final int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + final String responseBody = HttpUtils.readResponseBody(connection); + final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); + final Json responseJson = Json.read(responseBody); + String content; + content = responseJson.at("choices").at(0).at("message").at("content").asString(); + if (isPseudoFim) + content = content.trim(); + final int inputTokens = responseJson.at("usage").at("prompt_tokens").asInteger(); + final int outputTokens = responseJson.at("usage").at("completion_tokens").asInteger(); + return new LlmResponse(llmModelOption, content, responseBody, inputTokens, outputTokens, duration, false); + } else { + AiCoderActivator.log().log(new Status(IStatus.WARNING, AiCoderActivator.PLUGIN_ID, String.format("Error: %s (%s)", connection.getResponseMessage(), responseCode))); + final String responseBody = HttpUtils.readErrorResponseBody(connection); + final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); + return new LlmResponse(llmModelOption, "", responseBody, 0, 0, duration, true); + } } private static LlmResponse executeOpenAi(LlmOption llmModelOption, String systemPrompt, String prompt, String suffix) throws IOException { - final boolean isFillInTheMiddle = suffix != null; - final String urlString = AiCoderPreferences.getOpenAiBaseUrl(); - final String openAiApiKey = AiCoderPreferences.getOpenAiApiKey(); - final Json json = Json.object() - .set("model", llmModelOption.modelKey()) - .set("temperature", 0); - if (!isFillInTheMiddle) { - final Json messagesJson = Json.array(); - if (systemPrompt != null) { - messagesJson.add(Json.object() - .set("role", "system") - .set("content", systemPrompt)); - } - messagesJson.add(Json.object() - .set("role", "user") - .set("content", prompt)); - json.set("messages", messagesJson); - } else { - final String fimPrompt = JinjaUtils.applyTemplate(AiCoderPreferences.getOpenAiFimTemplate(), Map.ofEntries( - Map.entry("prefix", prompt), - Map.entry("suffix", suffix))); - json.set("prompt", fimPrompt) - .set("max_tokens", AiCoderPreferences.getMaxTokens()); - } - - final URL url = URI.create(urlString + "/").resolve(isFillInTheMiddle ? "./v1/completions" : "./v1/chat/completions").toURL(); - final long beforeTimestamp = System.currentTimeMillis(); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("Accept", "application/json"); - connection.setRequestProperty("Authorization", "Bearer " + openAiApiKey); - connection.setDoOutput(true); - HttpUtils.writeRequestBody(connection, json); - final int responseCode = connection.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - final String responseBody = HttpUtils.readResponseBody(connection); - final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); - final Json responseJson = Json.read(responseBody); - final String content = isFillInTheMiddle - ? responseJson.at("choices").at(0).at("text").asString() - : responseJson.at("choices").at(0).at("message").at("content").asString(); - final int inputTokens = responseJson.at("usage").at("prompt_tokens").asInteger(); - final int outputTokens = responseJson.at("usage").at("completion_tokens").asInteger(); - return new LlmResponse(llmModelOption, content, responseBody, inputTokens, outputTokens, duration, false); - } else { - AiCoderActivator.log().log(new Status(IStatus.WARNING, AiCoderActivator.PLUGIN_ID, String.format("Error: %s (%s)", connection.getResponseMessage(), responseCode))); - final String responseBody = HttpUtils.readErrorResponseBody(connection); - final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); - return new LlmResponse(llmModelOption, "", responseBody, 0, 0, duration, true); - } + final boolean isFillInTheMiddle = suffix != null; + final boolean isPseudoFim = isFillInTheMiddle && AiCoderPreferences.isEnablePseduoFim(); + final String urlString = AiCoderPreferences.getOpenAiBaseUrl(); + final String openAiApiKey = AiCoderPreferences.getOpenAiApiKey(); + final boolean multilineEnabled = AiCoderPreferences.isMultilineEnabled(); // Fetch multilineEnabled here + final Json json = Json.object() + .set("model", llmModelOption.modelKey()) + .set("temperature", 0); + if (!isFillInTheMiddle || isPseudoFim) { + final Json messagesJson = Json.array(); + String currentSystemPrompt = systemPrompt; + if (isPseudoFim) { + final String fimPrompt = JinjaUtils.applyTemplate(AiCoderPreferences.getOpenAiFimTemplate(), Map.ofEntries( + Map.entry("prefix", prompt), + Map.entry("suffix", suffix))); + currentSystemPrompt = getPseduoFIMSystemPrompt(AiCoderPreferences.getPseudoFimSystemPrompt(), multilineEnabled); // Use the new function for system prompt + prompt = fimPrompt; + json.set("max_tokens", AiCoderPreferences.getMaxTokens()); + } + if (currentSystemPrompt != null) { + messagesJson.add(Json.object() + .set("role", "system") + .set("content", currentSystemPrompt)); + } + messagesJson.add(Json.object() + .set("role", "user") + .set("content", prompt)); + json.set("messages", messagesJson); + } else { + final String fimPrompt = JinjaUtils.applyTemplate(AiCoderPreferences.getOpenAiFimTemplate(), Map.ofEntries( + Map.entry("prefix", prompt), + Map.entry("suffix", suffix))); + json.set("prompt", fimPrompt) + .set("max_tokens", AiCoderPreferences.getMaxTokens()); + } + + final URL url = URI.create(urlString + "/").resolve(isFillInTheMiddle && !isPseudoFim ? "./v1/completions" : "./v1/chat/completions").toURL(); + final long beforeTimestamp = System.currentTimeMillis(); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/json"); + connection.setRequestProperty("Authorization", "Bearer " + openAiApiKey); + connection.setDoOutput(true); + HttpUtils.writeRequestBody(connection, json); + final int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + final String responseBody = HttpUtils.readResponseBody(connection); + final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); + final Json responseJson = Json.read(responseBody); + String content; + if (isFillInTheMiddle && !isPseudoFim) { + content = responseJson.at("choices").at(0).at("text").asString(); + } else { + content = responseJson.at("choices").at(0).at("message").at("content").asString(); + if (isPseudoFim) + content = content.trim(); + } + final int inputTokens = responseJson.at("usage").at("prompt_tokens").asInteger(); + final int outputTokens = responseJson.at("usage").at("completion_tokens").asInteger(); + return new LlmResponse(llmModelOption, content, responseBody, inputTokens, outputTokens, duration, false); + } else { + AiCoderActivator.log().log(new Status(IStatus.WARNING, AiCoderActivator.PLUGIN_ID, String.format("Error: %s (%s)", connection.getResponseMessage(), responseCode))); + final String responseBody = HttpUtils.readErrorResponseBody(connection); + final Duration duration = Duration.ofMillis(System.currentTimeMillis() - beforeTimestamp); + return new LlmResponse(llmModelOption, "", responseBody, 0, 0, duration, true); + } + } + + private static String getPseduoFIMSystemPrompt(String fimSystemPrompt, boolean multilineEnabled) { + return fimSystemPrompt + (multilineEnabled?"":"\\nOnly generate a single line of code."); } private static Json createStop(final boolean multilineEnabled) { diff --git a/plugin/src/de/hetzge/eclipse/aicoder/preferences/AiCoderPreferences.java b/plugin/src/de/hetzge/eclipse/aicoder/preferences/AiCoderPreferences.java index fa3c5f3..55323cb 100644 --- a/plugin/src/de/hetzge/eclipse/aicoder/preferences/AiCoderPreferences.java +++ b/plugin/src/de/hetzge/eclipse/aicoder/preferences/AiCoderPreferences.java @@ -41,6 +41,8 @@ public final class AiCoderPreferences extends AbstractPreferenceInitializer { public static final String CHANGE_CODE_SYSTEM_PROMPT_KEY = "de.hetzge.eclipse.aicoder.change_code_system_prompt"; public static final String GENERATE_CODE_SYSTEM_PROMPT_KEY = "de.hetzge.eclipse.aicoder.generate_code_system_prompt"; public static final String OPENAI_FIM_TEMPLATE_KEY = "de.hetzge.eclipse.aicoder.openai_fim_template"; + public static final String ENABLE_PSEUDO_FIM_KEY = "de.hetzge.eclipse.aicoder.enable_pseduo_fim"; + public static final String PSEUDO_FIM_SYSTEM_PROMPT_KEY = "de.hetzge.eclipse.aicoder.pseudo_fim_system_prompt"; @Override public void initializeDefaultPreferences() { @@ -72,10 +74,13 @@ public void initializeDefaultPreferences() { store.setDefault(CHANGE_CODE_SYSTEM_PROMPT_KEY, LlmPromptTemplates.changeCodeSystemPrompt()); store.setDefault(GENERATE_CODE_SYSTEM_PROMPT_KEY, LlmPromptTemplates.generateCodeSystemPrompt()); store.setDefault(OPENAI_FIM_TEMPLATE_KEY, "<|fim_prefix|>{{prefix}}<|fim_suffix|>{{suffix}}<|fim_middle|>"); + store.setDefault(ENABLE_PSEUDO_FIM_KEY, false); + store.setDefault(PSEUDO_FIM_SYSTEM_PROMPT_KEY, LlmPromptTemplates.pseudoFimCodeSystemPrompt()); } public static String getCodestralApiKey() { return getStore().getString(CODESTRAL_API_KEY_KEY); + } public static String getOllamaBaseUrl() { @@ -202,9 +207,16 @@ public static String getChangeCodeSystemPrompt() { public static String getGenerateCodeSystemPrompt() { return getStore().getString(GENERATE_CODE_SYSTEM_PROMPT_KEY); } - + public static String getOpenAiFimTemplate() { return getStore().getString(OPENAI_FIM_TEMPLATE_KEY); } - + + public static boolean isEnablePseduoFim() { + return getStore().getBoolean(ENABLE_PSEUDO_FIM_KEY); + } + + public static String getPseudoFimSystemPrompt() { + return getStore().getString(PSEUDO_FIM_SYSTEM_PROMPT_KEY); + } } \ No newline at end of file diff --git a/plugin/src/de/hetzge/eclipse/aicoder/preferences/LlmPreferencePage.java b/plugin/src/de/hetzge/eclipse/aicoder/preferences/LlmPreferencePage.java index 158a326..bf9af57 100644 --- a/plugin/src/de/hetzge/eclipse/aicoder/preferences/LlmPreferencePage.java +++ b/plugin/src/de/hetzge/eclipse/aicoder/preferences/LlmPreferencePage.java @@ -5,6 +5,7 @@ import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.jface.preference.ComboFieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.StringFieldEditor; @@ -71,6 +72,11 @@ protected void createFieldEditors() { fillInMiddleModelEditor.setStringValue(llmOption.modelKey()); } })); + // Pseudo FIM + addField(new BooleanFieldEditor( + AiCoderPreferences.ENABLE_PSEUDO_FIM_KEY, + "Enable Pseudo FIM", + fillInMiddleModelGroup)); final Group quickFixModelGroup = new Group(getFieldEditorParent(), SWT.NONE); quickFixModelGroup.setText("Quick fix LLM"); diff --git a/plugin/src/de/hetzge/eclipse/aicoder/preferences/PromptsPreferencePage.java b/plugin/src/de/hetzge/eclipse/aicoder/preferences/PromptsPreferencePage.java index 997ecb0..e988ecf 100644 --- a/plugin/src/de/hetzge/eclipse/aicoder/preferences/PromptsPreferencePage.java +++ b/plugin/src/de/hetzge/eclipse/aicoder/preferences/PromptsPreferencePage.java @@ -24,5 +24,6 @@ protected void createFieldEditors() { addField(new StringFieldEditor(AiCoderPreferences.QUICK_FIX_PROMPT_KEY, "Quick fix prompt", StringFieldEditor.UNLIMITED, 7, StringFieldEditor.VALIDATE_ON_KEY_STROKE, getFieldEditorParent())); addField(new StringFieldEditor(AiCoderPreferences.CHANGE_CODE_SYSTEM_PROMPT_KEY, "Change code system prompt", StringFieldEditor.UNLIMITED, 7, StringFieldEditor.VALIDATE_ON_KEY_STROKE, getFieldEditorParent())); addField(new StringFieldEditor(AiCoderPreferences.GENERATE_CODE_SYSTEM_PROMPT_KEY, "Generate code system prompt", StringFieldEditor.UNLIMITED, 7, StringFieldEditor.VALIDATE_ON_KEY_STROKE, getFieldEditorParent())); + addField(new StringFieldEditor(AiCoderPreferences.PSEUDO_FIM_SYSTEM_PROMPT_KEY, "Pseduo FIM system prompt", StringFieldEditor.UNLIMITED, 7, StringFieldEditor.VALIDATE_ON_KEY_STROKE, getFieldEditorParent())); } }