Note: the OllamaChatRequestModel#getStream() property is not implemented. * @@ -881,7 +882,7 @@ public class Ollama { // only add tools if tools flag is set if (request.isUseTools()) { // add all registered tools to request - request.setTools(toolRegistry.getRegisteredTools()); + request.getTools().addAll(toolRegistry.getRegisteredTools()); } if (tokenHandler != null) { diff --git a/src/main/java/io/github/ollama4j/agent/Agent.java b/src/main/java/io/github/ollama4j/agent/Agent.java new file mode 100644 index 0000000..72bf2ed --- /dev/null +++ b/src/main/java/io/github/ollama4j/agent/Agent.java @@ -0,0 +1,318 @@ +/* + * 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.agent; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.github.ollama4j.Ollama; +import io.github.ollama4j.exceptions.OllamaException; +import io.github.ollama4j.impl.ConsoleOutputGenerateTokenHandler; +import io.github.ollama4j.models.chat.*; +import io.github.ollama4j.tools.ToolFunction; +import io.github.ollama4j.tools.Tools; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import lombok.*; + +/** + * The {@code Agent} class represents an AI assistant capable of interacting with the Ollama API + * server. + * + *
It supports the use of tools (interchangeable code components), persistent chat history, and + * interactive as well as pre-scripted chat sessions. + * + *
The YAML should define the agent, the model, and the desired tool functions (using their
+ * fully qualified class names for auto-discovery).
+ *
+ * @param yamlPathOrResource Path or classpath resource name of the YAML file.
+ * @return New Agent instance loaded according to the YAML definition.
+ * @throws RuntimeException if the YAML cannot be read or agent cannot be constructed.
+ */
+ public static Agent load(String yamlPathOrResource) {
+ try {
+ ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+
+ InputStream input =
+ Agent.class.getClassLoader().getResourceAsStream(yamlPathOrResource);
+ if (input == null) {
+ java.nio.file.Path filePath = java.nio.file.Paths.get(yamlPathOrResource);
+ if (java.nio.file.Files.exists(filePath)) {
+ input = java.nio.file.Files.newInputStream(filePath);
+ } else {
+ throw new RuntimeException(
+ yamlPathOrResource + " not found in classpath or file system");
+ }
+ }
+ AgentSpec agentSpec = mapper.readValue(input, AgentSpec.class);
+ List Type {@code exit} to break the loop and terminate the session.
+ *
+ * @throws OllamaException if any errors occur talking to the Ollama API.
+ */
+ public void runInteractive() throws OllamaException {
+ Scanner sc = new Scanner(System.in);
+ while (true) {
+ System.out.print("\n[You]: ");
+ String input = sc.nextLine();
+ if ("exit".equalsIgnoreCase(input)) break;
+ this.interact(
+ input,
+ new OllamaChatStreamObserver(
+ new ConsoleOutputGenerateTokenHandler(),
+ new ConsoleOutputGenerateTokenHandler()));
+ }
+ }
+
+ /**
+ * Bean describing an agent as definable from YAML.
+ *
+ *
+ *
+ *
+ * @param userInput The user's message or question for the agent.
+ * @return The model's response as a string.
+ * @throws OllamaException If there is a problem with the Ollama API.
+ */
+ public String interact(String userInput, OllamaChatStreamObserver chatTokenHandler)
+ throws OllamaException {
+ // Build a concise and readable description of available tools
+ String availableToolsDescription =
+ tools.isEmpty()
+ ? ""
+ : tools.stream()
+ .map(
+ t ->
+ String.format(
+ "- %s: %s",
+ t.getToolSpec().getName(),
+ t.getToolSpec().getDescription() != null
+ ? t.getToolSpec().getDescription()
+ : "No description"))
+ .reduce((a, b) -> a + "\n" + b)
+ .map(desc -> "\nYou have access to the following tools:\n" + desc)
+ .orElse("");
+
+ // Add system prompt if chatHistory is empty
+ if (chatHistory.isEmpty()) {
+ String systemPrompt =
+ String.format(
+ "You are a helpful AI assistant named %s. Your actions are limited to"
+ + " using the available tools. %s%s",
+ name,
+ (customPrompt != null ? customPrompt : ""),
+ availableToolsDescription);
+ chatHistory.add(new OllamaChatMessage(OllamaChatMessageRole.SYSTEM, systemPrompt));
+ }
+
+ // Add the user input as a message before sending request
+ chatHistory.add(new OllamaChatMessage(OllamaChatMessageRole.USER, userInput));
+
+ OllamaChatRequest request =
+ OllamaChatRequest.builder()
+ .withTools(tools)
+ .withUseTools(true)
+ .withModel(model)
+ .withMessages(chatHistory)
+ .build();
+ OllamaChatResult response = ollamaClient.chat(request, chatTokenHandler);
+
+ // Update chat history for continuity
+ chatHistory.clear();
+ chatHistory.addAll(response.getChatHistory());
+
+ return response.getResponseModel().getMessage().getResponse();
+ }
+
+ /**
+ * Launches an endless interactive console session with the agent, echoing user input and the
+ * agent's response using the provided chat model and tools.
+ *
+ *
+ *
+ */
+ @Data
+ public static class AgentSpec {
+ private String name;
+ private String description;
+ private List