Started implementing jar-based(plugin) tool loading
Core#plugin: - Plugin.java: Main framework for plugins - OllamaTool.java: Used for annotation based loading of tools - InjectPlugin.java: Annoataion for injecting the Plugin instance, used when annotation based loading is used - PluginMetadata.java: metadata of the plugin, a class-reflection of plugin.json file within each plugin - PluginLoadingException.java: Exception thrown when an error happens durring plugin loading
This commit is contained in:
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@@ -13,6 +13,7 @@
|
||||
<option value="$PROJECT_DIR$/Core" />
|
||||
<option value="$PROJECT_DIR$/Display" />
|
||||
<option value="$PROJECT_DIR$/MALAPITool" />
|
||||
<option value="$PROJECT_DIR$/Plugin" />
|
||||
<option value="$PROJECT_DIR$/launcher" />
|
||||
</set>
|
||||
</option>
|
||||
|
||||
@@ -5,12 +5,17 @@ import me.zacharias.chat.core.memory.GetMemoryFunction;
|
||||
import me.zacharias.chat.core.memory.RemoveMemoryFunction;
|
||||
import me.zacharias.chat.ollama.*;
|
||||
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
|
||||
import me.zacharias.chat.plugin.Plugin;
|
||||
import me.zacharias.chat.plugin.PluginLoader;
|
||||
import me.zacharias.chat.plugin.exceptions.PluginLoadingException;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
@@ -69,6 +74,7 @@ public class Core {
|
||||
|
||||
public static final String DATA;
|
||||
public static final File DATA_DIR;
|
||||
public static final File PLUGIN_DIRECTORY;
|
||||
|
||||
static {
|
||||
String data;
|
||||
@@ -98,6 +104,13 @@ public class Core {
|
||||
if(!DATA_DIR.exists()) {
|
||||
DATA_DIR.mkdirs();
|
||||
}
|
||||
|
||||
String pluginDir = DATA + "/plugins";
|
||||
PLUGIN_DIRECTORY = new File(pluginDir);
|
||||
|
||||
if(!PLUGIN_DIRECTORY.exists()) {
|
||||
PLUGIN_DIRECTORY.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -436,7 +449,33 @@ public class Core {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void enablePlugins(File pluginDirectory) {
|
||||
if(!pluginDirectory.exists()) {
|
||||
throw new IllegalArgumentException("Plugin directory does not exist");
|
||||
}
|
||||
if(!pluginDirectory.isDirectory()) {
|
||||
throw new IllegalArgumentException("Plugin directory is not a directory");
|
||||
}
|
||||
File[] files = pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
|
||||
if(files == null) {
|
||||
return;
|
||||
}
|
||||
PluginLoader loader = new PluginLoader();
|
||||
for(File file : files) {
|
||||
try(FileSystem fs = FileSystems.newFileSystem(file.toPath())){
|
||||
if(!fs.getPath("/plugin.json").toFile().exists())
|
||||
{
|
||||
throw new PluginLoadingException("Plugin does not contain a plugin.json file", file.getName());
|
||||
}
|
||||
JSONObject pluginJson = new JSONObject(new String(fs.getPath("/plugin.json").toFile().readAllBytes()));
|
||||
Plugin plugin = loader.loadPlugin(pluginJson, fs);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the source of a tool.
|
||||
* <p>
|
||||
|
||||
@@ -5,7 +5,7 @@ import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents a tool that can be called by Ollama.
|
||||
* Represents a tool that Ollama can call.
|
||||
*/
|
||||
public abstract class OllamaFunctionTool implements OllamaTool {
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.files.FileHandlerLocation;
|
||||
@@ -12,6 +13,10 @@ import org.json.JSONObject;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
5
Core/src/main/java/me/zacharias/chat/plugin/Plugin.java
Normal file
5
Core/src/main/java/me/zacharias/chat/plugin/Plugin.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package me.zacharias.chat.plugin;
|
||||
|
||||
public class Plugin {
|
||||
private final PluginMetadata metadata = null;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package me.zacharias.chat.plugin;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class PluginLoader {
|
||||
|
||||
public PluginLoader() {
|
||||
}
|
||||
|
||||
public Plugin loadPlugin(FileSystem pluginJar, JSONObject pluginMeta) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
String pluginName = pluginMeta.getString("name");
|
||||
String pluginEntryPoint = pluginMeta.getString("entryPoint");
|
||||
String pluginVersion = pluginMeta.getString("version");
|
||||
String pluginDescription = pluginMeta.optString("description", "No description provided");
|
||||
String[] pluginAuthors = pluginMeta.optJSONArray("author") != null ?
|
||||
pluginMeta.getJSONArray("author").toList().toArray(new String[0]) : new String[0];
|
||||
|
||||
PluginMetadata pluginMetadata = new PluginMetadata() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return pluginName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return pluginVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return pluginDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAuthor() {
|
||||
return pluginAuthors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String entryPoint() {
|
||||
return pluginEntryPoint;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
Plugin plugin = (Plugin) Class.forName(pluginEntryPoint).newInstance();
|
||||
Field metadataField = plugin.getClass().getDeclaredField("metadata");
|
||||
metadataField.set(plugin, pluginMetadata);
|
||||
if (metadataField.get(plugin) == null)
|
||||
throw new IllegalStateException("Plugin metadata field is null for plugin: " + pluginName);
|
||||
}catch (NoSuchFieldException e)
|
||||
{
|
||||
throw new IllegalStateException("Plugin class " + pluginEntryPoint + " does not have a 'metadata' field", e);
|
||||
}
|
||||
return null;
|
||||
//ClassLoader classLoader = pluginJar.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package me.zacharias.chat.plugin;
|
||||
|
||||
public interface PluginMetadata {
|
||||
public String getName();
|
||||
public String getVersion();
|
||||
public String getDescription();
|
||||
public String[] getAuthor();
|
||||
public String entryPoint();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package me.zacharias.chat.plugin.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface OllamaTool {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package me.zacharias.chat.plugin.annotation.injectons;
|
||||
|
||||
import me.zacharias.chat.plugin.Plugin;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
|
||||
public @interface InjectPlugin {
|
||||
Class<? extends Plugin> classType() default Plugin.class;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package me.zacharias.chat.plugin.exceptions;
|
||||
|
||||
public class PluginLoadingException extends RuntimeException {
|
||||
public PluginLoadingException(String message, String pluginName) {
|
||||
super("Plugin: \""+pluginName+"\"> "+message);
|
||||
}
|
||||
}
|
||||
6
Core/src/test/java/plugin/Test.java
Normal file
6
Core/src/test/java/plugin/Test.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package plugin;
|
||||
|
||||
import me.zacharias.chat.plugin.Plugin;
|
||||
|
||||
public class Test extends Plugin {
|
||||
}
|
||||
34
Core/src/test/java/plugin/Tool.java
Normal file
34
Core/src/test/java/plugin/Tool.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package plugin;
|
||||
|
||||
import me.zacharias.chat.ollama.OllamaFunctionArgument;
|
||||
import me.zacharias.chat.ollama.OllamaFunctionTool;
|
||||
import me.zacharias.chat.ollama.OllamaPerameter;
|
||||
import me.zacharias.chat.ollama.OllamaToolRespnce;
|
||||
import me.zacharias.chat.plugin.annotation.OllamaTool;
|
||||
import me.zacharias.chat.plugin.annotation.injectons.InjectPlugin;
|
||||
|
||||
@OllamaTool
|
||||
public class Tool extends OllamaFunctionTool {
|
||||
@InjectPlugin(classType = Test.class)
|
||||
Test core;
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public OllamaPerameter parameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OllamaToolRespnce function(OllamaFunctionArgument... args) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,8 @@ public class Display {
|
||||
//.addFileTools(FileHandlerLocation.DATA_FILES)
|
||||
.build());
|
||||
|
||||
core.enablePlugins(Core.PLUGIN_DIRECTORY);
|
||||
|
||||
core.addTool(new TimeTool(), Core.Source.INTERNAL);
|
||||
//core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
|
||||
core.addTools(new MALAPITool().getOllamaTools());
|
||||
|
||||
Reference in New Issue
Block a user