Attempt to have better control at task template
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Thu, 17 Jul 2025 12:05:42 +0000 (15:05 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Thu, 17 Jul 2025 12:05:42 +0000 (15:05 +0300)
src/main/java/eu/svjatoslav/alyverkko_cli/AiTask.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/mail_correspondant/MailCorrespondentCommand.java
src/test/java/eu/svjatoslav/alyverkko_cli/AiTaskTest.java [deleted file]

index fe360fe..1444baa 100644 (file)
@@ -67,71 +67,7 @@ public class AiTask {
      * @return a string containing the fully prepared query prompt.
      */
     private String buildAiQuery() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("SYSTEM:\n").append(mailQuery.systemPrompt).append("\n");
-
-        String filteredUserPrompt = filterParticipantsInUserInput(mailQuery.userPrompt);
-        if (!filteredUserPrompt.startsWith("USER:")) {
-            sb.append("USER:\n");
-        }
-        sb.append(filteredUserPrompt).append("\n");
-
-        sb.append(AI_RESPONSE_MARKER);
-        return sb.toString();
-    }
-
-    /**
-     * In the user input, rewrite lines like "* USER:" or "* ASSISTANT:"
-     * to "USER:" or "ASSISTANT:" so that we standardize them in the final prompt.
-     *
-     * @param input the raw user input.
-     * @return a sanitized or standardized version of the user prompt.
-     */
-    public static String filterParticipantsInUserInput(String input) {
-        StringBuilder result = new StringBuilder();
-        String[] lines = input.split("\n");
-        for (int i = 0; i < lines.length; i++) {
-            String line = lines[i];
-            if (i > 0) {
-                result.append("\n");
-            }
-            if ("* ASSISTANT:".equals(line)) {
-                line = "ASSISTANT:";
-            }
-            if ("* USER:".equals(line)) {
-                line = "USER:";
-            }
-            result.append(line);
-        }
-        return result.toString();
-    }
-
-    /**
-     * In the AI's response, revert lines like "ASSISTANT:" to "* ASSISTANT:"
-     * for easier reading in org-mode, plus append a * USER: prompt at the end
-     * to form the basis for a continuing conversation.
-     *
-     * @param response the raw AI response.
-     * @return a sanitized response for org-mode usage.
-     */
-    public static String filterParticipantsInAiResponse(String response) {
-        StringBuilder result = new StringBuilder();
-        String[] lines = response.split("\n");
-        for (int i = 0; i < lines.length; i++) {
-            String line = lines[i];
-            if (i > 0) {
-                result.append("\n");
-            }
-            if ("ASSISTANT:".equals(line)) {
-                line = "* ASSISTANT:";
-            }
-            if ("USER:".equals(line)) {
-                line = "* USER:";
-            }
-            result.append(line);
-        }
-        result.append("\n* USER:\n");
-        return result.toString();
+        return mailQuery.systemPrompt.replace("<TASK-FILE>", mailQuery.userPrompt);
     }
 
     /**
@@ -175,7 +111,7 @@ public class AiTask {
             mailQuery.endTimeMillis = System.currentTimeMillis();
 
             // Clean up the AI response: remove partial prompt text, end-of-text marker, etc.
-            return filterParticipantsInAiResponse(cleanupAiResponse(result.toString()));
+            return cleanupAiResponse(result.toString());
         } finally {
             deleteTemporaryFile();
         }
@@ -221,7 +157,7 @@ public class AiTask {
             }
         }
 
-        return result + "\n";
+        return result;
     }
 
     /**
@@ -240,10 +176,10 @@ public class AiTask {
                 "--threads " + configuration.getThreadCount(),
                 "--threads-batch " + configuration.getBatchThreadCount(),
 
-                "--top-k 1", // Restricts token selection to the K tokens with the highest probabilities.
+                "--top-k 20", // Restricts token selection to the K tokens with the highest probabilities.
                              // 1 mean true greedy decoding.
 
-                "--top-p 0",   // Restricts token selection to the smallest possible set
+                "--top-p 0.95",   // Restricts token selection to the smallest possible set
                                // of tokens whose cumulative probability exceeds the specified
                                // threshold P.
 
@@ -251,6 +187,8 @@ public class AiTask {
                                 // probability is at least a certain fraction (Min P) of the
                                 // probability of the most likely token.
 
+                // "--chat-format qwen3",   // Ensure that model sees the <|im_start|>system … / <|im_start|>user … markup it was trained on
+
                 // Avoid getting stuck in a forever repetition loop
                 "--repeat-penalty 1.05", // Very little penalty, because computer code is often repetitive
                 "--repeat-last-n 512",   // Last n tokens to consider for penalizing repetition
@@ -267,10 +205,10 @@ public class AiTask {
                 "--no-display-prompt",
                 "--no-warmup",
                 "--flash-attn",
-                "--temp 0", // Coding tasks need precision, not randomness
+                "--temp 0.6", // Coding tasks need precision, not randomness
                 "--ctx-size " + mailQuery.model.contextSizeTokens,
                 "--batch-size 512",
-                "--no-conversation",
+                "--single-turn", // run conversation for a single turn only, then exit when done
                 "-n -1",
                 "--file " + inputFile
         );
index 8fffb5c..d279166 100644 (file)
@@ -212,10 +212,7 @@ public class MailCorrespondentCommand implements Command {
         // The First line should be "DONE:" with settings used to process this file
         resultFileContent.append(getDoneLine(mailQuery));
 
-        // Ensure the user prompt block is labeled if it isn't already
-        if (!mailQuery.userPrompt.startsWith("* USER:\n")) {
-            resultFileContent.append("* USER:\n");
-        }
+        resultFileContent.append("* USER:\n");
 
         // Append the original user prompt (after the first line)
         resultFileContent.append(mailQuery.userPrompt).append("\n");
diff --git a/src/test/java/eu/svjatoslav/alyverkko_cli/AiTaskTest.java b/src/test/java/eu/svjatoslav/alyverkko_cli/AiTaskTest.java
deleted file mode 100644 (file)
index f8aaa1f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-package eu.svjatoslav.alyverkko_cli;
-
-import org.junit.jupiter.api.Test;
-
-import static org.testng.AssertJUnit.assertEquals;
-
-public class AiTaskTest {
-
-    @Test
-    void testFilterUserInput() {
-        String input = "* ASSISTANT:\nHello\n* USER:\nHi!";
-        String expectedOutput = "ASSISTANT:\nHello\nUSER:\nHi!";
-        String output = AiTask.filterParticipantsInUserInput(input);
-        assertEquals(expectedOutput, output);
-    }
-
-    @Test
-    void testFilterUserInputAnyNumberOfSpacesAtTheEnd() {
-        String input = "* ASSISTANT:        \nHello";
-        String expectedOutput = "ASSISTANT:\nHello";
-        String output = AiTask.filterParticipantsInUserInput(input);
-        assertEquals(expectedOutput, output);
-    }
-}
\ No newline at end of file