Ollama4j
A Java library (wrapper/binding) for Ollama server.
Loading...
Searching...
No Matches
Ollama.java
Go to the documentation of this file.
1/*
2 * Ollama4j - Java library for interacting with Ollama server.
3 * Copyright (c) 2025 Amith Koujalgi and contributors.
4 *
5 * Licensed under the MIT License (the "License");
6 * you may not use this file except in compliance with the License.
7 *
8*/
9package io.github.ollama4j;
10
11import com.fasterxml.jackson.annotation.JsonProperty;
12import com.fasterxml.jackson.databind.ObjectMapper;
13import io.github.ollama4j.exceptions.OllamaException;
14import io.github.ollama4j.exceptions.RoleNotFoundException;
15import io.github.ollama4j.exceptions.ToolInvocationException;
16import io.github.ollama4j.metrics.MetricsRecorder;
17import io.github.ollama4j.models.chat.*;
18import io.github.ollama4j.models.embed.OllamaEmbedRequest;
19import io.github.ollama4j.models.embed.OllamaEmbedResult;
20import io.github.ollama4j.models.generate.OllamaGenerateImageRequest;
21import io.github.ollama4j.models.generate.OllamaGenerateRequest;
22import io.github.ollama4j.models.generate.OllamaGenerateStreamObserver;
23import io.github.ollama4j.models.generate.OllamaGenerateTokenHandler;
24import io.github.ollama4j.models.ps.ModelProcessesResult;
25import io.github.ollama4j.models.request.*;
26import io.github.ollama4j.models.response.*;
27import io.github.ollama4j.tools.*;
28import io.github.ollama4j.tools.annotations.OllamaToolService;
29import io.github.ollama4j.tools.annotations.ToolProperty;
30import io.github.ollama4j.tools.annotations.ToolSpec;
31import io.github.ollama4j.utils.Constants;
32import io.github.ollama4j.utils.Utils;
33import io.modelcontextprotocol.client.McpClient;
34import io.modelcontextprotocol.client.McpSyncClient;
35import io.modelcontextprotocol.client.transport.ServerParameters;
36import io.modelcontextprotocol.client.transport.StdioClientTransport;
37import io.modelcontextprotocol.json.McpJsonMapper;
38import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
39import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
40import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
41import java.io.*;
42import java.lang.reflect.InvocationTargetException;
43import java.lang.reflect.Method;
44import java.lang.reflect.Parameter;
45import java.net.URI;
46import java.net.URISyntaxException;
47import java.net.http.HttpClient;
48import java.net.http.HttpRequest;
49import java.net.http.HttpResponse;
50import java.nio.charset.StandardCharsets;
51import java.nio.file.Files;
52import java.time.Duration;
53import java.util.*;
54import java.util.stream.Collectors;
55import lombok.AllArgsConstructor;
56import lombok.Data;
57import lombok.NoArgsConstructor;
58import lombok.Setter;
59import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
68@SuppressWarnings({"DuplicatedCode", "resource", "SpellCheckingInspection"})
69public class Ollama {
70
71 private static final Logger LOG = LoggerFactory.getLogger(Ollama.class);
72
73 private final String host;
74 private Auth auth;
75
76 private final ToolRegistry toolRegistry = new ToolRegistry();
77
84 @Setter private long requestTimeoutSeconds = 10;
85
87 @Setter private int imageURLReadTimeoutSeconds = 10;
88
90 @Setter private int imageURLConnectTimeoutSeconds = 10;
91
98 @Setter private int maxChatToolCallRetries = 3;
99
108 @Setter
109 @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
110 private int numberOfRetriesForModelPull = 0;
111
118 @Setter private boolean metricsEnabled = false;
119
123 @Setter private ModelPullListener modelPullListener;
124
126 public Ollama() {
127 this.host = "http://localhost:11434";
128 }
129
135 public Ollama(String host) {
136 if (host.endsWith("/")) {
137 this.host = host.substring(0, host.length() - 1);
138 } else {
139 this.host = host;
140 }
141 LOG.info("Ollama4j client initialized. Connected to Ollama server at: {}", this.host);
142 }
143
150 public void setBasicAuth(String username, String password) {
151 this.auth = new BasicAuth(username, password);
152 }
153
159 public void setBearerAuth(String bearerToken) {
160 this.auth = new BearerAuth(bearerToken);
161 }
162
169 public boolean ping() throws OllamaException {
170 long startTime = System.currentTimeMillis();
171 String url = "/api/tags";
172 int statusCode = -1;
173 Object out = null;
174 try {
175 HttpClient httpClient = HttpClient.newHttpClient();
176 HttpRequest httpRequest;
177 HttpResponse<String> response;
178 httpRequest =
179 getRequestBuilderDefault(new URI(this.host + url))
180 .header(
181 Constants.HttpConstants.HEADER_KEY_ACCEPT,
182 Constants.HttpConstants.APPLICATION_JSON)
183 .header(
184 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
185 Constants.HttpConstants.APPLICATION_JSON)
186 .GET()
187 .build();
188 response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
189 statusCode = response.statusCode();
190 return statusCode == 200;
191 } catch (InterruptedException ie) {
192 Thread.currentThread().interrupt();
193 throw new OllamaException("Ping interrupted", ie);
194 } catch (Exception e) {
195 throw new OllamaException("Ping failed", e);
196 } finally {
198 url,
199 "",
200 false,
202 false,
203 null,
204 null,
205 startTime,
206 statusCode,
207 out);
208 }
209 }
210
218 long startTime = System.currentTimeMillis();
219 String url = "/api/ps";
220 int statusCode = -1;
221 Object out = null;
222 try {
223 HttpClient httpClient = HttpClient.newHttpClient();
224 HttpRequest httpRequest = null;
225 try {
226 httpRequest =
227 getRequestBuilderDefault(new URI(this.host + url))
228 .header(
229 Constants.HttpConstants.HEADER_KEY_ACCEPT,
230 Constants.HttpConstants.APPLICATION_JSON)
231 .header(
232 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
233 Constants.HttpConstants.APPLICATION_JSON)
234 .GET()
235 .build();
236 } catch (URISyntaxException e) {
237 throw new OllamaException(e.getMessage(), e);
238 }
239 HttpResponse<String> response = null;
240 response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
241 statusCode = response.statusCode();
242 String responseString = response.body();
243 if (statusCode == 200) {
244 return Utils.getObjectMapper()
245 .readValue(responseString, ModelProcessesResult.class);
246 } else {
247 throw new OllamaException(statusCode + " - " + responseString);
248 }
249 } catch (InterruptedException ie) {
250 Thread.currentThread().interrupt();
251 throw new OllamaException("ps interrupted", ie);
252 } catch (Exception e) {
253 throw new OllamaException("ps failed", e);
254 } finally {
256 url,
257 "",
258 false,
260 false,
261 null,
262 null,
263 startTime,
264 statusCode,
265 out);
266 }
267 }
268
275 public List<Model> listModels() throws OllamaException {
276 long startTime = System.currentTimeMillis();
277 String url = "/api/tags";
278 int statusCode = -1;
279 Object out = null;
280 try {
281 HttpClient httpClient = HttpClient.newHttpClient();
282 HttpRequest httpRequest =
283 getRequestBuilderDefault(new URI(this.host + url))
284 .header(
285 Constants.HttpConstants.HEADER_KEY_ACCEPT,
286 Constants.HttpConstants.APPLICATION_JSON)
287 .header(
288 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
289 Constants.HttpConstants.APPLICATION_JSON)
290 .GET()
291 .build();
292 HttpResponse<String> response =
293 httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
294 statusCode = response.statusCode();
295 String responseString = response.body();
296 if (statusCode == 200) {
297 return Utils.getObjectMapper()
298 .readValue(responseString, ListModelsResponse.class)
299 .getModels();
300 } else {
301 throw new OllamaException(statusCode + " - " + responseString);
302 }
303 } catch (InterruptedException ie) {
304 Thread.currentThread().interrupt();
305 throw new OllamaException("listModels interrupted", ie);
306 } catch (Exception e) {
307 throw new OllamaException(e.getMessage(), e);
308 } finally {
310 url,
311 "",
312 false,
314 false,
315 null,
316 null,
317 startTime,
318 statusCode,
319 out);
320 }
321 }
322
332 private void handlePullRetry(
333 String modelName, int currentRetry, int maxRetries, long baseDelayMillis)
334 throws InterruptedException {
335 int attempt = currentRetry + 1;
336 if (attempt < maxRetries) {
337 long backoffMillis = baseDelayMillis * (1L << currentRetry);
338 LOG.error(
339 "Failed to pull model {}, retrying in {}s... (attempt {}/{})",
340 modelName,
341 backoffMillis / 1000,
342 attempt,
343 maxRetries);
344 try {
345 Thread.sleep(backoffMillis);
346 } catch (InterruptedException ie) {
347 Thread.currentThread().interrupt();
348 throw ie;
349 }
350 } else {
351 LOG.error(
352 "Failed to pull model {} after {} attempts, no more retries.",
353 modelName,
354 maxRetries);
355 }
356 }
357
365 private void doPullModel(String modelName, ModelPullListener listener) throws OllamaException {
366 long startTime = System.currentTimeMillis();
367 String url = "/api/pull";
368 int statusCode = -1;
369 Object out = null;
370 try {
371 String jsonData = new ModelRequest(modelName).toString();
372 HttpRequest request =
373 getRequestBuilderDefault(new URI(this.host + url))
374 .POST(HttpRequest.BodyPublishers.ofString(jsonData))
375 .header(
376 Constants.HttpConstants.HEADER_KEY_ACCEPT,
377 Constants.HttpConstants.APPLICATION_JSON)
378 .header(
379 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
380 Constants.HttpConstants.APPLICATION_JSON)
381 .build();
382 HttpClient client = HttpClient.newHttpClient();
383 HttpResponse<InputStream> response =
384 client.send(request, HttpResponse.BodyHandlers.ofInputStream());
385 statusCode = response.statusCode();
386 InputStream responseBodyStream = response.body();
387 String responseString = "";
388 boolean success = false; // Flag to check the pull success.
389
390 try (BufferedReader reader =
391 new BufferedReader(
392 new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
393 String line;
394 while ((line = reader.readLine()) != null) {
395 ModelPullResponse modelPullResponse =
396 Utils.getObjectMapper().readValue(line, ModelPullResponse.class);
397 success =
398 processModelPullResponse(modelPullResponse, modelName, listener)
399 || success;
400 }
401 }
402 if (!success) {
403 LOG.error("Model pull failed or returned invalid status.");
404 throw new OllamaException("Model pull failed or returned invalid status.");
405 }
406 if (statusCode != 200) {
407 throw new OllamaException(statusCode + " - " + responseString);
408 }
409 } catch (InterruptedException ie) {
410 Thread.currentThread().interrupt();
411 throw new OllamaException("Thread was interrupted during model pull.", ie);
412 } catch (Exception e) {
413 throw new OllamaException(e.getMessage(), e);
414 } finally {
416 url,
417 "",
418 false,
420 false,
421 null,
422 null,
423 startTime,
424 statusCode,
425 out);
426 }
427 }
428
439 @SuppressWarnings("RedundantIfStatement")
440 private boolean processModelPullResponse(
441 ModelPullResponse modelPullResponse, String modelName, ModelPullListener listener)
442 throws OllamaException {
443 if (modelPullResponse == null) {
444 LOG.error("Received null response for model pull.");
445 return false;
446 }
447 if (modelPullListener != null) {
448 modelPullListener.onStatusUpdate(modelName, modelPullResponse);
449 }
450 if (listener != null && listener != modelPullListener) {
451 listener.onStatusUpdate(modelName, modelPullResponse);
452 }
453 String error = modelPullResponse.getError();
454 if (error != null && !error.trim().isEmpty()) {
455 throw new OllamaException("Model pull failed: " + error);
456 }
457 String status = modelPullResponse.getStatus();
458 if (status != null) {
459 LOG.debug("{}: {}", modelName, status);
460 if ("success".equalsIgnoreCase(status)) {
461 return true;
462 }
463 }
464 return false;
465 }
466
473 public String getVersion() throws OllamaException {
474 String url = "/api/version";
475 long startTime = System.currentTimeMillis();
476 int statusCode = -1;
477 Object out = null;
478 try {
479 HttpClient httpClient = HttpClient.newHttpClient();
480 HttpRequest httpRequest =
481 getRequestBuilderDefault(new URI(this.host + url))
482 .header(
483 Constants.HttpConstants.HEADER_KEY_ACCEPT,
484 Constants.HttpConstants.APPLICATION_JSON)
485 .header(
486 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
487 Constants.HttpConstants.APPLICATION_JSON)
488 .GET()
489 .build();
490 HttpResponse<String> response =
491 httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
492 statusCode = response.statusCode();
493 String responseString = response.body();
494 if (statusCode == 200) {
495 return Utils.getObjectMapper()
496 .readValue(responseString, OllamaVersion.class)
497 .getVersion();
498 } else {
499 throw new OllamaException(statusCode + " - " + responseString);
500 }
501 } catch (InterruptedException ie) {
502 Thread.currentThread().interrupt();
503 throw new OllamaException("Thread was interrupted", ie);
504 } catch (Exception e) {
505 throw new OllamaException(e.getMessage(), e);
506 } finally {
508 url,
509 "",
510 false,
512 false,
513 null,
514 null,
515 startTime,
516 statusCode,
517 out);
518 }
519 }
520
529 public void pullModel(String modelName) throws OllamaException {
530 pullModel(modelName, null);
531 }
532
541 public void pullModel(String modelName, ModelPullListener listener) throws OllamaException {
542 try {
543 if (numberOfRetriesForModelPull == 0) {
544 this.doPullModel(modelName, listener);
545 return;
546 }
547 int numberOfRetries = 0;
548 long baseDelayMillis = 3000L; // 3 seconds base delay
549 while (numberOfRetries < numberOfRetriesForModelPull) {
550 try {
551 this.doPullModel(modelName, listener);
552 return;
553 } catch (OllamaException e) {
554 handlePullRetry(
555 modelName,
556 numberOfRetries,
557 numberOfRetriesForModelPull,
558 baseDelayMillis);
559 numberOfRetries++;
560 }
561 }
562 throw new OllamaException(
563 "Failed to pull model "
564 + modelName
565 + " after "
566 + numberOfRetriesForModelPull
567 + " retries");
568 } catch (InterruptedException ie) {
569 Thread.currentThread().interrupt();
570 throw new OllamaException("Thread was interrupted", ie);
571 } catch (Exception e) {
572 throw new OllamaException(e.getMessage(), e);
573 }
574 }
575
583 public ModelDetail getModelDetails(String modelName) throws OllamaException {
584 long startTime = System.currentTimeMillis();
585 String url = "/api/show";
586 int statusCode = -1;
587 Object out = null;
588 try {
589 String jsonData = new ModelRequest(modelName).toString();
590 HttpRequest request =
591 getRequestBuilderDefault(new URI(this.host + url))
592 .header(
593 Constants.HttpConstants.HEADER_KEY_ACCEPT,
594 Constants.HttpConstants.APPLICATION_JSON)
595 .header(
596 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
597 Constants.HttpConstants.APPLICATION_JSON)
598 .POST(HttpRequest.BodyPublishers.ofString(jsonData))
599 .build();
600 HttpClient client = HttpClient.newHttpClient();
601 HttpResponse<String> response =
602 client.send(request, HttpResponse.BodyHandlers.ofString());
603 statusCode = response.statusCode();
604 String responseBody = response.body();
605 if (statusCode == 200) {
606 return Utils.getObjectMapper().readValue(responseBody, ModelDetail.class);
607 } else {
608 throw new OllamaException(statusCode + " - " + responseBody);
609 }
610 } catch (InterruptedException ie) {
611 Thread.currentThread().interrupt();
612 throw new OllamaException("Thread was interrupted", ie);
613 } catch (Exception e) {
614 throw new OllamaException(e.getMessage(), e);
615 } finally {
617 url,
618 "",
619 false,
621 false,
622 null,
623 null,
624 startTime,
625 statusCode,
626 out);
627 }
628 }
629
637 public void createModel(CustomModelRequest customModelRequest) throws OllamaException {
638 createModel(customModelRequest, null);
639 }
640
648 public void createModel(CustomModelRequest customModelRequest, ModelPullListener listener)
649 throws OllamaException {
650 long startTime = System.currentTimeMillis();
651 String url = "/api/create";
652 int statusCode = -1;
653 Object out = null;
654 try {
655 String jsonData = customModelRequest.toString();
656 HttpRequest request =
657 getRequestBuilderDefault(new URI(this.host + url))
658 .header(
659 Constants.HttpConstants.HEADER_KEY_ACCEPT,
660 Constants.HttpConstants.APPLICATION_JSON)
661 .header(
662 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
663 Constants.HttpConstants.APPLICATION_JSON)
664 .POST(
665 HttpRequest.BodyPublishers.ofString(
666 jsonData, StandardCharsets.UTF_8))
667 .build();
668 HttpClient client = HttpClient.newHttpClient();
669 HttpResponse<InputStream> response =
670 client.send(request, HttpResponse.BodyHandlers.ofInputStream());
671 statusCode = response.statusCode();
672 if (statusCode != 200) {
673 String errorBody =
674 new String(response.body().readAllBytes(), StandardCharsets.UTF_8);
675 out = errorBody;
676 throw new OllamaException(statusCode + " - " + errorBody);
677 }
678 try (BufferedReader reader =
679 new BufferedReader(
680 new InputStreamReader(response.body(), StandardCharsets.UTF_8))) {
681 String line;
682 StringBuilder lines = new StringBuilder();
683 while ((line = reader.readLine()) != null) {
685 Utils.getObjectMapper().readValue(line, ModelPullResponse.class);
686 lines.append(line);
687 LOG.debug(res.getStatus());
688 if (modelPullListener != null) {
689 modelPullListener.onStatusUpdate(customModelRequest.getModel(), res);
690 }
691 if (listener != null && listener != modelPullListener) {
692 listener.onStatusUpdate(customModelRequest.getModel(), res);
693 }
694 if (res.getError() != null) {
695 out = res.getError();
696 throw new OllamaException(res.getError());
697 }
698 }
699 out = lines;
700 }
701 } catch (InterruptedException e) {
702 Thread.currentThread().interrupt();
703 throw new OllamaException("Thread was interrupted", e);
704 } catch (Exception e) {
705 throw new OllamaException(e.getMessage(), e);
706 } finally {
708 url,
709 "",
710 false,
712 false,
713 null,
714 null,
715 startTime,
716 statusCode,
717 out);
718 }
719 }
720
729 public void deleteModel(String modelName, boolean ignoreIfNotPresent) throws OllamaException {
730 long startTime = System.currentTimeMillis();
731 String url = "/api/delete";
732 int statusCode = -1;
733 Object out = null;
734 try {
735 String jsonData = new ModelRequest(modelName).toString();
736 HttpRequest request =
737 getRequestBuilderDefault(new URI(this.host + url))
738 .method(
739 "DELETE",
740 HttpRequest.BodyPublishers.ofString(
741 jsonData, StandardCharsets.UTF_8))
742 .header(
743 Constants.HttpConstants.HEADER_KEY_ACCEPT,
744 Constants.HttpConstants.APPLICATION_JSON)
745 .header(
746 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
747 Constants.HttpConstants.APPLICATION_JSON)
748 .build();
749 HttpClient client = HttpClient.newHttpClient();
750 HttpResponse<String> response =
751 client.send(request, HttpResponse.BodyHandlers.ofString());
752 statusCode = response.statusCode();
753 String responseBody = response.body();
754 out = responseBody;
755 if (statusCode == 404
756 && responseBody.contains("model")
757 && responseBody.contains("not found")) {
758 return;
759 }
760 if (statusCode != 200) {
761 throw new OllamaException(statusCode + " - " + responseBody);
762 }
763 } catch (InterruptedException e) {
764 Thread.currentThread().interrupt();
765 throw new OllamaException("Thread was interrupted", e);
766 } catch (Exception e) {
767 throw new OllamaException(statusCode + " - " + out, e);
768 } finally {
770 url,
771 "",
772 false,
774 false,
775 null,
776 null,
777 startTime,
778 statusCode,
779 out);
780 }
781 }
782
792 public void unloadModel(String modelName) throws OllamaException {
793 long startTime = System.currentTimeMillis();
794 String url = "/api/generate";
795 int statusCode = -1;
796 Object out = null;
797 try {
798 ObjectMapper objectMapper = new ObjectMapper();
799 Map<String, Object> jsonMap = new java.util.HashMap<>();
800 jsonMap.put("model", modelName);
801 jsonMap.put("keep_alive", 0);
802 String jsonData = objectMapper.writeValueAsString(jsonMap);
803 HttpRequest request =
804 getRequestBuilderDefault(new URI(this.host + url))
805 .method(
806 "POST",
807 HttpRequest.BodyPublishers.ofString(
808 jsonData, StandardCharsets.UTF_8))
809 .header(
810 Constants.HttpConstants.HEADER_KEY_ACCEPT,
811 Constants.HttpConstants.APPLICATION_JSON)
812 .header(
813 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
814 Constants.HttpConstants.APPLICATION_JSON)
815 .build();
816 LOG.debug("Unloading model with request: {}", jsonData);
817 HttpClient client = HttpClient.newHttpClient();
818 HttpResponse<String> response =
819 client.send(request, HttpResponse.BodyHandlers.ofString());
820 statusCode = response.statusCode();
821 String responseBody = response.body();
822 if (statusCode == 404
823 && responseBody.contains("model")
824 && responseBody.contains("not found")) {
825 LOG.debug("Unload response: {} - {}", statusCode, responseBody);
826 return;
827 }
828 if (statusCode != 200) {
829 LOG.debug("Unload response: {} - {}", statusCode, responseBody);
830 throw new OllamaException(statusCode + " - " + responseBody);
831 }
832 } catch (InterruptedException e) {
833 Thread.currentThread().interrupt();
834 LOG.debug("Unload interrupted: {} - {}", statusCode, out);
835 throw new OllamaException(statusCode + " - " + out, e);
836 } catch (Exception e) {
837 LOG.debug("Unload failed: {} - {}", statusCode, out);
838 throw new OllamaException(statusCode + " - " + out, e);
839 } finally {
841 url,
842 "",
843 false,
845 false,
846 null,
847 null,
848 startTime,
849 statusCode,
850 out);
851 }
852 }
853
862 long startTime = System.currentTimeMillis();
863 String url = "/api/embed";
864 int statusCode = -1;
865 Object out = null;
866 try {
867 String jsonData = Utils.getObjectMapper().writeValueAsString(modelRequest);
868 HttpClient httpClient = HttpClient.newHttpClient();
869 HttpRequest request =
870 HttpRequest.newBuilder(new URI(this.host + url))
871 .header(
872 Constants.HttpConstants.HEADER_KEY_ACCEPT,
873 Constants.HttpConstants.APPLICATION_JSON)
874 .POST(HttpRequest.BodyPublishers.ofString(jsonData))
875 .build();
876 HttpResponse<String> response =
877 httpClient.send(request, HttpResponse.BodyHandlers.ofString());
878 statusCode = response.statusCode();
879 String responseBody = response.body();
880 if (statusCode == 200) {
881 return Utils.getObjectMapper().readValue(responseBody, OllamaEmbedResult.class);
882 } else {
883 throw new OllamaException(statusCode + " - " + responseBody);
884 }
885 } catch (InterruptedException e) {
886 Thread.currentThread().interrupt();
887 throw new OllamaException("Thread was interrupted", e);
888 } catch (Exception e) {
889 throw new OllamaException(e.getMessage(), e);
890 } finally {
892 url,
893 "",
894 false,
896 false,
897 null,
898 null,
899 startTime,
900 statusCode,
901 out);
902 }
903 }
904
916 throws OllamaException {
917 try {
918 if (request.isUseTools()) {
919 return generateWithToolsInternal(request, streamObserver);
920 }
921
922 if (streamObserver != null) {
923 if (!request.getThink().equals(ThinkMode.DISABLED)) {
924 return generateSyncForOllamaRequestModel(
925 request,
926 streamObserver.getThinkingStreamHandler(),
927 streamObserver.getResponseStreamHandler());
928 } else {
929 return generateSyncForOllamaRequestModel(
930 request, null, streamObserver.getResponseStreamHandler());
931 }
932 }
933 return generateSyncForOllamaRequestModel(request, null, null);
934 } catch (Exception e) {
935 throw new OllamaException(e.getMessage(), e);
936 }
937 }
938
950 throws OllamaException {
951 long startTime = System.currentTimeMillis();
952 String url = "/api/generate";
953 int statusCode = -1;
954 Object out = null;
955 try {
956 String jsonData = Utils.getObjectMapper().writeValueAsString(request);
957 HttpClient httpClient = HttpClient.newHttpClient();
958 HttpRequest httpRequest =
959 HttpRequest.newBuilder(new URI(this.host + url))
960 .header(
961 Constants.HttpConstants.HEADER_KEY_ACCEPT,
962 Constants.HttpConstants.APPLICATION_JSON)
963 .header(
964 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
965 Constants.HttpConstants.APPLICATION_JSON)
966 .POST(HttpRequest.BodyPublishers.ofString(jsonData))
967 .build();
968
969 HttpResponse<InputStream> response =
970 httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());
971 statusCode = response.statusCode();
972
973 if (statusCode != 200) {
974 throw new OllamaException(statusCode + " - " + response.body());
975 }
976
977 InputStream inputStream = response.body();
978 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
979 String line;
980 OllamaImageResult finalResult = null;
981 while ((line = reader.readLine()) != null) {
982 if (line.trim().isEmpty()) continue;
983
984 // Try to detect a "done": true final response to return as OllamaImageResult
985 try {
986 // Attempt to parse any response as an OllamaImageResult, keep latest
987 // "done":true one
988 OllamaImageResult result =
989 Utils.getObjectMapper().readValue(line, OllamaImageResult.class);
990 if (result.getCompleted() != null && result.getTotal() != null) {
991 int progressPercentage =
992 (int) ((result.getCompleted() * 100f) / result.getTotal());
993 LOG.debug(
994 "["
995 + result.getCompleted()
996 + " of "
997 + result.getTotal()
998 + " steps complete] - "
999 + progressPercentage
1000 + "%");
1001 }
1002 if (result != null && result.isDone()) {
1003 finalResult = result;
1004 break; // Stream complete
1005 }
1006 } catch (Exception ignore) {
1007 // May be an intermediate/status update, not full object, or parse error
1008 }
1009 }
1010
1011 if (finalResult != null) {
1012 return finalResult;
1013 } else {
1014 throw new OllamaException("Did not receive a valid image result.");
1015 }
1016 } catch (Exception e) {
1017 throw new OllamaException(e.getMessage(), e);
1018 } finally {
1020 url,
1021 request.getModel(),
1022 false,
1024 false,
1025 null,
1026 null,
1027 startTime,
1028 statusCode,
1029 out);
1030 }
1031 }
1032
1033 // (No javadoc for private helper, as is standard)
1034 private OllamaResult generateWithToolsInternal(
1036 throws OllamaException {
1037 ArrayList<OllamaChatMessage> msgs = new ArrayList<>();
1038 OllamaChatRequest chatRequest = new OllamaChatRequest();
1039 chatRequest.setModel(request.getModel());
1041 ocm.setRole(OllamaChatMessageRole.USER);
1042 ocm.setResponse(request.getPrompt());
1043 chatRequest.setMessages(msgs);
1044 msgs.add(ocm);
1045
1046 // Merge request's tools and globally registered tools into a new list to avoid
1047 // mutating the
1048 // original request
1049 List<Tools.Tool> allTools = new ArrayList<>();
1050 if (request.getTools() != null) {
1051 allTools.addAll(request.getTools());
1052 }
1053 List<Tools.Tool> registeredTools = this.getRegisteredTools();
1054 if (registeredTools != null) {
1055 allTools.addAll(registeredTools);
1056 }
1057
1058 OllamaChatTokenHandler hdlr = null;
1059 chatRequest.setUseTools(true);
1060 chatRequest.setTools(allTools);
1061 if (streamObserver != null) {
1062 chatRequest.setStream(true);
1063 if (streamObserver.getResponseStreamHandler() != null) {
1064 hdlr =
1065 chatResponseModel ->
1066 streamObserver
1067 .getResponseStreamHandler()
1068 .accept(chatResponseModel.getMessage().getResponse());
1069 }
1070 }
1071 OllamaChatResult res = chat(chatRequest, hdlr);
1072 return new OllamaResult(
1073 res.getResponseModel().getMessage().getResponse(),
1074 res.getResponseModel().getMessage().getThinking(),
1075 res.getResponseModel().getTotalDuration(),
1076 -1);
1077 }
1078
1090 String model, String prompt, boolean raw, ThinkMode think) throws OllamaException {
1091 long startTime = System.currentTimeMillis();
1092 String url = "/api/generate";
1093 int statusCode = -1;
1094 try {
1095 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
1096 ollamaRequestModel.setRaw(raw);
1097 ollamaRequestModel.setThink(think);
1098 OllamaAsyncResultStreamer ollamaAsyncResultStreamer =
1100 getRequestBuilderDefault(new URI(this.host + url)),
1101 ollamaRequestModel,
1102 requestTimeoutSeconds);
1103 ollamaAsyncResultStreamer.start();
1104 statusCode = ollamaAsyncResultStreamer.getHttpStatusCode();
1105 return ollamaAsyncResultStreamer;
1106 } catch (Exception e) {
1107 throw new OllamaException(e.getMessage(), e);
1108 } finally {
1110 url, model, raw, think, true, null, null, startTime, statusCode, null);
1111 }
1112 }
1113
1127 throws OllamaException {
1128 try {
1129 OllamaChatEndpointCaller requestCaller =
1130 new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds);
1131 OllamaChatResult result;
1132
1133 // only add tools if tools flag is set
1134 if (request.isUseTools()) {
1135 // add all registered tools to request
1136 request.getTools().addAll(toolRegistry.getRegisteredTools());
1137 }
1138
1139 if (tokenHandler != null) {
1140 request.setStream(true);
1141 result = requestCaller.call(request, tokenHandler);
1142 } else {
1143 result = requestCaller.callSync(request);
1144 }
1145
1146 // check if toolCallIsWanted
1147 List<OllamaChatToolCalls> toolCalls =
1148 result.getResponseModel().getMessage().getToolCalls();
1149
1150 int toolCallTries = 0;
1151 while (toolCalls != null
1152 && !toolCalls.isEmpty()
1153 && toolCallTries < maxChatToolCallRetries) {
1154 for (OllamaChatToolCalls toolCall : toolCalls) {
1155 String toolName = toolCall.getFunction().getName();
1156 for (Tools.Tool t : request.getTools()) {
1157 if (t.getToolSpec().getName().equals(toolName)) {
1158 ToolFunction toolFunction = t.getToolFunction();
1159 if (toolFunction == null) {
1160 throw new ToolInvocationException(
1161 "Tool function not found: " + toolName);
1162 }
1163 LOG.debug(
1164 "Invoking tool {} with arguments: {}",
1165 toolCall.getFunction().getName(),
1166 toolCall.getFunction().getArguments());
1167 Map<String, Object> arguments = toolCall.getFunction().getArguments();
1168 Object res = toolFunction.apply(arguments);
1169 String argumentKeys =
1170 arguments.keySet().stream()
1171 .map(Object::toString)
1172 .collect(Collectors.joining(", "));
1173 request.getMessages()
1174 .add(
1177 "[TOOL_RESULTS] "
1178 + toolName
1179 + "("
1180 + argumentKeys
1181 + "): "
1182 + res
1183 + " [/TOOL_RESULTS]"));
1184 }
1185 }
1186 }
1187 if (tokenHandler != null) {
1188 result = requestCaller.call(request, tokenHandler);
1189 } else {
1190 result = requestCaller.callSync(request);
1191 }
1192 toolCalls = result.getResponseModel().getMessage().getToolCalls();
1193 toolCallTries++;
1194 }
1195 return result;
1196 } catch (InterruptedException e) {
1197 Thread.currentThread().interrupt();
1198 throw new OllamaException("Thread was interrupted", e);
1199 } catch (Exception e) {
1200 throw new OllamaException(e.getMessage(), e);
1201 }
1202 }
1203
1209 public void registerTool(Tools.Tool tool) {
1210 toolRegistry.addTool(tool);
1211 LOG.debug("Registered tool: {}", tool.getToolSpec().getName());
1212 }
1213
1220 public void registerTools(List<Tools.Tool> tools) {
1221 toolRegistry.addTools(tools);
1222 }
1223
1225 return toolRegistry.getRegisteredTools();
1226 }
1227
1232 public void deregisterTools() {
1233 toolRegistry.clear();
1234 LOG.debug("All tools have been deregistered.");
1235 }
1236
1246 try {
1247 Class<?> callerClass = null;
1248 try {
1249 callerClass =
1250 Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
1251 } catch (ClassNotFoundException e) {
1252 throw new OllamaException(e.getMessage(), e);
1253 }
1254
1255 OllamaToolService ollamaToolServiceAnnotation =
1256 callerClass.getDeclaredAnnotation(OllamaToolService.class);
1257 if (ollamaToolServiceAnnotation == null) {
1258 throw new IllegalStateException(
1259 callerClass + " is not annotated as " + OllamaToolService.class);
1260 }
1261
1262 Class<?>[] providers = ollamaToolServiceAnnotation.providers();
1263 for (Class<?> provider : providers) {
1264 registerAnnotatedTools(provider.getDeclaredConstructor().newInstance());
1265 }
1266 } catch (InstantiationException
1267 | NoSuchMethodException
1268 | IllegalAccessException
1269 | InvocationTargetException e) {
1270 throw new OllamaException(e.getMessage());
1271 }
1272 }
1273
1283 public void registerAnnotatedTools(Object object) {
1284 Class<?> objectClass = object.getClass();
1285 Method[] methods = objectClass.getMethods();
1286 for (Method m : methods) {
1287 ToolSpec toolSpec = m.getDeclaredAnnotation(ToolSpec.class);
1288 if (toolSpec == null) {
1289 continue;
1290 }
1291 String operationName = !toolSpec.name().isBlank() ? toolSpec.name() : m.getName();
1292 String operationDesc = !toolSpec.desc().isBlank() ? toolSpec.desc() : operationName;
1293
1294 final Map<String, Tools.Property> params = new HashMap<String, Tools.Property>() {};
1295 LinkedHashMap<String, String> methodParams = new LinkedHashMap<>();
1296 for (Parameter parameter : m.getParameters()) {
1297 final ToolProperty toolPropertyAnn =
1298 parameter.getDeclaredAnnotation(ToolProperty.class);
1299 String propType = parameter.getType().getTypeName();
1300 if (toolPropertyAnn == null) {
1301 methodParams.put(parameter.getName(), null);
1302 continue;
1303 }
1304 String propName =
1305 !toolPropertyAnn.name().isBlank()
1306 ? toolPropertyAnn.name()
1307 : parameter.getName();
1308 methodParams.put(propName, propType);
1309 params.put(
1310 propName,
1311 Tools.Property.builder()
1312 .type(propType)
1313 .description(toolPropertyAnn.desc())
1314 .required(toolPropertyAnn.required())
1315 .build());
1316 }
1317 Tools.ToolSpec toolSpecification =
1318 Tools.ToolSpec.builder()
1319 .name(operationName)
1320 .description(operationDesc)
1321 .parameters(Tools.Parameters.of(params))
1322 .build();
1323 ReflectionalToolFunction reflectionalToolFunction =
1324 new ReflectionalToolFunction(object, m, methodParams);
1325 toolRegistry.addTool(
1326 Tools.Tool.builder()
1327 .toolFunction(reflectionalToolFunction)
1328 .toolSpec(toolSpecification)
1329 .build());
1330 }
1331 }
1332
1339 public OllamaChatMessageRole addCustomRole(String roleName) {
1340 return OllamaChatMessageRole.newCustomRole(roleName);
1341 }
1342
1348 public List<OllamaChatMessageRole> listRoles() {
1350 }
1351
1359 public OllamaChatMessageRole getRole(String roleName) throws RoleNotFoundException {
1360 return OllamaChatMessageRole.getRole(roleName);
1361 }
1362
1363 public void loadMCPToolsFromJson(String mcpConfigJsonFilePath) throws IOException {
1364 String jsonContent =
1365 java.nio.file.Files.readString(java.nio.file.Paths.get(mcpConfigJsonFilePath));
1366 MCPToolsConfig config =
1367 McpJsonMapper.getDefault().readValue(jsonContent, MCPToolsConfig.class);
1368
1369 if (config.mcpServers != null && !config.mcpServers.isEmpty()) {
1370 for (Map.Entry<String, MCPToolConfig> tool : config.mcpServers.entrySet()) {
1371 ServerParameters.Builder serverParamsBuilder =
1372 ServerParameters.builder(tool.getValue().command);
1373 if (tool.getValue().args != null && !tool.getValue().args.isEmpty()) {
1374 LOG.debug(
1375 "Runnable MCP Tool command: \n\n\t{} {}\n\n",
1376 tool.getValue().command,
1377 String.join(" ", tool.getValue().args));
1378 serverParamsBuilder.args(tool.getValue().args.toArray(new String[0]));
1379 }
1380 ServerParameters serverParameters = serverParamsBuilder.build();
1381 StdioClientTransport transport =
1382 new StdioClientTransport(serverParameters, McpJsonMapper.getDefault());
1383
1384 int mcpToolRequestTimeoutSeconds = 30;
1385 try {
1386 McpSyncClient client =
1387 McpClient.sync(transport)
1388 .requestTimeout(
1389 Duration.ofSeconds(mcpToolRequestTimeoutSeconds))
1390 .build();
1391 client.initialize();
1392
1393 ListToolsResult result = client.listTools();
1394 for (io.modelcontextprotocol.spec.McpSchema.Tool mcpTool : result.tools()) {
1395 Tools.Tool mcpToolAsOllama4jTool =
1396 createOllamaToolFromMCPTool(
1397 tool.getKey(), mcpTool, serverParameters);
1398 toolRegistry.addTool(mcpToolAsOllama4jTool);
1399 }
1400 client.close();
1401 } finally {
1402 transport.close();
1403 }
1404 }
1405 }
1406 }
1407
1420 private CallToolResult callMCPTool(
1421 String mcpServerName, String toolName, Map<String, Object> arguments) {
1422 for (Tools.Tool tool : getRegisteredTools()) {
1423 if (tool.isMCPTool() && tool.getMcpServerName().equals(mcpServerName)) {
1424 if (tool.getToolSpec().getName().equals(toolName)) {
1425 ServerParameters serverParameters = tool.getMcpServerParameters();
1426 StdioClientTransport stdioTransport =
1427 new StdioClientTransport(serverParameters, McpJsonMapper.getDefault());
1428 try {
1429 LOG.info(
1430 "Calling MCP Tool: '{}.{}' with arguments: {}",
1431 mcpServerName,
1432 toolName,
1433 arguments);
1434 try (McpSyncClient client =
1435 McpClient.sync(stdioTransport)
1436 .requestTimeout(Duration.ofSeconds(requestTimeoutSeconds))
1437 .build()) {
1438 client.initialize();
1439 CallToolRequest request = new CallToolRequest(toolName, arguments);
1440 return client.callTool(request);
1441 }
1442 } finally {
1443 stdioTransport.close();
1444 }
1445 }
1446 }
1447 }
1448 throw new IllegalArgumentException(
1449 "No MCP tool found for server name: "
1450 + mcpServerName
1451 + " and tool name: "
1452 + toolName);
1453 }
1454
1455 // technical private methods //
1456
1464 private static String encodeFileToBase64(File file) throws IOException {
1465 return Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
1466 }
1467
1474 private static String encodeByteArrayToBase64(byte[] bytes) {
1475 return Base64.getEncoder().encodeToString(bytes);
1476 }
1477
1491 private OllamaResult generateSyncForOllamaRequestModel(
1492 OllamaGenerateRequest ollamaRequestModel,
1493 OllamaGenerateTokenHandler thinkingStreamHandler,
1494 OllamaGenerateTokenHandler responseStreamHandler)
1495 throws OllamaException {
1496 long startTime = System.currentTimeMillis();
1497 int statusCode = -1;
1498 Object out = null;
1499 try {
1500 OllamaGenerateEndpointCaller requestCaller =
1501 new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds);
1502 OllamaResult result;
1503 if (responseStreamHandler != null) {
1504 ollamaRequestModel.setStream(true);
1505 result =
1506 requestCaller.call(
1507 ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
1508 } else {
1509 result = requestCaller.callSync(ollamaRequestModel);
1510 }
1511 statusCode = result.getHttpStatusCode();
1512 out = result;
1513 return result;
1514 } catch (InterruptedException e) {
1515 Thread.currentThread().interrupt();
1516 throw new OllamaException("Thread was interrupted", e);
1517 } catch (Exception e) {
1518 throw new OllamaException(e.getMessage(), e);
1519 } finally {
1522 ollamaRequestModel.getModel(),
1523 ollamaRequestModel.isRaw(),
1524 ollamaRequestModel.getThink(),
1525 ollamaRequestModel.isStream(),
1526 ollamaRequestModel.getOptions(),
1527 ollamaRequestModel.getFormat(),
1528 startTime,
1529 statusCode,
1530 out);
1531 }
1532 }
1533
1540 private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
1541 HttpRequest.Builder requestBuilder =
1542 HttpRequest.newBuilder(uri)
1543 .header(
1544 Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
1545 Constants.HttpConstants.APPLICATION_JSON)
1546 .timeout(Duration.ofSeconds(requestTimeoutSeconds));
1547 if (isAuthSet()) {
1548 requestBuilder.header("Authorization", auth.getAuthHeaderValue());
1549 }
1550 return requestBuilder;
1551 }
1552
1558 private boolean isAuthSet() {
1559 return auth != null;
1560 }
1561
1562 @Data
1563 @NoArgsConstructor
1564 @AllArgsConstructor
1565 public static class OllamaMCPTool {
1566 private String mcpServerName;
1567 private List<MCPToolInfo> toolInfos;
1568 private StdioClientTransport transport;
1569 }
1570
1571 @Data
1572 @NoArgsConstructor
1573 @AllArgsConstructor
1574 public static class MCPToolInfo {
1575 private String toolName;
1576 private String toolDescription;
1577 }
1578
1579 public static class MCPToolConfig {
1580 @JsonProperty("command")
1581 public String command;
1582
1583 @JsonProperty("args")
1584 public List<String> args;
1585 }
1586
1587 public static class MCPToolsConfig {
1588 @JsonProperty("mcpServers")
1589 public Map<String, MCPToolConfig> mcpServers;
1590 }
1591
1592 @Data
1593 @NoArgsConstructor
1594 @AllArgsConstructor
1595 public static class OllamaMCPToolMatchResponse {
1596 @JsonProperty("mcpServerName")
1597 public String mcpServerName;
1598
1599 @JsonProperty("toolName")
1600 public String toolName;
1601
1602 @JsonProperty("arguments")
1603 public Map<String, Object> arguments;
1604 }
1605
1616 private Tools.Tool createOllamaToolFromMCPTool(
1617 String mcpServerName,
1618 io.modelcontextprotocol.spec.McpSchema.Tool mcpTool,
1619 ServerParameters serverParameters) {
1620 Map<String, Tools.Property> properties = new java.util.HashMap<>();
1621 java.util.List<String> requiredList = new java.util.ArrayList<>();
1622
1623 if (mcpTool.inputSchema() != null && mcpTool.inputSchema().properties() != null) {
1624 // Prepare set for fast required lookup (since original is List<String>)
1625 java.util.Set<String> requiredSet = new java.util.HashSet<>();
1626 if (mcpTool.inputSchema().required() != null) {
1627 requiredSet.addAll(mcpTool.inputSchema().required());
1628 }
1629 for (Map.Entry<String, Object> entry : mcpTool.inputSchema().properties().entrySet()) {
1630 String propName = entry.getKey();
1631 Object propertyValue = entry.getValue();
1632 Map<String, Object> propertyMap = null;
1633
1634 if (propertyValue instanceof Map) {
1635 propertyMap = (Map<String, Object>) propertyValue;
1636 } else {
1637 // Defensive fallback, unexpected schema
1638 continue;
1639 }
1640
1641 // Extract standard fields; fallback to empty/defaults
1642 String type =
1643 propertyMap.get("type") != null ? propertyMap.get("type").toString() : null;
1644
1645 String description = null;
1646 if (propertyMap.get("description") != null) {
1647 description = propertyMap.get("description").toString();
1648 } else if (propertyMap.get("title") != null) {
1649 // Use 'title' as fallback for description if 'description' is missing
1650 description = propertyMap.get("title").toString();
1651 }
1652
1653 // 'required' is determined from the parent 'required' list
1654 boolean propRequired = requiredSet.contains(propName);
1655
1656 Tools.Property property =
1657 Tools.Property.builder()
1658 .type(type)
1659 .description(description)
1660 .required(propRequired)
1661 .build();
1662
1663 properties.put(propName, property);
1664 if (propRequired) {
1665 requiredList.add(propName);
1666 }
1667 }
1668 }
1669
1670 Tools.Parameters params = new Tools.Parameters();
1671 params.setProperties(properties);
1672 params.setRequired(requiredList);
1673
1674 return Tools.Tool.builder()
1675 .toolSpec(
1676 Tools.ToolSpec.builder()
1677 .name(mcpTool.name())
1678 .description(mcpTool.description())
1679 .parameters(params)
1680 .build())
1681 .toolFunction(
1682 arguments -> {
1683 CallToolResult result =
1684 this.callMCPTool(mcpServerName, mcpTool.name(), arguments);
1685 return result.toString();
1686 })
1687 .isMCPTool(true)
1688 .mcpServerName(mcpServerName)
1689 .mcpServerParameters(serverParameters)
1690 .build();
1691 }
1692}
void setBasicAuth(String username, String password)
Definition Ollama.java:150
OllamaChatMessageRole getRole(String roleName)
Definition Ollama.java:1359
OllamaEmbedResult embed(OllamaEmbedRequest modelRequest)
Definition Ollama.java:861
OllamaAsyncResultStreamer generateAsync(String model, String prompt, boolean raw, ThinkMode think)
Definition Ollama.java:1089
void loadMCPToolsFromJson(String mcpConfigJsonFilePath)
Definition Ollama.java:1363
List< Tools.Tool > getRegisteredTools()
Definition Ollama.java:1224
OllamaResult generate(OllamaGenerateRequest request, OllamaGenerateStreamObserver streamObserver)
Definition Ollama.java:914
void unloadModel(String modelName)
Definition Ollama.java:792
void registerTool(Tools.Tool tool)
Definition Ollama.java:1209
void pullModel(String modelName)
Definition Ollama.java:529
OllamaChatResult chat(OllamaChatRequest request, OllamaChatTokenHandler tokenHandler)
Definition Ollama.java:1126
List< Model > listModels()
Definition Ollama.java:275
List< OllamaChatMessageRole > listRoles()
Definition Ollama.java:1348
OllamaChatMessageRole addCustomRole(String roleName)
Definition Ollama.java:1339
void setBearerAuth(String bearerToken)
Definition Ollama.java:159
ModelProcessesResult ps()
Definition Ollama.java:217
void createModel(CustomModelRequest customModelRequest, ModelPullListener listener)
Definition Ollama.java:648
void pullModel(String modelName, ModelPullListener listener)
Definition Ollama.java:541
void createModel(CustomModelRequest customModelRequest)
Definition Ollama.java:637
void registerAnnotatedTools(Object object)
Definition Ollama.java:1283
void registerTools(List< Tools.Tool > tools)
Definition Ollama.java:1220
void deleteModel(String modelName, boolean ignoreIfNotPresent)
Definition Ollama.java:729
ModelDetail getModelDetails(String modelName)
Definition Ollama.java:583
OllamaImageResult generateImage(OllamaGenerateImageRequest request)
Definition Ollama.java:949
static void record(String endpoint, String model, boolean raw, ThinkMode thinkMode, boolean streaming, Map< String, Object > options, Object format, long startTime, int responseHttpStatus, Object response)
static OllamaChatMessageRole newCustomRole(String roleName)
static OllamaChatMessageRole getRole(String roleName)
OllamaChatResult call(OllamaChatRequest body, OllamaChatTokenHandler tokenHandler)
OllamaResult call(OllamaRequestBody body, OllamaGenerateTokenHandler thinkingStreamHandler, OllamaGenerateTokenHandler responseStreamHandler)
void addTools(List< Tools.Tool > tools)
static ObjectMapper getObjectMapper()
Definition Utils.java:32
Object apply(Map< String, Object > arguments)