diff --git a/pom.xml b/pom.xml
index f19ef4d..d05cf48 100644
--- a/pom.xml
+++ b/pom.xml
@@ -259,6 +259,12 @@
jackson-databind
2.20.0
+
+ tools.jackson.dataformat
+ jackson-dataformat-yaml
+ 3.0.0
+
+
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
diff --git a/src/main/java/io/github/ollama4j/agent/Agent.java b/src/main/java/io/github/ollama4j/agent/Agent.java
index 942968c..7b3f665 100644
--- a/src/main/java/io/github/ollama4j/agent/Agent.java
+++ b/src/main/java/io/github/ollama4j/agent/Agent.java
@@ -12,10 +12,14 @@ 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.*;
+import tools.jackson.dataformat.yaml.YAMLMapper;
public class Agent {
private final String name;
@@ -23,13 +27,75 @@ public class Agent {
private final Ollama ollamaClient;
private final String model;
private final List chatHistory;
+ private final String customPrompt;
- public Agent(String name, Ollama ollamaClient, String model, List tools) {
+ public Agent(
+ String name,
+ Ollama ollamaClient,
+ String model,
+ String customPrompt,
+ List tools) {
this.name = name;
this.ollamaClient = ollamaClient;
this.chatHistory = new ArrayList<>();
this.tools = tools;
this.model = model;
+ this.customPrompt = customPrompt;
+ }
+
+ public static Agent fromYaml(String agentYaml) {
+ try {
+ YAMLMapper mapper = new YAMLMapper();
+ InputStream input = Agent.class.getClassLoader().getResourceAsStream(agentYaml);
+ if (input == null) {
+ java.nio.file.Path filePath = java.nio.file.Paths.get(agentYaml);
+ 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");
+ }
+ }
+ AgentSpec agentSpec = mapper.readValue(input, AgentSpec.class);
+ List tools = agentSpec.getTools();
+ for (AgentToolSpec tool : tools) {
+ String fqcn = tool.getToolFunctionFQCN();
+ if (fqcn != null && !fqcn.isEmpty()) {
+ try {
+ Class> clazz = Class.forName(fqcn);
+ Object instance = clazz.getDeclaredConstructor().newInstance();
+ if (instance instanceof ToolFunction) {
+ tool.setToolFunctionInstance((ToolFunction) instance);
+ } else {
+ throw new RuntimeException(
+ "Class does not implement ToolFunction: " + fqcn);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Failed to instantiate tool function: " + fqcn, e);
+ }
+ }
+ }
+ List agentTools = new ArrayList<>();
+ for (AgentToolSpec a : tools) {
+ Tools.Tool t = new Tools.Tool();
+ t.setToolFunction(a.getToolFunctionInstance());
+ Tools.ToolSpec ts = new Tools.ToolSpec();
+ ts.setName(a.getName());
+ ts.setDescription(a.getDescription());
+ ts.setParameters(a.getParameters());
+ t.setToolSpec(ts);
+ agentTools.add(t);
+ }
+ return new Agent(
+ agentSpec.getName(),
+ new Ollama(agentSpec.getHost()),
+ agentSpec.getModel(),
+ agentSpec.getCustomPrompt(),
+ agentTools);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load agent from YAML", e);
+ }
}
public String think(String userInput) throws OllamaException {
@@ -48,17 +114,34 @@ public class Agent {
}
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. You"
+ // + " respond very precisely and you don't
+ // overthink or be too"
+ // + " creative. Do not ever reveal the tool
+ // specification in"
+ // + " terms of code or JSON or in a way that
+ // a software engineer"
+ // + " sees it. Just be careful with your
+ // responses and respond"
+ // + " like a human. Note that you only
+ // execute tools provided to"
+ // + " you. Following are the tools that you
+ // have access to and"
+ // + " you can perform right actions using
+ // right tools."
+ // + availableToolsDescription));
new OllamaChatMessage(
OllamaChatMessageRole.SYSTEM,
"You are a helpful assistant named "
+ name
- + ". You only perform tasks using tools available for you. You"
- + " respond very precisely and you don't overthink or be too"
- + " creative. Do not ever reveal the tool specification in"
- + " terms of code or JSON or in a way that a software engineer"
- + " sees it. Just be careful with your responses and respond"
- + " like a human. Note that you only execute tools provided to"
- + " you. Following are the tools that you have access to and"
+ + ". 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));
}
@@ -90,4 +173,23 @@ public class Agent {
String response = this.think(input);
}
}
+
+ @Data
+ public static class AgentSpec {
+ private String name;
+ private String description;
+ private List tools;
+ private Tools.Parameters parameters;
+ private String host;
+ private String model;
+ private String customPrompt;
+ }
+
+ @Data
+ @Setter
+ @Getter
+ private static class AgentToolSpec extends Tools.ToolSpec {
+ private String toolFunctionFQCN = null;
+ private ToolFunction toolFunctionInstance = null;
+ }
}
diff --git a/src/main/java/io/github/ollama4j/agent/SampleAgent.java b/src/main/java/io/github/ollama4j/agent/SampleAgent.java
index 3f55273..43652e4 100644
--- a/src/main/java/io/github/ollama4j/agent/SampleAgent.java
+++ b/src/main/java/io/github/ollama4j/agent/SampleAgent.java
@@ -8,181 +8,218 @@
*/
package io.github.ollama4j.agent;
-import io.github.ollama4j.Ollama;
import io.github.ollama4j.exceptions.OllamaException;
import io.github.ollama4j.tools.ToolFunction;
-import io.github.ollama4j.tools.Tools;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
-/**
- * Example usage of the Agent API with some dummy tool functions.
- */
+/** Example usage of the Agent API with some dummy tool functions. */
public class SampleAgent {
public static void main(String[] args) throws OllamaException {
- Ollama ollama = new Ollama("http://192.168.29.224:11434");
- ollama.setRequestTimeoutSeconds(120);
- String model = "mistral:7b";
- ollama.pullModel(model);
-
- List tools = new ArrayList<>();
- // Weather tool
- tools.add(
- Tools.Tool.builder()
- .toolSpec(
- Tools.ToolSpec.builder()
- .name("weather-tool")
- .description(
- "Gets the current weather for a given location and"
- + " day.")
- .parameters(
- Tools.Parameters.of(
- Map.of(
- "location",
- Tools.Property.builder()
- .type("string")
- .description(
- "The location for"
- + " which to"
- + " get the"
- + " weather.")
- .required(true)
- .build(),
- "day",
- Tools.Property.builder()
- .type("string")
- .description(
- "The day of the"
- + " week for"
- + " which to"
- + " get the"
- + " weather.")
- .required(true)
- .build())))
- .build())
- .toolFunction(new WeatherToolFunction())
- .build());
-
- // Calculator tool
- tools.add(
- Tools.Tool.builder()
- .toolSpec(
- Tools.ToolSpec.builder()
- .name("calculator-tool")
- .description(
- "Performs a simple arithmetic operation between two"
- + " numbers.")
- .parameters(
- Tools.Parameters.of(
- Map.of(
- "operation",
- Tools.Property.builder()
- .type("string")
- .description(
- "The arithmetic"
- + " operation"
- + " to perform."
- + " One of:"
- + " add,"
- + " subtract,"
- + " multiply,"
- + " divide.")
- .required(true)
- .build(),
- "a",
- Tools.Property.builder()
- .type("number")
- .description(
- "The first"
- + " operand.")
- .required(true)
- .build(),
- "b",
- Tools.Property.builder()
- .type("number")
- .description(
- "The second"
- + " operand.")
- .required(true)
- .build())))
- .build())
- .toolFunction(new CalculatorToolFunction())
- .build());
-
- // Hotel Booking tool (dummy)
- tools.add(
- Tools.Tool.builder()
- .toolSpec(
- Tools.ToolSpec.builder()
- .name("hotel-booking-tool")
- .description(
- "Books a hotel room in a specified city for given"
- + " dates and number of guests.")
- .parameters(
- Tools.Parameters.of(
- Map.of(
- "city",
- Tools.Property.builder()
- .type("string")
- .description(
- "The city where the"
- + " hotel will"
- + " be booked.")
- .required(true)
- .build(),
- "checkin_date",
- Tools.Property.builder()
- .type("string")
- .description(
- "Check-in date"
- + " (e.g."
- + " 2025-08-10).")
- .required(true)
- .build(),
- "checkout_date",
- Tools.Property.builder()
- .type("string")
- .description(
- "Check-out date"
- + " (e.g."
- + " 2025-08-12).")
- .required(true)
- .build(),
- "guests",
- Tools.Property.builder()
- .type("number")
- .description(
- "Number of guests"
- + " for the"
- + " booking.")
- .required(true)
- .build())))
- .build())
- .toolFunction(new HotelBookingToolFunction())
- .build());
-
- Agent agent = new Agent("Nimma Mirta", ollama, model, tools);
+ // Ollama ollama = new Ollama("http://192.168.29.224:11434");
+ // ollama.setRequestTimeoutSeconds(120);
+ // String model = "mistral:7b";
+ // ollama.pullModel(model);
+ // List tools = new ArrayList<>();
+ // // Weather tool
+ // tools.add(
+ // Tools.Tool.builder()
+ // .toolSpec(
+ // Tools.ToolSpec.builder()
+ // .name("weather-tool")
+ // .description(
+ // "Gets the current weather for a given
+ // location and"
+ // + " day.")
+ // .parameters(
+ // Tools.Parameters.of(
+ // Map.of(
+ // "location",
+ // Tools.Property.builder()
+ // .type("string")
+ // .description(
+ // "The
+ // location for"
+ // + "
+ // which to"
+ // + "
+ // get the"
+ // + "
+ // weather.")
+ // .required(true)
+ // .build(),
+ // "day",
+ // Tools.Property.builder()
+ // .type("string")
+ // .description(
+ // "The day
+ // of the"
+ // + "
+ // week for"
+ // + "
+ // which to"
+ // + "
+ // get the"
+ // + "
+ // weather.")
+ // .required(true)
+ // .build())))
+ // .build())
+ // .toolFunction(new WeatherToolFunction())
+ // .build());
+ //
+ // // Calculator tool
+ // tools.add(
+ // Tools.Tool.builder()
+ // .toolSpec(
+ // Tools.ToolSpec.builder()
+ // .name("calculator-tool")
+ // .description(
+ // "Performs a simple arithmetic operation
+ // between two"
+ // + " numbers.")
+ // .parameters(
+ // Tools.Parameters.of(
+ // Map.of(
+ // "operation",
+ // Tools.Property.builder()
+ // .type("string")
+ // .description(
+ // "The
+ // arithmetic"
+ // + "
+ // operation"
+ // + " to
+ // perform."
+ // + "
+ // One of:"
+ // + "
+ // add,"
+ // + "
+ // subtract,"
+ // + "
+ // multiply,"
+ // + "
+ // divide.")
+ // .required(true)
+ // .build(),
+ // "a",
+ // Tools.Property.builder()
+ // .type("number")
+ // .description(
+ // "The
+ // first"
+ // + "
+ // operand.")
+ // .required(true)
+ // .build(),
+ // "b",
+ // Tools.Property.builder()
+ // .type("number")
+ // .description(
+ // "The
+ // second"
+ // + "
+ // operand.")
+ // .required(true)
+ // .build())))
+ // .build())
+ // .toolFunction(new CalculatorToolFunction())
+ // .build());
+ //
+ // // Hotel Booking tool (dummy)
+ // tools.add(
+ // Tools.Tool.builder()
+ // .toolSpec(
+ // Tools.ToolSpec.builder()
+ // .name("hotel-booking-tool")
+ // .description(
+ // "Books a hotel room in a specified city
+ // for given"
+ // + " dates and number of guests.")
+ // .parameters(
+ // Tools.Parameters.of(
+ // Map.of(
+ // "city",
+ // Tools.Property.builder()
+ // .type("string")
+ // .description(
+ // "The city
+ // where the"
+ // + "
+ // hotel will"
+ // + " be
+ // booked.")
+ // .required(true)
+ // .build(),
+ // "checkin_date",
+ // Tools.Property.builder()
+ // .type("string")
+ // .description(
+ // "Hotel
+ // check-in date"
+ // + "
+ // (e.g."
+ // + "
+ // 2025-08-10).")
+ // .required(true)
+ // .build(),
+ // "checkout_date",
+ // Tools.Property.builder()
+ // .type("string")
+ // .description(
+ //
+ // "HotelCheck-out date"
+ // + "
+ // (e.g."
+ // + "
+ // 2025-08-12).")
+ // .required(true)
+ // .build(),
+ // "guests",
+ // Tools.Property.builder()
+ // .type("number")
+ // .description(
+ // "Number of
+ // guests"
+ // + "
+ // for the"
+ // + "
+ // booking.")
+ // .required(true)
+ // .build())))
+ // .build())
+ // .toolFunction(new HotelBookingToolFunction())
+ // .build());
+ //
+ // Map functionMap = Map.of(
+ // "weather-tool", new WeatherToolFunction(),
+ // "calculator-tool", new CalculatorToolFunction()
+ // );
+ // List tools =
+ // Tools.fromYAMLFile("/Users/amithkoujalgi/Downloads/tools.yaml", functionMap);
+ // Agent agent = new Agent("Nimma Mirta", ollama, model, tools);
+ Agent agent = Agent.fromYaml("agent.yaml");
agent.runInteractive();
}
}
-/**
- * ToolFunction implementation that returns a dummy weekly weather forecast.
- */
+/** ToolFunction implementation that returns a dummy weekly weather forecast. */
class WeatherToolFunction implements ToolFunction {
@Override
public Object apply(Map arguments) {
String response =
- "Monday: Pleasant, Tuesday: Sunny, Wednesday: Windy, Thursday: Cloudy, Friday:"
- + " Rainy, Saturday: Heavy rains, Sunday: Clear";
+ "Monday: Pleasant."
+ + "Tuesday: Sunny."
+ + "Wednesday: Windy."
+ + "Thursday: Cloudy."
+ + "Friday: Rainy."
+ + "Saturday: Heavy rains."
+ + "Sunday: Clear.";
return response;
}
}
-/**
- * ToolFunction implementation for basic arithmetic calculations.
- */
+/** ToolFunction implementation for basic arithmetic calculations. */
class CalculatorToolFunction implements ToolFunction {
@Override
public Object apply(Map arguments) {
@@ -213,9 +250,7 @@ class CalculatorToolFunction implements ToolFunction {
}
}
-/**
- * ToolFunction implementation simulating a hotel booking.
- */
+/** ToolFunction implementation simulating a hotel booking. */
class HotelBookingToolFunction implements ToolFunction {
@Override
public Object apply(Map arguments) {
diff --git a/src/main/java/io/github/ollama4j/tools/Tools.java b/src/main/java/io/github/ollama4j/tools/Tools.java
index 79fa8e6..b1b4795 100644
--- a/src/main/java/io/github/ollama4j/tools/Tools.java
+++ b/src/main/java/io/github/ollama4j/tools/Tools.java
@@ -11,7 +11,9 @@ 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.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -19,6 +21,8 @@ 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() {}
@@ -116,4 +120,53 @@ public class Tools {
@JsonIgnore private boolean required;
}
+
+ public static List fromJSONFile(String filePath, Map functionMap) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ List