forked from Mirror/ollama4j
		
	Remove SampleAgent class and associated YAML configuration file, streamlining the project by eliminating example implementations and their dependencies.
This commit is contained in:
		
							
								
								
									
										9
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -260,11 +260,10 @@ | ||||
|             <version>2.20.0</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>tools.jackson.dataformat</groupId> | ||||
|             <groupId>com.fasterxml.jackson.dataformat</groupId> | ||||
|             <artifactId>jackson-dataformat-yaml</artifactId> | ||||
|             <version>3.0.0</version> | ||||
|             <version>2.20.0</version> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.fasterxml.jackson.datatype</groupId> | ||||
|             <artifactId>jackson-datatype-jsr310</artifactId> | ||||
| @@ -281,7 +280,6 @@ | ||||
|             <artifactId>slf4j-api</artifactId> | ||||
|             <version>2.0.17</version> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.junit.jupiter</groupId> | ||||
|             <artifactId>junit-jupiter-api</artifactId> | ||||
| @@ -300,7 +298,6 @@ | ||||
|             <version>20250517</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.testcontainers</groupId> | ||||
|             <artifactId>ollama</artifactId> | ||||
| @@ -313,14 +310,12 @@ | ||||
|             <version>1.21.3</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Prometheus metrics dependencies --> | ||||
|         <dependency> | ||||
|             <groupId>io.prometheus</groupId> | ||||
|             <artifactId>simpleclient</artifactId> | ||||
|             <version>0.16.0</version> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.google.guava</groupId> | ||||
|             <artifactId>guava</artifactId> | ||||
|   | ||||
| @@ -8,6 +8,8 @@ | ||||
| */ | ||||
| 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; | ||||
| @@ -19,16 +21,50 @@ import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Scanner; | ||||
| import lombok.*; | ||||
| import tools.jackson.dataformat.yaml.YAMLMapper; | ||||
|  | ||||
| /** | ||||
|  * The {@code Agent} class represents an AI assistant capable of interacting with the Ollama API | ||||
|  * server. | ||||
|  * | ||||
|  * <p>It supports the use of tools (interchangeable code components), persistent chat history, and | ||||
|  * interactive as well as pre-scripted chat sessions. | ||||
|  * | ||||
|  * <h2>Usage</h2> | ||||
|  * | ||||
|  * <ul> | ||||
|  *   <li>Instantiate an Agent via {@link #fromYaml(String)} for YAML-based configuration. | ||||
|  *   <li>Handle conversation turns via {@link #think(String)}. | ||||
|  *   <li>Use {@link #runInteractive()} for an interactive console-based session. | ||||
|  * </ul> | ||||
|  */ | ||||
| public class Agent { | ||||
|     /** The agent's display name */ | ||||
|     private final String name; | ||||
|  | ||||
|     /** List of supported tools for this agent */ | ||||
|     private final List<Tools.Tool> tools; | ||||
|  | ||||
|     /** Ollama client instance for communication with the API */ | ||||
|     private final Ollama ollamaClient; | ||||
|  | ||||
|     /** The model name used for chat completions */ | ||||
|     private final String model; | ||||
|  | ||||
|     /** Persists chat message history across rounds */ | ||||
|     private final List<OllamaChatMessage> chatHistory; | ||||
|  | ||||
|     /** Optional custom system prompt for the agent */ | ||||
|     private final String customPrompt; | ||||
|  | ||||
|     /** | ||||
|      * Constructs a new Agent. | ||||
|      * | ||||
|      * @param name The agent's given name. | ||||
|      * @param ollamaClient The Ollama API client instance to use. | ||||
|      * @param model The model name to use for chat completion. | ||||
|      * @param customPrompt A custom prompt to prepend to all conversations (may be null). | ||||
|      * @param tools List of available tools for function calling. | ||||
|      */ | ||||
|     public Agent( | ||||
|             String name, | ||||
|             Ollama ollamaClient, | ||||
| @@ -43,17 +79,29 @@ public class Agent { | ||||
|         this.customPrompt = customPrompt; | ||||
|     } | ||||
|  | ||||
|     public static Agent fromYaml(String agentYaml) { | ||||
|     /** | ||||
|      * Loads and constructs an Agent from a YAML configuration file (classpath or filesystem). | ||||
|      * | ||||
|      * <p>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 { | ||||
|             YAMLMapper mapper = new YAMLMapper(); | ||||
|             InputStream input = Agent.class.getClassLoader().getResourceAsStream(agentYaml); | ||||
|             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(agentYaml); | ||||
|                 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( | ||||
|                             agentYaml + " not found in classpath or file system"); | ||||
|                             yamlPathOrResource + " not found in classpath or file system"); | ||||
|                 } | ||||
|             } | ||||
|             AgentSpec agentSpec = mapper.readValue(input, AgentSpec.class); | ||||
| @@ -100,61 +148,105 @@ public class Agent { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public String think(String userInput) throws OllamaException { | ||||
|         StringBuilder availableToolsDescription = new StringBuilder(); | ||||
|         if (!tools.isEmpty()) { | ||||
|             for (Tools.Tool t : tools) { | ||||
|                 String toolName = t.getToolSpec().getName(); | ||||
|                 String toolDescription = t.getToolSpec().getDescription(); | ||||
|                 availableToolsDescription.append( | ||||
|                         "\nTool name: '" | ||||
|                                 + toolName | ||||
|                                 + "'. Tool Description: '" | ||||
|                                 + toolDescription | ||||
|                                 + "'.\n"); | ||||
|             } | ||||
|         } | ||||
|     /** | ||||
|      * Facilitates a single round of chat for the agent: | ||||
|      * | ||||
|      * <ul> | ||||
|      *   <li>Builds/promotes the system prompt on the first turn if necessary | ||||
|      *   <li>Adds the user's input to chat history | ||||
|      *   <li>Submits the chat turn to the Ollama model (with tool/function support) | ||||
|      *   <li>Updates internal chat history in accordance with the Ollama chat result | ||||
|      * </ul> | ||||
|      * | ||||
|      * @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) 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()) { | ||||
|             chatHistory.add( | ||||
|                     new OllamaChatMessage( | ||||
|                             OllamaChatMessageRole.SYSTEM, | ||||
|                             "You are a helpful assistant named " | ||||
|                                     + name | ||||
|                                     + ". You only perform tasks using tools available for you. " | ||||
|                                     + customPrompt | ||||
|                                     + ". Following are the tools that you have access to and" | ||||
|                                     + " you can perform right actions using right tools." | ||||
|                                     + availableToolsDescription)); | ||||
|             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) | ||||
|                         .withMessage(OllamaChatMessageRole.USER, userInput) | ||||
|                         .build(); | ||||
|         request.withMessage(OllamaChatMessageRole.USER, userInput); | ||||
|  | ||||
|         OllamaChatStreamObserver chatTokenHandler = | ||||
|                 new OllamaChatStreamObserver( | ||||
|                         new ConsoleOutputGenerateTokenHandler(), | ||||
|                         new ConsoleOutputGenerateTokenHandler()); | ||||
|         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. | ||||
|      * | ||||
|      * <p>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; | ||||
|             String response = this.think(input); | ||||
|             this.interact(input); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Bean describing an agent as definable from YAML. | ||||
|      * | ||||
|      * <ul> | ||||
|      *   <li>{@code name}: Agent display name | ||||
|      *   <li>{@code description}: Freeform description | ||||
|      *   <li>{@code tools}: List of tools/functions to enable | ||||
|      *   <li>{@code host}: Target Ollama host address | ||||
|      *   <li>{@code model}: Name of Ollama model to use | ||||
|      *   <li>{@code customPrompt}: Agent's custom base prompt | ||||
|      *   <li>{@code requestTimeoutSeconds}: Timeout for requests | ||||
|      * </ul> | ||||
|      */ | ||||
|     @Data | ||||
|     public static class AgentSpec { | ||||
|         private String name; | ||||
| @@ -166,19 +258,36 @@ public class Agent { | ||||
|         private int requestTimeoutSeconds; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Subclass extension of {@link Tools.ToolSpec}, which allows associating a tool with a function | ||||
|      * implementation (via FQCN). | ||||
|      */ | ||||
|     @Data | ||||
|     @Setter | ||||
|     @Getter | ||||
|     private static class AgentToolSpec extends Tools.ToolSpec { | ||||
|         /** Fully qualified class name of the tool's {@link ToolFunction} implementation */ | ||||
|         private String toolFunctionFQCN = null; | ||||
|  | ||||
|         /** Instance of the {@link ToolFunction} to invoke */ | ||||
|         private ToolFunction toolFunctionInstance = null; | ||||
|     } | ||||
|  | ||||
|     /** Bean for describing a tool function parameter for use in agent YAML definitions. */ | ||||
|     @Data | ||||
|     public class AgentToolParameter { | ||||
|         /** The parameter's type (e.g., string, number, etc.) */ | ||||
|         private String type; | ||||
|  | ||||
|         /** Description of the parameter */ | ||||
|         private String description; | ||||
|  | ||||
|         /** Whether this parameter is required */ | ||||
|         private boolean required; | ||||
|  | ||||
|         /** | ||||
|          * Enum values (if any) that this parameter may take; _enum used because 'enum' is reserved | ||||
|          */ | ||||
|         private List<String> _enum; // `enum` is a reserved keyword, so use _enum or similar | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,84 +0,0 @@ | ||||
| /* | ||||
|  * 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 io.github.ollama4j.exceptions.OllamaException; | ||||
| import io.github.ollama4j.tools.ToolFunction; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** Example usage of the Agent API with some dummy tool functions. */ | ||||
| public class SampleAgent { | ||||
|     public static void main(String[] args) throws OllamaException { | ||||
|         Agent agent = Agent.fromYaml("agent.yaml"); | ||||
|         agent.runInteractive(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** ToolFunction implementation that returns a dummy weekly weather forecast. */ | ||||
| class WeatherToolFunction implements ToolFunction { | ||||
|     @Override | ||||
|     public Object apply(Map<String, Object> arguments) { | ||||
|         String response = | ||||
|                 "Monday: Pleasant." | ||||
|                         + "Tuesday: Sunny." | ||||
|                         + "Wednesday: Windy." | ||||
|                         + "Thursday: Cloudy." | ||||
|                         + "Friday: Rainy." | ||||
|                         + "Saturday: Heavy rains." | ||||
|                         + "Sunday: Clear."; | ||||
|         return response; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** ToolFunction implementation for basic arithmetic calculations. */ | ||||
| class CalculatorToolFunction implements ToolFunction { | ||||
|     @Override | ||||
|     public Object apply(Map<String, Object> arguments) { | ||||
|         String operation = (String) arguments.get("operation"); | ||||
|         double a = ((Number) arguments.get("a")).doubleValue(); | ||||
|         double b = ((Number) arguments.get("b")).doubleValue(); | ||||
|         double result; | ||||
|         switch (operation.toLowerCase()) { | ||||
|             case "add": | ||||
|                 result = a + b; | ||||
|                 break; | ||||
|             case "subtract": | ||||
|                 result = a - b; | ||||
|                 break; | ||||
|             case "multiply": | ||||
|                 result = a * b; | ||||
|                 break; | ||||
|             case "divide": | ||||
|                 if (b == 0) { | ||||
|                     return "Cannot divide by zero."; | ||||
|                 } | ||||
|                 result = a / b; | ||||
|                 break; | ||||
|             default: | ||||
|                 return "Unknown operation: " + operation; | ||||
|         } | ||||
|         return "Result: " + result; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** ToolFunction implementation simulating a hotel booking. */ | ||||
| class HotelBookingToolFunction implements ToolFunction { | ||||
|     @Override | ||||
|     public Object apply(Map<String, Object> arguments) { | ||||
|         String city = (String) arguments.get("city"); | ||||
|         String checkin = (String) arguments.get("checkin_date"); | ||||
|         String checkout = (String) arguments.get("checkout_date"); | ||||
|         int guests = ((Number) arguments.get("guests")).intValue(); | ||||
|  | ||||
|         // Dummy booking confirmation logic | ||||
|         return String.format( | ||||
|                 "Booking confirmed! %d guest(s) in %s from %s to %s. (Confirmation #DUMMY1234)", | ||||
|                 guests, city, checkin, checkout); | ||||
|     } | ||||
| } | ||||
| @@ -11,8 +11,10 @@ package io.github.ollama4j.tools; | ||||
| import com.fasterxml.jackson.annotation.JsonIgnore; | ||||
| import com.fasterxml.jackson.annotation.JsonInclude; | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| import com.fasterxml.jackson.core.type.TypeReference; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.fasterxml.jackson.databind.node.ObjectNode; | ||||
| import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; | ||||
| import java.io.File; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| @@ -21,8 +23,6 @@ import lombok.AllArgsConstructor; | ||||
| import lombok.Builder; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import tools.jackson.core.type.TypeReference; | ||||
| import tools.jackson.dataformat.yaml.YAMLMapper; | ||||
|  | ||||
| public class Tools { | ||||
|     private Tools() {} | ||||
| @@ -150,7 +150,7 @@ public class Tools { | ||||
|  | ||||
|     public static List<Tool> fromYAMLFile(String filePath, Map<String, ToolFunction> functionMap) { | ||||
|         try { | ||||
|             YAMLMapper mapper = new YAMLMapper(); | ||||
|             ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); | ||||
|             List<Map<String, Object>> rawTools = | ||||
|                     mapper.readValue(new File(filePath), new TypeReference<>() {}); | ||||
|             List<Tool> tools = new ArrayList<>(); | ||||
|   | ||||
| @@ -1,46 +0,0 @@ | ||||
| name: Nimma Mitra | ||||
| host: http://192.168.29.224:11434 | ||||
| model: mistral:7b | ||||
| requestTimeoutSeconds: 120 | ||||
| customPrompt: > | ||||
|   Only use tools and do not use your creativity. | ||||
|   Do not ever tell me to call the tool or how to use the tool or command myself. | ||||
|   You do that for me. That is why you exist. | ||||
|   You call tool on my behalf and give me a response from the tool. | ||||
| tools: | ||||
|   - name: weather-tool | ||||
|     toolFunctionFQCN: io.github.ollama4j.agent.WeatherToolFunction | ||||
|     description: Gets the current weather for a given location and day. | ||||
|     parameters: | ||||
|       properties: | ||||
|         location: | ||||
|           type: string | ||||
|           description: The location for which to get the weather. | ||||
|           required: true | ||||
|         day: | ||||
|           type: string | ||||
|           description: The day of the week for which to get the weather. | ||||
|           required: true | ||||
|  | ||||
|   - name: calculator-tool | ||||
|     toolFunctionFQCN: io.github.ollama4j.agent.CalculatorToolFunction | ||||
|     description: Performs a simple arithmetic operation between two numbers. | ||||
|     parameters: | ||||
|       properties: | ||||
|         operation: | ||||
|           type: string | ||||
|           description: The arithmetic operation to perform. | ||||
|           enum: | ||||
|             - add | ||||
|             - subtract | ||||
|             - multiply | ||||
|             - divide | ||||
|           required: true | ||||
|         a: | ||||
|           type: number | ||||
|           description: The first operand. | ||||
|           required: true | ||||
|         b: | ||||
|           type: number | ||||
|           description: The second operand. | ||||
|           required: true | ||||
		Reference in New Issue
	
	Block a user
	 amithkoujalgi
					amithkoujalgi