diff --git a/.gitignore b/.gitignore index 788123e..0c97cfe 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ pom.xml.* release.properties !.idea/icon.svg -src/main/java/io/github/ollama4j/localtests \ No newline at end of file +src/main/java/io/github/ollama4j/localtests diff --git a/LICENSE b/LICENSE index 85c8a43..883ee94 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Amith Koujalgi +Copyright (c) 2023 Amith Koujalgi and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/pom.xml b/pom.xml index 82d69a0..345dcff 100644 --- a/pom.xml +++ b/pom.xml @@ -163,6 +163,71 @@ Etc/UTC + + + com.diffplug.spotless + spotless-maven-plugin + 2.46.1 + + + + + + + + + .gitattributes + .gitignore + + + + + + true + 4 + + + + + + + + + + 1.28.0 + + true + false + + + + + + + + + + + + + + check + + compile + + + diff --git a/src/main/java/io/github/ollama4j/OllamaAPI.java b/src/main/java/io/github/ollama4j/OllamaAPI.java index 7626eb4..5e6a768 100644 --- a/src/main/java/io/github/ollama4j/OllamaAPI.java +++ b/src/main/java/io/github/ollama4j/OllamaAPI.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j; import com.fasterxml.jackson.core.JsonParseException; @@ -22,10 +30,6 @@ import io.github.ollama4j.tools.annotations.ToolSpec; import io.github.ollama4j.utils.Constants; import io.github.ollama4j.utils.Options; import io.github.ollama4j.utils.Utils; -import lombok.Setter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -41,6 +45,9 @@ import java.nio.file.Files; import java.time.Duration; import java.util.*; import java.util.stream.Collectors; +import lombok.Setter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The base Ollama API class. @@ -61,14 +68,12 @@ public class OllamaAPI { * for a response * from the Ollama server before timing out. */ - @Setter - private long requestTimeoutSeconds = 10; + @Setter private long requestTimeoutSeconds = 10; - @Setter - private int imageURLReadTimeoutSeconds = 10; + @Setter private int imageURLReadTimeoutSeconds = 10; + + @Setter private int imageURLConnectTimeoutSeconds = 10; - @Setter - private int imageURLConnectTimeoutSeconds = 10; /** * The maximum number of retries for tool calls during chat interactions. *

@@ -76,8 +81,7 @@ public class OllamaAPI { * event of a failure. * Default is 3. */ - @Setter - private int maxChatToolCallRetries = 3; + @Setter private int maxChatToolCallRetries = 3; /** * The number of retries to attempt when pulling a model from the Ollama server. @@ -98,8 +102,7 @@ public class OllamaAPI { *

* Default is false for backward compatibility. */ - @Setter - private boolean clientHandlesTools = false; + @Setter private boolean clientHandlesTools = false; /** * Instantiates the Ollama API with default Ollama host: @@ -154,11 +157,16 @@ public class OllamaAPI { HttpClient httpClient = HttpClient.newHttpClient(); HttpRequest httpRequest; try { - httpRequest = getRequestBuilderDefault(new URI(url)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .GET() - .build(); + httpRequest = + getRequestBuilderDefault(new URI(url)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .GET() + .build(); } catch (URISyntaxException e) { throw new RuntimeException(e); } @@ -183,15 +191,22 @@ public class OllamaAPI { * @throws InterruptedException if the operation is interrupted * @throws OllamaBaseException if the response indicates an error status */ - public ModelsProcessResponse ps() throws IOException, InterruptedException, OllamaBaseException { + public ModelsProcessResponse ps() + throws IOException, InterruptedException, OllamaBaseException { String url = this.host + "/api/ps"; HttpClient httpClient = HttpClient.newHttpClient(); HttpRequest httpRequest = null; try { - httpRequest = getRequestBuilderDefault(new URI(url)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .GET().build(); + httpRequest = + getRequestBuilderDefault(new URI(url)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .GET() + .build(); } catch (URISyntaxException e) { throw new RuntimeException(e); } @@ -215,18 +230,28 @@ public class OllamaAPI { * @throws InterruptedException if the operation is interrupted * @throws URISyntaxException if the URI for the request is malformed */ - public List listModels() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { + public List listModels() + throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { String url = this.host + "/api/tags"; HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest httpRequest = getRequestBuilderDefault(new URI(url)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET() - .build(); - HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + HttpRequest httpRequest = + getRequestBuilderDefault(new URI(url)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .GET() + .build(); + HttpResponse response = + httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); String responseString = response.body(); if (statusCode == 200) { - return Utils.getObjectMapper().readValue(responseString, ListModelsResponse.class).getModels(); + return Utils.getObjectMapper() + .readValue(responseString, ListModelsResponse.class) + .getModels(); } else { throw new OllamaBaseException(statusCode + " - " + responseString); } @@ -266,24 +291,34 @@ public class OllamaAPI { this.doPullModel(modelName); return; } catch (OllamaBaseException e) { - handlePullRetry(modelName, numberOfRetries, numberOfRetriesForModelPull, baseDelayMillis); + handlePullRetry( + modelName, numberOfRetries, numberOfRetriesForModelPull, baseDelayMillis); numberOfRetries++; } } throw new OllamaBaseException( - "Failed to pull model " + modelName + " after " + numberOfRetriesForModelPull + " retries"); + "Failed to pull model " + + modelName + + " after " + + numberOfRetriesForModelPull + + " retries"); } /** * Handles retry backoff for pullModel. */ - private void handlePullRetry(String modelName, int currentRetry, int maxRetries, long baseDelayMillis) + private void handlePullRetry( + String modelName, int currentRetry, int maxRetries, long baseDelayMillis) throws InterruptedException { int attempt = currentRetry + 1; if (attempt < maxRetries) { long backoffMillis = baseDelayMillis * (1L << currentRetry); - LOG.error("Failed to pull model {}, retrying in {}s... (attempt {}/{})", - modelName, backoffMillis / 1000, attempt, maxRetries); + LOG.error( + "Failed to pull model {}, retrying in {}s... (attempt {}/{})", + modelName, + backoffMillis / 1000, + attempt, + maxRetries); try { Thread.sleep(backoffMillis); } catch (InterruptedException ie) { @@ -291,7 +326,10 @@ public class OllamaAPI { throw ie; } } else { - LOG.error("Failed to pull model {} after {} attempts, no more retries.", modelName, maxRetries); + LOG.error( + "Failed to pull model {} after {} attempts, no more retries.", + modelName, + maxRetries); } } @@ -299,25 +337,36 @@ public class OllamaAPI { throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { String url = this.host + "/api/pull"; String jsonData = new ModelRequest(modelName).toString(); - HttpRequest request = getRequestBuilderDefault(new URI(url)).POST(HttpRequest.BodyPublishers.ofString(jsonData)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .build(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .POST(HttpRequest.BodyPublishers.ofString(jsonData)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .build(); HttpClient client = HttpClient.newHttpClient(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()); + HttpResponse response = + client.send(request, HttpResponse.BodyHandlers.ofInputStream()); int statusCode = response.statusCode(); InputStream responseBodyStream = response.body(); String responseString = ""; boolean success = false; // Flag to check the pull success. - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { + try (BufferedReader reader = + new BufferedReader( + new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { - ModelPullResponse modelPullResponse = Utils.getObjectMapper().readValue(line, ModelPullResponse.class); + ModelPullResponse modelPullResponse = + Utils.getObjectMapper().readValue(line, ModelPullResponse.class); if (modelPullResponse != null) { // Check for error in response body first - if (modelPullResponse.getError() != null && !modelPullResponse.getError().trim().isEmpty()) { - throw new OllamaBaseException("Model pull failed: " + modelPullResponse.getError()); + if (modelPullResponse.getError() != null + && !modelPullResponse.getError().trim().isEmpty()) { + throw new OllamaBaseException( + "Model pull failed: " + modelPullResponse.getError()); } if (modelPullResponse.getStatus() != null) { @@ -341,18 +390,28 @@ public class OllamaAPI { } } - public String getVersion() throws URISyntaxException, IOException, InterruptedException, OllamaBaseException { + public String getVersion() + throws URISyntaxException, IOException, InterruptedException, OllamaBaseException { String url = this.host + "/api/version"; HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest httpRequest = getRequestBuilderDefault(new URI(url)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET() - .build(); - HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + HttpRequest httpRequest = + getRequestBuilderDefault(new URI(url)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .GET() + .build(); + HttpResponse response = + httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); String responseString = response.body(); if (statusCode == 200) { - return Utils.getObjectMapper().readValue(responseString, OllamaVersion.class).getVersion(); + return Utils.getObjectMapper() + .readValue(responseString, OllamaVersion.class) + .getVersion(); } else { throw new OllamaBaseException(statusCode + " - " + responseString); } @@ -374,7 +433,8 @@ public class OllamaAPI { */ public void pullModel(LibraryModelTag libraryModelTag) throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { - String tagToPull = String.format("%s:%s", libraryModelTag.getName(), libraryModelTag.getTag()); + String tagToPull = + String.format("%s:%s", libraryModelTag.getName(), libraryModelTag.getTag()); pullModel(tagToPull); } @@ -392,10 +452,16 @@ public class OllamaAPI { throws IOException, OllamaBaseException, InterruptedException, URISyntaxException { String url = this.host + "/api/show"; String jsonData = new ModelRequest(modelName).toString(); - HttpRequest request = getRequestBuilderDefault(new URI(url)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .POST(HttpRequest.BodyPublishers.ofString(jsonData)).build(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(jsonData)) + .build(); HttpClient client = HttpClient.newHttpClient(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); @@ -422,10 +488,16 @@ public class OllamaAPI { throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { String url = this.host + "/api/create"; String jsonData = customModelRequest.toString(); - HttpRequest request = getRequestBuilderDefault(new URI(url)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) + .build(); HttpClient client = HttpClient.newHttpClient(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); @@ -454,16 +526,26 @@ public class OllamaAPI { throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { String url = this.host + "/api/delete"; String jsonData = new ModelRequest(modelName).toString(); - HttpRequest request = getRequestBuilderDefault(new URI(url)) - .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .build(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .method( + "DELETE", + HttpRequest.BodyPublishers.ofString( + jsonData, StandardCharsets.UTF_8)) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .build(); HttpClient client = HttpClient.newHttpClient(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); String responseBody = response.body(); - if (statusCode == 404 && responseBody.contains("model") && responseBody.contains("not found")) { + if (statusCode == 404 + && responseBody.contains("model") + && responseBody.contains("not found")) { return; } if (statusCode != 200) { @@ -486,11 +568,16 @@ public class OllamaAPI { String jsonData = Utils.getObjectMapper().writeValueAsString(modelRequest); HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest request = HttpRequest.newBuilder(uri) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .POST(HttpRequest.BodyPublishers.ofString(jsonData)).build(); + HttpRequest request = + HttpRequest.newBuilder(uri) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(jsonData)) + .build(); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); String responseBody = response.body(); @@ -527,8 +614,13 @@ public class OllamaAPI { * @throws IOException if an I/O error occurs during the HTTP request * @throws InterruptedException if the operation is interrupted */ - public OllamaResult generate(String model, String prompt, boolean raw, Options options, - OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException { + public OllamaResult generate( + String model, + String prompt, + boolean raw, + Options options, + OllamaStreamHandler responseStreamHandler) + throws OllamaBaseException, IOException, InterruptedException { OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt); ollamaRequestModel.setRaw(raw); ollamaRequestModel.setThink(false); @@ -563,14 +655,20 @@ public class OllamaAPI { * @throws IOException if an I/O error occurs during the HTTP request * @throws InterruptedException if the operation is interrupted */ - public OllamaResult generate(String model, String prompt, boolean raw, Options options, - OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) + public OllamaResult generate( + String model, + String prompt, + boolean raw, + Options options, + OllamaStreamHandler thinkingStreamHandler, + OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException { OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt); ollamaRequestModel.setRaw(raw); ollamaRequestModel.setThink(true); ollamaRequestModel.setOptions(options.getOptionsMap()); - return generateSyncForOllamaRequestModel(ollamaRequestModel, thinkingStreamHandler, responseStreamHandler); + return generateSyncForOllamaRequestModel( + ollamaRequestModel, thinkingStreamHandler, responseStreamHandler); } /** @@ -596,7 +694,8 @@ public class OllamaAPI { * @throws IOException if an I/O error occurs during the HTTP request * @throws InterruptedException if the operation is interrupted */ - public OllamaResult generate(String model, String prompt, boolean raw, boolean think, Options options) + public OllamaResult generate( + String model, String prompt, boolean raw, boolean think, Options options) throws OllamaBaseException, IOException, InterruptedException { if (think) { return generate(model, prompt, raw, options, null, null); @@ -635,27 +734,41 @@ public class OllamaAPI { String jsonData = Utils.getObjectMapper().writeValueAsString(requestBody); HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest request = getRequestBuilderDefault(uri) - .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .POST(HttpRequest.BodyPublishers.ofString(jsonData)).build(); + HttpRequest request = + getRequestBuilderDefault(uri) + .header( + Constants.HttpConstants.HEADER_KEY_ACCEPT, + Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .POST(HttpRequest.BodyPublishers.ofString(jsonData)) + .build(); try { - String prettyJson = Utils.getObjectMapper().writerWithDefaultPrettyPrinter() - .writeValueAsString(Utils.getObjectMapper().readValue(jsonData, Object.class)); + String prettyJson = + Utils.getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString( + Utils.getObjectMapper().readValue(jsonData, Object.class)); LOG.debug("Asking model:\n{}", prettyJson); } catch (Exception e) { LOG.debug("Asking model: {}", jsonData); } - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); int statusCode = response.statusCode(); String responseBody = response.body(); if (statusCode == 200) { - OllamaStructuredResult structuredResult = Utils.getObjectMapper().readValue(responseBody, - OllamaStructuredResult.class); - OllamaResult ollamaResult = new OllamaResult(structuredResult.getResponse(), structuredResult.getThinking(), - structuredResult.getResponseTime(), statusCode); + OllamaStructuredResult structuredResult = + Utils.getObjectMapper().readValue(responseBody, OllamaStructuredResult.class); + OllamaResult ollamaResult = + new OllamaResult( + structuredResult.getResponse(), + structuredResult.getThinking(), + structuredResult.getResponseTime(), + statusCode); ollamaResult.setModel(structuredResult.getModel()); ollamaResult.setCreatedAt(structuredResult.getCreatedAt()); @@ -671,8 +784,11 @@ public class OllamaAPI { LOG.debug("Model response:\n{}", ollamaResult); return ollamaResult; } else { - LOG.debug("Model response:\n{}", - Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseBody)); + LOG.debug( + "Model response:\n{}", + Utils.getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(responseBody)); throw new OllamaBaseException(statusCode + " - " + responseBody); } } @@ -688,7 +804,6 @@ public class OllamaAPI { * using the registered tool implementations, and their results are collected. *

* - *

* Typical usage: *

{@code
      * OllamaToolsResult result = ollamaAPI.generateWithTools(
@@ -700,7 +815,6 @@ public class OllamaAPI {
      * String modelResponse = result.getModelResult().getResponse();
      * Map toolResults = result.getToolResults();
      * }
- *

* * @param model the name or identifier of the AI model to use for generating the response * @param prompt the input text or prompt to provide to the AI model @@ -713,7 +827,8 @@ public class OllamaAPI { * @throws InterruptedException if the operation is interrupted * @throws ToolInvocationException if a tool call fails to execute */ - public OllamaToolsResult generateWithTools(String model, String prompt, Options options, OllamaStreamHandler streamHandler) + public OllamaToolsResult generateWithTools( + String model, String prompt, Options options, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException { boolean raw = true; OllamaToolsResult toolResult = new OllamaToolsResult(); @@ -744,11 +859,18 @@ public class OllamaAPI { // Try to parse the string to see if it's a valid JSON objectMapper.readTree(toolsResponse); } catch (JsonParseException e) { - LOG.warn("Response from model does not contain any tool calls. Returning the response as is."); + LOG.warn( + "Response from model does not contain any tool calls. Returning the" + + " response as is."); return toolResult; } - toolFunctionCallSpecs = objectMapper.readValue(toolsResponse, - objectMapper.getTypeFactory().constructCollectionType(List.class, ToolFunctionCallSpec.class)); + toolFunctionCallSpecs = + objectMapper.readValue( + toolsResponse, + objectMapper + .getTypeFactory() + .constructCollectionType( + List.class, ToolFunctionCallSpec.class)); } for (ToolFunctionCallSpec toolFunctionCallSpec : toolFunctionCallSpecs) { toolResults.put(toolFunctionCallSpec, invokeTool(toolFunctionCallSpec)); @@ -795,13 +917,15 @@ public class OllamaAPI { * @return an {@link OllamaAsyncResultStreamer} handle for polling and * retrieving streamed results */ - public OllamaAsyncResultStreamer generate(String model, String prompt, boolean raw, boolean think) { + public OllamaAsyncResultStreamer generate( + String model, String prompt, boolean raw, boolean think) { OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt); ollamaRequestModel.setRaw(raw); ollamaRequestModel.setThink(think); URI uri = URI.create(this.host + "/api/generate"); - OllamaAsyncResultStreamer ollamaAsyncResultStreamer = new OllamaAsyncResultStreamer( - getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds); + OllamaAsyncResultStreamer ollamaAsyncResultStreamer = + new OllamaAsyncResultStreamer( + getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds); ollamaAsyncResultStreamer.start(); return ollamaAsyncResultStreamer; } @@ -833,8 +957,14 @@ public class OllamaAPI { * @throws InterruptedException if the operation is interrupted * @throws URISyntaxException if an image URL is malformed */ - public OllamaResult generateWithImages(String model, String prompt, List images, Options options, Map format, - OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { + public OllamaResult generateWithImages( + String model, + String prompt, + List images, + Options options, + Map format, + OllamaStreamHandler streamHandler) + throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { List encodedImages = new ArrayList<>(); for (Object image : images) { if (image instanceof File) { @@ -845,12 +975,19 @@ public class OllamaAPI { encodedImages.add(encodeByteArrayToBase64((byte[]) image)); } else if (image instanceof String) { LOG.debug("Using image URL: {}", image); - encodedImages.add(encodeByteArrayToBase64(Utils.loadImageBytesFromUrl((String) image, imageURLConnectTimeoutSeconds, imageURLReadTimeoutSeconds))); + encodedImages.add( + encodeByteArrayToBase64( + Utils.loadImageBytesFromUrl( + (String) image, + imageURLConnectTimeoutSeconds, + imageURLReadTimeoutSeconds))); } else { - throw new OllamaBaseException("Unsupported image type. Please provide a File, byte[], or a URL String."); + throw new OllamaBaseException( + "Unsupported image type. Please provide a File, byte[], or a URL String."); } } - OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt, encodedImages); + OllamaGenerateRequest ollamaRequestModel = + new OllamaGenerateRequest(model, prompt, encodedImages); if (format != null) { ollamaRequestModel.setFormat(format); } @@ -879,12 +1016,15 @@ public class OllamaAPI { */ public OllamaChatResult chat(OllamaChatRequest request, OllamaTokenHandler tokenHandler) throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException { - OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds); + OllamaChatEndpointCaller requestCaller = + new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds); OllamaChatResult result; // add all registered tools to Request - request.setTools(toolRegistry.getRegisteredSpecs().stream().map(Tools.ToolSpecification::getToolPrompt) - .collect(Collectors.toList())); + request.setTools( + toolRegistry.getRegisteredSpecs().stream() + .map(Tools.ToolSpecification::getToolPrompt) + .collect(Collectors.toList())); if (tokenHandler != null) { request.setStream(true); @@ -900,7 +1040,9 @@ public class OllamaAPI { // check if toolCallIsWanted List toolCalls = result.getResponseModel().getMessage().getToolCalls(); int toolCallTries = 0; - while (toolCalls != null && !toolCalls.isEmpty() && toolCallTries < maxChatToolCallRetries) { + while (toolCalls != null + && !toolCalls.isEmpty() + && toolCallTries < maxChatToolCallRetries) { for (OllamaChatToolCalls toolCall : toolCalls) { String toolName = toolCall.getFunction().getName(); ToolFunction toolFunction = toolRegistry.getToolFunction(toolName); @@ -909,11 +1051,21 @@ public class OllamaAPI { } Map arguments = toolCall.getFunction().getArguments(); Object res = toolFunction.apply(arguments); - String argumentKeys = arguments.keySet().stream() - .map(Object::toString) - .collect(Collectors.joining(", ")); - request.getMessages().add(new OllamaChatMessage(OllamaChatMessageRole.TOOL, - "[TOOL_RESULTS] " + toolName + "(" + argumentKeys + "): " + res + " [/TOOL_RESULTS]")); + String argumentKeys = + arguments.keySet().stream() + .map(Object::toString) + .collect(Collectors.joining(", ")); + request.getMessages() + .add( + new OllamaChatMessage( + OllamaChatMessageRole.TOOL, + "[TOOL_RESULTS] " + + toolName + + "(" + + argumentKeys + + "): " + + res + + " [/TOOL_RESULTS]")); } if (tokenHandler != null) { @@ -982,22 +1134,27 @@ public class OllamaAPI { try { Class callerClass = null; try { - callerClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()); + callerClass = + Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } - OllamaToolService ollamaToolServiceAnnotation = callerClass.getDeclaredAnnotation(OllamaToolService.class); + OllamaToolService ollamaToolServiceAnnotation = + callerClass.getDeclaredAnnotation(OllamaToolService.class); if (ollamaToolServiceAnnotation == null) { - throw new IllegalStateException(callerClass + " is not annotated as " + OllamaToolService.class); + throw new IllegalStateException( + callerClass + " is not annotated as " + OllamaToolService.class); } Class[] providers = ollamaToolServiceAnnotation.providers(); for (Class provider : providers) { registerAnnotatedTools(provider.getDeclaredConstructor().newInstance()); } - } catch (InstantiationException | NoSuchMethodException | IllegalAccessException - | InvocationTargetException e) { + } catch (InstantiationException + | NoSuchMethodException + | IllegalAccessException + | InvocationTargetException e) { throw new RuntimeException(e); } } @@ -1029,36 +1186,61 @@ public class OllamaAPI { final Tools.PropsBuilder propsBuilder = new Tools.PropsBuilder(); LinkedHashMap methodParams = new LinkedHashMap<>(); for (Parameter parameter : m.getParameters()) { - final ToolProperty toolPropertyAnn = parameter.getDeclaredAnnotation(ToolProperty.class); + final ToolProperty toolPropertyAnn = + parameter.getDeclaredAnnotation(ToolProperty.class); String propType = parameter.getType().getTypeName(); if (toolPropertyAnn == null) { methodParams.put(parameter.getName(), null); continue; } - String propName = !toolPropertyAnn.name().isBlank() ? toolPropertyAnn.name() : parameter.getName(); + String propName = + !toolPropertyAnn.name().isBlank() + ? toolPropertyAnn.name() + : parameter.getName(); methodParams.put(propName, propType); - propsBuilder.withProperty(propName, Tools.PromptFuncDefinition.Property.builder().type(propType) - .description(toolPropertyAnn.desc()).required(toolPropertyAnn.required()).build()); + propsBuilder.withProperty( + propName, + Tools.PromptFuncDefinition.Property.builder() + .type(propType) + .description(toolPropertyAnn.desc()) + .required(toolPropertyAnn.required()) + .build()); } final Map params = propsBuilder.build(); - List reqProps = params.entrySet().stream().filter(e -> e.getValue().isRequired()) - .map(Map.Entry::getKey).collect(Collectors.toList()); + List reqProps = + params.entrySet().stream() + .filter(e -> e.getValue().isRequired()) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); - Tools.ToolSpecification toolSpecification = Tools.ToolSpecification.builder().functionName(operationName) - .functionDescription(operationDesc) - .toolPrompt(Tools.PromptFuncDefinition.builder().type("function") - .function(Tools.PromptFuncDefinition.PromptFuncSpec.builder().name(operationName) - .description(operationDesc).parameters(Tools.PromptFuncDefinition.Parameters - .builder().type("object").properties(params).required(reqProps).build()) - .build()) - .build()) - .build(); + Tools.ToolSpecification toolSpecification = + Tools.ToolSpecification.builder() + .functionName(operationName) + .functionDescription(operationDesc) + .toolPrompt( + Tools.PromptFuncDefinition.builder() + .type("function") + .function( + Tools.PromptFuncDefinition.PromptFuncSpec + .builder() + .name(operationName) + .description(operationDesc) + .parameters( + Tools.PromptFuncDefinition + .Parameters.builder() + .type("object") + .properties(params) + .required(reqProps) + .build()) + .build()) + .build()) + .build(); - ReflectionalToolFunction reflectionalToolFunction = new ReflectionalToolFunction(object, m, methodParams); + ReflectionalToolFunction reflectionalToolFunction = + new ReflectionalToolFunction(object, m, methodParams); toolSpecification.setToolFunction(reflectionalToolFunction); toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification); } - } /** @@ -1135,14 +1317,19 @@ public class OllamaAPI { * process. * @throws InterruptedException if the thread is interrupted during the request. */ - private OllamaResult generateSyncForOllamaRequestModel(OllamaGenerateRequest ollamaRequestModel, - OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) + private OllamaResult generateSyncForOllamaRequestModel( + OllamaGenerateRequest ollamaRequestModel, + OllamaStreamHandler thinkingStreamHandler, + OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException { - OllamaGenerateEndpointCaller requestCaller = new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds); + OllamaGenerateEndpointCaller requestCaller = + new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds); OllamaResult result; if (responseStreamHandler != null) { ollamaRequestModel.setStream(true); - result = requestCaller.call(ollamaRequestModel, thinkingStreamHandler, responseStreamHandler); + result = + requestCaller.call( + ollamaRequestModel, thinkingStreamHandler, responseStreamHandler); } else { result = requestCaller.callSync(ollamaRequestModel); } @@ -1156,9 +1343,12 @@ public class OllamaAPI { * @return HttpRequest.Builder */ private HttpRequest.Builder getRequestBuilderDefault(URI uri) { - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) - .timeout(Duration.ofSeconds(requestTimeoutSeconds)); + HttpRequest.Builder requestBuilder = + HttpRequest.newBuilder(uri) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .timeout(Duration.ofSeconds(requestTimeoutSeconds)); if (isAuthSet()) { requestBuilder.header("Authorization", auth.getAuthHeaderValue()); } @@ -1174,7 +1364,8 @@ public class OllamaAPI { return auth != null; } - private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) throws ToolInvocationException { + private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) + throws ToolInvocationException { try { String methodName = toolFunctionCallSpec.getName(); Map arguments = toolFunctionCallSpec.getArguments(); @@ -1182,11 +1373,14 @@ public class OllamaAPI { LOG.debug("Invoking function {} with arguments {}", methodName, arguments); if (function == null) { throw new ToolNotFoundException( - "No such tool: " + methodName + ". Please register the tool before invoking it."); + "No such tool: " + + methodName + + ". Please register the tool before invoking it."); } return function.apply(arguments); } catch (Exception e) { - throw new ToolInvocationException("Failed to invoke tool: " + toolFunctionCallSpec.getName(), e); + throw new ToolInvocationException( + "Failed to invoke tool: " + toolFunctionCallSpec.getName(), e); } } } diff --git a/src/main/java/io/github/ollama4j/exceptions/OllamaBaseException.java b/src/main/java/io/github/ollama4j/exceptions/OllamaBaseException.java index 9474d72..d4d2bf5 100644 --- a/src/main/java/io/github/ollama4j/exceptions/OllamaBaseException.java +++ b/src/main/java/io/github/ollama4j/exceptions/OllamaBaseException.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.exceptions; public class OllamaBaseException extends Exception { diff --git a/src/main/java/io/github/ollama4j/exceptions/RoleNotFoundException.java b/src/main/java/io/github/ollama4j/exceptions/RoleNotFoundException.java index a7d1d18..11c6370 100644 --- a/src/main/java/io/github/ollama4j/exceptions/RoleNotFoundException.java +++ b/src/main/java/io/github/ollama4j/exceptions/RoleNotFoundException.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.exceptions; public class RoleNotFoundException extends Exception { diff --git a/src/main/java/io/github/ollama4j/exceptions/ToolInvocationException.java b/src/main/java/io/github/ollama4j/exceptions/ToolInvocationException.java index 4707e55..1bcb8f9 100644 --- a/src/main/java/io/github/ollama4j/exceptions/ToolInvocationException.java +++ b/src/main/java/io/github/ollama4j/exceptions/ToolInvocationException.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.exceptions; public class ToolInvocationException extends Exception { diff --git a/src/main/java/io/github/ollama4j/exceptions/ToolNotFoundException.java b/src/main/java/io/github/ollama4j/exceptions/ToolNotFoundException.java index bd3e007..28e4b7f 100644 --- a/src/main/java/io/github/ollama4j/exceptions/ToolNotFoundException.java +++ b/src/main/java/io/github/ollama4j/exceptions/ToolNotFoundException.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.exceptions; public class ToolNotFoundException extends Exception { diff --git a/src/main/java/io/github/ollama4j/impl/ConsoleOutputStreamHandler.java b/src/main/java/io/github/ollama4j/impl/ConsoleOutputStreamHandler.java index b5b3da8..a5a9ef4 100644 --- a/src/main/java/io/github/ollama4j/impl/ConsoleOutputStreamHandler.java +++ b/src/main/java/io/github/ollama4j/impl/ConsoleOutputStreamHandler.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.impl; import io.github.ollama4j.models.generate.OllamaStreamHandler; diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessage.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessage.java index e3d7912..2b18c73 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessage.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessage.java @@ -1,15 +1,22 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.github.ollama4j.utils.FileToBase64Serializer; -import lombok.*; - import java.util.List; - -import static io.github.ollama4j.utils.Utils.getObjectMapper; +import lombok.*; /** * Defines a single Message to be used inside a chat request against the ollama /api/chat endpoint. @@ -23,11 +30,9 @@ import static io.github.ollama4j.utils.Utils.getObjectMapper; @JsonIgnoreProperties(ignoreUnknown = true) public class OllamaChatMessage { - @NonNull - private OllamaChatMessageRole role; + @NonNull private OllamaChatMessageRole role; - @NonNull - private String content; + @NonNull private String content; private String thinking; diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessageRole.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessageRole.java index 37d9d5c..676d6c0 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessageRole.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatMessageRole.java @@ -1,11 +1,18 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; import com.fasterxml.jackson.annotation.JsonValue; import io.github.ollama4j.exceptions.RoleNotFoundException; -import lombok.Getter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; /** * Defines the possible Chat Message roles. @@ -19,8 +26,7 @@ public class OllamaChatMessageRole { public static final OllamaChatMessageRole ASSISTANT = new OllamaChatMessageRole("assistant"); public static final OllamaChatMessageRole TOOL = new OllamaChatMessageRole("tool"); - @JsonValue - private final String roleName; + @JsonValue private final String roleName; private OllamaChatMessageRole(String roleName) { this.roleName = roleName; @@ -28,8 +34,8 @@ public class OllamaChatMessageRole { } public static OllamaChatMessageRole newCustomRole(String roleName) { -// OllamaChatMessageRole customRole = new OllamaChatMessageRole(roleName); -// roles.add(customRole); + // OllamaChatMessageRole customRole = new OllamaChatMessageRole(roleName); + // roles.add(customRole); return new OllamaChatMessageRole(roleName); } diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequest.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequest.java index 7b19e02..7f1eb68 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequest.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequest.java @@ -1,13 +1,20 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; import io.github.ollama4j.models.request.OllamaCommonRequest; import io.github.ollama4j.tools.Tools; import io.github.ollama4j.utils.OllamaRequestBody; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - /** * Defines a Request to use against the ollama /api/chat endpoint. * @@ -25,8 +32,7 @@ public class OllamaChatRequest extends OllamaCommonRequest implements OllamaRequ private boolean think; - public OllamaChatRequest() { - } + public OllamaChatRequest() {} public OllamaChatRequest(String model, boolean think, List messages) { this.model = model; @@ -42,5 +48,4 @@ public class OllamaChatRequest extends OllamaCommonRequest implements OllamaRequ return this.toString().equals(o.toString()); } - } diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java index b540beb..6f3c0a2 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java @@ -1,10 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; import io.github.ollama4j.utils.Options; import io.github.ollama4j.utils.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -12,6 +17,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Helper class for creating {@link OllamaChatRequest} objects using the builder-pattern. @@ -23,7 +30,8 @@ public class OllamaChatRequestBuilder { private int imageURLConnectTimeoutSeconds = 10; private int imageURLReadTimeoutSeconds = 10; - public OllamaChatRequestBuilder withImageURLConnectTimeoutSeconds(int imageURLConnectTimeoutSeconds) { + public OllamaChatRequestBuilder withImageURLConnectTimeoutSeconds( + int imageURLConnectTimeoutSeconds) { this.imageURLConnectTimeoutSeconds = imageURLConnectTimeoutSeconds; return this; } @@ -55,40 +63,67 @@ public class OllamaChatRequestBuilder { return withMessage(role, content, Collections.emptyList()); } - public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List toolCalls) { + public OllamaChatRequestBuilder withMessage( + OllamaChatMessageRole role, String content, List toolCalls) { List messages = this.request.getMessages(); messages.add(new OllamaChatMessage(role, content, null, toolCalls, null)); return this; } - public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List toolCalls, List images) { + public OllamaChatRequestBuilder withMessage( + OllamaChatMessageRole role, + String content, + List toolCalls, + List images) { List messages = this.request.getMessages(); - List binaryImages = images.stream().map(file -> { - try { - return Files.readAllBytes(file.toPath()); - } catch (IOException e) { - LOG.warn("File '{}' could not be accessed, will not add to message!", file.toPath(), e); - return new byte[0]; - } - }).collect(Collectors.toList()); + List binaryImages = + images.stream() + .map( + file -> { + try { + return Files.readAllBytes(file.toPath()); + } catch (IOException e) { + LOG.warn( + "File '{}' could not be accessed, will not add to" + + " message!", + file.toPath(), + e); + return new byte[0]; + } + }) + .collect(Collectors.toList()); messages.add(new OllamaChatMessage(role, content, null, toolCalls, binaryImages)); return this; } - public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List toolCalls, String... imageUrls) { + public OllamaChatRequestBuilder withMessage( + OllamaChatMessageRole role, + String content, + List toolCalls, + String... imageUrls) { List messages = this.request.getMessages(); List binaryImages = null; if (imageUrls.length > 0) { binaryImages = new ArrayList<>(); for (String imageUrl : imageUrls) { try { - binaryImages.add(Utils.loadImageBytesFromUrl(imageUrl, imageURLConnectTimeoutSeconds, imageURLReadTimeoutSeconds)); + binaryImages.add( + Utils.loadImageBytesFromUrl( + imageUrl, + imageURLConnectTimeoutSeconds, + imageURLReadTimeoutSeconds)); } catch (IOException e) { - LOG.warn("Content of URL '{}' could not be read, will not add to message!", imageUrl, e); + LOG.warn( + "Content of URL '{}' could not be read, will not add to message!", + imageUrl, + e); } catch (InterruptedException e) { - LOG.warn("Loading image from URL '{}' was interrupted, will not add to message!", imageUrl, e); + LOG.warn( + "Loading image from URL '{}' was interrupted, will not add to message!", + imageUrl, + e); } } } diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatResponseModel.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatResponseModel.java index 2ccc731..1705604 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatResponseModel.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatResponseModel.java @@ -1,9 +1,16 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data public class OllamaChatResponseModel { diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatResult.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatResult.java index 21af4d7..1495eef 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatResult.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatResult.java @@ -1,12 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; -import com.fasterxml.jackson.core.JsonProcessingException; -import lombok.Getter; - -import java.util.List; - import static io.github.ollama4j.utils.Utils.getObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.List; +import lombok.Getter; + /** * Specific chat-API result that contains the chat history sent to the model and appends the answer as {@link OllamaChatResult} given by the * {@link OllamaChatMessageRole#ASSISTANT} role. @@ -18,7 +25,8 @@ public class OllamaChatResult { private final OllamaChatResponseModel responseModel; - public OllamaChatResult(OllamaChatResponseModel responseModel, List chatHistory) { + public OllamaChatResult( + OllamaChatResponseModel responseModel, List chatHistory) { this.chatHistory = chatHistory; this.responseModel = responseModel; appendAnswerToChatHistory(responseModel); diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatStreamObserver.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatStreamObserver.java index 2ccdb74..2c38d61 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatStreamObserver.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatStreamObserver.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; import io.github.ollama4j.models.generate.OllamaStreamHandler; @@ -23,16 +31,15 @@ public class OllamaChatStreamObserver implements OllamaTokenHandler { boolean hasThinking = thinking != null && !thinking.isEmpty(); boolean hasContent = !content.isEmpty(); -// if (hasThinking && !hasContent) { -//// message += thinking; -// message = thinking; -// } else { -//// message += content; -// message = content; -// } -// -// responseStreamHandler.accept(message); - + // if (hasThinking && !hasContent) { + //// message += thinking; + // message = thinking; + // } else { + //// message += content; + // message = content; + // } + // + // responseStreamHandler.accept(message); if (!hasContent && hasThinking && thinkingStreamHandler != null) { // message = message + thinking; diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatToolCalls.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatToolCalls.java index de1a081..29faeb1 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatToolCalls.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatToolCalls.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.chat; import io.github.ollama4j.tools.OllamaToolCallsFunction; @@ -11,6 +19,4 @@ import lombok.NoArgsConstructor; public class OllamaChatToolCalls { private OllamaToolCallsFunction function; - - } diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java index 1c8ec86..bee9f45 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java @@ -1,7 +1,14 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.embeddings; import io.github.ollama4j.utils.Options; - import java.util.List; /** diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestModel.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestModel.java index 8cb2002..a16e035 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestModel.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestModel.java @@ -1,26 +1,31 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.embeddings; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.List; +import java.util.Map; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import java.util.List; -import java.util.Map; - -import static io.github.ollama4j.utils.Utils.getObjectMapper; - @Data @RequiredArgsConstructor @NoArgsConstructor public class OllamaEmbedRequestModel { - @NonNull - private String model; + @NonNull private String model; - @NonNull - private List input; + @NonNull private List input; private Map options; diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedResponseModel.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedResponseModel.java index b4f808c..a97354b 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedResponseModel.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedResponseModel.java @@ -1,9 +1,16 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.embeddings; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.List; +import lombok.Data; @SuppressWarnings("unused") @Data diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java index 95af359..152ac78 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java @@ -1,9 +1,16 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.embeddings; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.List; +import lombok.Data; @SuppressWarnings("unused") @Data diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java index d28c0d2..8f9e41c 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.embeddings; import io.github.ollama4j.utils.Options; @@ -28,5 +36,4 @@ public class OllamaEmbeddingsRequestBuilder { this.request.setKeepAlive(keepAlive); return this; } - } diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java index 56173ff..9ca6ad5 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java @@ -1,27 +1,33 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.embeddings; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.Map; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import java.util.Map; - -import static io.github.ollama4j.utils.Utils.getObjectMapper; - @Data @RequiredArgsConstructor @NoArgsConstructor @Deprecated(since = "1.0.90") public class OllamaEmbeddingsRequestModel { - @NonNull - private String model; - @NonNull - private String prompt; + @NonNull private String model; + @NonNull private String prompt; protected Map options; + @JsonProperty(value = "keep_alive") private String keepAlive; diff --git a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequest.java b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequest.java index 1239841..67d5e37 100644 --- a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequest.java +++ b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequest.java @@ -1,13 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.generate; - import io.github.ollama4j.models.request.OllamaCommonRequest; import io.github.ollama4j.utils.OllamaRequestBody; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class OllamaGenerateRequest extends OllamaCommonRequest implements OllamaRequestBody { @@ -19,8 +25,7 @@ public class OllamaGenerateRequest extends OllamaCommonRequest implements Ollama private boolean raw; private boolean think; - public OllamaGenerateRequest() { - } + public OllamaGenerateRequest() {} public OllamaGenerateRequest(String model, String prompt) { this.model = model; diff --git a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequestBuilder.java b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequestBuilder.java index f3f949e..a05e5d2 100644 --- a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequestBuilder.java +++ b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateRequestBuilder.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.generate; import io.github.ollama4j.utils.Options; @@ -51,5 +59,4 @@ public class OllamaGenerateRequestBuilder { this.request.setKeepAlive(keepAlive); return this; } - } diff --git a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateResponseModel.java b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateResponseModel.java index a3d23ec..091738d 100644 --- a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateResponseModel.java +++ b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateResponseModel.java @@ -1,10 +1,17 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.generate; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateStreamObserver.java b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateStreamObserver.java index 67ae571..8a0164a 100644 --- a/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateStreamObserver.java +++ b/src/main/java/io/github/ollama4j/models/generate/OllamaGenerateStreamObserver.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.generate; import java.util.ArrayList; @@ -12,7 +20,8 @@ public class OllamaGenerateStreamObserver { private String message = ""; - public OllamaGenerateStreamObserver(OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) { + public OllamaGenerateStreamObserver( + OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) { this.responseStreamHandler = responseStreamHandler; this.thinkingStreamHandler = thinkingStreamHandler; } diff --git a/src/main/java/io/github/ollama4j/models/generate/OllamaStreamHandler.java b/src/main/java/io/github/ollama4j/models/generate/OllamaStreamHandler.java index e2da640..810985b 100644 --- a/src/main/java/io/github/ollama4j/models/generate/OllamaStreamHandler.java +++ b/src/main/java/io/github/ollama4j/models/generate/OllamaStreamHandler.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.generate; import java.util.function.Consumer; diff --git a/src/main/java/io/github/ollama4j/models/generate/OllamaTokenHandler.java b/src/main/java/io/github/ollama4j/models/generate/OllamaTokenHandler.java index a0aed8c..78b325b 100644 --- a/src/main/java/io/github/ollama4j/models/generate/OllamaTokenHandler.java +++ b/src/main/java/io/github/ollama4j/models/generate/OllamaTokenHandler.java @@ -1,8 +1,14 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.generate; import io.github.ollama4j.models.chat.OllamaChatResponseModel; - import java.util.function.Consumer; -public interface OllamaTokenHandler extends Consumer { -} +public interface OllamaTokenHandler extends Consumer {} diff --git a/src/main/java/io/github/ollama4j/models/ps/ModelsProcessResponse.java b/src/main/java/io/github/ollama4j/models/ps/ModelsProcessResponse.java index 490d362..a29f9da 100644 --- a/src/main/java/io/github/ollama4j/models/ps/ModelsProcessResponse.java +++ b/src/main/java/io/github/ollama4j/models/ps/ModelsProcessResponse.java @@ -1,12 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.ps; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - @Data @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/src/main/java/io/github/ollama4j/models/request/Auth.java b/src/main/java/io/github/ollama4j/models/request/Auth.java index 8ab9e60..d81e817 100644 --- a/src/main/java/io/github/ollama4j/models/request/Auth.java +++ b/src/main/java/io/github/ollama4j/models/request/Auth.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; public abstract class Auth { diff --git a/src/main/java/io/github/ollama4j/models/request/BasicAuth.java b/src/main/java/io/github/ollama4j/models/request/BasicAuth.java index e7a75ec..80e6653 100644 --- a/src/main/java/io/github/ollama4j/models/request/BasicAuth.java +++ b/src/main/java/io/github/ollama4j/models/request/BasicAuth.java @@ -1,11 +1,18 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; +import java.util.Base64; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.Base64; - @Data @AllArgsConstructor @EqualsAndHashCode(callSuper = false) diff --git a/src/main/java/io/github/ollama4j/models/request/BearerAuth.java b/src/main/java/io/github/ollama4j/models/request/BearerAuth.java index 4d876f2..cc25309 100644 --- a/src/main/java/io/github/ollama4j/models/request/BearerAuth.java +++ b/src/main/java/io/github/ollama4j/models/request/BearerAuth.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; import lombok.AllArgsConstructor; diff --git a/src/main/java/io/github/ollama4j/models/request/CustomModelFileContentsRequest.java b/src/main/java/io/github/ollama4j/models/request/CustomModelFileContentsRequest.java index 7707a55..2a2c06a 100644 --- a/src/main/java/io/github/ollama4j/models/request/CustomModelFileContentsRequest.java +++ b/src/main/java/io/github/ollama4j/models/request/CustomModelFileContentsRequest.java @@ -1,11 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.core.JsonProcessingException; import lombok.AllArgsConstructor; import lombok.Data; -import static io.github.ollama4j.utils.Utils.getObjectMapper; - @Data @AllArgsConstructor public class CustomModelFileContentsRequest { diff --git a/src/main/java/io/github/ollama4j/models/request/CustomModelFilePathRequest.java b/src/main/java/io/github/ollama4j/models/request/CustomModelFilePathRequest.java index 7d59af5..9ac9eb4 100644 --- a/src/main/java/io/github/ollama4j/models/request/CustomModelFilePathRequest.java +++ b/src/main/java/io/github/ollama4j/models/request/CustomModelFilePathRequest.java @@ -1,11 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.core.JsonProcessingException; import lombok.AllArgsConstructor; import lombok.Data; -import static io.github.ollama4j.utils.Utils.getObjectMapper; - @Data @AllArgsConstructor public class CustomModelFilePathRequest { diff --git a/src/main/java/io/github/ollama4j/models/request/CustomModelRequest.java b/src/main/java/io/github/ollama4j/models/request/CustomModelRequest.java index b2ecb91..8025a12 100644 --- a/src/main/java/io/github/ollama4j/models/request/CustomModelRequest.java +++ b/src/main/java/io/github/ollama4j/models/request/CustomModelRequest.java @@ -1,15 +1,21 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; -import com.fasterxml.jackson.core.JsonProcessingException; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; - -import java.util.List; -import java.util.Map; - import static io.github.ollama4j.utils.Utils.getObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; @Data @AllArgsConstructor diff --git a/src/main/java/io/github/ollama4j/models/request/ModelRequest.java b/src/main/java/io/github/ollama4j/models/request/ModelRequest.java index 1662aa2..9d771ef 100644 --- a/src/main/java/io/github/ollama4j/models/request/ModelRequest.java +++ b/src/main/java/io/github/ollama4j/models/request/ModelRequest.java @@ -1,11 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.core.JsonProcessingException; import lombok.AllArgsConstructor; import lombok.Data; -import static io.github.ollama4j.utils.Utils.getObjectMapper; - @Data @AllArgsConstructor public class ModelRequest { diff --git a/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java b/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java index c278fba..b3a76f0 100644 --- a/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java +++ b/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; import com.fasterxml.jackson.core.JsonProcessingException; @@ -7,9 +15,6 @@ import io.github.ollama4j.models.chat.*; import io.github.ollama4j.models.generate.OllamaTokenHandler; import io.github.ollama4j.models.response.OllamaErrorResponse; import io.github.ollama4j.utils.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -20,6 +25,8 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Specialization class for requests @@ -52,11 +59,15 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller { * @return TRUE, if ollama-Response has 'done' state */ @Override - protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) { + protected boolean parseResponseAndAddToBuffer( + String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) { try { - OllamaChatResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class); - // it seems that under heavy load ollama responds with an empty chat message part in the streamed response - // thus, we null check the message and hope that the next streamed response has some message content again + OllamaChatResponseModel ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class); + // it seems that under heavy load ollama responds with an empty chat message part in the + // streamed response + // thus, we null check the message and hope that the next streamed response has some + // message content again OllamaChatMessage message = ollamaResponseModel.getMessage(); if (message != null) { if (message.getThinking() != null) { @@ -81,14 +92,13 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller { return callSync(body); } - public OllamaChatResult callSync(OllamaChatRequest body) throws OllamaBaseException, IOException, InterruptedException { + public OllamaChatResult callSync(OllamaChatRequest body) + throws OllamaBaseException, IOException, InterruptedException { // Create Request HttpClient httpClient = HttpClient.newHttpClient(); URI uri = URI.create(getHost() + getEndpointSuffix()); HttpRequest.Builder requestBuilder = - getRequestBuilderDefault(uri) - .POST( - body.getBodyPublisher()); + getRequestBuilderDefault(uri).POST(body.getBodyPublisher()); HttpRequest request = requestBuilder.build(); LOG.debug("Asking model: {}", body); HttpResponse response = @@ -101,7 +111,8 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller { OllamaChatResponseModel ollamaChatResponseModel = null; List wantedToolsForStream = null; try (BufferedReader reader = - new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { + new BufferedReader( + new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { @@ -114,22 +125,27 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller { LOG.warn("Status code: 401 (Unauthorized)"); OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper() - .readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class); + .readValue( + "{\"error\":\"Unauthorized\"}", + OllamaErrorResponse.class); responseBuffer.append(ollamaResponseModel.getError()); } else if (statusCode == 400) { LOG.warn("Status code: 400 (Bad Request)"); - OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, - OllamaErrorResponse.class); + OllamaErrorResponse ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); responseBuffer.append(ollamaResponseModel.getError()); } else if (statusCode == 500) { LOG.warn("Status code: 500 (Internal Server Error)"); - OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, - OllamaErrorResponse.class); + OllamaErrorResponse ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); responseBuffer.append(ollamaResponseModel.getError()); } else { - boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer); - ollamaChatResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class); - if (body.stream && ollamaChatResponseModel.getMessage().getToolCalls() != null) { + boolean finished = + parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer); + ollamaChatResponseModel = + Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class); + if (body.stream + && ollamaChatResponseModel.getMessage().getToolCalls() != null) { wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls(); } if (finished && body.stream) { diff --git a/src/main/java/io/github/ollama4j/models/request/OllamaCommonRequest.java b/src/main/java/io/github/ollama4j/models/request/OllamaCommonRequest.java index 6213090..aa3768d 100644 --- a/src/main/java/io/github/ollama4j/models/request/OllamaCommonRequest.java +++ b/src/main/java/io/github/ollama4j/models/request/OllamaCommonRequest.java @@ -1,32 +1,43 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import io.github.ollama4j.utils.Utils; -import lombok.Data; - import java.util.Map; +import lombok.Data; @Data @JsonInclude(JsonInclude.Include.NON_NULL) public abstract class OllamaCommonRequest { protected String model; + // @JsonSerialize(using = BooleanToJsonFormatFlagSerializer.class) -// this can either be set to format=json or format={"key1": "val1", "key2": "val2"} + // this can either be set to format=json or format={"key1": "val1", "key2": "val2"} @JsonProperty(value = "format", required = false, defaultValue = "json") protected Object format; + protected Map options; protected String template; protected boolean stream; + @JsonProperty(value = "keep_alive") protected String keepAlive; - public String toString() { try { - return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + return Utils.getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(this); } catch (JsonProcessingException e) { throw new RuntimeException(e); } diff --git a/src/main/java/io/github/ollama4j/models/request/OllamaEndpointCaller.java b/src/main/java/io/github/ollama4j/models/request/OllamaEndpointCaller.java index 50247ae..1d73185 100644 --- a/src/main/java/io/github/ollama4j/models/request/OllamaEndpointCaller.java +++ b/src/main/java/io/github/ollama4j/models/request/OllamaEndpointCaller.java @@ -1,11 +1,18 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; import io.github.ollama4j.utils.Constants; -import lombok.Getter; - import java.net.URI; import java.net.http.HttpRequest; import java.time.Duration; +import lombok.Getter; /** * Abstract helperclass to call the ollama api server. @@ -25,8 +32,8 @@ public abstract class OllamaEndpointCaller { protected abstract String getEndpointSuffix(); - protected abstract boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer); - + protected abstract boolean parseResponseAndAddToBuffer( + String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer); /** * Get default request builder. @@ -37,7 +44,9 @@ public abstract class OllamaEndpointCaller { protected HttpRequest.Builder getRequestBuilderDefault(URI uri) { HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri) - .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) .timeout(Duration.ofSeconds(this.requestTimeoutSeconds)); if (isAuthCredentialsSet()) { requestBuilder.header("Authorization", this.auth.getAuthHeaderValue()); @@ -53,5 +62,4 @@ public abstract class OllamaEndpointCaller { protected boolean isAuthCredentialsSet() { return this.auth != null; } - } diff --git a/src/main/java/io/github/ollama4j/models/request/OllamaGenerateEndpointCaller.java b/src/main/java/io/github/ollama4j/models/request/OllamaGenerateEndpointCaller.java index 2c70f62..3100f38 100644 --- a/src/main/java/io/github/ollama4j/models/request/OllamaGenerateEndpointCaller.java +++ b/src/main/java/io/github/ollama4j/models/request/OllamaGenerateEndpointCaller.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.request; import com.fasterxml.jackson.core.JsonProcessingException; @@ -9,9 +17,6 @@ import io.github.ollama4j.models.response.OllamaErrorResponse; import io.github.ollama4j.models.response.OllamaResult; import io.github.ollama4j.utils.OllamaRequestBody; import io.github.ollama4j.utils.Utils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -21,6 +26,8 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @SuppressWarnings("resource") public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller { @@ -39,9 +46,11 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller { } @Override - protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) { + protected boolean parseResponseAndAddToBuffer( + String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) { try { - OllamaGenerateResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class); + OllamaGenerateResponseModel ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class); if (ollamaResponseModel.getResponse() != null) { responseBuffer.append(ollamaResponseModel.getResponse()); } @@ -58,8 +67,13 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller { } } - public OllamaResult call(OllamaRequestBody body, OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException { - responseStreamObserver = new OllamaGenerateStreamObserver(thinkingStreamHandler, responseStreamHandler); + public OllamaResult call( + OllamaRequestBody body, + OllamaStreamHandler thinkingStreamHandler, + OllamaStreamHandler responseStreamHandler) + throws OllamaBaseException, IOException, InterruptedException { + responseStreamObserver = + new OllamaGenerateStreamObserver(thinkingStreamHandler, responseStreamHandler); return callSync(body); } @@ -73,40 +87,54 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller { * @throws InterruptedException in case the server is not reachable or network issues happen */ @SuppressWarnings("DuplicatedCode") - public OllamaResult callSync(OllamaRequestBody body) throws OllamaBaseException, IOException, InterruptedException { + public OllamaResult callSync(OllamaRequestBody body) + throws OllamaBaseException, IOException, InterruptedException { // Create Request long startTime = System.currentTimeMillis(); HttpClient httpClient = HttpClient.newHttpClient(); URI uri = URI.create(getHost() + getEndpointSuffix()); - HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri).POST(body.getBodyPublisher()); + HttpRequest.Builder requestBuilder = + getRequestBuilderDefault(uri).POST(body.getBodyPublisher()); HttpRequest request = requestBuilder.build(); LOG.debug("Asking model: {}", body); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); int statusCode = response.statusCode(); InputStream responseBodyStream = response.body(); StringBuilder responseBuffer = new StringBuilder(); StringBuilder thinkingBuffer = new StringBuilder(); OllamaGenerateResponseModel ollamaGenerateResponseModel = null; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { + try (BufferedReader reader = + new BufferedReader( + new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { if (statusCode == 404) { LOG.warn("Status code: 404 (Not Found)"); - OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); + OllamaErrorResponse ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); responseBuffer.append(ollamaResponseModel.getError()); } else if (statusCode == 401) { LOG.warn("Status code: 401 (Unauthorized)"); - OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class); + OllamaErrorResponse ollamaResponseModel = + Utils.getObjectMapper() + .readValue( + "{\"error\":\"Unauthorized\"}", + OllamaErrorResponse.class); responseBuffer.append(ollamaResponseModel.getError()); } else if (statusCode == 400) { LOG.warn("Status code: 400 (Bad Request)"); - OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); + OllamaErrorResponse ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); responseBuffer.append(ollamaResponseModel.getError()); } else { - boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer); + boolean finished = + parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer); if (finished) { - ollamaGenerateResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class); + ollamaGenerateResponseModel = + Utils.getObjectMapper() + .readValue(line, OllamaGenerateResponseModel.class); break; } } @@ -118,7 +146,12 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller { throw new OllamaBaseException(responseBuffer.toString()); } else { long endTime = System.currentTimeMillis(); - OllamaResult ollamaResult = new OllamaResult(responseBuffer.toString(), thinkingBuffer.toString(), endTime - startTime, statusCode); + OllamaResult ollamaResult = + new OllamaResult( + responseBuffer.toString(), + thinkingBuffer.toString(), + endTime - startTime, + statusCode); ollamaResult.setModel(ollamaGenerateResponseModel.getModel()); ollamaResult.setCreatedAt(ollamaGenerateResponseModel.getCreatedAt()); diff --git a/src/main/java/io/github/ollama4j/models/response/LibraryModel.java b/src/main/java/io/github/ollama4j/models/response/LibraryModel.java index c5f1627..4b08fe7 100644 --- a/src/main/java/io/github/ollama4j/models/response/LibraryModel.java +++ b/src/main/java/io/github/ollama4j/models/response/LibraryModel.java @@ -1,9 +1,16 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class LibraryModel { diff --git a/src/main/java/io/github/ollama4j/models/response/LibraryModelDetail.java b/src/main/java/io/github/ollama4j/models/response/LibraryModelDetail.java index 142873c..cfe56b1 100644 --- a/src/main/java/io/github/ollama4j/models/response/LibraryModelDetail.java +++ b/src/main/java/io/github/ollama4j/models/response/LibraryModelDetail.java @@ -1,8 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data public class LibraryModelDetail { diff --git a/src/main/java/io/github/ollama4j/models/response/LibraryModelTag.java b/src/main/java/io/github/ollama4j/models/response/LibraryModelTag.java index cd65d32..ca8df63 100644 --- a/src/main/java/io/github/ollama4j/models/response/LibraryModelTag.java +++ b/src/main/java/io/github/ollama4j/models/response/LibraryModelTag.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import lombok.Data; diff --git a/src/main/java/io/github/ollama4j/models/response/ListModelsResponse.java b/src/main/java/io/github/ollama4j/models/response/ListModelsResponse.java index e22b796..c7e2bdf 100644 --- a/src/main/java/io/github/ollama4j/models/response/ListModelsResponse.java +++ b/src/main/java/io/github/ollama4j/models/response/ListModelsResponse.java @@ -1,8 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data public class ListModelsResponse { diff --git a/src/main/java/io/github/ollama4j/models/response/Model.java b/src/main/java/io/github/ollama4j/models/response/Model.java index 768b96f..a419f8d 100644 --- a/src/main/java/io/github/ollama4j/models/response/Model.java +++ b/src/main/java/io/github/ollama4j/models/response/Model.java @@ -1,12 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import io.github.ollama4j.utils.Utils; -import lombok.Data; - import java.time.OffsetDateTime; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) @@ -14,16 +21,19 @@ public class Model { private String name; private String model; + @JsonProperty("modified_at") private OffsetDateTime modifiedAt; + @JsonProperty("expires_at") private OffsetDateTime expiresAt; + private String digest; private long size; + @JsonProperty("details") private ModelMeta modelMeta; - /** * Returns the model name without its version * @@ -45,10 +55,11 @@ public class Model { @Override public String toString() { try { - return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + return Utils.getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(this); } catch (JsonProcessingException e) { throw new RuntimeException(e); } } - } diff --git a/src/main/java/io/github/ollama4j/models/response/ModelDetail.java b/src/main/java/io/github/ollama4j/models/response/ModelDetail.java index a6a64e2..2140bfd 100644 --- a/src/main/java/io/github/ollama4j/models/response/ModelDetail.java +++ b/src/main/java/io/github/ollama4j/models/response/ModelDetail.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -22,7 +30,9 @@ public class ModelDetail { @Override public String toString() { try { - return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + return Utils.getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(this); } catch (JsonProcessingException e) { throw new RuntimeException(e); } diff --git a/src/main/java/io/github/ollama4j/models/response/ModelMeta.java b/src/main/java/io/github/ollama4j/models/response/ModelMeta.java index f7f364c..3c5a4c4 100644 --- a/src/main/java/io/github/ollama4j/models/response/ModelMeta.java +++ b/src/main/java/io/github/ollama4j/models/response/ModelMeta.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -27,7 +35,9 @@ public class ModelMeta { @Override public String toString() { try { - return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + return Utils.getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(this); } catch (JsonProcessingException e) { throw new RuntimeException(e); } diff --git a/src/main/java/io/github/ollama4j/models/response/ModelPullResponse.java b/src/main/java/io/github/ollama4j/models/response/ModelPullResponse.java index eac1870..2078348 100644 --- a/src/main/java/io/github/ollama4j/models/response/ModelPullResponse.java +++ b/src/main/java/io/github/ollama4j/models/response/ModelPullResponse.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/src/main/java/io/github/ollama4j/models/response/OllamaAsyncResultStreamer.java b/src/main/java/io/github/ollama4j/models/response/OllamaAsyncResultStreamer.java index f4a68f7..516e328 100644 --- a/src/main/java/io/github/ollama4j/models/response/OllamaAsyncResultStreamer.java +++ b/src/main/java/io/github/ollama4j/models/response/OllamaAsyncResultStreamer.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import io.github.ollama4j.exceptions.OllamaBaseException; @@ -5,11 +13,6 @@ import io.github.ollama4j.models.generate.OllamaGenerateRequest; import io.github.ollama4j.models.generate.OllamaGenerateResponseModel; import io.github.ollama4j.utils.Constants; import io.github.ollama4j.utils.Utils; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -19,6 +22,10 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.time.Duration; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; @Data @EqualsAndHashCode(callSuper = true) @@ -31,32 +38,30 @@ public class OllamaAsyncResultStreamer extends Thread { private String completeResponse; private String completeThinkingResponse; - /** * -- GETTER -- Returns the status of the request. Indicates if the request was successful or a * failure. If the request was a failure, the `getResponse()` method will return the error * message. */ - @Getter - private boolean succeeded; + @Getter private boolean succeeded; - @Setter - private long requestTimeoutSeconds; + @Setter private long requestTimeoutSeconds; /** * -- GETTER -- Returns the HTTP response status code for the request that was made to Ollama * server. */ - @Getter - private int httpStatusCode; + @Getter private int httpStatusCode; /** * -- GETTER -- Returns the response time in milliseconds. */ - @Getter - private long responseTime = 0; + @Getter private long responseTime = 0; - public OllamaAsyncResultStreamer(HttpRequest.Builder requestBuilder, OllamaGenerateRequest ollamaRequestModel, long requestTimeoutSeconds) { + public OllamaAsyncResultStreamer( + HttpRequest.Builder requestBuilder, + OllamaGenerateRequest ollamaRequestModel, + long requestTimeoutSeconds) { this.requestBuilder = requestBuilder; this.ollamaRequestModel = ollamaRequestModel; this.completeResponse = ""; @@ -70,25 +75,41 @@ public class OllamaAsyncResultStreamer extends Thread { HttpClient httpClient = HttpClient.newHttpClient(); long startTime = System.currentTimeMillis(); try { - HttpRequest request = requestBuilder.POST(HttpRequest.BodyPublishers.ofString(Utils.getObjectMapper().writeValueAsString(ollamaRequestModel))).header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).timeout(Duration.ofSeconds(requestTimeoutSeconds)).build(); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + HttpRequest request = + requestBuilder + .POST( + HttpRequest.BodyPublishers.ofString( + Utils.getObjectMapper() + .writeValueAsString(ollamaRequestModel))) + .header( + Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, + Constants.HttpConstants.APPLICATION_JSON) + .timeout(Duration.ofSeconds(requestTimeoutSeconds)) + .build(); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); int statusCode = response.statusCode(); this.httpStatusCode = statusCode; InputStream responseBodyStream = response.body(); BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8)); + reader = + new BufferedReader( + new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8)); String line; StringBuilder thinkingBuffer = new StringBuilder(); StringBuilder responseBuffer = new StringBuilder(); while ((line = reader.readLine()) != null) { if (statusCode == 404) { - OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); + OllamaErrorResponse ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class); responseStream.add(ollamaResponseModel.getError()); responseBuffer.append(ollamaResponseModel.getError()); } else { - OllamaGenerateResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class); + OllamaGenerateResponseModel ollamaResponseModel = + Utils.getObjectMapper() + .readValue(line, OllamaGenerateResponseModel.class); String thinkingTokens = ollamaResponseModel.getThinking(); String responseTokens = ollamaResponseModel.getResponse(); if (thinkingTokens == null) { @@ -134,5 +155,4 @@ public class OllamaAsyncResultStreamer extends Thread { this.completeResponse = "[FAILED] " + e.getMessage(); } } - } diff --git a/src/main/java/io/github/ollama4j/models/response/OllamaErrorResponse.java b/src/main/java/io/github/ollama4j/models/response/OllamaErrorResponse.java index c57549d..74faf2e 100644 --- a/src/main/java/io/github/ollama4j/models/response/OllamaErrorResponse.java +++ b/src/main/java/io/github/ollama4j/models/response/OllamaErrorResponse.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/src/main/java/io/github/ollama4j/models/response/OllamaResult.java b/src/main/java/io/github/ollama4j/models/response/OllamaResult.java index ce6d5e3..1c1abb5 100644 --- a/src/main/java/io/github/ollama4j/models/response/OllamaResult.java +++ b/src/main/java/io/github/ollama4j/models/response/OllamaResult.java @@ -1,16 +1,23 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; -import lombok.Data; -import lombok.Getter; - import java.util.HashMap; import java.util.List; import java.util.Map; - -import static io.github.ollama4j.utils.Utils.getObjectMapper; +import lombok.Data; +import lombok.Getter; /** * The type Ollama result. @@ -24,14 +31,17 @@ public class OllamaResult { * Get the completion/response text */ private final String response; + /** * Get the thinking text (if available) */ private final String thinking; + /** * Get the response status code. */ private int httpStatusCode; + /** * Get the response time in milliseconds. */ @@ -75,7 +85,9 @@ public class OllamaResult { responseMap.put("promptEvalDuration", this.promptEvalDuration); responseMap.put("evalCount", this.evalCount); responseMap.put("evalDuration", this.evalDuration); - return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseMap); + return getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(responseMap); } catch (JsonProcessingException e) { throw new RuntimeException(e); } @@ -95,17 +107,18 @@ public class OllamaResult { try { // Check if the response is a valid JSON - if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) || - (!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) { + if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) + || (!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) { throw new IllegalArgumentException("Response is not a valid JSON object"); } - Map response = getObjectMapper().readValue(responseStr, - new TypeReference>() { - }); + Map response = + getObjectMapper() + .readValue(responseStr, new TypeReference>() {}); return response; } catch (JsonProcessingException e) { - throw new IllegalArgumentException("Failed to parse response as JSON: " + e.getMessage(), e); + throw new IllegalArgumentException( + "Failed to parse response as JSON: " + e.getMessage(), e); } } @@ -126,13 +139,14 @@ public class OllamaResult { try { // Check if the response is a valid JSON - if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) || - (!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) { + if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) + || (!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) { throw new IllegalArgumentException("Response is not a valid JSON object"); } return getObjectMapper().readValue(responseStr, clazz); } catch (JsonProcessingException e) { - throw new IllegalArgumentException("Failed to parse response as JSON: " + e.getMessage(), e); + throw new IllegalArgumentException( + "Failed to parse response as JSON: " + e.getMessage(), e); } } } diff --git a/src/main/java/io/github/ollama4j/models/response/OllamaResultStream.java b/src/main/java/io/github/ollama4j/models/response/OllamaResultStream.java index de44d63..ace70f1 100644 --- a/src/main/java/io/github/ollama4j/models/response/OllamaResultStream.java +++ b/src/main/java/io/github/ollama4j/models/response/OllamaResultStream.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import java.util.Iterator; diff --git a/src/main/java/io/github/ollama4j/models/response/OllamaStructuredResult.java b/src/main/java/io/github/ollama4j/models/response/OllamaStructuredResult.java index d655b7c..7cdc4bc 100644 --- a/src/main/java/io/github/ollama4j/models/response/OllamaStructuredResult.java +++ b/src/main/java/io/github/ollama4j/models/response/OllamaStructuredResult.java @@ -1,18 +1,25 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; +import static io.github.ollama4j.utils.Utils.getObjectMapper; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; +import java.util.List; +import java.util.Map; import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; -import java.util.Map; - -import static io.github.ollama4j.utils.Utils.getObjectMapper; - @Getter @SuppressWarnings("unused") @Data @@ -58,9 +65,11 @@ public class OllamaStructuredResult { */ public Map getStructuredResponse() { try { - Map response = getObjectMapper().readValue(this.getResponse(), - new TypeReference>() { - }); + Map response = + getObjectMapper() + .readValue( + this.getResponse(), + new TypeReference>() {}); return response; } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/src/main/java/io/github/ollama4j/models/response/OllamaVersion.java b/src/main/java/io/github/ollama4j/models/response/OllamaVersion.java index 11b7524..a1bd907 100644 --- a/src/main/java/io/github/ollama4j/models/response/OllamaVersion.java +++ b/src/main/java/io/github/ollama4j/models/response/OllamaVersion.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.models.response; import lombok.Data; diff --git a/src/main/java/io/github/ollama4j/tools/OllamaToolCallsFunction.java b/src/main/java/io/github/ollama4j/tools/OllamaToolCallsFunction.java index e928ebc..b7feb79 100644 --- a/src/main/java/io/github/ollama4j/tools/OllamaToolCallsFunction.java +++ b/src/main/java/io/github/ollama4j/tools/OllamaToolCallsFunction.java @@ -1,12 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.Map; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Map; - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/src/main/java/io/github/ollama4j/tools/OllamaToolsResult.java b/src/main/java/io/github/ollama4j/tools/OllamaToolsResult.java index 35fada3..9854211 100644 --- a/src/main/java/io/github/ollama4j/tools/OllamaToolsResult.java +++ b/src/main/java/io/github/ollama4j/tools/OllamaToolsResult.java @@ -1,13 +1,20 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; import io.github.ollama4j.models.response.OllamaResult; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - import java.util.ArrayList; import java.util.List; import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; @Data @NoArgsConstructor @@ -22,7 +29,8 @@ public class OllamaToolsResult { return results; } for (Map.Entry r : this.toolResults.entrySet()) { - results.add(new ToolResult(r.getKey().getName(), r.getKey().getArguments(), r.getValue())); + results.add( + new ToolResult(r.getKey().getName(), r.getKey().getArguments(), r.getValue())); } return results; } diff --git a/src/main/java/io/github/ollama4j/tools/ReflectionalToolFunction.java b/src/main/java/io/github/ollama4j/tools/ReflectionalToolFunction.java index 524943e..d85793d 100644 --- a/src/main/java/io/github/ollama4j/tools/ReflectionalToolFunction.java +++ b/src/main/java/io/github/ollama4j/tools/ReflectionalToolFunction.java @@ -1,13 +1,20 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.LinkedHashMap; import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; /** * Specification of a {@link ToolFunction} that provides the implementation via java reflection calling. @@ -25,7 +32,8 @@ public class ReflectionalToolFunction implements ToolFunction { public Object apply(Map arguments) { LinkedHashMap argumentsCopy = new LinkedHashMap<>(this.propertyDefinition); for (Map.Entry param : this.propertyDefinition.entrySet()) { - argumentsCopy.replace(param.getKey(), typeCast(arguments.get(param.getKey()), param.getValue())); + argumentsCopy.replace( + param.getKey(), typeCast(arguments.get(param.getKey()), param.getValue())); } try { return function.invoke(functionHolder, argumentsCopy.values().toArray()); @@ -50,5 +58,4 @@ public class ReflectionalToolFunction implements ToolFunction { return inputValueString; } } - } diff --git a/src/main/java/io/github/ollama4j/tools/ToolFunction.java b/src/main/java/io/github/ollama4j/tools/ToolFunction.java index 51ab8c5..c2dc6bf 100644 --- a/src/main/java/io/github/ollama4j/tools/ToolFunction.java +++ b/src/main/java/io/github/ollama4j/tools/ToolFunction.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; import java.util.Map; diff --git a/src/main/java/io/github/ollama4j/tools/ToolFunctionCallSpec.java b/src/main/java/io/github/ollama4j/tools/ToolFunctionCallSpec.java index 13d582f..afcefcd 100644 --- a/src/main/java/io/github/ollama4j/tools/ToolFunctionCallSpec.java +++ b/src/main/java/io/github/ollama4j/tools/ToolFunctionCallSpec.java @@ -1,11 +1,18 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; +import java.util.Map; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Map; - @Data @AllArgsConstructor @NoArgsConstructor diff --git a/src/main/java/io/github/ollama4j/tools/ToolRegistry.java b/src/main/java/io/github/ollama4j/tools/ToolRegistry.java index b106042..3745abd 100644 --- a/src/main/java/io/github/ollama4j/tools/ToolRegistry.java +++ b/src/main/java/io/github/ollama4j/tools/ToolRegistry.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; import java.util.Collection; diff --git a/src/main/java/io/github/ollama4j/tools/Tools.java b/src/main/java/io/github/ollama4j/tools/Tools.java index eb8dcca..59baaaf 100644 --- a/src/main/java/io/github/ollama4j/tools/Tools.java +++ b/src/main/java/io/github/ollama4j/tools/Tools.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -6,15 +14,14 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import io.github.ollama4j.utils.Utils; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; public class Tools { @Data @@ -62,11 +69,12 @@ public class Tools { public static class Property { private String type; private String description; + @JsonProperty("enum") @JsonInclude(JsonInclude.Include.NON_NULL) private List enumValues; - @JsonIgnore - private boolean required; + + @JsonIgnore private boolean required; } } @@ -89,7 +97,11 @@ public class Tools { private String promptText; public String build() throws JsonProcessingException { - return "[AVAILABLE_TOOLS] " + Utils.getObjectMapper().writeValueAsString(tools) + "[/AVAILABLE_TOOLS][INST] " + promptText + " [/INST]"; + return "[AVAILABLE_TOOLS] " + + Utils.getObjectMapper().writeValueAsString(tools) + + "[/AVAILABLE_TOOLS][INST] " + + promptText + + " [/INST]"; } public PromptBuilder withPrompt(String prompt) throws JsonProcessingException { @@ -101,7 +113,8 @@ public class Tools { PromptFuncDefinition def = new PromptFuncDefinition(); def.setType("function"); - PromptFuncDefinition.PromptFuncSpec functionDetail = new PromptFuncDefinition.PromptFuncSpec(); + PromptFuncDefinition.PromptFuncSpec functionDetail = + new PromptFuncDefinition.PromptFuncSpec(); functionDetail.setName(spec.getFunctionName()); functionDetail.setDescription(spec.getFunctionDescription()); @@ -110,7 +123,8 @@ public class Tools { parameters.setProperties(spec.getToolPrompt().getFunction().parameters.getProperties()); List requiredValues = new ArrayList<>(); - for (Map.Entry p : spec.getToolPrompt().getFunction().getParameters().getProperties().entrySet()) { + for (Map.Entry p : + spec.getToolPrompt().getFunction().getParameters().getProperties().entrySet()) { if (p.getValue().isRequired()) { requiredValues.add(p.getKey()); } diff --git a/src/main/java/io/github/ollama4j/tools/annotations/OllamaToolService.java b/src/main/java/io/github/ollama4j/tools/annotations/OllamaToolService.java index 5118430..726e31f 100644 --- a/src/main/java/io/github/ollama4j/tools/annotations/OllamaToolService.java +++ b/src/main/java/io/github/ollama4j/tools/annotations/OllamaToolService.java @@ -1,7 +1,14 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools.annotations; import io.github.ollama4j.OllamaAPI; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/src/main/java/io/github/ollama4j/tools/annotations/ToolProperty.java b/src/main/java/io/github/ollama4j/tools/annotations/ToolProperty.java index 28d9acc..f9721b5 100644 --- a/src/main/java/io/github/ollama4j/tools/annotations/ToolProperty.java +++ b/src/main/java/io/github/ollama4j/tools/annotations/ToolProperty.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools.annotations; import java.lang.annotation.ElementType; diff --git a/src/main/java/io/github/ollama4j/tools/annotations/ToolSpec.java b/src/main/java/io/github/ollama4j/tools/annotations/ToolSpec.java index 7f99768..33bf8dc 100644 --- a/src/main/java/io/github/ollama4j/tools/annotations/ToolSpec.java +++ b/src/main/java/io/github/ollama4j/tools/annotations/ToolSpec.java @@ -1,7 +1,14 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools.annotations; import io.github.ollama4j.OllamaAPI; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/src/main/java/io/github/ollama4j/tools/sampletools/WeatherTool.java b/src/main/java/io/github/ollama4j/tools/sampletools/WeatherTool.java index 7a32ab0..2a13ece 100644 --- a/src/main/java/io/github/ollama4j/tools/sampletools/WeatherTool.java +++ b/src/main/java/io/github/ollama4j/tools/sampletools/WeatherTool.java @@ -1,15 +1,21 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.tools.sampletools; import io.github.ollama4j.tools.Tools; - import java.util.Map; @SuppressWarnings("resource") public class WeatherTool { private String paramCityName = "cityName"; - public WeatherTool() { - } + public WeatherTool() {} public String getCurrentWeather(Map arguments) { String city = (String) arguments.get(paramCityName); @@ -20,14 +26,14 @@ public class WeatherTool { return Tools.ToolSpecification.builder() .functionName("weather-reporter") .functionDescription( - "You are a tool who simply finds the city name from the user's message input/query about weather.") + "You are a tool who simply finds the city name from the user's message" + + " input/query about weather.") .toolFunction(this::getCurrentWeather) .toolPrompt( Tools.PromptFuncDefinition.builder() .type("prompt") .function( - Tools.PromptFuncDefinition.PromptFuncSpec - .builder() + Tools.PromptFuncDefinition.PromptFuncSpec.builder() .name("get-city-name") .description("Get the city name") .parameters( @@ -37,15 +43,24 @@ public class WeatherTool { .properties( Map.of( paramCityName, - Tools.PromptFuncDefinition.Property + Tools + .PromptFuncDefinition + .Property .builder() - .type("string") + .type( + "string") .description( - "The name of the city. e.g. Bengaluru") - .required(true) + "The name" + + " of the" + + " city." + + " e.g." + + " Bengaluru") + .required( + true) .build())) - .required(java.util.List - .of(paramCityName)) + .required( + java.util.List.of( + paramCityName)) .build()) .build()) .build()) diff --git a/src/main/java/io/github/ollama4j/types/OllamaModelType.java b/src/main/java/io/github/ollama4j/types/OllamaModelType.java index 8153e84..33f636d 100644 --- a/src/main/java/io/github/ollama4j/types/OllamaModelType.java +++ b/src/main/java/io/github/ollama4j/types/OllamaModelType.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.types; /** diff --git a/src/main/java/io/github/ollama4j/utils/BooleanToJsonFormatFlagSerializer.java b/src/main/java/io/github/ollama4j/utils/BooleanToJsonFormatFlagSerializer.java index ed7bf20..6608097 100644 --- a/src/main/java/io/github/ollama4j/utils/BooleanToJsonFormatFlagSerializer.java +++ b/src/main/java/io/github/ollama4j/utils/BooleanToJsonFormatFlagSerializer.java @@ -1,15 +1,23 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; - import java.io.IOException; public class BooleanToJsonFormatFlagSerializer extends JsonSerializer { @Override - public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) + throws IOException { gen.writeString("json"); } diff --git a/src/main/java/io/github/ollama4j/utils/Constants.java b/src/main/java/io/github/ollama4j/utils/Constants.java index dfe5377..690b1ab 100644 --- a/src/main/java/io/github/ollama4j/utils/Constants.java +++ b/src/main/java/io/github/ollama4j/utils/Constants.java @@ -1,9 +1,16 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; public final class Constants { public static final class HttpConstants { - private HttpConstants() { - } + private HttpConstants() {} public static final String APPLICATION_JSON = "application/json"; public static final String APPLICATION_XML = "application/xml"; diff --git a/src/main/java/io/github/ollama4j/utils/FileToBase64Serializer.java b/src/main/java/io/github/ollama4j/utils/FileToBase64Serializer.java index c54d83f..9fe2ece 100644 --- a/src/main/java/io/github/ollama4j/utils/FileToBase64Serializer.java +++ b/src/main/java/io/github/ollama4j/utils/FileToBase64Serializer.java @@ -1,9 +1,16 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; - import java.io.IOException; import java.util.Base64; import java.util.Collection; @@ -11,7 +18,9 @@ import java.util.Collection; public class FileToBase64Serializer extends JsonSerializer> { @Override - public void serialize(Collection value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException { + public void serialize( + Collection value, JsonGenerator jsonGenerator, SerializerProvider serializers) + throws IOException { jsonGenerator.writeStartArray(); for (byte[] file : value) { jsonGenerator.writeString(Base64.getEncoder().encodeToString(file)); diff --git a/src/main/java/io/github/ollama4j/utils/OllamaRequestBody.java b/src/main/java/io/github/ollama4j/utils/OllamaRequestBody.java index e95fa67..f6abf19 100644 --- a/src/main/java/io/github/ollama4j/utils/OllamaRequestBody.java +++ b/src/main/java/io/github/ollama4j/utils/OllamaRequestBody.java @@ -1,8 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; - import java.net.http.HttpRequest.BodyPublisher; import java.net.http.HttpRequest.BodyPublishers; @@ -19,8 +26,7 @@ public interface OllamaRequestBody { @JsonIgnore default BodyPublisher getBodyPublisher() { try { - return BodyPublishers.ofString( - Utils.getObjectMapper().writeValueAsString(this)); + return BodyPublishers.ofString(Utils.getObjectMapper().writeValueAsString(this)); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Request not Body convertible.", e); } diff --git a/src/main/java/io/github/ollama4j/utils/Options.java b/src/main/java/io/github/ollama4j/utils/Options.java index c4ce149..9b5333d 100644 --- a/src/main/java/io/github/ollama4j/utils/Options.java +++ b/src/main/java/io/github/ollama4j/utils/Options.java @@ -1,8 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; -import lombok.Data; - import java.util.Map; +import lombok.Data; /** * Class for options for Ollama model. diff --git a/src/main/java/io/github/ollama4j/utils/OptionsBuilder.java b/src/main/java/io/github/ollama4j/utils/OptionsBuilder.java index 2f94e0e..21d89a7 100644 --- a/src/main/java/io/github/ollama4j/utils/OptionsBuilder.java +++ b/src/main/java/io/github/ollama4j/utils/OptionsBuilder.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; import java.util.HashMap; @@ -230,15 +238,16 @@ public class OptionsBuilder { * @return The updated OptionsBuilder. * @throws IllegalArgumentException if parameter has an unsupported type */ - public OptionsBuilder setCustomOption(String name, Object value) throws IllegalArgumentException { + public OptionsBuilder setCustomOption(String name, Object value) + throws IllegalArgumentException { if (!(value instanceof Integer || value instanceof Float || value instanceof String)) { - throw new IllegalArgumentException("Invalid type for parameter. Allowed types are: Integer, Float, or String."); + throw new IllegalArgumentException( + "Invalid type for parameter. Allowed types are: Integer, Float, or String."); } options.getOptionsMap().put(name, value); return this; } - /** * Builds the options map. * @@ -247,6 +256,4 @@ public class OptionsBuilder { public Options build() { return options; } - - } diff --git a/src/main/java/io/github/ollama4j/utils/PromptBuilder.java b/src/main/java/io/github/ollama4j/utils/PromptBuilder.java index 3345b40..fbb4fed 100644 --- a/src/main/java/io/github/ollama4j/utils/PromptBuilder.java +++ b/src/main/java/io/github/ollama4j/utils/PromptBuilder.java @@ -1,3 +1,11 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; /** diff --git a/src/main/java/io/github/ollama4j/utils/Utils.java b/src/main/java/io/github/ollama4j/utils/Utils.java index 0c6f000..afd1f3e 100644 --- a/src/main/java/io/github/ollama4j/utils/Utils.java +++ b/src/main/java/io/github/ollama4j/utils/Utils.java @@ -1,10 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.utils; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.net.URI; @@ -13,6 +18,8 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Utils { private static final Logger LOG = LoggerFactory.getLogger(Utils.class); @@ -27,26 +34,40 @@ public class Utils { return objectMapper; } - public static byte[] loadImageBytesFromUrl(String imageUrl, int connectTimeoutSeconds, int readTimeoutSeconds) + public static byte[] loadImageBytesFromUrl( + String imageUrl, int connectTimeoutSeconds, int readTimeoutSeconds) throws IOException, InterruptedException { - LOG.debug("Attempting to load image from URL: {} (connectTimeout={}s, readTimeout={}s)", imageUrl, connectTimeoutSeconds, readTimeoutSeconds); - HttpClient client = HttpClient.newBuilder() - .connectTimeout(Duration.ofSeconds(connectTimeoutSeconds)) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(imageUrl)) - .timeout(Duration.ofSeconds(readTimeoutSeconds)) - .header("User-Agent", "Mozilla/5.0") - .GET() - .build(); + LOG.debug( + "Attempting to load image from URL: {} (connectTimeout={}s, readTimeout={}s)", + imageUrl, + connectTimeoutSeconds, + readTimeoutSeconds); + HttpClient client = + HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(connectTimeoutSeconds)) + .build(); + HttpRequest request = + HttpRequest.newBuilder() + .uri(URI.create(imageUrl)) + .timeout(Duration.ofSeconds(readTimeoutSeconds)) + .header("User-Agent", "Mozilla/5.0") + .GET() + .build(); LOG.debug("Sending HTTP GET request to {}", imageUrl); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); + HttpResponse response = + client.send(request, HttpResponse.BodyHandlers.ofByteArray()); LOG.debug("Received HTTP response with status code: {}", response.statusCode()); if (response.statusCode() >= 200 && response.statusCode() < 300) { - LOG.debug("Successfully loaded image from URL: {} ({} bytes)", imageUrl, response.body().length); + LOG.debug( + "Successfully loaded image from URL: {} ({} bytes)", + imageUrl, + response.body().length); return response.body(); } else { - LOG.error("Failed to load image from URL: {}. HTTP status: {}", imageUrl, response.statusCode()); + LOG.error( + "Failed to load image from URL: {}. HTTP status: {}", + imageUrl, + response.statusCode()); throw new IOException("Failed to load image: HTTP " + response.statusCode()); } } diff --git a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java index 6d17fc9..f84a424 100644 --- a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java +++ b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java @@ -1,5 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.integrationtests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.OllamaAPI; import io.github.ollama4j.exceptions.OllamaBaseException; import io.github.ollama4j.exceptions.ToolInvocationException; @@ -15,6 +25,11 @@ import io.github.ollama4j.tools.ToolFunction; import io.github.ollama4j.tools.Tools; import io.github.ollama4j.tools.annotations.OllamaToolService; import io.github.ollama4j.utils.OptionsBuilder; +import java.io.File; +import java.io.IOException; +import java.net.ConnectException; +import java.net.URISyntaxException; +import java.util.*; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; import org.junit.jupiter.api.Order; @@ -24,17 +39,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.ollama.OllamaContainer; -import java.io.File; -import java.io.IOException; -import java.net.ConnectException; -import java.net.URISyntaxException; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; - @OllamaToolService(providers = {AnnotatedTool.class}) @TestMethodOrder(OrderAnnotation.class) - @SuppressWarnings({"HttpUrlsUsage", "SpellCheckingInspection"}) class OllamaAPIIntegrationTest { private static final Logger LOG = LoggerFactory.getLogger(OllamaAPIIntegrationTest.class); @@ -51,7 +57,8 @@ class OllamaAPIIntegrationTest { @BeforeAll static void setUp() { try { - boolean useExternalOllamaHost = Boolean.parseBoolean(System.getenv("USE_EXTERNAL_OLLAMA_HOST")); + boolean useExternalOllamaHost = + Boolean.parseBoolean(System.getenv("USE_EXTERNAL_OLLAMA_HOST")); String ollamaHost = System.getenv("OLLAMA_HOST"); if (useExternalOllamaHost) { @@ -59,7 +66,11 @@ class OllamaAPIIntegrationTest { api = new OllamaAPI(ollamaHost); } else { throw new RuntimeException( - "USE_EXTERNAL_OLLAMA_HOST is not set so, we will be using Testcontainers Ollama host for the tests now. If you would like to use an external host, please set the env var to USE_EXTERNAL_OLLAMA_HOST=true and set the env var OLLAMA_HOST=http://localhost:11435 or a different host/port."); + "USE_EXTERNAL_OLLAMA_HOST is not set so, we will be using Testcontainers" + + " Ollama host for the tests now. If you would like to use an external" + + " host, please set the env var to USE_EXTERNAL_OLLAMA_HOST=true and" + + " set the env var OLLAMA_HOST=http://localhost:11435 or a different" + + " host/port."); } } catch (Exception e) { String ollamaVersion = "0.6.1"; @@ -72,7 +83,12 @@ class OllamaAPIIntegrationTest { ollama.setPortBindings(portBindings); ollama.start(); LOG.info("Using Testcontainer Ollama host..."); - api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort)); + api = + new OllamaAPI( + "http://" + + ollama.getHost() + + ":" + + ollama.getMappedPort(internalPort)); } api.setRequestTimeoutSeconds(120); api.setNumberOfRetriesForModelPull(5); @@ -87,7 +103,8 @@ class OllamaAPIIntegrationTest { @Test @Order(1) - void testVersionAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { + void testVersionAPI() + throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { // String expectedVersion = ollama.getDockerImageName().split(":")[1]; String actualVersion = api.getVersion(); assertNotNull(actualVersion); @@ -97,14 +114,16 @@ class OllamaAPIIntegrationTest { @Test @Order(1) - void testPing() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { + void testPing() + throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { boolean pingResponse = api.ping(); assertTrue(pingResponse, "Ping should return true"); } @Test @Order(2) - void testListModelsAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { + void testListModelsAPI() + throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { // Fetch the list of models List models = api.listModels(); // Assert that the models list is not null @@ -115,7 +134,8 @@ class OllamaAPIIntegrationTest { @Test @Order(3) - void testPullModelAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { + void testPullModelAPI() + throws URISyntaxException, IOException, OllamaBaseException, InterruptedException { api.pullModel(EMBEDDING_MODEL); List models = api.listModels(); assertNotNull(models, "Models should not be null"); @@ -124,7 +144,8 @@ class OllamaAPIIntegrationTest { @Test @Order(4) - void testListModelDetails() throws IOException, OllamaBaseException, URISyntaxException, InterruptedException { + void testListModelDetails() + throws IOException, OllamaBaseException, URISyntaxException, InterruptedException { api.pullModel(EMBEDDING_MODEL); ModelDetail modelDetails = api.getModelDetails(EMBEDDING_MODEL); assertNotNull(modelDetails); @@ -149,19 +170,25 @@ class OllamaAPIIntegrationTest { throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { api.pullModel(TOOLS_MODEL); - String prompt = "The sun is shining brightly and is directly overhead at the zenith, casting my shadow over my foot, so it must be noon."; + String prompt = + "The sun is shining brightly and is directly overhead at the zenith, casting my" + + " shadow over my foot, so it must be noon."; Map format = new HashMap<>(); format.put("type", "object"); - format.put("properties", new HashMap() { - { - put("isNoon", new HashMap() { + format.put( + "properties", + new HashMap() { { - put("type", "boolean"); + put( + "isNoon", + new HashMap() { + { + put("type", "boolean"); + } + }); } }); - } - }); format.put("required", List.of("isNoon")); OllamaResult result = api.generate(TOOLS_MODEL, prompt, format); @@ -180,9 +207,14 @@ class OllamaAPIIntegrationTest { api.pullModel(GENERAL_PURPOSE_MODEL); boolean raw = false; boolean thinking = false; - OllamaResult result = api.generate(GENERAL_PURPOSE_MODEL, - "What is the capital of France? And what's France's connection with Mona Lisa?", raw, - thinking, new OptionsBuilder().build()); + OllamaResult result = + api.generate( + GENERAL_PURPOSE_MODEL, + "What is the capital of France? And what's France's connection with Mona" + + " Lisa?", + raw, + thinking, + new OptionsBuilder().build()); assertNotNull(result); assertNotNull(result.getResponse()); assertFalse(result.getResponse().isEmpty()); @@ -195,12 +227,17 @@ class OllamaAPIIntegrationTest { api.pullModel(GENERAL_PURPOSE_MODEL); boolean raw = false; StringBuffer sb = new StringBuffer(); - OllamaResult result = api.generate(GENERAL_PURPOSE_MODEL, - "What is the capital of France? And what's France's connection with Mona Lisa?", raw, - new OptionsBuilder().build(), (s) -> { - LOG.info(s); - sb.append(s); - }); + OllamaResult result = + api.generate( + GENERAL_PURPOSE_MODEL, + "What is the capital of France? And what's France's connection with Mona" + + " Lisa?", + raw, + new OptionsBuilder().build(), + (s) -> { + LOG.info(s); + sb.append(s); + }); assertNotNull(result); assertNotNull(result.getResponse()); @@ -210,17 +247,27 @@ class OllamaAPIIntegrationTest { @Test @Order(8) - void testGenerateWithOptions() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testGenerateWithOptions() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { api.pullModel(GENERAL_PURPOSE_MODEL); - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(GENERAL_PURPOSE_MODEL); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM, - "You are a helpful assistant who can generate random person's first and last names in the format [First name, Last name].") - .build(); - requestModel = builder.withMessages(requestModel.getMessages()) - .withMessage(OllamaChatMessageRole.USER, "Give me a cool name") - .withOptions(new OptionsBuilder().setTemperature(0.5f).build()).build(); + OllamaChatRequestBuilder builder = + OllamaChatRequestBuilder.getInstance(GENERAL_PURPOSE_MODEL); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.SYSTEM, + "You are a helpful assistant who can generate random person's first" + + " and last names in the format [First name, Last name].") + .build(); + requestModel = + builder.withMessages(requestModel.getMessages()) + .withMessage(OllamaChatMessageRole.USER, "Give me a cool name") + .withOptions(new OptionsBuilder().setTemperature(0.5f).build()) + .build(); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult); @@ -230,24 +277,37 @@ class OllamaAPIIntegrationTest { @Test @Order(9) - void testChatWithSystemPrompt() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testChatWithSystemPrompt() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { api.pullModel(GENERAL_PURPOSE_MODEL); String expectedResponse = "Bhai"; - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(GENERAL_PURPOSE_MODEL); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM, String.format( - "[INSTRUCTION-START] You are an obidient and helpful bot named %s. You always answer with only one word and that word is your name. [INSTRUCTION-END]", - expectedResponse)).withMessage(OllamaChatMessageRole.USER, "Who are you?") - .withOptions(new OptionsBuilder().setTemperature(0.0f).build()).build(); + OllamaChatRequestBuilder builder = + OllamaChatRequestBuilder.getInstance(GENERAL_PURPOSE_MODEL); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.SYSTEM, + String.format( + "[INSTRUCTION-START] You are an obidient and helpful bot" + + " named %s. You always answer with only one word and" + + " that word is your name. [INSTRUCTION-END]", + expectedResponse)) + .withMessage(OllamaChatMessageRole.USER, "Who are you?") + .withOptions(new OptionsBuilder().setTemperature(0.0f).build()) + .build(); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult); assertNotNull(chatResult.getResponseModel()); assertNotNull(chatResult.getResponseModel().getMessage()); assertFalse(chatResult.getResponseModel().getMessage().getContent().isBlank()); - assertTrue(chatResult.getResponseModel().getMessage().getContent().contains(expectedResponse)); + assertTrue( + chatResult.getResponseModel().getMessage().getContent().contains(expectedResponse)); assertEquals(3, chatResult.getChatHistory().size()); } @@ -255,47 +315,69 @@ class OllamaAPIIntegrationTest { @Order(10) void testChat() throws Exception { api.pullModel(THINKING_TOOL_MODEL); - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(THINKING_TOOL_MODEL); + OllamaChatRequestBuilder builder = + OllamaChatRequestBuilder.getInstance(THINKING_TOOL_MODEL); // Create the initial user question - OllamaChatRequest requestModel = builder - .withMessage(OllamaChatMessageRole.USER, "What is 1+1? Answer only in numbers.") - .build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, "What is 1+1? Answer only in numbers.") + .build(); // Start conversation with model OllamaChatResult chatResult = api.chat(requestModel, null); - assertTrue(chatResult.getChatHistory().stream().anyMatch(chat -> chat.getContent().contains("2")), + assertTrue( + chatResult.getChatHistory().stream() + .anyMatch(chat -> chat.getContent().contains("2")), "Expected chat history to contain '2'"); - requestModel = builder.withMessages(chatResult.getChatHistory()) - .withMessage(OllamaChatMessageRole.USER, "And what is its squared value?").build(); + requestModel = + builder.withMessages(chatResult.getChatHistory()) + .withMessage(OllamaChatMessageRole.USER, "And what is its squared value?") + .build(); // Continue conversation with model chatResult = api.chat(requestModel, null); - assertTrue(chatResult.getChatHistory().stream().anyMatch(chat -> chat.getContent().contains("4")), + assertTrue( + chatResult.getChatHistory().stream() + .anyMatch(chat -> chat.getContent().contains("4")), "Expected chat history to contain '4'"); // Create the next user question: the third question - requestModel = builder.withMessages(chatResult.getChatHistory()).withMessage(OllamaChatMessageRole.USER, - "What is the largest value between 2, 4 and 6?").build(); + requestModel = + builder.withMessages(chatResult.getChatHistory()) + .withMessage( + OllamaChatMessageRole.USER, + "What is the largest value between 2, 4 and 6?") + .build(); // Continue conversation with the model for the third question chatResult = api.chat(requestModel, null); // verify the result assertNotNull(chatResult, "Chat result should not be null"); - assertTrue(chatResult.getChatHistory().size() > 2, + assertTrue( + chatResult.getChatHistory().size() > 2, "Chat history should contain more than two messages"); - assertTrue(chatResult.getChatHistory().get(chatResult.getChatHistory().size() - 1).getContent() - .contains("6"), "Response should contain '6'"); + assertTrue( + chatResult + .getChatHistory() + .get(chatResult.getChatHistory().size() - 1) + .getContent() + .contains("6"), + "Response should contain '6'"); } @Test @Order(11) - void testChatWithExplicitToolDefinition() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testChatWithExplicitToolDefinition() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { // Ensure default behavior (library handles tools) for baseline assertions api.setClientHandlesTools(false); String theToolModel = TOOLS_MODEL; @@ -304,37 +386,54 @@ class OllamaAPIIntegrationTest { api.registerTool(employeeFinderTool()); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, - "Give me the ID and address of the employee Rahul Kumar.").build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "Give me the ID and address of the employee Rahul Kumar.") + .build(); requestModel.setOptions(new OptionsBuilder().setTemperature(0.9f).build().getOptionsMap()); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult, "chatResult should not be null"); assertNotNull(chatResult.getResponseModel(), "Response model should not be null"); - assertNotNull(chatResult.getResponseModel().getMessage(), "Response message should not be null"); + assertNotNull( + chatResult.getResponseModel().getMessage(), "Response message should not be null"); assertEquals( OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName(), - "Role of the response message should be ASSISTANT" - ); + "Role of the response message should be ASSISTANT"); List toolCalls = chatResult.getChatHistory().get(1).getToolCalls(); - assertEquals(1, toolCalls.size(), "There should be exactly one tool call in the second chat history message"); + assertEquals( + 1, + toolCalls.size(), + "There should be exactly one tool call in the second chat history message"); OllamaToolCallsFunction function = toolCalls.get(0).getFunction(); - assertEquals("get-employee-details", function.getName(), "Tool function name should be 'get-employee-details'"); - assertFalse(function.getArguments().isEmpty(), "Tool function arguments should not be empty"); + assertEquals( + "get-employee-details", + function.getName(), + "Tool function name should be 'get-employee-details'"); + assertFalse( + function.getArguments().isEmpty(), "Tool function arguments should not be empty"); Object employeeName = function.getArguments().get("employee-name"); assertNotNull(employeeName, "Employee name argument should not be null"); assertEquals("Rahul Kumar", employeeName, "Employee name argument should be 'Rahul Kumar'"); - assertTrue(chatResult.getChatHistory().size() > 2, "Chat history should have more than 2 messages"); - List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls(); + assertTrue( + chatResult.getChatHistory().size() > 2, + "Chat history should have more than 2 messages"); + List finalToolCalls = + chatResult.getResponseModel().getMessage().getToolCalls(); assertNull(finalToolCalls, "Final tool calls in the response message should be null"); } @Test @Order(13) - void testChatWithExplicitToolDefinitionWithClientHandlesTools() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testChatWithExplicitToolDefinitionWithClientHandlesTools() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { String theToolModel = TOOLS_MODEL; api.pullModel(theToolModel); OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(theToolModel); @@ -345,35 +444,50 @@ class OllamaAPIIntegrationTest { // enable client-handled tools so the library does not auto-execute tool calls api.setClientHandlesTools(true); - OllamaChatRequest requestModel = builder - .withMessage(OllamaChatMessageRole.USER, "Give me the ID and address of the employee Rahul Kumar.") - .build(); - requestModel.setOptions(new OptionsBuilder().setTemperature(0.9f).build().getOptionsMap()); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "Give me the ID and address of the employee Rahul Kumar.") + .build(); + requestModel.setOptions( + new OptionsBuilder().setTemperature(0.9f).build().getOptionsMap()); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult, "chatResult should not be null"); assertNotNull(chatResult.getResponseModel(), "Response model should not be null"); - assertNotNull(chatResult.getResponseModel().getMessage(), "Response message should not be null"); + assertNotNull( + chatResult.getResponseModel().getMessage(), + "Response message should not be null"); assertEquals( OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName(), - "Role of the response message should be ASSISTANT" - ); + "Role of the response message should be ASSISTANT"); // When clientHandlesTools is true, the assistant message should contain tool calls - List toolCalls = chatResult.getResponseModel().getMessage().getToolCalls(); - assertNotNull(toolCalls, "Assistant message should contain tool calls when clientHandlesTools is true"); + List toolCalls = + chatResult.getResponseModel().getMessage().getToolCalls(); + assertNotNull( + toolCalls, + "Assistant message should contain tool calls when clientHandlesTools is true"); assertFalse(toolCalls.isEmpty(), "Tool calls should not be empty"); OllamaToolCallsFunction function = toolCalls.get(0).getFunction(); - assertEquals("get-employee-details", function.getName(), "Tool function name should be 'get-employee-details'"); + assertEquals( + "get-employee-details", + function.getName(), + "Tool function name should be 'get-employee-details'"); Object employeeName = function.getArguments().get("employee-name"); assertNotNull(employeeName, "Employee name argument should not be null"); - assertEquals("Rahul Kumar", employeeName, "Employee name argument should be 'Rahul Kumar'"); + assertEquals( + "Rahul Kumar", employeeName, "Employee name argument should be 'Rahul Kumar'"); - // Since tools were not auto-executed, chat history should contain only the user and assistant messages - assertEquals(2, chatResult.getChatHistory().size(), - "Chat history should contain only user and assistant (tool call) messages when clientHandlesTools is true"); + // Since tools were not auto-executed, chat history should contain only the user and + // assistant messages + assertEquals( + 2, + chatResult.getChatHistory().size(), + "Chat history should contain only user and assistant (tool call) messages when" + + " clientHandlesTools is true"); } finally { // reset to default to avoid affecting other tests api.setClientHandlesTools(false); @@ -382,8 +496,12 @@ class OllamaAPIIntegrationTest { @Test @Order(14) - void testChatWithToolsAndStream() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testChatWithToolsAndStream() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { // Ensure default behavior (library handles tools) for streamed test api.setClientHandlesTools(false); String theToolModel = TOOLS_MODEL; @@ -393,58 +511,82 @@ class OllamaAPIIntegrationTest { api.registerTool(employeeFinderTool()); - OllamaChatRequest requestModel = builder - .withMessage(OllamaChatMessageRole.USER, "Give me the ID and address of employee Rahul Kumar") - .withKeepAlive("0m").withOptions(new OptionsBuilder().setTemperature(0.9f).build()) - .build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "Give me the ID and address of employee Rahul Kumar") + .withKeepAlive("0m") + .withOptions(new OptionsBuilder().setTemperature(0.9f).build()) + .build(); - OllamaChatResult chatResult = api.chat(requestModel, new OllamaChatStreamObserver((s) -> { - LOG.info(s.toUpperCase()); - }, (s) -> { - LOG.info(s.toLowerCase()); - })); + OllamaChatResult chatResult = + api.chat( + requestModel, + new OllamaChatStreamObserver( + (s) -> { + LOG.info(s.toUpperCase()); + }, + (s) -> { + LOG.info(s.toLowerCase()); + })); assertNotNull(chatResult, "chatResult should not be null"); assertNotNull(chatResult.getResponseModel(), "Response model should not be null"); - assertNotNull(chatResult.getResponseModel().getMessage(), "Response message should not be null"); + assertNotNull( + chatResult.getResponseModel().getMessage(), "Response message should not be null"); assertEquals( OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName(), - "Role of the response message should be ASSISTANT" - ); + "Role of the response message should be ASSISTANT"); List toolCalls = chatResult.getChatHistory().get(1).getToolCalls(); - assertEquals(1, toolCalls.size(), "There should be exactly one tool call in the second chat history message"); + assertEquals( + 1, + toolCalls.size(), + "There should be exactly one tool call in the second chat history message"); OllamaToolCallsFunction function = toolCalls.get(0).getFunction(); - assertEquals("get-employee-details", function.getName(), "Tool function name should be 'get-employee-details'"); - assertFalse(function.getArguments().isEmpty(), "Tool function arguments should not be empty"); + assertEquals( + "get-employee-details", + function.getName(), + "Tool function name should be 'get-employee-details'"); + assertFalse( + function.getArguments().isEmpty(), "Tool function arguments should not be empty"); Object employeeName = function.getArguments().get("employee-name"); assertNotNull(employeeName, "Employee name argument should not be null"); assertEquals("Rahul Kumar", employeeName, "Employee name argument should be 'Rahul Kumar'"); - assertTrue(chatResult.getChatHistory().size() > 2, "Chat history should have more than 2 messages"); - List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls(); + assertTrue( + chatResult.getChatHistory().size() > 2, + "Chat history should have more than 2 messages"); + List finalToolCalls = + chatResult.getResponseModel().getMessage().getToolCalls(); assertNull(finalToolCalls, "Final tool calls in the response message should be null"); } @Test @Order(12) - void testChatWithAnnotatedToolsAndSingleParam() throws OllamaBaseException, IOException, InterruptedException, - URISyntaxException, ToolInvocationException { + void testChatWithAnnotatedToolsAndSingleParam() + throws OllamaBaseException, + IOException, + InterruptedException, + URISyntaxException, + ToolInvocationException { String theToolModel = TOOLS_MODEL; api.pullModel(theToolModel); OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(theToolModel); api.registerAnnotatedTools(); - OllamaChatRequest requestModel = builder - .withMessage(OllamaChatMessageRole.USER, - "Compute the most important constant in the world using 5 digits") - .build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "Compute the most important constant in the world using 5 digits") + .build(); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult); assertNotNull(chatResult.getResponseModel()); assertNotNull(chatResult.getResponseModel().getMessage()); - assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), + assertEquals( + OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName()); List toolCalls = chatResult.getChatHistory().get(1).getToolCalls(); assertEquals(1, toolCalls.size()); @@ -455,29 +597,38 @@ class OllamaAPIIntegrationTest { assertNotNull(noOfDigits); assertEquals("5", noOfDigits.toString()); assertTrue(chatResult.getChatHistory().size() > 2); - List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls(); + List finalToolCalls = + chatResult.getResponseModel().getMessage().getToolCalls(); assertNull(finalToolCalls); } @Test @Order(13) - void testChatWithAnnotatedToolsAndMultipleParams() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testChatWithAnnotatedToolsAndMultipleParams() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { String theToolModel = TOOLS_MODEL; api.pullModel(theToolModel); OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(theToolModel); api.registerAnnotatedTools(new AnnotatedTool()); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, - "Greet Rahul with a lot of hearts and respond to me with count of emojis that have been in used in the greeting") - .build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "Greet Rahul with a lot of hearts and respond to me with count of" + + " emojis that have been in used in the greeting") + .build(); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult); assertNotNull(chatResult.getResponseModel()); assertNotNull(chatResult.getResponseModel().getMessage()); - assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), + assertEquals( + OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName()); List toolCalls = chatResult.getChatHistory().get(1).getToolCalls(); assertEquals(1, toolCalls.size()); @@ -491,28 +642,42 @@ class OllamaAPIIntegrationTest { assertNotNull(numberOfHearts); assertTrue(Integer.parseInt(numberOfHearts.toString()) > 1); assertTrue(chatResult.getChatHistory().size() > 2); - List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls(); + List finalToolCalls = + chatResult.getResponseModel().getMessage().getToolCalls(); assertNull(finalToolCalls); } @Test @Order(15) - void testChatWithStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, - ToolInvocationException { + void testChatWithStream() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { api.deregisterTools(); api.pullModel(GENERAL_PURPOSE_MODEL); - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(GENERAL_PURPOSE_MODEL); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, - "What is the capital of France? And what's France's connection with Mona Lisa?") - .build(); + OllamaChatRequestBuilder builder = + OllamaChatRequestBuilder.getInstance(GENERAL_PURPOSE_MODEL); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "What is the capital of France? And what's France's connection with" + + " Mona Lisa?") + .build(); requestModel.setThink(false); StringBuffer sb = new StringBuffer(); - OllamaChatResult chatResult = api.chat(requestModel, new OllamaChatStreamObserver((s) -> { - LOG.info(s.toUpperCase()); - }, (s) -> { - LOG.info(s.toLowerCase()); - })); + OllamaChatResult chatResult = + api.chat( + requestModel, + new OllamaChatStreamObserver( + (s) -> { + LOG.info(s.toUpperCase()); + }, + (s) -> { + LOG.info(s.toLowerCase()); + })); assertNotNull(chatResult); assertNotNull(chatResult.getResponseModel()); assertNotNull(chatResult.getResponseModel().getMessage()); @@ -522,40 +687,64 @@ class OllamaAPIIntegrationTest { @Test @Order(15) - void testChatWithThinkingAndStream() throws OllamaBaseException, IOException, URISyntaxException, - InterruptedException, ToolInvocationException { + void testChatWithThinkingAndStream() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { api.pullModel(THINKING_TOOL_MODEL); - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(THINKING_TOOL_MODEL); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, - "What is the capital of France? And what's France's connection with Mona Lisa?") - .withThinking(true).withKeepAlive("0m").build(); + OllamaChatRequestBuilder builder = + OllamaChatRequestBuilder.getInstance(THINKING_TOOL_MODEL); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "What is the capital of France? And what's France's connection with" + + " Mona Lisa?") + .withThinking(true) + .withKeepAlive("0m") + .build(); StringBuffer sb = new StringBuffer(); - OllamaChatResult chatResult = api.chat(requestModel, new OllamaChatStreamObserver((s) -> { - LOG.info(s.toUpperCase()); - }, (s) -> { - LOG.info(s.toLowerCase()); - })); + OllamaChatResult chatResult = + api.chat( + requestModel, + new OllamaChatStreamObserver( + (s) -> { + LOG.info(s.toUpperCase()); + }, + (s) -> { + LOG.info(s.toLowerCase()); + })); assertNotNull(chatResult); assertNotNull(chatResult.getResponseModel()); assertNotNull(chatResult.getResponseModel().getMessage()); assertNotNull(chatResult.getResponseModel().getMessage().getContent()); - assertEquals(sb.toString(), chatResult.getResponseModel().getMessage().getThinking() - + chatResult.getResponseModel().getMessage().getContent()); + assertEquals( + sb.toString(), + chatResult.getResponseModel().getMessage().getThinking() + + chatResult.getResponseModel().getMessage().getContent()); } @Test @Order(10) - void testChatWithImageFromURL() throws OllamaBaseException, IOException, InterruptedException, - URISyntaxException, ToolInvocationException { + void testChatWithImageFromURL() + throws OllamaBaseException, + IOException, + InterruptedException, + URISyntaxException, + ToolInvocationException { api.pullModel(VISION_MODEL); OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(VISION_MODEL); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, - "What's in the picture?", Collections.emptyList(), - "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg") - .build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "What's in the picture?", + Collections.emptyList(), + "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg") + .build(); api.registerAnnotatedTools(new OllamaAPIIntegrationTest()); OllamaChatResult chatResult = api.chat(requestModel, null); @@ -564,21 +753,31 @@ class OllamaAPIIntegrationTest { @Test @Order(10) - void testChatWithImageFromFileWithHistoryRecognition() throws OllamaBaseException, IOException, - URISyntaxException, InterruptedException, ToolInvocationException { + void testChatWithImageFromFileWithHistoryRecognition() + throws OllamaBaseException, + IOException, + URISyntaxException, + InterruptedException, + ToolInvocationException { api.pullModel(VISION_MODEL); OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(VISION_MODEL); - OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, - "What's in the picture?", Collections.emptyList(), - List.of(getImageFileFromClasspath("emoji-smile.jpeg"))).build(); + OllamaChatRequest requestModel = + builder.withMessage( + OllamaChatMessageRole.USER, + "What's in the picture?", + Collections.emptyList(), + List.of(getImageFileFromClasspath("emoji-smile.jpeg"))) + .build(); OllamaChatResult chatResult = api.chat(requestModel, null); assertNotNull(chatResult); assertNotNull(chatResult.getResponseModel()); builder.reset(); - requestModel = builder.withMessages(chatResult.getChatHistory()) - .withMessage(OllamaChatMessageRole.USER, "What's the color?").build(); + requestModel = + builder.withMessages(chatResult.getChatHistory()) + .withMessage(OllamaChatMessageRole.USER, "What's the color?") + .build(); chatResult = api.chat(requestModel, null); assertNotNull(chatResult); @@ -591,9 +790,15 @@ class OllamaAPIIntegrationTest { throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { api.pullModel(VISION_MODEL); - OllamaResult result = api.generateWithImages(VISION_MODEL, "What is in this image?", - List.of("https://i.pinimg.com/736x/f9/4e/cb/f94ecba040696a3a20b484d2e15159ec.jpg"), - new OptionsBuilder().build(), null, null); + OllamaResult result = + api.generateWithImages( + VISION_MODEL, + "What is in this image?", + List.of( + "https://i.pinimg.com/736x/f9/4e/cb/f94ecba040696a3a20b484d2e15159ec.jpg"), + new OptionsBuilder().build(), + null, + null); assertNotNull(result); assertNotNull(result.getResponse()); assertFalse(result.getResponse().isEmpty()); @@ -606,8 +811,14 @@ class OllamaAPIIntegrationTest { api.pullModel(VISION_MODEL); File imageFile = getImageFileFromClasspath("roses.jpg"); try { - OllamaResult result = api.generateWithImages(VISION_MODEL, "What is in this image?", - List.of(imageFile), new OptionsBuilder().build(), null, null); + OllamaResult result = + api.generateWithImages( + VISION_MODEL, + "What is in this image?", + List.of(imageFile), + new OptionsBuilder().build(), + null, + null); assertNotNull(result); assertNotNull(result.getResponse()); assertFalse(result.getResponse().isEmpty()); @@ -626,17 +837,17 @@ class OllamaAPIIntegrationTest { StringBuffer sb = new StringBuffer(); - OllamaResult result = api.generateWithImages( - VISION_MODEL, - "What is in this image?", - List.of(imageFile), - new OptionsBuilder().build(), - null, - (s) -> { - LOG.info(s); - sb.append(s); - } - ); + OllamaResult result = + api.generateWithImages( + VISION_MODEL, + "What is in this image?", + List.of(imageFile), + new OptionsBuilder().build(), + null, + (s) -> { + LOG.info(s); + sb.append(s); + }); assertNotNull(result); assertNotNull(result.getResponse()); assertFalse(result.getResponse().isEmpty()); @@ -652,8 +863,13 @@ class OllamaAPIIntegrationTest { boolean raw = false; boolean think = true; - OllamaResult result = api.generate(THINKING_TOOL_MODEL, "Who are you?", raw, think, - new OptionsBuilder().build()); + OllamaResult result = + api.generate( + THINKING_TOOL_MODEL, + "Who are you?", + raw, + think, + new OptionsBuilder().build()); assertNotNull(result); assertNotNull(result.getResponse()); assertFalse(result.getResponse().isEmpty()); @@ -670,17 +886,20 @@ class OllamaAPIIntegrationTest { boolean raw = false; StringBuffer sb = new StringBuffer(); - OllamaResult result = api.generate(THINKING_TOOL_MODEL, "Who are you?", raw, - new OptionsBuilder().build(), - (thinkingToken) -> { - sb.append(thinkingToken); - LOG.info(thinkingToken); - }, - (resToken) -> { - sb.append(resToken); - LOG.info(resToken); - } - ); + OllamaResult result = + api.generate( + THINKING_TOOL_MODEL, + "Who are you?", + raw, + new OptionsBuilder().build(), + (thinkingToken) -> { + sb.append(thinkingToken); + LOG.info(thinkingToken); + }, + (resToken) -> { + sb.append(resToken); + LOG.info(resToken); + }); assertNotNull(result); assertNotNull(result.getResponse()); assertFalse(result.getResponse().isEmpty()); @@ -698,58 +917,113 @@ class OllamaAPIIntegrationTest { return Tools.ToolSpecification.builder() .functionName("get-employee-details") .functionDescription("Get details for a person or an employee") - .toolPrompt(Tools.PromptFuncDefinition.builder().type("function") - .function(Tools.PromptFuncDefinition.PromptFuncSpec.builder() - .name("get-employee-details") - .description("Get details for a person or an employee") - .parameters(Tools.PromptFuncDefinition.Parameters - .builder().type("object") - .properties(new Tools.PropsBuilder() - .withProperty("employee-name", - Tools.PromptFuncDefinition.Property + .toolPrompt( + Tools.PromptFuncDefinition.builder() + .type("function") + .function( + Tools.PromptFuncDefinition.PromptFuncSpec.builder() + .name("get-employee-details") + .description( + "Get details for a person or an employee") + .parameters( + Tools.PromptFuncDefinition.Parameters .builder() - .type("string") - .description("The name of the employee, e.g. John Doe") - .required(true) - .build()) - .withProperty("employee-address", - Tools.PromptFuncDefinition.Property - .builder() - .type("string") - .description("The address of the employee, Always eturns a random address. For example, Church St, Bengaluru, India") - .required(true) - .build()) - .withProperty("employee-phone", - Tools.PromptFuncDefinition.Property - .builder() - .type("string") - .description("The phone number of the employee. Always returns a random phone number. For example, 9911002233") - .required(true) + .type("object") + .properties( + new Tools.PropsBuilder() + .withProperty( + "employee-name", + Tools + .PromptFuncDefinition + .Property + .builder() + .type( + "string") + .description( + "The name" + + " of the" + + " employee," + + " e.g." + + " John" + + " Doe") + .required( + true) + .build()) + .withProperty( + "employee-address", + Tools + .PromptFuncDefinition + .Property + .builder() + .type( + "string") + .description( + "The address" + + " of the" + + " employee," + + " Always" + + " eturns" + + " a random" + + " address." + + " For example," + + " Church" + + " St, Bengaluru," + + " India") + .required( + true) + .build()) + .withProperty( + "employee-phone", + Tools + .PromptFuncDefinition + .Property + .builder() + .type( + "string") + .description( + "The phone" + + " number" + + " of the" + + " employee." + + " Always" + + " returns" + + " a random" + + " phone" + + " number." + + " For example," + + " 9911002233") + .required( + true) + .build()) + .build()) + .required(List.of("employee-name")) .build()) .build()) - .required(List.of("employee-name")) - .build()) .build()) - .build()) - .toolFunction(new ToolFunction() { - @Override - public Object apply(Map arguments) { - LOG.info("Invoking employee finder tool with arguments: {}", arguments); - String employeeName = arguments.get("employee-name").toString(); - String address = null; - String phone = null; - if (employeeName.equalsIgnoreCase("Rahul Kumar")) { - address = "Pune, Maharashtra, India"; - phone = "9911223344"; - } else { - address = "Karol Bagh, Delhi, India"; - phone = "9911002233"; - } - // perform DB operations here - return String.format( - "Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", - UUID.randomUUID(), employeeName, address, phone); - } - }).build(); + .toolFunction( + new ToolFunction() { + @Override + public Object apply(Map arguments) { + LOG.info( + "Invoking employee finder tool with arguments: {}", + arguments); + String employeeName = arguments.get("employee-name").toString(); + String address = null; + String phone = null; + if (employeeName.equalsIgnoreCase("Rahul Kumar")) { + address = "Pune, Maharashtra, India"; + phone = "9911223344"; + } else { + address = "Karol Bagh, Delhi, India"; + phone = "9911002233"; + } + // perform DB operations here + return String.format( + "Employee Details {ID: %s, Name: %s, Address: %s, Phone:" + + " %s}", + UUID.randomUUID(), employeeName, address, phone); + } + }) + .build(); } } diff --git a/src/test/java/io/github/ollama4j/integrationtests/WithAuth.java b/src/test/java/io/github/ollama4j/integrationtests/WithAuth.java index 821a23e..08a1bc9 100644 --- a/src/test/java/io/github/ollama4j/integrationtests/WithAuth.java +++ b/src/test/java/io/github/ollama4j/integrationtests/WithAuth.java @@ -1,10 +1,28 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.integrationtests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.OllamaAPI; import io.github.ollama4j.exceptions.OllamaBaseException; import io.github.ollama4j.models.response.OllamaResult; import io.github.ollama4j.samples.AnnotatedTool; import io.github.ollama4j.tools.annotations.OllamaToolService; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URISyntaxException; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; import org.junit.jupiter.api.Order; @@ -19,20 +37,14 @@ import org.testcontainers.ollama.OllamaContainer; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.Duration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; - @OllamaToolService(providers = {AnnotatedTool.class}) @TestMethodOrder(OrderAnnotation.class) -@SuppressWarnings({"HttpUrlsUsage", "SpellCheckingInspection", "resource", "ResultOfMethodCallIgnored"}) +@SuppressWarnings({ + "HttpUrlsUsage", + "SpellCheckingInspection", + "resource", + "ResultOfMethodCallIgnored" +}) public class WithAuth { private static final Logger LOG = LoggerFactory.getLogger(WithAuth.class); @@ -42,8 +54,7 @@ public class WithAuth { private static final String NGINX_VERSION = "nginx:1.23.4-alpine"; private static final String BEARER_AUTH_TOKEN = "secret-token"; private static final String GENERAL_PURPOSE_MODEL = "gemma3:270m"; -// private static final String THINKING_MODEL = "gpt-oss:20b"; - + // private static final String THINKING_MODEL = "gpt-oss:20b"; private static OllamaContainer ollama; private static GenericContainer nginx; @@ -63,43 +74,48 @@ public class WithAuth { api.setRequestTimeoutSeconds(120); api.setNumberOfRetriesForModelPull(3); - String ollamaUrl = "http://" + ollama.getHost() + ":" + ollama.getMappedPort(OLLAMA_INTERNAL_PORT); + String ollamaUrl = + "http://" + ollama.getHost() + ":" + ollama.getMappedPort(OLLAMA_INTERNAL_PORT); String nginxUrl = "http://" + nginx.getHost() + ":" + nginx.getMappedPort(NGINX_PORT); LOG.info( - "The Ollama service is now accessible via the Nginx proxy with bearer-auth authentication mode.\n" + - "→ Ollama URL: {}\n" + - "→ Proxy URL: {}", - ollamaUrl, nginxUrl - ); + "The Ollama service is now accessible via the Nginx proxy with bearer-auth" + + " authentication mode.\n" + + "→ Ollama URL: {}\n" + + "→ Proxy URL: {}", + ollamaUrl, + nginxUrl); LOG.info("OllamaAPI initialized with bearer auth token: {}", BEARER_AUTH_TOKEN); } private static OllamaContainer createOllamaContainer() { - return new OllamaContainer("ollama/ollama:" + OLLAMA_VERSION).withExposedPorts(OLLAMA_INTERNAL_PORT); + return new OllamaContainer("ollama/ollama:" + OLLAMA_VERSION) + .withExposedPorts(OLLAMA_INTERNAL_PORT); } private static String generateNginxConfig(int ollamaPort) { - return String.format("events {}\n" + - "\n" + - "http {\n" + - " server {\n" + - " listen 80;\n" + - "\n" + - " location / {\n" + - " set $auth_header $http_authorization;\n" + - "\n" + - " if ($auth_header != \"Bearer secret-token\") {\n" + - " return 401;\n" + - " }\n" + - "\n" + - " proxy_pass http://host.docker.internal:%s/;\n" + - " proxy_set_header Host $host;\n" + - " proxy_set_header X-Real-IP $remote_addr;\n" + - " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n" + - " proxy_set_header X-Forwarded-Proto $scheme;\n" + - " }\n" + - " }\n" + - "}\n", ollamaPort); + return String.format( + "events {}\n" + + "\n" + + "http {\n" + + " server {\n" + + " listen 80;\n" + + "\n" + + " location / {\n" + + " set $auth_header $http_authorization;\n" + + "\n" + + " if ($auth_header != \"Bearer secret-token\") {\n" + + " return 401;\n" + + " }\n" + + "\n" + + " proxy_pass http://host.docker.internal:%s/;\n" + + " proxy_set_header Host $host;\n" + + " proxy_set_header X-Real-IP $remote_addr;\n" + + " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n" + + " proxy_set_header X-Forwarded-Proto $scheme;\n" + + " }\n" + + " }\n" + + "}\n", + ollamaPort); } public static GenericContainer createNginxContainer(int ollamaPort) { @@ -117,14 +133,12 @@ public class WithAuth { .withExposedPorts(NGINX_PORT) .withCopyFileToContainer( MountableFile.forHostPath(nginxConf.getAbsolutePath()), - "/etc/nginx/nginx.conf" - ) + "/etc/nginx/nginx.conf") .withExtraHost("host.docker.internal", "host-gateway") .waitingFor( Wait.forHttp("/") .forStatusCode(401) - .withStartupTimeout(Duration.ofSeconds(30)) - ); + .withStartupTimeout(Duration.ofSeconds(30))); } catch (IOException e) { throw new RuntimeException("Failed to create nginx.conf", e); } @@ -134,14 +148,18 @@ public class WithAuth { @Order(1) void testOllamaBehindProxy() { api.setBearerAuth(BEARER_AUTH_TOKEN); - assertTrue(api.ping(), "Expected OllamaAPI to successfully ping through NGINX with valid auth token."); + assertTrue( + api.ping(), + "Expected OllamaAPI to successfully ping through NGINX with valid auth token."); } @Test @Order(1) void testWithWrongToken() { api.setBearerAuth("wrong-token"); - assertFalse(api.ping(), "Expected OllamaAPI ping to fail through NGINX with an invalid auth token."); + assertFalse( + api.ping(), + "Expected OllamaAPI ping to fail through NGINX with an invalid auth token."); } @Test @@ -152,19 +170,25 @@ public class WithAuth { String model = GENERAL_PURPOSE_MODEL; api.pullModel(model); - String prompt = "The sun is shining brightly and is directly overhead at the zenith, casting my shadow over my foot, so it must be noon."; + String prompt = + "The sun is shining brightly and is directly overhead at the zenith, casting my" + + " shadow over my foot, so it must be noon."; Map format = new HashMap<>(); format.put("type", "object"); - format.put("properties", new HashMap() { - { - put("isNoon", new HashMap() { + format.put( + "properties", + new HashMap() { { - put("type", "boolean"); + put( + "isNoon", + new HashMap() { + { + put("type", "boolean"); + } + }); } }); - } - }); format.put("required", List.of("isNoon")); OllamaResult result = api.generate(model, prompt, format); diff --git a/src/test/java/io/github/ollama4j/samples/AnnotatedTool.java b/src/test/java/io/github/ollama4j/samples/AnnotatedTool.java index 243a9fe..4e458d1 100644 --- a/src/test/java/io/github/ollama4j/samples/AnnotatedTool.java +++ b/src/test/java/io/github/ollama4j/samples/AnnotatedTool.java @@ -1,21 +1,35 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.samples; import io.github.ollama4j.tools.annotations.ToolProperty; import io.github.ollama4j.tools.annotations.ToolSpec; - import java.math.BigDecimal; public class AnnotatedTool { @ToolSpec(desc = "Computes the most important constant all around the globe!") - public String computeImportantConstant(@ToolProperty(name = "noOfDigits", desc = "Number of digits that shall be returned") Integer noOfDigits) { + public String computeImportantConstant( + @ToolProperty(name = "noOfDigits", desc = "Number of digits that shall be returned") + Integer noOfDigits) { return BigDecimal.valueOf((long) (Math.random() * 1000000L), noOfDigits).toString(); } @ToolSpec(desc = "Says hello to a friend!") - public String sayHello(@ToolProperty(name = "name", desc = "Name of the friend") String name, @ToolProperty(name = "numberOfHearts", desc = "number of heart emojis that should be used", required = false) Integer numberOfHearts) { + public String sayHello( + @ToolProperty(name = "name", desc = "Name of the friend") String name, + @ToolProperty( + name = "numberOfHearts", + desc = "number of heart emojis that should be used", + required = false) + Integer numberOfHearts) { String hearts = numberOfHearts != null ? "♡".repeat(numberOfHearts) : ""; return "Hello, " + name + "! " + hearts; } - } diff --git a/src/test/java/io/github/ollama4j/unittests/TestAnnotations.java b/src/test/java/io/github/ollama4j/unittests/TestAnnotations.java index 6f2d18c..4401253 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestAnnotations.java +++ b/src/test/java/io/github/ollama4j/unittests/TestAnnotations.java @@ -1,25 +1,32 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.tools.annotations.OllamaToolService; import io.github.ollama4j.tools.annotations.ToolProperty; import io.github.ollama4j.tools.annotations.ToolSpec; -import org.junit.jupiter.api.Test; - import java.lang.reflect.Method; import java.lang.reflect.Parameter; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class TestAnnotations { @OllamaToolService(providers = {SampleProvider.class}) - static class SampleToolService { - } + static class SampleToolService {} static class SampleProvider { @ToolSpec(name = "sum", desc = "adds two numbers") - public int sum(@ToolProperty(name = "a", desc = "first addend") int a, - @ToolProperty(name = "b", desc = "second addend", required = false) int b) { + public int sum( + @ToolProperty(name = "a", desc = "first addend") int a, + @ToolProperty(name = "b", desc = "second addend", required = false) int b) { return a + b; } } @@ -28,7 +35,7 @@ class TestAnnotations { void testOllamaToolServiceProvidersPresent() throws Exception { OllamaToolService ann = SampleToolService.class.getAnnotation(OllamaToolService.class); assertNotNull(ann); - assertArrayEquals(new Class[]{SampleProvider.class}, ann.providers()); + assertArrayEquals(new Class[] {SampleProvider.class}, ann.providers()); } @Test diff --git a/src/test/java/io/github/ollama4j/unittests/TestAuth.java b/src/test/java/io/github/ollama4j/unittests/TestAuth.java index f5ab2d7..0078509 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestAuth.java +++ b/src/test/java/io/github/ollama4j/unittests/TestAuth.java @@ -1,12 +1,20 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import io.github.ollama4j.models.request.BasicAuth; import io.github.ollama4j.models.request.BearerAuth; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - class TestAuth { @Test diff --git a/src/test/java/io/github/ollama4j/unittests/TestBooleanToJsonFormatFlagSerializer.java b/src/test/java/io/github/ollama4j/unittests/TestBooleanToJsonFormatFlagSerializer.java index 7aeb915..cb1643a 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestBooleanToJsonFormatFlagSerializer.java +++ b/src/test/java/io/github/ollama4j/unittests/TestBooleanToJsonFormatFlagSerializer.java @@ -1,5 +1,15 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -8,8 +18,6 @@ import io.github.ollama4j.utils.BooleanToJsonFormatFlagSerializer; import io.github.ollama4j.utils.Utils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - class TestBooleanToJsonFormatFlagSerializer { static class Holder { diff --git a/src/test/java/io/github/ollama4j/unittests/TestFileToBase64Serializer.java b/src/test/java/io/github/ollama4j/unittests/TestFileToBase64Serializer.java index 15b2298..e8a16f1 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestFileToBase64Serializer.java +++ b/src/test/java/io/github/ollama4j/unittests/TestFileToBase64Serializer.java @@ -1,15 +1,22 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.github.ollama4j.utils.FileToBase64Serializer; import io.github.ollama4j.utils.Utils; -import org.junit.jupiter.api.Test; - import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class TestFileToBase64Serializer { diff --git a/src/test/java/io/github/ollama4j/unittests/TestMockedAPIs.java b/src/test/java/io/github/ollama4j/unittests/TestMockedAPIs.java index 3795c4d..4944b32 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestMockedAPIs.java +++ b/src/test/java/io/github/ollama4j/unittests/TestMockedAPIs.java @@ -1,5 +1,17 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.*; + import io.github.ollama4j.OllamaAPI; import io.github.ollama4j.exceptions.OllamaBaseException; import io.github.ollama4j.exceptions.RoleNotFoundException; @@ -12,18 +24,13 @@ import io.github.ollama4j.models.response.OllamaAsyncResultStreamer; import io.github.ollama4j.models.response.OllamaResult; import io.github.ollama4j.types.OllamaModelType; import io.github.ollama4j.utils.OptionsBuilder; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; class TestMockedAPIs { @Test @@ -54,7 +61,12 @@ class TestMockedAPIs { @Test void testCreateModel() { OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); - CustomModelRequest customModelRequest = CustomModelRequest.builder().model("mario").from("llama3.2:latest").system("You are Mario from Super Mario Bros.").build(); + CustomModelRequest customModelRequest = + CustomModelRequest.builder() + .model("mario") + .from("llama3.2:latest") + .system("You are Mario from Super Mario Bros.") + .build(); try { doNothing().when(ollamaAPI).createModel(customModelRequest); ollamaAPI.createModel(customModelRequest); @@ -128,7 +140,8 @@ class TestMockedAPIs { String model = OllamaModelType.LLAMA2; List inputs = List.of("some prompt text"); try { - when(ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs))).thenReturn(new OllamaEmbedResponseModel()); + when(ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs))) + .thenReturn(new OllamaEmbedResponseModel()); ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs)); verify(ollamaAPI, times(1)).embed(new OllamaEmbedRequestModel(model, inputs)); } catch (IOException | OllamaBaseException | InterruptedException e) { @@ -146,7 +159,8 @@ class TestMockedAPIs { when(ollamaAPI.generate(model, prompt, false, false, optionsBuilder.build())) .thenReturn(new OllamaResult("", "", 0, 200)); ollamaAPI.generate(model, prompt, false, false, optionsBuilder.build()); - verify(ollamaAPI, times(1)).generate(model, prompt, false, false, optionsBuilder.build()); + verify(ollamaAPI, times(1)) + .generate(model, prompt, false, false, optionsBuilder.build()); } catch (IOException | OllamaBaseException | InterruptedException e) { throw new RuntimeException(e); } @@ -159,13 +173,28 @@ class TestMockedAPIs { String prompt = "some prompt text"; try { when(ollamaAPI.generateWithImages( - model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null)) + model, + prompt, + Collections.emptyList(), + new OptionsBuilder().build(), + null, + null)) .thenReturn(new OllamaResult("", "", 0, 200)); ollamaAPI.generateWithImages( - model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null); + model, + prompt, + Collections.emptyList(), + new OptionsBuilder().build(), + null, + null); verify(ollamaAPI, times(1)) .generateWithImages( - model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null); + model, + prompt, + Collections.emptyList(), + new OptionsBuilder().build(), + null, + null); } catch (Exception e) { throw new RuntimeException(e); } @@ -178,13 +207,28 @@ class TestMockedAPIs { String prompt = "some prompt text"; try { when(ollamaAPI.generateWithImages( - model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null)) + model, + prompt, + Collections.emptyList(), + new OptionsBuilder().build(), + null, + null)) .thenReturn(new OllamaResult("", "", 0, 200)); ollamaAPI.generateWithImages( - model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null); + model, + prompt, + Collections.emptyList(), + new OptionsBuilder().build(), + null, + null); verify(ollamaAPI, times(1)) .generateWithImages( - model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null); + model, + prompt, + Collections.emptyList(), + new OptionsBuilder().build(), + null, + null); } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) { throw new RuntimeException(e); } @@ -229,7 +273,8 @@ class TestMockedAPIs { OllamaAPI ollamaAPI = mock(OllamaAPI.class); String roleName = "non-existing-role"; try { - when(ollamaAPI.getRole(roleName)).thenThrow(new RoleNotFoundException("Role not found")); + when(ollamaAPI.getRole(roleName)) + .thenThrow(new RoleNotFoundException("Role not found")); } catch (RoleNotFoundException exception) { throw new RuntimeException("Failed to run test: testGetRoleNotFound"); } diff --git a/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessage.java b/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessage.java index cd44ea9..b2b7925 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessage.java +++ b/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessage.java @@ -1,23 +1,33 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import io.github.ollama4j.models.chat.OllamaChatMessage; import io.github.ollama4j.models.chat.OllamaChatMessageRole; import org.json.JSONObject; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - class TestOllamaChatMessage { @Test void testToStringProducesJson() { - OllamaChatMessage msg = new OllamaChatMessage(OllamaChatMessageRole.USER, "hello", null, null, null); + OllamaChatMessage msg = + new OllamaChatMessage(OllamaChatMessageRole.USER, "hello", null, null, null); String json = msg.toString(); JSONObject obj = new JSONObject(json); assertEquals("user", obj.getString("role")); assertEquals("hello", obj.getString("content")); assertTrue(obj.has("tool_calls")); - // thinking and images may or may not be present depending on null handling, just ensure no exception + // thinking and images may or may not be present depending on null handling, just ensure no + // exception } } diff --git a/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessageRole.java b/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessageRole.java index 6bdbc03..e53179b 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessageRole.java +++ b/src/test/java/io/github/ollama4j/unittests/TestOllamaChatMessageRole.java @@ -1,12 +1,19 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.exceptions.RoleNotFoundException; import io.github.ollama4j.models.chat.OllamaChatMessageRole; -import org.junit.jupiter.api.Test; - import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class TestOllamaChatMessageRole { @@ -33,12 +40,14 @@ class TestOllamaChatMessageRole { void testCustomRoleCreationAndLookup() throws Exception { OllamaChatMessageRole custom = OllamaChatMessageRole.newCustomRole("myrole"); assertEquals("myrole", custom.toString()); - // custom roles are registered globally (per current implementation), so lookup should succeed + // custom roles are registered globally (per current implementation), so lookup should + // succeed assertSame(custom, OllamaChatMessageRole.getRole("myrole")); } @Test void testGetRoleThrowsOnUnknown() { - assertThrows(RoleNotFoundException.class, () -> OllamaChatMessageRole.getRole("does-not-exist")); + assertThrows( + RoleNotFoundException.class, () -> OllamaChatMessageRole.getRole("does-not-exist")); } } diff --git a/src/test/java/io/github/ollama4j/unittests/TestOllamaChatRequestBuilder.java b/src/test/java/io/github/ollama4j/unittests/TestOllamaChatRequestBuilder.java index 6c06864..af29841 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestOllamaChatRequestBuilder.java +++ b/src/test/java/io/github/ollama4j/unittests/TestOllamaChatRequestBuilder.java @@ -1,22 +1,30 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.models.chat.OllamaChatMessage; import io.github.ollama4j.models.chat.OllamaChatMessageRole; import io.github.ollama4j.models.chat.OllamaChatRequest; import io.github.ollama4j.models.chat.OllamaChatRequestBuilder; -import org.junit.jupiter.api.Test; - import java.util.Collections; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class TestOllamaChatRequestBuilder { @Test void testResetClearsMessagesButKeepsModelAndThink() { - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("my-model") - .withThinking(true) - .withMessage(OllamaChatMessageRole.USER, "first"); + OllamaChatRequestBuilder builder = + OllamaChatRequestBuilder.getInstance("my-model") + .withThinking(true) + .withMessage(OllamaChatMessageRole.USER, "first"); OllamaChatRequest beforeReset = builder.build(); assertEquals("my-model", beforeReset.getModel()); @@ -33,18 +41,23 @@ class TestOllamaChatRequestBuilder { @Test void testImageUrlFailuresAreIgnoredAndDoNotBreakBuild() { - // Provide a syntactically invalid URL, but catch the expected exception to verify builder robustness + // Provide a syntactically invalid URL, but catch the expected exception to verify builder + // robustness OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("m"); try { - builder.withMessage(OllamaChatMessageRole.USER, "hi", Collections.emptyList(), + builder.withMessage( + OllamaChatMessageRole.USER, + "hi", + Collections.emptyList(), "ht!tp://invalid url \n not a uri"); fail("Expected IllegalArgumentException due to malformed URL"); } catch (IllegalArgumentException e) { // Expected: malformed URL should throw IllegalArgumentException } // The builder should still be usable after the exception - OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "hello", Collections.emptyList()) - .build(); + OllamaChatRequest req = + builder.withMessage(OllamaChatMessageRole.USER, "hello", Collections.emptyList()) + .build(); assertNotNull(req.getMessages()); assertEquals(1, req.getMessages().size()); diff --git a/src/test/java/io/github/ollama4j/unittests/TestOllamaRequestBody.java b/src/test/java/io/github/ollama4j/unittests/TestOllamaRequestBody.java index 204e1bc..2e14063 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestOllamaRequestBody.java +++ b/src/test/java/io/github/ollama4j/unittests/TestOllamaRequestBody.java @@ -1,15 +1,22 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertEquals; + import io.github.ollama4j.utils.OllamaRequestBody; import io.github.ollama4j.utils.Utils; -import org.junit.jupiter.api.Test; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.Flow; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; class TestOllamaRequestBody { @@ -30,29 +37,29 @@ class TestOllamaRequestBody { var publisher = req.getBodyPublisher(); StringBuilder data = new StringBuilder(); - publisher.subscribe(new Flow.Subscriber<>() { - @Override - public void onSubscribe(Flow.Subscription subscription) { - subscription.request(Long.MAX_VALUE); - } + publisher.subscribe( + new Flow.Subscriber<>() { + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(Long.MAX_VALUE); + } - @Override - public void onNext(ByteBuffer item) { - data.append(StandardCharsets.UTF_8.decode(item)); - } + @Override + public void onNext(ByteBuffer item) { + data.append(StandardCharsets.UTF_8.decode(item)); + } - @Override - public void onError(Throwable throwable) { - } + @Override + public void onError(Throwable throwable) {} - @Override - public void onComplete() { - } - }); + @Override + public void onComplete() {} + }); // Trigger the publishing by converting it to a string via the same mapper for determinism String expected = Utils.getObjectMapper().writeValueAsString(req); - // Due to asynchronous nature, expected content already delivered synchronously by StringPublisher + // Due to asynchronous nature, expected content already delivered synchronously by + // StringPublisher assertEquals(expected, data.toString()); } } diff --git a/src/test/java/io/github/ollama4j/unittests/TestOllamaToolsResult.java b/src/test/java/io/github/ollama4j/unittests/TestOllamaToolsResult.java index 5ff36be..9e7f451 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestOllamaToolsResult.java +++ b/src/test/java/io/github/ollama4j/unittests/TestOllamaToolsResult.java @@ -1,15 +1,22 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.models.response.OllamaResult; import io.github.ollama4j.tools.OllamaToolsResult; import io.github.ollama4j.tools.ToolFunctionCallSpec; -import org.junit.jupiter.api.Test; - import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestOllamaToolsResult { diff --git a/src/test/java/io/github/ollama4j/unittests/TestOptionsAndUtils.java b/src/test/java/io/github/ollama4j/unittests/TestOptionsAndUtils.java index 63efc71..409237c 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestOptionsAndUtils.java +++ b/src/test/java/io/github/ollama4j/unittests/TestOptionsAndUtils.java @@ -1,40 +1,48 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.utils.Options; import io.github.ollama4j.utils.OptionsBuilder; import io.github.ollama4j.utils.PromptBuilder; import io.github.ollama4j.utils.Utils; -import org.junit.jupiter.api.Test; - import java.io.File; import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class TestOptionsAndUtils { @Test void testOptionsBuilderSetsValues() { - Options options = new OptionsBuilder() - .setMirostat(1) - .setMirostatEta(0.2f) - .setMirostatTau(4.5f) - .setNumCtx(1024) - .setNumGqa(8) - .setNumGpu(2) - .setNumThread(6) - .setRepeatLastN(32) - .setRepeatPenalty(1.2f) - .setTemperature(0.7f) - .setSeed(42) - .setStop("STOP") - .setTfsZ(1.5f) - .setNumPredict(256) - .setTopK(50) - .setTopP(0.95f) - .setMinP(0.05f) - .setCustomOption("custom_param", 123) - .build(); + Options options = + new OptionsBuilder() + .setMirostat(1) + .setMirostatEta(0.2f) + .setMirostatTau(4.5f) + .setNumCtx(1024) + .setNumGqa(8) + .setNumGpu(2) + .setNumThread(6) + .setRepeatLastN(32) + .setRepeatPenalty(1.2f) + .setTemperature(0.7f) + .setSeed(42) + .setStop("STOP") + .setTfsZ(1.5f) + .setNumPredict(256) + .setTopK(50) + .setTopP(0.95f) + .setMinP(0.05f) + .setCustomOption("custom_param", 123) + .build(); Map map = options.getOptionsMap(); assertEquals(1, map.get("mirostat")); @@ -60,19 +68,22 @@ class TestOptionsAndUtils { @Test void testOptionsBuilderRejectsUnsupportedCustomType() { OptionsBuilder builder = new OptionsBuilder(); - assertThrows(IllegalArgumentException.class, () -> builder.setCustomOption("bad", new Object())); + assertThrows( + IllegalArgumentException.class, () -> builder.setCustomOption("bad", new Object())); } @Test void testPromptBuilderBuildsExpectedString() { - String prompt = new PromptBuilder() - .add("Hello") - .addLine(", world!") - .addSeparator() - .add("Continue.") - .build(); + String prompt = + new PromptBuilder() + .add("Hello") + .addLine(", world!") + .addSeparator() + .add("Continue.") + .build(); - String expected = "Hello, world!\n\n--------------------------------------------------\nContinue."; + String expected = + "Hello, world!\n\n--------------------------------------------------\nContinue."; assertEquals(expected, prompt); } @@ -80,7 +91,8 @@ class TestOptionsAndUtils { void testUtilsGetObjectMapperSingletonAndModule() { assertSame(Utils.getObjectMapper(), Utils.getObjectMapper()); // Basic serialization sanity check with JavaTimeModule registered - assertDoesNotThrow(() -> Utils.getObjectMapper().writeValueAsString(java.time.OffsetDateTime.now())); + assertDoesNotThrow( + () -> Utils.getObjectMapper().writeValueAsString(java.time.OffsetDateTime.now())); } @Test diff --git a/src/test/java/io/github/ollama4j/unittests/TestReflectionalToolFunction.java b/src/test/java/io/github/ollama4j/unittests/TestReflectionalToolFunction.java index 9bd47a7..ca75691 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestReflectionalToolFunction.java +++ b/src/test/java/io/github/ollama4j/unittests/TestReflectionalToolFunction.java @@ -1,14 +1,21 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; -import io.github.ollama4j.tools.ReflectionalToolFunction; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import io.github.ollama4j.tools.ReflectionalToolFunction; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.LinkedHashMap; import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class TestReflectionalToolFunction { @@ -25,7 +32,9 @@ class TestReflectionalToolFunction { @Test void testApplyInvokesMethodWithTypeCasting() throws Exception { SampleToolHolder holder = new SampleToolHolder(); - Method method = SampleToolHolder.class.getMethod("combine", Integer.class, Boolean.class, BigDecimal.class, String.class); + Method method = + SampleToolHolder.class.getMethod( + "combine", Integer.class, Boolean.class, BigDecimal.class, String.class); LinkedHashMap propDef = new LinkedHashMap<>(); // preserve order to match method parameters @@ -36,12 +45,13 @@ class TestReflectionalToolFunction { ReflectionalToolFunction fn = new ReflectionalToolFunction(holder, method, propDef); - Map args = Map.of( - "i", "42", - "b", "true", - "d", "3.14", - "s", 123 // not a string; should be toString()'d by implementation - ); + Map args = + Map.of( + "i", "42", + "b", "true", + "d", "3.14", + "s", 123 // not a string; should be toString()'d by implementation + ); Object result = fn.apply(args); assertEquals("i=42,b=true,d=3.14,s=123", result); @@ -50,7 +60,9 @@ class TestReflectionalToolFunction { @Test void testTypeCastNullsWhenClassOrValueIsNull() throws Exception { SampleToolHolder holder = new SampleToolHolder(); - Method method = SampleToolHolder.class.getMethod("combine", Integer.class, Boolean.class, BigDecimal.class, String.class); + Method method = + SampleToolHolder.class.getMethod( + "combine", Integer.class, Boolean.class, BigDecimal.class, String.class); LinkedHashMap propDef = new LinkedHashMap<>(); propDef.put("i", null); // className null -> expect null passed diff --git a/src/test/java/io/github/ollama4j/unittests/TestToolRegistry.java b/src/test/java/io/github/ollama4j/unittests/TestToolRegistry.java index b4d20e1..04c7135 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestToolRegistry.java +++ b/src/test/java/io/github/ollama4j/unittests/TestToolRegistry.java @@ -1,13 +1,20 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.tools.ToolFunction; import io.github.ollama4j.tools.ToolRegistry; import io.github.ollama4j.tools.Tools; -import org.junit.jupiter.api.Test; - import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class TestToolRegistry { @@ -16,11 +23,12 @@ class TestToolRegistry { ToolRegistry registry = new ToolRegistry(); ToolFunction fn = args -> "ok:" + args.get("x"); - Tools.ToolSpecification spec = Tools.ToolSpecification.builder() - .functionName("test") - .functionDescription("desc") - .toolFunction(fn) - .build(); + Tools.ToolSpecification spec = + Tools.ToolSpecification.builder() + .functionName("test") + .functionDescription("desc") + .toolFunction(fn) + .build(); registry.addTool("test", spec); ToolFunction retrieved = registry.getToolFunction("test"); diff --git a/src/test/java/io/github/ollama4j/unittests/TestToolsPromptBuilder.java b/src/test/java/io/github/ollama4j/unittests/TestToolsPromptBuilder.java index 6ce8521..81a7d81 100644 --- a/src/test/java/io/github/ollama4j/unittests/TestToolsPromptBuilder.java +++ b/src/test/java/io/github/ollama4j/unittests/TestToolsPromptBuilder.java @@ -1,56 +1,67 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.fasterxml.jackson.core.JsonProcessingException; import io.github.ollama4j.tools.Tools; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; class TestToolsPromptBuilder { @Test void testPromptBuilderIncludesToolsAndPrompt() throws JsonProcessingException { - Tools.PromptFuncDefinition.Property cityProp = Tools.PromptFuncDefinition.Property.builder() - .type("string") - .description("city name") - .required(true) - .build(); + Tools.PromptFuncDefinition.Property cityProp = + Tools.PromptFuncDefinition.Property.builder() + .type("string") + .description("city name") + .required(true) + .build(); - Tools.PromptFuncDefinition.Property unitsProp = Tools.PromptFuncDefinition.Property.builder() - .type("string") - .description("units") - .enumValues(List.of("metric", "imperial")) - .required(false) - .build(); + Tools.PromptFuncDefinition.Property unitsProp = + Tools.PromptFuncDefinition.Property.builder() + .type("string") + .description("units") + .enumValues(List.of("metric", "imperial")) + .required(false) + .build(); - Tools.PromptFuncDefinition.Parameters params = Tools.PromptFuncDefinition.Parameters.builder() - .type("object") - .properties(Map.of("city", cityProp, "units", unitsProp)) - .build(); + Tools.PromptFuncDefinition.Parameters params = + Tools.PromptFuncDefinition.Parameters.builder() + .type("object") + .properties(Map.of("city", cityProp, "units", unitsProp)) + .build(); - Tools.PromptFuncDefinition.PromptFuncSpec spec = Tools.PromptFuncDefinition.PromptFuncSpec.builder() - .name("getWeather") - .description("Get weather for a city") - .parameters(params) - .build(); + Tools.PromptFuncDefinition.PromptFuncSpec spec = + Tools.PromptFuncDefinition.PromptFuncSpec.builder() + .name("getWeather") + .description("Get weather for a city") + .parameters(params) + .build(); - Tools.PromptFuncDefinition def = Tools.PromptFuncDefinition.builder() - .type("function") - .function(spec) - .build(); + Tools.PromptFuncDefinition def = + Tools.PromptFuncDefinition.builder().type("function").function(spec).build(); - Tools.ToolSpecification toolSpec = Tools.ToolSpecification.builder() - .functionName("getWeather") - .functionDescription("Get weather for a city") - .toolPrompt(def) - .build(); + Tools.ToolSpecification toolSpec = + Tools.ToolSpecification.builder() + .functionName("getWeather") + .functionDescription("Get weather for a city") + .toolPrompt(def) + .build(); - Tools.PromptBuilder pb = new Tools.PromptBuilder() - .withToolSpecification(toolSpec) - .withPrompt("Tell me the weather."); + Tools.PromptBuilder pb = + new Tools.PromptBuilder() + .withToolSpecification(toolSpec) + .withPrompt("Tell me the weather."); String built = pb.build(); assertTrue(built.contains("[AVAILABLE_TOOLS]")); diff --git a/src/test/java/io/github/ollama4j/unittests/jackson/AbstractSerializationTest.java b/src/test/java/io/github/ollama4j/unittests/jackson/AbstractSerializationTest.java index 8476ca0..904b78e 100644 --- a/src/test/java/io/github/ollama4j/unittests/jackson/AbstractSerializationTest.java +++ b/src/test/java/io/github/ollama4j/unittests/jackson/AbstractSerializationTest.java @@ -1,12 +1,20 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests.jackson; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.ollama4j.utils.Utils; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; - public abstract class AbstractSerializationTest { protected ObjectMapper mapper = Utils.getObjectMapper(); @@ -29,8 +37,7 @@ public abstract class AbstractSerializationTest { } } - protected void assertEqualsAfterUnmarshalling(T unmarshalledObject, - T req) { + protected void assertEqualsAfterUnmarshalling(T unmarshalledObject, T req) { assertEquals(req, unmarshalledObject); } } diff --git a/src/test/java/io/github/ollama4j/unittests/jackson/TestChatRequestSerialization.java b/src/test/java/io/github/ollama4j/unittests/jackson/TestChatRequestSerialization.java index 984bc22..9c577a5 100644 --- a/src/test/java/io/github/ollama4j/unittests/jackson/TestChatRequestSerialization.java +++ b/src/test/java/io/github/ollama4j/unittests/jackson/TestChatRequestSerialization.java @@ -1,19 +1,26 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests.jackson; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + import io.github.ollama4j.models.chat.OllamaChatMessageRole; import io.github.ollama4j.models.chat.OllamaChatRequest; import io.github.ollama4j.models.chat.OllamaChatRequestBuilder; import io.github.ollama4j.utils.OptionsBuilder; -import org.json.JSONObject; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.io.File; import java.util.Collections; import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TestChatRequestSerialization extends AbstractSerializationTest { @@ -26,24 +33,31 @@ public class TestChatRequestSerialization extends AbstractSerializationTest { - OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt") - .withOptions(b.setCustomOption("cust_obj", new Object()).build()) - .build(); - }); + assertThrowsExactly( + IllegalArgumentException.class, + () -> { + OllamaChatRequest req = + builder.withMessage(OllamaChatMessageRole.USER, "Some prompt") + .withOptions( + b.setCustomOption("cust_obj", new Object()).build()) + .build(); + }); } @Test public void testWithJsonFormat() { - OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt") - .withGetJsonResponse().build(); + OllamaChatRequest req = + builder.withMessage(OllamaChatMessageRole.USER, "Some prompt") + .withGetJsonResponse() + .build(); String jsonRequest = serialize(req); // no jackson deserialization as format property is not boolean ==> omit as deserialization @@ -108,8 +129,7 @@ public class TestChatRequestSerialization extends AbstractSerializationTest { +public class TestEmbedRequestSerialization + extends AbstractSerializationTest { private OllamaEmbedRequestBuilder builder; @@ -21,17 +30,18 @@ public class TestEmbedRequestSerialization extends AbstractSerializationTest { +public class TestGenerateRequestSerialization + extends AbstractSerializationTest { private OllamaGenerateRequestBuilder builder; @@ -33,15 +42,15 @@ public class TestGenerateRequestSerialization extends AbstractSerializationTest< builder.withPrompt("Some prompt").withOptions(b.setMirostat(1).build()).build(); String jsonRequest = serialize(req); - OllamaGenerateRequest deserializeRequest = deserialize(jsonRequest, OllamaGenerateRequest.class); + OllamaGenerateRequest deserializeRequest = + deserialize(jsonRequest, OllamaGenerateRequest.class); assertEqualsAfterUnmarshalling(deserializeRequest, req); assertEquals(1, deserializeRequest.getOptions().get("mirostat")); } @Test public void testWithJsonFormat() { - OllamaGenerateRequest req = - builder.withPrompt("Some prompt").withGetJsonResponse().build(); + OllamaGenerateRequest req = builder.withPrompt("Some prompt").withGetJsonResponse().build(); String jsonRequest = serialize(req); System.out.printf(jsonRequest); diff --git a/src/test/java/io/github/ollama4j/unittests/jackson/TestModelPullResponseSerialization.java b/src/test/java/io/github/ollama4j/unittests/jackson/TestModelPullResponseSerialization.java index 59d601d..a767030 100644 --- a/src/test/java/io/github/ollama4j/unittests/jackson/TestModelPullResponseSerialization.java +++ b/src/test/java/io/github/ollama4j/unittests/jackson/TestModelPullResponseSerialization.java @@ -1,17 +1,26 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests.jackson; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.models.response.ModelPullResponse; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * Test serialization and deserialization of ModelPullResponse, * This test verifies that the ModelPullResponse class can properly parse * error responses from Ollama server that return HTTP 200 with error messages * in the JSON body. */ -public class TestModelPullResponseSerialization extends AbstractSerializationTest { +public class TestModelPullResponseSerialization + extends AbstractSerializationTest { /** * Test the specific error case reported in GitHub issue #138. @@ -20,7 +29,16 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes @Test public void testDeserializationWithErrorFromGitHubIssue138() { // This is the exact error JSON from GitHub issue #138 - String errorJson = "{\"error\":\"pull model manifest: 412: \\n\\nThe model you are attempting to pull requires a newer version of Ollama.\\n\\nPlease download the latest version at:\\n\\n\\thttps://ollama.com/download\\n\\n\"}"; + String errorJson = + "{\"error\":\"pull model manifest: 412: \\n" + + "\\n" + + "The model you are attempting to pull requires a newer version of Ollama.\\n" + + "\\n" + + "Please download the latest version at:\\n" + + "\\n" + + "\\thttps://ollama.com/download\\n" + + "\\n" + + "\"}"; ModelPullResponse response = deserialize(errorJson, ModelPullResponse.class); @@ -59,7 +77,9 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes */ @Test public void testDeserializationWithProgressFields() { - String progressJson = "{\"status\":\"pulling digestname\",\"digest\":\"sha256:abc123\",\"total\":2142590208,\"completed\":241970}"; + String progressJson = + "{\"status\":\"pulling" + + " digestname\",\"digest\":\"sha256:abc123\",\"total\":2142590208,\"completed\":241970}"; ModelPullResponse response = deserialize(progressJson, ModelPullResponse.class); @@ -95,7 +115,8 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes */ @Test public void testDeserializationWithAllFields() { - String completeJson = "{\"status\":\"downloading\",\"digest\":\"sha256:def456\",\"total\":1000000,\"completed\":500000,\"error\":null}"; + String completeJson = + "{\"status\":\"downloading\",\"digest\":\"sha256:def456\",\"total\":1000000,\"completed\":500000,\"error\":null}"; ModelPullResponse response = deserialize(completeJson, ModelPullResponse.class); @@ -115,7 +136,9 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes @Test public void testDeserializationWithUnknownFields() { // Test that unknown fields are ignored due to @JsonIgnoreProperties(ignoreUnknown = true) - String jsonWithUnknownFields = "{\"status\":\"pulling\",\"unknown_field\":\"should_be_ignored\",\"error\":\"test error\",\"another_unknown\":123,\"nested_unknown\":{\"key\":\"value\"}}"; + String jsonWithUnknownFields = + "{\"status\":\"pulling\",\"unknown_field\":\"should_be_ignored\",\"error\":\"test" + + " error\",\"another_unknown\":123,\"nested_unknown\":{\"key\":\"value\"}}"; ModelPullResponse response = deserialize(jsonWithUnknownFields, ModelPullResponse.class); @@ -227,21 +250,25 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes String errorJson = "{\"error\":\"test error\"}"; ModelPullResponse errorResponse = deserialize(errorJson, ModelPullResponse.class); - assertTrue(errorResponse.getError() != null && !errorResponse.getError().trim().isEmpty(), + assertTrue( + errorResponse.getError() != null && !errorResponse.getError().trim().isEmpty(), "Error response should trigger error handling logic"); // Normal case - should not trigger error handling String normalJson = "{\"status\":\"pulling\"}"; ModelPullResponse normalResponse = deserialize(normalJson, ModelPullResponse.class); - assertFalse(normalResponse.getError() != null && !normalResponse.getError().trim().isEmpty(), + assertFalse( + normalResponse.getError() != null && !normalResponse.getError().trim().isEmpty(), "Normal response should not trigger error handling logic"); // Empty error case - should not trigger error handling String emptyErrorJson = "{\"error\":\"\",\"status\":\"pulling\"}"; ModelPullResponse emptyErrorResponse = deserialize(emptyErrorJson, ModelPullResponse.class); - assertFalse(emptyErrorResponse.getError() != null && !emptyErrorResponse.getError().trim().isEmpty(), + assertFalse( + emptyErrorResponse.getError() != null + && !emptyErrorResponse.getError().trim().isEmpty(), "Empty error response should not trigger error handling logic"); } } diff --git a/src/test/java/io/github/ollama4j/unittests/jackson/TestModelRequestSerialization.java b/src/test/java/io/github/ollama4j/unittests/jackson/TestModelRequestSerialization.java index 961dd43..a48dc33 100644 --- a/src/test/java/io/github/ollama4j/unittests/jackson/TestModelRequestSerialization.java +++ b/src/test/java/io/github/ollama4j/unittests/jackson/TestModelRequestSerialization.java @@ -1,33 +1,45 @@ +/* + * Ollama4j - Java library for interacting with Ollama server. + * Copyright (c) 2025 Amith Koujalgi and contributors. + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * +*/ package io.github.ollama4j.unittests.jackson; +import static org.junit.jupiter.api.Assertions.*; + import io.github.ollama4j.models.response.Model; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class TestModelRequestSerialization extends AbstractSerializationTest { @Test public void testDeserializationOfModelResponseWithOffsetTime() { - String serializedTestStringWithOffsetTime = "{\n" + - " \"name\": \"codellama:13b\",\n" + - " \"modified_at\": \"2023-11-04T14:56:49.277302595-07:00\",\n" + - " \"size\": 7365960935,\n" + - " \"digest\": \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n" + - " \"details\": {\n" + - " \"format\": \"gguf\",\n" + - " \"family\": \"llama\",\n" + - " \"families\": null,\n" + - " \"parameter_size\": \"13B\",\n" + - " \"quantization_level\": \"Q4_0\"\n" + - " }\n" + - "}"; + String serializedTestStringWithOffsetTime = + "{\n" + + " \"name\": \"codellama:13b\",\n" + + " \"modified_at\": \"2023-11-04T14:56:49.277302595-07:00\",\n" + + " \"size\": 7365960935,\n" + + " \"digest\":" + + " \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n" + + " \"details\": {\n" + + " \"format\": \"gguf\",\n" + + " \"family\": \"llama\",\n" + + " \"families\": null,\n" + + " \"parameter_size\": \"13B\",\n" + + " \"quantization_level\": \"Q4_0\"\n" + + " }\n" + + "}"; Model model = deserialize(serializedTestStringWithOffsetTime, Model.class); assertNotNull(model); assertEquals("codellama:13b", model.getName()); assertEquals("2023-11-04T21:56:49.277302595Z", model.getModifiedAt().toString()); assertEquals(7365960935L, model.getSize()); - assertEquals("9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697", model.getDigest()); + assertEquals( + "9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697", + model.getDigest()); assertNotNull(model.getModelMeta()); assertEquals("gguf", model.getModelMeta().getFormat()); assertEquals("llama", model.getModelMeta().getFamily()); @@ -38,25 +50,29 @@ public class TestModelRequestSerialization extends AbstractSerializationTest