package eu.svjatoslav.alyverkko_cli.commands;
import eu.svjatoslav.alyverkko_cli.Command;
-import eu.svjatoslav.alyverkko_cli.model.ModelLibrary;
+import eu.svjatoslav.alyverkko_cli.configuration.ModelLibrary;
import java.io.IOException;
package eu.svjatoslav.alyverkko_cli.commands.task_processor;
+import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationModel;
import eu.svjatoslav.alyverkko_cli.configuration.SkillConfig;
-import eu.svjatoslav.alyverkko_cli.model.Model;
import static eu.svjatoslav.alyverkko_cli.Main.configuration;
/**
* The AI model to be used for processing this query.
*/
- public Model model;
+ public ConfigurationModel model;
/**
* The start time of the query (milliseconds since epoch).
* Calculate effective temperature based on override hierarchy.
*/
public Float getEffectiveTemperature() {
- // 1. Skill specific temperature has priority
+ // 1. Skill-specific temperature has priority
if (skill != null && skill.getTemperature() != null) return skill.getTemperature();
// 2. If not in skill, check if model specifies it
- if (model.temperature != null) return model.temperature;
+ if (model.getTemperature() != null) return model.getTemperature();
// 3. Fall back to global default
return configuration.getDefaultTemperature();
* @return the applicable top-p value for this query
*/
public Float getEffectiveTopP() {
- // Skill-specific has highest priority
+ // Skill-specific has the highest priority
if (skill != null && skill.getTopP() != null) return skill.getTopP();
// Model-specific next
- if (model.topP != null) return model.topP;
+ if (model.getTopP() != null) return model.getTopP();
// Global default as fallback
return configuration.getDefaultTopP();
* @return the applicable repeat penalty for this query
*/
public Float getEffectiveRepeatPenalty() {
- // Skill-specific has highest priority
+ // Skill-specific has the highest priority
if (skill != null && skill.getRepeatPenalty() != null) return skill.getRepeatPenalty();
// Model-specific next
- if (model.repeatPenalty != null) return model.repeatPenalty;
+ if (model.getRepeatPenalty() != null) return model.getRepeatPenalty();
// Global default as fallback
return configuration.getDefaultRepeatPenalty();
public Float getEffectiveTopK() {
if (skill != null && skill.getTopK() != null) return skill.getTopK();
- else if (model.topK != null) return model.topK;
+ else if (model.getTopK() != null) return model.getTopK();
else return configuration.getDefaultTopK();
}
public Float getEffectiveMinP() {
if (skill != null && skill.getMinP() != null) return skill.getMinP();
- else if (model.minP != null) return model.minP;
+ else if (model.getMinP() != null) return model.getMinP();
else return configuration.getDefaultMinP();
}
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;
* </ol>
*
* <p>Temperature settings, context size, and thread counts are all derived from the current configuration.
- * The response is formatted to match org-mode conventions while preserving original conversation structure.
+ * The response is formatted to match org-mode conventions while preserving the original conversation structure.
*/
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.
/**
* Creates a new AI task with a given mail query.
*
- * @param task the mail query containing model and prompts.
+ * @param task the mail query containing model and prompts.
+ * @param modelLibrary model library containing all available models.
*/
- public TaskProcess(Task task) {
+ public TaskProcess(Task task, ModelLibrary modelLibrary) {
this.task = task;
+ this.modelLibrary = modelLibrary;
}
/**
private String cleanupAiResponse(String result) {
// remove text after the end of text marker if it exists
- if (task.model.endOfTextMarker != null) {
- int endOfTextMarkerIndex = result.indexOf(task.model.endOfTextMarker);
+ if (task.model.getEndOfTextMarker() != null) {
+ int endOfTextMarkerIndex = result.indexOf(task.model.getEndOfTextMarker());
if (endOfTextMarkerIndex != -1) {
result = result.substring(0, endOfTextMarkerIndex);
}
ArrayList <String> args = new ArrayList<>();
args.add("nice -n " + niceValue);
args.add(executablePath);
- args.add("--model " + task.model.filesystemPath);
+ args.add("--model " + modelLibrary.getModelFullFilesystemPath(task.model));
args.add("--threads " + configuration.getThreadCount());
args.add("--threads-batch " + configuration.getBatchThreadCount());
Float temperature = task.getEffectiveTemperature();
if (temperature != null) args.add("--temp " + task.getEffectiveTemperature());
- args.add("--ctx-size " + task.model.contextSizeTokens);
+ args.add("--ctx-size " + task.model.getContextSizeTokens());
args.add("--batch-size 512");
args.add("--single-turn");
args.add("-n -1");
// "--cache-type-k q8_0",
// might save RAM, need to test if precision loss is acceptable
- // might save RAM, need to test if precision loss is acceptable
+ // might save RAM, need to test it if precision loss is acceptable
// "--cache-type-v q8_0",
}
import eu.svjatoslav.alyverkko_cli.*;
import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper;
+import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationModel;
import eu.svjatoslav.alyverkko_cli.configuration.SkillConfig;
-import eu.svjatoslav.alyverkko_cli.model.Model;
-import eu.svjatoslav.alyverkko_cli.model.ModelLibrary;
+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;
*/
File taskDirectory;
- public TaskProcessorCommand() {
- Comparator<TaskQueueEntry> comparator = (a, b) -> {
- int priorityCompare = Integer.compare(b.priority, a.priority);
- if (priorityCompare != 0) {
- return priorityCompare;
- }
- return a.tiebreaker.compareTo(b.tiebreaker);
- };
- }
/**
* @return the name of this command, i.e., "process".
// Append the original user prompt (after the first line)
resultFileContent.append(task.userPrompt).append("\n");
- // Check for final answer indicator in the model's configuration
- String finalAnswerIndicator = task.model.finalAnswerIndicator;
+ // Check for the final answer indicator in the model's configuration
+ String finalAnswerIndicator = task.model.getFinalAnswerIndicator();
if (finalAnswerIndicator != null && !finalAnswerIndicator.isEmpty()) {
int index = aiResponse.indexOf(finalAnswerIndicator);
if (index != -1) {
try {
Task task = buildTaskFromFile(file);
- TaskProcess aiTask = new TaskProcess(task);
+ TaskProcess aiTask = new TaskProcess(task, modelLibrary);
String aiGeneratedResponse = aiTask.runAiQuery();
saveAiResponseToFile(file, task, aiGeneratedResponse);
*/
private static String getDoneLine(Task task) {
return "DONE: skill=" + task.skillName +
- " model=" + task.model.alias +
+ " model=" + task.model.getAlias() +
" duration=" + getDuration(task.startTimeMillis, task.endTimeMillis) + "\n";
}
// 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<ConfigurationModel> modelOptional = modelLibrary.findModelByAlias(modelAlias);
if (!modelOptional.isPresent()) {
throw new IllegalArgumentException("Model with alias '" + modelAlias + "' not found.");
}
package eu.svjatoslav.alyverkko_cli.configuration;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@JsonProperty("final_answer_indicator")
private String finalAnswerIndicator;
+ /**
+ * <p>Prints the model's metadata to standard output in a consistent format. This includes the model's alias,
+ * filesystem path, and context token capacity. The output format is designed to be both human-readable and
+ * machine-parsable when needed.
+ * <p>Typical output:
+ * <pre>
+ * Model: default
+ * Path: /path/to/model.gguf
+ * Context size: 32768
+ * </pre>
+ */
+ public void printModelDetails() {
+ System.out.println("Model: " + alias);
+ System.out.println(" Path: " + filesystemPath);
+ System.out.println(" Context size: " + contextSizeTokens);
+ }
+
}
--- /dev/null
+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<ConfigurationModel> models;
+
+ /**
+ * The default model for this library (e.g., the first successfully
+ * loaded model in the list).
+ */
+ private static ConfigurationModel defaultModel;
+
+ /**
+ * Base directory containing the model files.
+ */
+ private final File modelsBaseDirectory;
+
+ /**
+ * Constructs a library of AI models from the provided list of
+ * {@link ConfigurationModel}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<ConfigurationModel> configModels) {
+ this.modelsBaseDirectory = modelsBaseDirectory;
+ this.models = new ArrayList<>();
+
+ for (ConfigurationModel 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(ConfigurationModel 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<ConfigurationModel> 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<ConfigurationModel> findModelByAlias(String alias) {
+ return models.stream()
+ .filter(model -> model.getAlias().equals(alias))
+ .findFirst();
+ }
+
+ /**
+ * @return the default model (first loaded model).
+ */
+ public ConfigurationModel 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 (ConfigurationModel model : models) {
+ model.printModelDetails();
+ System.out.println();
+ }
+ }
+
+ public String getModelFullFilesystemPath(ConfigurationModel model) {
+ return new File(modelsBaseDirectory, model.getFilesystemPath()).getAbsolutePath();
+ }
+
+}
\ No newline at end of file
+++ /dev/null
-package eu.svjatoslav.alyverkko_cli.model;
-
-import java.io.File;
-
-
-/**
- * <p>Represents an AI model stored on the filesystem with metadata about its capabilities and identification.
- * This class serves as a lightweight container for model information, enabling quick lookup and validation.
- * <p>Models are typically discovered through configuration files and stored in the ModelLibrary for easy access.
- * <p>Key fields include:
- * <ul>
- * <li>filesystemPath - Location of the model file</li>
- * <li>contextSizeTokens - Maximum token capacity for this model</li>
- * <li>alias - User-friendly identifier for the model</li>
- * <li>endOfTextMarker - Optional response completion marker</li>
- * </ul>
- */
-public class Model {
-
- /**
- * The path to the model file on the filesystem.
- */
- public final File filesystemPath;
-
- /**
- * The size of the context (in tokens) that this model is able to handle.
- */
- public final int contextSizeTokens;
-
- /**
- * A user-friendly alias for the model, e.g. "default" or "mistral".
- */
- public final String alias;
-
- /**
- * An optional marker indicating end of the AI-generated text (e.g., "###").
- * If non-null, it can be used to detect where the model has finished answering.
- */
- public final String endOfTextMarker;
-
- /**
- * Model-specific temperature value (null if not configured).
- */
- public Float temperature;
-
- /**
- * Model-specific top-p value (null if not configured).
- */
- public Float topP;
-
- /**
- * Model-specific Top-K parameter controlling token selection (null if not configured).
- */
- public Float topK;
-
- /**
- * Minimum probability threshold for candidate tokens (null if not configured).
- */
- public Float minP;
-
- /**
- * Model-specific repeat penalty value (null if not configured).
- */
- public Float repeatPenalty;
-
- /**
- * Optional string indicating where the final answer starts in the model's response.
- * If present in the response, the output is split into ASSISTANT (before indicator) and FINAL ANSWER (after indicator) sections.
- */
- public String finalAnswerIndicator;
-
- /**
- * Constructs a {@link Model} instance with all hyperparameters.
- *
- * @param filesystemPath The path to the model file on the filesystem.
- * @param contextSizeTokens Maximum token capacity of this model.
- * @param modelAlias User-friendly identifier for the model.
- * @param endOfTextMarker Optional response completion marker.
- * @param temperature Sampling temperature (higher = more creative)
- * @param topP Nucleus sampling threshold (0.0-1.0)
- * @param repeatPenalty Penalty for token repetition (>0.0)
- * @param topK Token selection cutoff for Top-K sampling (>=1)
- * @param minP Minimum relative probability threshold (0.0-1.0)
- * @param finalAnswerIndicator Optional string indicating where the final answer starts in the response.
- */
- public Model(File filesystemPath, int contextSizeTokens,
- String modelAlias, String endOfTextMarker,
- Float temperature, Float topP, Float repeatPenalty,
- Float topK, Float minP, String finalAnswerIndicator) {
- this.filesystemPath = filesystemPath;
- this.contextSizeTokens = contextSizeTokens;
- this.alias = modelAlias;
- this.endOfTextMarker = endOfTextMarker;
- this.temperature = temperature;
- this.topP = topP;
- this.repeatPenalty = repeatPenalty;
- this.topK = topK;
- this.minP = minP;
- this.finalAnswerIndicator = finalAnswerIndicator;
- }
-
- /**
- * <p>Prints the model's metadata to standard output in a consistent format. This includes the model's alias,
- * filesystem path, and context token capacity. The output format is designed to be both human-readable and
- * machine-parsable when needed.
- * <p>Typical output:
- * <pre>
- * Model: default
- * Path: /path/to/model.gguf
- * Context size: 32768
- * </pre>
- */
- public void printModelDetails() {
- System.out.println("Model: " + alias);
- System.out.println(" Path: " + filesystemPath);
- System.out.println(" Context size: " + contextSizeTokens);
- }
-}
+++ /dev/null
-package eu.svjatoslav.alyverkko_cli.model;
-
-import eu.svjatoslav.alyverkko_cli.Utils;
-import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationModel;
-
-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 ConfigurationModel}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<ConfigurationModel> configModels) {
- this.modelsBaseDirectory = modelsBaseDirectory;
- this.models = new ArrayList<>();
-
- for (ConfigurationModel configModel : configModels) {
- addModelFromConfig(configModel);
- }
-
- if (models.isEmpty()) {
- throw new RuntimeException("No models are defined!");
- }
-
- defaultModel = models.get(0);
- }
-
- /**
- * Attempts to construct a {@link Model} from configuration, verifying file existence.
- */
- private void addModelFromConfig(ConfigurationModel configModel) {
- File modelFile = new File(modelsBaseDirectory, configModel.getFilesystemPath());
- if (!modelFile.exists()) {
- Utils.printRedMessageToConsole("WARN: Model file not found: " + modelFile.getAbsolutePath() + " . Skipping model.");
- return;
- }
-
- addModel(new Model(
- modelFile,
- configModel.getContextSizeTokens(),
- configModel.getAlias(),
- configModel.getEndOfTextMarker(),
-
- configModel.getTemperature(),
- configModel.getTopP(),
- configModel.getRepeatPenalty(),
-
- configModel.getTopK(),
- configModel.getMinP(),
- configModel.getFinalAnswerIndicator()
- ));
-
- }
-
- /**
- * 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.alias).isPresent()) {
- throw new RuntimeException("Model with alias \"" + model.alias + "\" 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.alias.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();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/**
- * <p>This package defines the model management system for the Älyverkko CLI.
- * It includes classes for representing AI models and maintaining a library of available models.
- * <p>Key features:
- * <ul>
- * <li>Model metadata storage and validation</li>
- * <li>Default model selection and management</li>
- * <li>File system integration for model discovery</li>
- * </ul>
- */
-
-package eu.svjatoslav.alyverkko_cli.model;
\ No newline at end of file