Enhanced tool management in OllamaObject and added Maven publishing configuration.
Some checks failed
build / build (push) Has been cancelled
Some checks failed
build / build (push) Has been cancelled
- Updated `OllamaObject` to support tool registration with sources. - Improved error handling and debug logging in multiple classes. - Added Maven plugin and publication setup in `build.gradle`. - Updated version to `1.3`. Signed-off-by: Zacharias <zacharias@4zellen.se>
This commit is contained in:
@@ -3,7 +3,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = 'me.zacharias'
|
||||
version = '1.0-SNAPSHOT'
|
||||
version = '1.3'
|
||||
|
||||
dependencies {
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static me.zacharias.chat.ollama.OllamaFunctionArgument.deconstructOllamaFunctionArguments;
|
||||
|
||||
/**
|
||||
* The Main class for the System, responsible for managing the OllamaObject, tools, and the Ollama API.
|
||||
*/
|
||||
@@ -52,7 +54,7 @@ public class Core {
|
||||
/**
|
||||
* The IP of the Ollama API.
|
||||
*/
|
||||
private String ollamaIP = "192.168.5.178";//"192.168.5.184";
|
||||
private String ollamaIP = "10.0.1.101";//"192.168.5.184";
|
||||
/**
|
||||
* The port of the Ollama API.
|
||||
*/
|
||||
@@ -71,11 +73,15 @@ public class Core {
|
||||
*/
|
||||
private boolean supportColor;
|
||||
|
||||
public static final String DATA;
|
||||
public static final File DATA_DIR;
|
||||
public static final File PLUGIN_DIRECTORY;
|
||||
public static String DATA;
|
||||
public static File DATA_DIR;
|
||||
public static File PLUGIN_DIRECTORY;
|
||||
|
||||
static {
|
||||
setDataDirectory("AI-Chat");
|
||||
}
|
||||
|
||||
public static void setDataDirectory(String dataDirectory) {
|
||||
String data;
|
||||
|
||||
if(System.getenv("AI_CHAT_DEBUG") != null) {
|
||||
@@ -86,13 +92,13 @@ public class Core {
|
||||
if(localappdata == null) {
|
||||
localappdata = System.getenv("APPDATA");
|
||||
}
|
||||
data = localappdata + "/AI-CHAT";
|
||||
data = localappdata + "/"+ dataDirectory;
|
||||
}
|
||||
else if (System.getProperty("os.name").toLowerCase().contains("linux")) {
|
||||
data = System.getenv("HOME") + "/.local/share/AI-CHAT";
|
||||
data = System.getenv("HOME") + "/.local/share/" + dataDirectory;
|
||||
}
|
||||
else if (System.getProperty("os.name").toLowerCase().contains("mac")) {
|
||||
data = System.getProperty("user.home") + "/Library/Application Support/AI-CHAT";
|
||||
data = System.getProperty("user.home") + "/Library/Application Support/"+ dataDirectory;
|
||||
}
|
||||
else {
|
||||
data = "./data";
|
||||
@@ -193,7 +199,7 @@ public class Core {
|
||||
messagesWriter.write(messages.toString());
|
||||
messagesWriter.close();
|
||||
|
||||
File f = new File("./data/messages.json");
|
||||
File f = new File(DATA_DIR,"messages.json");
|
||||
if(f.exists())
|
||||
{
|
||||
f.delete();
|
||||
@@ -261,7 +267,7 @@ public class Core {
|
||||
*/
|
||||
public void addTool(OllamaFunctionTool functionTool, @MagicConstant(valuesFromClass = Source.class) String source) {
|
||||
funtionTools.add(new Pair<>(functionTool, source));
|
||||
ollamaObject.addTool(functionTool);
|
||||
ollamaObject.addTool(functionTool, source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,32 +410,34 @@ public class Core {
|
||||
JSONObject function = jsonObject.getJSONObject("function");
|
||||
List<Pair<OllamaFunctionTool, String>> functions = funtionTools.stream().filter(func -> (func.getKey().name()+func.getValue()).equalsIgnoreCase(function.getString("name"))).toList();
|
||||
|
||||
ArrayList<OllamaFunctionArgument> argumentArrayList = new ArrayList<>();
|
||||
|
||||
JSONObject arguments = function.getJSONObject("arguments");
|
||||
|
||||
for (String key : arguments.keySet()) {
|
||||
argumentArrayList.add(new OllamaFunctionArgument(key, arguments.get(key)));
|
||||
}
|
||||
|
||||
if(functions.isEmpty()) {
|
||||
ollamaObject.addMessage(new OllamaToolError("Function '"+function.getString("name")+"' does not exist"));
|
||||
printMessageHandler.printMessage((supportColor ?"\u001b[31m":"")+"Tried funtion call "+function.getString("name")+" but failed to find it."+(printMessageHandler.color()?"\u001b[0m":""));
|
||||
printMessageHandler.printMessage((supportColor ?"\u001b[31m":"")+"Tried funtion call "+function.getString("name")+"("+deconstructOllamaFunctionArguments(argumentArrayList)+") but failed to find it."+(printMessageHandler.color()?"\u001b[0m":""));
|
||||
writeLog("Failed function call to "+function.getString("name"));
|
||||
}
|
||||
else {
|
||||
|
||||
OllamaFunctionTool func = functions.getFirst().getKey();
|
||||
|
||||
ArrayList<OllamaFunctionArgument> argumentArrayList = new ArrayList<>();
|
||||
|
||||
JSONObject arguments = function.getJSONObject("arguments");
|
||||
|
||||
for (String key : arguments.keySet()) {
|
||||
argumentArrayList.add(new OllamaFunctionArgument(key, arguments.get(key)));
|
||||
}
|
||||
// TODO: Check so all arguments is the correct type, else error out in a safe mannet.
|
||||
|
||||
try {
|
||||
OllamaToolRespnce function1 = func.function(argumentArrayList.toArray(new OllamaFunctionArgument[0]));
|
||||
ollamaObject.addMessage(function1);
|
||||
printMessageHandler.printMessage((supportColor?"\u001b[34m":"")+"Call "+func.name() + (supportColor?"\u001b[0m":""));
|
||||
printMessageHandler.printMessage((supportColor?"\u001b[34m":"")+"Call "+func.name() + "(" + deconstructOllamaFunctionArguments(argumentArrayList) + ")" + (supportColor?"\u001b[0m":""));
|
||||
writeLog("Successfully function call " + func.name() + " output: " + function1.getResponse());
|
||||
} catch (OllamaToolErrorException e) {
|
||||
ollamaObject.addMessage(new OllamaToolError(e.getMessage()));
|
||||
printMessageHandler.printMessage((supportColor?"\u001b[31m":"")+"Tried funtion call " + func.name() + " but failed due to " + e.getError() + (supportColor?"\u001b[0m":""));
|
||||
writeLog(e.getMessage());
|
||||
printMessageHandler.printMessage((supportColor?"\u001b[31m":"")+"Tried funtion call " + func.name() + "("+deconstructOllamaFunctionArguments(argumentArrayList)+") but failed due to " + e.getError() + (supportColor?"\u001b[0m":""));
|
||||
writeLog("ERROR: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ public class LaunchOptions {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private LaunchOptions() {}
|
||||
|
||||
private boolean loadOld = true;
|
||||
private boolean autoAccept;
|
||||
private boolean serverMode;
|
||||
|
||||
@@ -18,4 +18,18 @@ public interface PrintMessageHandler {
|
||||
* @return a boolean indicating if color is supported by the PrintMessageHandler.
|
||||
*/
|
||||
boolean color();
|
||||
|
||||
/**
|
||||
* Default method to print error messages to the user or API Client.
|
||||
* This uses ANSI escape codes to color the output red if color is supported.
|
||||
* @param message The error message to be printed.
|
||||
* If color is not supported, it will print the message without color.
|
||||
*/
|
||||
default void printError(String message) {
|
||||
if (color()) {
|
||||
printMessage("\u001B[31m" + message + "\u001B[0m"); // Red color for errors
|
||||
} else {
|
||||
printMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.zacharias.chat.ollama;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Represents an argument passed to a tool.
|
||||
*
|
||||
@@ -37,4 +39,24 @@ public record OllamaFunctionArgument(String argument, Object value) {
|
||||
public Object value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String deconstructOllamaFunctionArgument(OllamaFunctionArgument argument) {
|
||||
return argument.argument() + ": " + argument.value();
|
||||
}
|
||||
|
||||
public static String deconstructOllamaFunctionArguments(OllamaFunctionArgument... arguments) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (OllamaFunctionArgument argument : arguments) {
|
||||
sb.append(deconstructOllamaFunctionArgument(argument)).append(", ");
|
||||
}
|
||||
return sb.toString().replaceAll(", $", "");
|
||||
}
|
||||
|
||||
public static String deconstructOllamaFunctionArguments(ArrayList<OllamaFunctionArgument> arguments) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (OllamaFunctionArgument argument : arguments) {
|
||||
sb.append(deconstructOllamaFunctionArgument(argument)).append(", ");
|
||||
}
|
||||
return sb.toString().replaceAll(", $", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,15 @@ import org.json.JSONObject;
|
||||
*/
|
||||
public abstract class OllamaFunctionTool implements OllamaTool {
|
||||
|
||||
protected String source = "";
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("tool", "function");
|
||||
|
||||
JSONObject function = new JSONObject();
|
||||
function.put("name", name());
|
||||
function.put("name", name()+(source != null ? source : ""));
|
||||
function.put("description", description());
|
||||
function.put("parameters", (parameters() == null?
|
||||
new JSONObject() : new JSONObject(parameters().toString())));
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.zacharias.chat.ollama;
|
||||
import com.sun.source.util.Plugin;
|
||||
import me.zacharias.chat.core.Core;
|
||||
import me.zacharias.chat.core.LaunchOptions;
|
||||
import me.zacharias.chat.core.Pair;
|
||||
import me.zacharias.chat.core.files.FileHandlerLocation;
|
||||
import me.zacharias.chat.core.files.FileHandler;
|
||||
|
||||
@@ -13,6 +14,7 @@ import org.json.JSONObject;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
@@ -41,7 +43,7 @@ public class OllamaObject {
|
||||
/**
|
||||
* The tools of the Ollama Object.
|
||||
*/
|
||||
ArrayList<OllamaTool> tools;
|
||||
ArrayList<Pair<OllamaTool, String>> tools;
|
||||
/**
|
||||
* The format of the Ollama Object.
|
||||
*/
|
||||
@@ -69,7 +71,7 @@ public class OllamaObject {
|
||||
* @param stream If the Ollama Object is streamed. see {@link OllamaObject#stream}
|
||||
* @param keep_alive The keep alive of the Ollama Object. see {@link OllamaObject#keep_alive}
|
||||
*/
|
||||
private OllamaObject(String model, ArrayList<OllamaMessage> messages, ArrayList<OllamaTool> tools, JSONObject format, Map<String, Object> options, boolean stream, String keep_alive) {
|
||||
private OllamaObject(String model, ArrayList<OllamaMessage> messages, ArrayList<Pair<OllamaTool, String>> tools, JSONObject format, Map<String, Object> options, boolean stream, String keep_alive) {
|
||||
this.model = model;
|
||||
this.messages = messages;
|
||||
this.tools = tools;
|
||||
@@ -77,7 +79,7 @@ public class OllamaObject {
|
||||
this.options = options;
|
||||
this.stream = stream;
|
||||
this.keep_alive = keep_alive;
|
||||
LaunchOptions launchOptions = new LaunchOptions();
|
||||
LaunchOptions launchOptions = LaunchOptions.getInstance();
|
||||
if(launchOptions.isLoadOld()) {
|
||||
System.out.println("Loading old data...");
|
||||
File f = new File(Core.DATA_DIR+"/messages.json");
|
||||
@@ -105,6 +107,10 @@ public class OllamaObject {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("No old data found, skipping loading old data.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +134,7 @@ public class OllamaObject {
|
||||
* Gets the tools
|
||||
* @return The tools
|
||||
*/
|
||||
public ArrayList<OllamaTool> getTools() {
|
||||
public ArrayList<Pair<OllamaTool, String>> getTools() {
|
||||
return tools;
|
||||
}
|
||||
|
||||
@@ -136,8 +142,29 @@ public class OllamaObject {
|
||||
* Adds a tool to the Ollama Object
|
||||
* @param tool The tool to add
|
||||
*/
|
||||
public void addTool(OllamaTool tool) {
|
||||
tools.add(tool);
|
||||
public void addTool(OllamaTool tool, @MagicConstant(valuesFromClass = Core.Source.class) String source) {
|
||||
// We inject the source into the tool's source field if it exists, This is to not cause issues with duplicate tools
|
||||
Class<? extends Object> clazz = tool.getClass();
|
||||
Field field = null;
|
||||
while(!clazz.equals(Object.class)) {
|
||||
try {
|
||||
field = clazz.getDeclaredField("source");
|
||||
if (field != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (NoSuchFieldException ignore){}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
field.set(tool, source);
|
||||
} catch (IllegalAccessException e) {
|
||||
Core.writeLog("ERROR: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
tools.add(new Pair<>(tool, source));
|
||||
}
|
||||
|
||||
public void removeTool(OllamaTool tool) {
|
||||
@@ -189,8 +216,11 @@ public class OllamaObject {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
JSONArray tools = new JSONArray();
|
||||
for (OllamaTool tool : this.tools) {
|
||||
tools.put(new JSONObject(tool.toString()));
|
||||
for (Pair<OllamaTool, String> tool : this.tools) {
|
||||
if(tool.getKey().getClass().isInterface()) continue;
|
||||
JSONObject obj = new JSONObject(tool.getKey().toString());
|
||||
//obj.put("name", obj.getString("name") + tool.getValue()); // Injects the source of the tool into the name
|
||||
tools.put(obj);
|
||||
}
|
||||
|
||||
JSONArray messages = new JSONArray();
|
||||
@@ -207,7 +237,7 @@ public class OllamaObject {
|
||||
json.put("keep_alive", keep_alive);
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of OllamaObjectBuilder.
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
@@ -232,7 +262,7 @@ public class OllamaObject {
|
||||
/**
|
||||
* The tools of the Ollama Object.
|
||||
*/
|
||||
ArrayList<OllamaTool> tools = new ArrayList<>();
|
||||
ArrayList<Pair<OllamaTool, String>> tools = new ArrayList<>();
|
||||
/**
|
||||
* The format of the Ollama Object.
|
||||
*/
|
||||
@@ -321,30 +351,72 @@ public class OllamaObject {
|
||||
|
||||
/**
|
||||
* Adds a tool to the Ollama Object
|
||||
* Assumes the tool is from an external source, see {@link OllamaObject.OllamaObjectBuilder#addTool(OllamaTool, String)} to specify the source
|
||||
* @param tool The tool to add
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
*/
|
||||
public OllamaObjectBuilder addTool(OllamaTool tool) {
|
||||
this.tools.add(tool);
|
||||
this.tools.add(new Pair<>(tool, Core.Source.EXTERNAL));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tool to the Ollama Object
|
||||
* This allows you to specify the source of the tool, see {@link OllamaObject.OllamaObjectBuilder#addTool(OllamaTool)} to add a tool from an external source
|
||||
* @param tool The tool to add
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
*/
|
||||
public OllamaObjectBuilder addTool(OllamaTool tool, @MagicConstant(valuesFromClass = Core.Source.class) String source) {
|
||||
this.tools.add(new Pair<>(tool, source));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tools to the Ollama Object
|
||||
* Assumes the tools are from an external source, see {@link OllamaObject.OllamaObjectBuilder#addTools(ArrayList)}} to specify the source
|
||||
* @param tools The tools to add
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
*/
|
||||
public OllamaObjectBuilder addTools(ArrayList<? extends OllamaTool> tools) {
|
||||
this.tools.addAll(tools);
|
||||
public OllamaObjectBuilder addToolsExternal(ArrayList<? extends OllamaTool> tools) {
|
||||
for (OllamaTool tool : tools) {
|
||||
this.tools.add(new Pair<>(tool, Core.Source.EXTERNAL));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tools to the Ollama Object
|
||||
* This allows you to specify the source of the tools, see {@link OllamaObject.OllamaObjectBuilder#addToolsExternal(ArrayList)}} to add tools from an external source
|
||||
* @param tools The tools to add
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
*/
|
||||
public OllamaObjectBuilder addTools(ArrayList<Pair<? extends OllamaTool, String>> tools) {
|
||||
for(Pair<? extends OllamaTool, String> tool : tools) {
|
||||
this.tools.add(new Pair<>(tool.getKey(), tool.getValue()));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tools to the Ollama Object
|
||||
* Assumes the tools are from an external source, see {@link OllamaObject.OllamaObjectBuilder#addTools(Pair[])}} to specify the source
|
||||
* @param tools The tools to add
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
*/
|
||||
public OllamaObjectBuilder addTools(OllamaTool... tools) {
|
||||
for(OllamaTool tool : tools) {
|
||||
this.tools.add(new Pair<>(tool, Core.Source.EXTERNAL));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tools to the Ollama Object
|
||||
* This allows you to specify the source of the tools, see {@link OllamaObject.OllamaObjectBuilder#addTools(OllamaTool[])} to add tools from an external source
|
||||
* @param tools The tools to add
|
||||
* @return The {@link OllamaObjectBuilder}
|
||||
*/
|
||||
public OllamaObjectBuilder addTools(Pair<OllamaTool, String>... tools) {
|
||||
this.tools.addAll(List.of(tools));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,11 @@ public class OllamaPerameter {
|
||||
/**
|
||||
* Represents a array parameter.
|
||||
*/
|
||||
ARRAY("array");
|
||||
ARRAY("array"),
|
||||
/**
|
||||
* Represents a object parameter.
|
||||
*/
|
||||
OBJECT("object");
|
||||
|
||||
/**
|
||||
* The type of the parameter.
|
||||
|
||||
Reference in New Issue
Block a user