Refactor to remove `ConfigurationHelper` and `ModelLibrary`, consolidating functional...
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 18 Jan 2026 20:43:49 +0000 (22:43 +0200)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 18 Jan 2026 20:43:49 +0000 (22:43 +0200)
src/main/java/eu/svjatoslav/alyverkko_cli/Utils.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/AddTaskHeaderCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/JoinFilesCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/ListModelsCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/WizardCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/task_processor/TaskProcess.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/task_processor/TaskProcessorCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/configuration/Configuration.java
src/main/java/eu/svjatoslav/alyverkko_cli/configuration/ConfigurationHelper.java [deleted file]
src/main/java/eu/svjatoslav/alyverkko_cli/configuration/ModelLibrary.java [deleted file]

index c01c2a7..b80f9e7 100644 (file)
@@ -1,5 +1,10 @@
 package eu.svjatoslav.alyverkko_cli;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import eu.svjatoslav.alyverkko_cli.configuration.Configuration;
+import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.FileOption;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
@@ -51,5 +56,42 @@ public class Utils {
         return firstLine != null && firstLine.startsWith("TOCOMPUTE:");
     }
 
+    /**
+     * The default path for the YAML config file, typically under the user's home directory.
+     */
+    public static final String DEFAULT_CONFIG_FILE_PATH = "~/.config/alyverkko-cli/alyverkko-cli.yaml".replaceFirst("^~", System.getProperty("user.home"));
+
+    /**
+     * Loads the configuration from a given file, or from the default
+     * path if {@code configFile} is null.
+     *
+     * @param configFile the file containing the YAML config; may be null.
+     * @return the {@link Configuration} object, or null if not found/invalid.
+     * @throws IOException if file I/O fails during reading.
+     */
+    public static Configuration loadConfiguration(File configFile) throws IOException {
+
+        if (!configFile.exists()) {
+            System.err.println("Configuration file not found: " + configFile);
+            return null;
+        }
+
+        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        return mapper.readValue(configFile, Configuration.class);
+    }
+
+    /**
+     * Returns the configuration file from the given option, or the default path if not present.
+     * @param configFileOption the CLI option for the config file.
+     * @return the configuration file to load.
+     */
+    public static File getConfigurationFile(FileOption configFileOption) {
+        if (configFileOption != null)
+            if (configFileOption.isPresent())
+                return configFileOption.getValue();
+
+        return new File(DEFAULT_CONFIG_FILE_PATH);
+    }
+
 
 }
index e108ce0..e1cbce4 100644 (file)
@@ -2,7 +2,6 @@ package eu.svjatoslav.alyverkko_cli.commands;
 
 import eu.svjatoslav.alyverkko_cli.Command;
 import eu.svjatoslav.alyverkko_cli.configuration.Configuration;
-import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper;
 import eu.svjatoslav.alyverkko_cli.configuration.Model;
 
 import java.io.*;
@@ -10,7 +9,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.*;
 import java.util.*;
 
-import static eu.svjatoslav.alyverkko_cli.Utils.fileHasToComputeMarker;
+import static eu.svjatoslav.alyverkko_cli.Utils.*;
 
 /**
  * This command recursively adds a TOCOMPUTE header to all non-hidden files in the current directory
@@ -49,7 +48,7 @@ public class AddTaskHeaderCommand implements Command {
     @Override
     public void executeCommand(String[] cliArguments) throws IOException, InterruptedException {
         // Load configuration to validate skills and models
-        Configuration config = ConfigurationHelper.loadConfiguration(ConfigurationHelper.getConfigurationFile(null));
+        Configuration config = loadConfiguration(getConfigurationFile(null));
         if (config == null) {
             System.err.println("ERROR: Failed to load configuration file");
             return;
index 700b853..7f30f84 100644 (file)
@@ -14,8 +14,8 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.*;
 
 import static eu.svjatoslav.alyverkko_cli.Main.configuration;
-import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.getConfigurationFile;
-import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.loadConfiguration;
+import static eu.svjatoslav.alyverkko_cli.Utils.getConfigurationFile;
+import static eu.svjatoslav.alyverkko_cli.Utils.loadConfiguration;
 
 /**
  * The JoinFilesCommand aggregates multiple files (optionally matching
@@ -94,7 +94,7 @@ public class JoinFilesCommand implements Command {
      */
     @Override
     public void executeCommand(String[] cliArguments) throws IOException {
-        configuration = loadConfiguration(getConfigurationFile(null));
+        configuration =  loadConfiguration(getConfigurationFile(null));
         if (configuration == null){
             System.out.println("Failed to load configuration file");
             return;
index 6ffe1ba..63b6cab 100644 (file)
@@ -1,13 +1,11 @@
 package eu.svjatoslav.alyverkko_cli.commands;
 
 import eu.svjatoslav.alyverkko_cli.Command;
-import eu.svjatoslav.alyverkko_cli.configuration.ModelLibrary;
+import eu.svjatoslav.alyverkko_cli.Utils;
 
 import java.io.IOException;
 
 import static eu.svjatoslav.alyverkko_cli.Main.configuration;
-import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.getConfigurationFile;
-import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.loadConfiguration;
 
 /**
  * <p>Displays all available AI models in the configured models directory. This command provides a quick overview of
@@ -40,14 +38,13 @@ public class ListModelsCommand implements Command {
      */
     @Override
     public void executeCommand(String[] cliArguments) throws IOException {
-        configuration = loadConfiguration(getConfigurationFile(null));
+        configuration = Utils.loadConfiguration(Utils.getConfigurationFile(null));
         if (configuration == null){
             System.out.println("Failed to load configuration file");
             return;
         }
 
         System.out.println("Listing models in directory: " + configuration.getModelsDirectory());
-        ModelLibrary modelLibrary = new ModelLibrary(configuration.getModelsDirectory(), configuration.getModels());
-        modelLibrary.printModels();
+        configuration.printModels();
     }
 }
index 5056ecb..0d8c2b2 100644 (file)
@@ -3,8 +3,8 @@ package eu.svjatoslav.alyverkko_cli.commands;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import eu.svjatoslav.alyverkko_cli.Command;
+import eu.svjatoslav.alyverkko_cli.Utils;
 import eu.svjatoslav.alyverkko_cli.configuration.Configuration;
-import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper;
 import eu.svjatoslav.alyverkko_cli.configuration.Model;
 import eu.svjatoslav.commons.cli_helper.parameter_parser.Parser;
 import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.FileOption;
@@ -15,7 +15,6 @@ import java.util.ArrayList;
 import java.util.List;
 
 import static eu.svjatoslav.alyverkko_cli.Utils.printRedMessageToConsole;
-import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.getConfigurationFile;
 import static eu.svjatoslav.commons.cli_helper.CLIHelper.*;
 
 /**
@@ -67,7 +66,7 @@ public class WizardCommand implements Command {
             return;
         }
 
-        configurationFile = getConfigurationFile(configFileOption);
+        configurationFile = Utils.getConfigurationFile(configFileOption);
         loadOrCreateConfiguration();
 
         checkAndFixGeneralParameters();
@@ -86,7 +85,7 @@ public class WizardCommand implements Command {
 
         if (configurationFile.exists()) {
             System.out.println("Found existing configuration at: \"" + configurationFile.getAbsolutePath() + "\"");
-            configuration = ConfigurationHelper.loadConfiguration(configurationFile);
+            configuration = Utils.loadConfiguration(configurationFile);
         } else {
             // If no config found, create a fresh one
             System.out.println("Existing configuration not found at \""
index 061991b..ad6f68a 100644 (file)
@@ -1,7 +1,6 @@
 package eu.svjatoslav.alyverkko_cli.commands.task_processor;
 
 import eu.svjatoslav.alyverkko_cli.Utils;
-import eu.svjatoslav.alyverkko_cli.configuration.ModelLibrary;
 
 import java.io.*;
 import java.nio.file.Files;
@@ -39,7 +38,6 @@ public class TaskProcess {
      * The mail query defining system prompt, user prompt, and which model to use.
      */
     private final Task task;
-    private final ModelLibrary modelLibrary;
 
     /**
      * Temporary file used as input to the llama.cpp CLI.
@@ -50,11 +48,9 @@ public class TaskProcess {
      * Creates a new AI task with a given mail query.
      *
      * @param task         the mail query containing model and prompts.
-     * @param modelLibrary model library containing all available models.
      */
-    public TaskProcess(Task task, ModelLibrary modelLibrary) {
+    public TaskProcess(Task task) {
         this.task = task;
-        this.modelLibrary = modelLibrary;
     }
 
     /**
@@ -169,7 +165,7 @@ public class TaskProcess {
         ArrayList <String> args = new ArrayList<>();
         args.add("nice -n " + niceValue);
         args.add(executablePath);
-        args.add("--model " +  modelLibrary.getModelFullFilesystemPath(task.model));
+        args.add("--model " +  configuration.getModelFullFilesystemPath(task.model));
         args.add("--threads " + configuration.getThreadCount());
         args.add("--threads-batch " + configuration.getBatchThreadCount());
 
index 7ac02c2..0653afa 100644 (file)
@@ -1,16 +1,12 @@
 package eu.svjatoslav.alyverkko_cli.commands.task_processor;
 
 import eu.svjatoslav.alyverkko_cli.*;
-import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper;
 import eu.svjatoslav.alyverkko_cli.configuration.Model;
 import eu.svjatoslav.alyverkko_cli.configuration.SkillConfig;
-import eu.svjatoslav.alyverkko_cli.configuration.ModelLibrary;
 import eu.svjatoslav.commons.cli_helper.parameter_parser.Parser;
 import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.FileOption;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileReader;
 import java.io.IOException;
 import java.nio.file.*;
 import java.util.*;
@@ -56,11 +52,6 @@ public class TaskProcessorCommand implements Command {
             .addAliases("--config", "-c")
             .mustExist();
 
-    /**
-     * The library of available models, constructed from configuration.
-     */
-    ModelLibrary modelLibrary;
-
     /**
      * The WatchService instance for monitoring file system changes in
      * the mail directory.
@@ -98,13 +89,12 @@ public class TaskProcessorCommand implements Command {
             return;
         }
 
-        configuration = ConfigurationHelper.loadConfiguration(ConfigurationHelper.getConfigurationFile(configFileOption));
+        configuration = Utils.loadConfiguration(Utils.getConfigurationFile(configFileOption));
         if (configuration == null) {
             System.out.println("Failed to load configuration file");
             return;
         }
 
-        modelLibrary = new ModelLibrary(configuration.getModelsDirectory(), configuration.getModels());
         taskDirectory = configuration.getTasksDirectory();
 
         // Set up a directory watch service
@@ -245,7 +235,7 @@ public class TaskProcessorCommand implements Command {
 
         try {
             Task task = buildTaskFromFile(file);
-            TaskProcess aiTask = new TaskProcess(task, modelLibrary);
+            TaskProcess aiTask = new TaskProcess(task);
             String aiGeneratedResponse = aiTask.runAiQuery();
 
             saveAiResponseToFile(file, task, aiGeneratedResponse);
@@ -321,7 +311,7 @@ public class TaskProcessorCommand implements Command {
         // Set AI model using hierarchy: TOCOMPUTE > skill config > default
         String modelAlias = fileProcessingSettings.getOrDefault("model",
                 skill.getModelAlias() != null ? skill.getModelAlias() : "default");
-        Optional<Model> modelOptional = modelLibrary.findModelByAlias(modelAlias);
+        Optional<Model> modelOptional = configuration.findModelByAlias(modelAlias);
         if (!modelOptional.isPresent()) {
             throw new IllegalArgumentException("Model with alias '" + modelAlias + "' not found.");
         }
index abe5b33..1e425f9 100644 (file)
@@ -5,6 +5,8 @@ import lombok.Data;
 
 import java.io.*;
 import java.util.List;
+import java.util.Optional;
+
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 
@@ -115,4 +117,27 @@ public class Configuration {
         return mapper.readValue(promptFile, SkillConfig.class);
     }
 
+
+
+    /**
+     * Prints the details of each model in the library to standard output.
+     */
+    public void printModels() {
+        System.out.println("Available models:\n");
+        for (Model model : models) {
+            model.printModelDetails();
+            System.out.println();
+        }
+    }
+
+    public String getModelFullFilesystemPath(Model model) {
+        return new File(modelsDirectory, model.getFilesystemPath()).getAbsolutePath();
+    }
+
+    public Optional<Model> findModelByAlias(String modelAlias) {
+        for (Model model : models) {
+            if (model.getAlias().equals(modelAlias)) return Optional.of(model);
+        }
+        return Optional.empty();
+    }
 }
diff --git a/src/main/java/eu/svjatoslav/alyverkko_cli/configuration/ConfigurationHelper.java b/src/main/java/eu/svjatoslav/alyverkko_cli/configuration/ConfigurationHelper.java
deleted file mode 100644 (file)
index 6c39b8a..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package eu.svjatoslav.alyverkko_cli.configuration;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.FileOption;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * <p>Helper class for configuration file operations. Provides methods for loading configurations
- * and determining the default configuration file path in the user's home directory.
- * <p>Key functionality includes:
- * <ul>
- *   <li>Configuration file path resolution</li>
- *   <li>YAML deserialization</li>
- *   <li>Error handling for missing configurations</li>
- * </ul>
- */
-public class ConfigurationHelper {
-
-    /**
-     * The default path for the YAML config file, typically under the user's home directory.
-     */
-    public static final String DEFAULT_CONFIG_FILE_PATH = "~/.config/alyverkko-cli/alyverkko-cli.yaml".replaceFirst("^~", System.getProperty("user.home"));
-
-    /**
-     * Loads the configuration from a given file, or from the default
-     * path if {@code configFile} is null.
-     *
-     * @param configFile the file containing the YAML config; may be null.
-     * @return the {@link Configuration} object, or null if not found/invalid.
-     * @throws IOException if file I/O fails during reading.
-     */
-    public static Configuration loadConfiguration(File configFile) throws IOException {
-
-        if (!configFile.exists()) {
-            System.err.println("Configuration file not found: " + configFile);
-            return null;
-        }
-
-        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
-        return mapper.readValue(configFile, Configuration.class);
-    }
-
-    /**
-     * Returns the configuration file from the given option, or the default path if not present.
-     * @param configFileOption the CLI option for the config file.
-     * @return the configuration file to load.
-     */
-    public static File getConfigurationFile(FileOption configFileOption) {
-        if (configFileOption != null)
-            if (configFileOption.isPresent())
-                return configFileOption.getValue();
-
-        return new File(DEFAULT_CONFIG_FILE_PATH);
-    }
-}
diff --git a/src/main/java/eu/svjatoslav/alyverkko_cli/configuration/ModelLibrary.java b/src/main/java/eu/svjatoslav/alyverkko_cli/configuration/ModelLibrary.java
deleted file mode 100644 (file)
index 68c5ece..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-package eu.svjatoslav.alyverkko_cli.configuration;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * A container (library) for multiple AI models, providing
- * functionality for adding and retrieving models by alias.
- */
-public class ModelLibrary {
-
-    /**
-     * The list of all successfully loaded models in this library.
-     */
-    private final List<Model> models;
-
-    /**
-     * The default model for this library (e.g., the first successfully
-     * loaded model in the list).
-     */
-    private static Model defaultModel;
-
-    /**
-     * Base directory containing the model files.
-     */
-    private final File modelsBaseDirectory;
-
-    /**
-     * Constructs a library of AI models from the provided list of
-     * {@link Model}s, ignoring those whose paths do not exist.
-     *
-     * @param modelsBaseDirectory the root directory where model files are stored.
-     * @param configModels        a list of model configurations.
-     */
-    public ModelLibrary(File modelsBaseDirectory, List<Model> configModels) {
-        this.modelsBaseDirectory = modelsBaseDirectory;
-        this.models = new ArrayList<>();
-
-        for (Model configModel : configModels) {
-            addModel(configModel);
-        }
-
-        if (models.isEmpty()) {
-            throw new RuntimeException("No models are defined!");
-        }
-
-        defaultModel = models.get(0);
-    }
-
-
-    /**
-     * Adds a model to the library if no model with the same alias
-     * already exists.
-     *
-     * @param model the model to add.
-     * @throws RuntimeException if a model with the same alias already exists.
-     */
-    public void addModel(Model model) {
-        if (findModelByAlias(model.getAlias()).isPresent()) {
-            throw new RuntimeException("Model with alias \"" + model.getAlias() + "\" already exists!");
-        }
-        models.add(model);
-    }
-
-    /**
-     * @return the list of loaded models in this library.
-     */
-    public List<Model> getModels() {
-        return models;
-    }
-
-    /**
-     * Finds a model by its alias in this library.
-     *
-     * @param alias the model alias to look for.
-     * @return an {@link Optional} describing the found model, or empty if none match.
-     */
-    public Optional<Model> findModelByAlias(String alias) {
-        return models.stream()
-                .filter(model -> model.getAlias().equals(alias))
-                .findFirst();
-    }
-
-    /**
-     * @return the default model (first loaded model).
-     */
-    public Model getDefaultModel() {
-        return defaultModel;
-    }
-
-    /**
-     * Prints the details of each model in the library to standard output.
-     */
-    public void printModels() {
-        System.out.println("Available models:\n");
-        for (Model model : models) {
-            model.printModelDetails();
-            System.out.println();
-        }
-    }
-
-    public String getModelFullFilesystemPath(Model model) {
-        return new File(modelsBaseDirectory, model.getFilesystemPath()).getAbsolutePath();
-    }
-
-}
\ No newline at end of file