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 00000000..72bf2ed0 --- /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