- Updated Makefile to add a new remote integration test command.

- Updated docs – Enhanced DBQueryFunction to validate input arguments and throw a RuntimeException if required arguments are missing.
- Updated docs – Refactored tool specifications for fuel price, weather, and employee details to use a unified prompt function structure.  (Addresses #116).
- Improved javadoc for `chatStreaming()` API. (Addresses #115).
- Introduced `ToolInvocationException` to handle errors during tool invocation in OllamaAPI. (Addresses #117).
- Updated integration tests to include `ToolInvocationException` in method signatures for better error handling.
This commit is contained in:
amithkoujalgi
2025-04-06 23:05:26 +05:30
parent 70b4a7961a
commit a2d95a052a
5 changed files with 233 additions and 68 deletions

View File

@@ -1058,7 +1058,7 @@ public class OllamaAPI {
* @param model the ollama model to ask the question to
* @param messages chat history / message stack to send to the model
* @return {@link OllamaChatResult} containing the api response and the message
* history including the newly aqcuired assistant response.
* history including the newly acquired assistant response.
* @throws OllamaBaseException any response code than 200 has been returned
* @throws IOException in case the responseStream can not be read
* @throws InterruptedException in case the server is not reachable or network
@@ -1066,9 +1066,10 @@ public class OllamaAPI {
* @throws OllamaBaseException if the response indicates an error status
* @throws IOException if an I/O error occurs during the HTTP request
* @throws InterruptedException if the operation is interrupted
* @throws ToolInvocationException if the tool invocation fails
*/
public OllamaChatResult chat(String model, List<OllamaChatMessage> messages)
throws OllamaBaseException, IOException, InterruptedException {
throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(model);
return chat(builder.withMessages(messages).build());
}
@@ -1088,9 +1089,10 @@ public class OllamaAPI {
* @throws OllamaBaseException if the response indicates an error status
* @throws IOException if an I/O error occurs during the HTTP request
* @throws InterruptedException if the operation is interrupted
* @throws ToolInvocationException if the tool invocation fails
*/
public OllamaChatResult chat(OllamaChatRequest request)
throws OllamaBaseException, IOException, InterruptedException {
throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
return chat(request, null);
}
@@ -1102,7 +1104,7 @@ public class OllamaAPI {
*
* @param request request object to be sent to the server
* @param streamHandler callback handler to handle the last message from stream
* (caution: all previous messages from stream will be
* (caution: all previous tokens from stream will be
* concatenated)
* @return {@link OllamaChatResult}
* @throws OllamaBaseException any response code than 200 has been returned
@@ -1112,9 +1114,10 @@ public class OllamaAPI {
* @throws OllamaBaseException if the response indicates an error status
* @throws IOException if an I/O error occurs during the HTTP request
* @throws InterruptedException if the operation is interrupted
* @throws ToolInvocationException if the tool invocation fails
*/
public OllamaChatResult chat(OllamaChatRequest request, OllamaStreamHandler streamHandler)
throws OllamaBaseException, IOException, InterruptedException {
throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
return chatStreaming(request, new OllamaChatStreamObserver(streamHandler));
}
@@ -1126,7 +1129,7 @@ public class OllamaAPI {
*
* @param request request object to be sent to the server
* @param tokenHandler callback handler to handle the last token from stream
* (caution: all previous messages from stream will be
* (caution: the previous tokens from stream will not be
* concatenated)
* @return {@link OllamaChatResult}
* @throws OllamaBaseException any response code than 200 has been returned
@@ -1138,7 +1141,7 @@ public class OllamaAPI {
* @throws InterruptedException if the operation is interrupted
*/
public OllamaChatResult chatStreaming(OllamaChatRequest request, OllamaTokenHandler tokenHandler)
throws OllamaBaseException, IOException, InterruptedException {
throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds,
verbose);
OllamaChatResult result;
@@ -1161,6 +1164,9 @@ public class OllamaAPI {
for (OllamaChatToolCalls toolCall : toolCalls) {
String toolName = toolCall.getFunction().getName();
ToolFunction toolFunction = toolRegistry.getToolFunction(toolName);
if (toolFunction == null) {
throw new ToolInvocationException("Tool function not found: " + toolName);
}
Map<String, Object> arguments = toolCall.getFunction().getArguments();
Object res = toolFunction.apply(arguments);
request.getMessages().add(new OllamaChatMessage(OllamaChatMessageRole.TOOL,

View File

@@ -2,6 +2,10 @@ package io.github.ollama4j.exceptions;
public class ToolInvocationException extends Exception {
public ToolInvocationException(String s) {
super(s);
}
public ToolInvocationException(String s, Exception e) {
super(s, e);
}

View File

@@ -3,6 +3,7 @@ package io.github.ollama4j.integrationtests;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.exceptions.OllamaBaseException;
import io.github.ollama4j.exceptions.ToolInvocationException;
import io.github.ollama4j.models.chat.*;
import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel;
import io.github.ollama4j.models.response.LibraryModel;
@@ -233,7 +234,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(8)
void testAskModelWithOptions()
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(CHAT_MODEL_INSTRUCT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_INSTRUCT);
@@ -253,7 +254,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(9)
void testChatWithSystemPrompt()
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM,
@@ -318,7 +319,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(10)
void testChatWithImageFromURL()
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException, ToolInvocationException {
api.pullModel(IMAGE_MODEL_LLAVA);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(IMAGE_MODEL_LLAVA);
@@ -336,7 +337,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(10)
void testChatWithImageFromFileWithHistoryRecognition()
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(IMAGE_MODEL_LLAVA);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(IMAGE_MODEL_LLAVA);
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,
@@ -360,7 +361,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(11)
void testChatWithExplicitToolDefinition()
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
@@ -440,7 +441,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(12)
void testChatWithAnnotatedToolsAndSingleParam()
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException, ToolInvocationException {
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
@@ -471,7 +472,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(13)
void testChatWithAnnotatedToolsAndMultipleParams()
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
@@ -508,7 +509,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(14)
void testChatWithToolsAndStream()
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
@@ -585,7 +586,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(15)
void testChatWithStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
void testChatWithStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException, ToolInvocationException {
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,