From 18f705cd59b2db126990658dedc9cb96c184e281 Mon Sep 17 00:00:00 2001 From: Can Date: Mon, 16 Feb 2026 15:02:34 +0100 Subject: [PATCH 1/2] Fix bug that uses prompt filename as prompt itself and startQuery overload helper --- .../meitrex/common/ollama/OllamaClient.java | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClient.java b/src/main/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClient.java index 81e2dfd..c53f7ef 100644 --- a/src/main/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClient.java +++ b/src/main/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClient.java @@ -6,7 +6,6 @@ import de.unistuttgart.iste.meitrex.common.service.JsonSchemaGeneratorService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.Nullable; @@ -17,7 +16,6 @@ import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; @@ -60,8 +58,7 @@ public String getTemplate(final String templateFileName) { } } catch (IOException e) { log.error("Failed to read template file: {}", templateFileName, e); - final StringBuilder error = new StringBuilder("Failed to read template file: ").append(templateFileName); - throw new RuntimeException(error.toString(), e); + throw new RuntimeException("Failed to read template file: " + templateFileName, e); } } @@ -107,25 +104,28 @@ public String fillTemplate(final String promptTemplate, final Map the target type for the structured JSON response + * @param responseType the class of the target type to parse the response into + * @param templateFileName the name of the file in the prompt folder (e.g., "analysis_prompt.md") + * @param argMap a map of placeholder keys (without braces) and their replacement values + * @param error the fallback value to return if the query, parsing, or template loading fails + * @param modelOverride optional model name (e.g., "llama3.3:70b") to bypass the default config. + * If null/blank, the default from {@link OllamaConfig} is used. + * @return the parsed response object of type ResponseType, or the provided error fallback */ public ResponseType startQuery( final Class responseType, - final String prompt, + final String templateFileName, final Map argMap, final ResponseType error, @Nullable final String modelOverride) { try { - final String filledPrompt = fillTemplate(prompt, argMap); + final String promptTemplate = getTemplate(templateFileName); + + final String filledPrompt = fillTemplate(promptTemplate, argMap); final TypeReference> typeRef = new TypeReference<>() {}; final String jsonSchema = jsonSchemaService.getJsonSchema(responseType); @@ -159,6 +159,24 @@ public ResponseType startQuery( } } + /** + * Overloaded helper method for backward compatibility. + * Starts a query using the default model defined in the configuration. + * + * @param responseType the target class to parse the response into + * @param templateFileName the name of the file in the prompt folder (e.g., "analysis_prompt.md") + * @param argMap A map of placeholder keys and their replacement values. + * @param error the fallback value if parsing or the request fails + * @return the parsed response or the fallback error value + */ + public ResponseType startQuery( + final Class responseType, + final String templateFileName, + final Map argMap, + final ResponseType error) { + return startQuery(responseType, templateFileName, argMap, error, null); + } + /** * Sends the given request to the Ollama LLM endpoint and returns the raw response. * From fcd4232b03c300fcc82f9aee0d9c9cb46e6059f3 Mon Sep 17 00:00:00 2001 From: Can Date: Mon, 16 Feb 2026 15:08:11 +0100 Subject: [PATCH 2/2] Fix tests --- .../common/ollama/OllamaClientTest.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/test/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClientTest.java b/src/test/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClientTest.java index 6b2bbed..434833e 100644 --- a/src/test/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClientTest.java +++ b/src/test/java/de/unistuttgart/iste/meitrex/common/ollama/OllamaClientTest.java @@ -40,11 +40,10 @@ class OllamaClientTest { @BeforeEach void setUp() { - ollamaClient = new OllamaClient(config, jsonSchemaService, jsonMapper, httpClient); + OllamaClient realClient = new OllamaClient(config, jsonSchemaService, jsonMapper, httpClient); + ollamaClient = spy(realClient); } - // --- Tests for fillTemplate --- - @Test void testFillTemplateSuccess() { String template = "Hello {{name}}, welcome to {{place}}!"; @@ -71,11 +70,14 @@ void testFillTemplateThrowsOnUnknownArgument() { @Test void testStartQuerySuccess() throws IOException, InterruptedException { - String prompt = "Calculate 1+1"; + String templateFileName = "test_prompt.md"; + String templateContent = "Calculate 1+1"; Map args = Map.of(); String mockSchema = "{\"type\":\"object\"}"; String ollamaJsonResponse = "{\"response\": \"{\\\"result\\\": 2}\", \"done\": true}"; + doReturn(templateContent).when(ollamaClient).getTemplate(templateFileName); + when(config.getModel()).thenReturn("llama3"); when(config.getUrl()).thenReturn("http://localhost:11434"); when(config.getEndpoint()).thenReturn("api/generate"); @@ -92,7 +94,7 @@ void testStartQuerySuccess() throws IOException, InterruptedException { TestResponseDto result = ollamaClient.startQuery( TestResponseDto.class, - prompt, + templateFileName, args, new TestResponseDto(0) ); @@ -109,6 +111,9 @@ void testStartQuerySuccess() throws IOException, InterruptedException { @Test void testStartQueryHandlesNetworkError() throws IOException, InterruptedException { + String templateFileName = "error_test.md"; + doReturn("some prompt").when(ollamaClient).getTemplate(templateFileName); + when(config.getModel()).thenReturn("llama3"); when(config.getUrl()).thenReturn("http://localhost:11434"); when(config.getEndpoint()).thenReturn("api/generate"); @@ -123,7 +128,7 @@ void testStartQueryHandlesNetworkError() throws IOException, InterruptedExceptio TestResponseDto fallback = new TestResponseDto(-1); TestResponseDto result = ollamaClient.startQuery( - TestResponseDto.class, "prompt", Map.of(), fallback + TestResponseDto.class, templateFileName, Map.of(), fallback ); assertThat(result, sameInstance(fallback)); @@ -131,6 +136,9 @@ void testStartQueryHandlesNetworkError() throws IOException, InterruptedExceptio @Test void testStartQueryHandlesOllamaError() throws IOException, InterruptedException { + String templateFileName = "ollama_error.md"; + doReturn("some prompt").when(ollamaClient).getTemplate(templateFileName); + when(config.getModel()).thenReturn("llama3"); when(config.getUrl()).thenReturn("http://localhost:11434"); when(config.getEndpoint()).thenReturn("api/generate"); @@ -149,7 +157,7 @@ void testStartQueryHandlesOllamaError() throws IOException, InterruptedException TestResponseDto fallback = new TestResponseDto(-1); TestResponseDto result = ollamaClient.startQuery( - TestResponseDto.class, "prompt", Map.of(), fallback + TestResponseDto.class, templateFileName, Map.of(), fallback ); assertThat(result, sameInstance(fallback));