refactor: redesign plugin system and enhance message handling
build / build (push) Has been cancelled
build / build (push) Has been cancelled
- Move plugin and tool-related classes to a dedicated `Plugin-API` module. - Introduce a new plugin lifecycle (`onInit`, `onEnable`, `onDisable`) and a more robust `Tool` API. - Refactor `Core` to use `PrintAdvanceMessageHandler` for improved handling of assistant messages, tool responses, and errors. - Rename `PluginLoader` to `Loader` and migrate it to `me.zacharias.chat.plugin.loader`. - Update build configurations and Java toolchains across modules. - Clean up obsolete plugin annotations and interfaces in the `Core` module.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package me.zacharias.chat.plugin;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public abstract class Data {
|
||||
public abstract File getDataDictionary();
|
||||
public abstract LoadedPlugins getLoadedPlugins();
|
||||
public abstract File getCacheDirectory();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package me.zacharias.chat.plugin;
|
||||
|
||||
|
||||
import me.zacharias.chat.plugin.annotations.InjectPluginMetadata;
|
||||
import me.zacharias.chat.plugin.annotations.PluginEntryPoint;
|
||||
import me.zacharias.chat.plugin.tool.Tool;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Entry point for the plugin, this is required for the plugin to work, and you MUST annotate it with {@link PluginEntryPoint}
|
||||
*/
|
||||
public abstract class Plugin {
|
||||
|
||||
/**
|
||||
* This shuld be used if {@link PluginEntryPoint#requireData()} is false (default)
|
||||
* @apiNote While in this constructor, it is not safe to assume any plugin is loaded other than potentially defined plugins in {@link PluginEntryPoint#dependencies()}. See {@link this#onInit}
|
||||
*/
|
||||
public Plugin() {}
|
||||
|
||||
/**
|
||||
* This shuld be used if {@link PluginEntryPoint#requireData()} is true
|
||||
* @apiNote While in this constructor, it is not safe to assume any plugin is loaded other than potentially defined plugins in {@link PluginEntryPoint#dependencies()}. See {@link this#onInit}
|
||||
* @param data the {@link Data} generated by the plugin loader
|
||||
*/
|
||||
public Plugin(Data data) {}
|
||||
|
||||
/**
|
||||
* This will be called once every plugin has been loaded
|
||||
*/
|
||||
public void onInit(){}
|
||||
|
||||
/**
|
||||
* This will be called if the core gets a "fetal" exception or fails to fetch certain info
|
||||
*/
|
||||
public void onDisable(){}
|
||||
|
||||
/**
|
||||
* This will be called after all plugins have been initialised; here it is safe to perform potential stuff where you load data from optional dependencies, or similar things
|
||||
*/
|
||||
public void onEnable(){}
|
||||
|
||||
/**
|
||||
* The "main" method of a plugin, it will be the one returning a list of all tools you define.
|
||||
* @return An array of all {@link Tool}s you provide in this plugin, see {@link Tool} for definitions or <a href="https://git.server.4zellen.se/Chat_things/NeuroDock/src/branch/master/MALAPITool">MAL API tool</a> for ideas or examples
|
||||
*/
|
||||
public Tool[] getTools(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents your plugin's Metadata
|
||||
* @return A {@link PluginMetadata} object representing the metadata for your plugin
|
||||
*/
|
||||
@NotNull
|
||||
public abstract PluginMetadata getMetadata();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package me.zacharias.chat.plugin;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Interface defining the core properties/information about the plugin
|
||||
*/
|
||||
public interface PluginMetadata {
|
||||
/**
|
||||
* Returns the name of the plugin
|
||||
* @return String containing the name
|
||||
*/
|
||||
@NotNull
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Version of the project
|
||||
* @return String returning the version, expected format Major.Minor.Path see <a href="https://semver.org/">semver.org</a>
|
||||
*/
|
||||
@NotNull
|
||||
public String getVersion();
|
||||
|
||||
/**
|
||||
* Description for the tool, shuld be an explanatory, yet simple description
|
||||
* @return String containing the description
|
||||
*/
|
||||
default String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A String containing a list of all authors for this<br>
|
||||
* May be empty, but may not be null
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
default String[] getAuthor() {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package me.zacharias.chat.plugin.annotations;
|
||||
|
||||
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)
|
||||
public @interface InjectPluginMetadata {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package me.zacharias.chat.plugin.annotations;
|
||||
|
||||
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 PluginEntryPoint {
|
||||
boolean requireData() default true;
|
||||
String[] dependencies() default {};
|
||||
}
|
||||
+7
@@ -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);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package me.zacharias.chat.plugin.exceptions;
|
||||
|
||||
import me.zacharias.chat.plugin.tool.Tool;
|
||||
|
||||
public class ToolRuntimeException extends Exception {
|
||||
String toolName;
|
||||
|
||||
public String getToolName() {
|
||||
return toolName;
|
||||
}
|
||||
|
||||
public ToolRuntimeException(Tool tool, String message) {
|
||||
super(message);
|
||||
this.toolName = tool.name();
|
||||
}
|
||||
|
||||
public ToolRuntimeException(String toolName, String message) {
|
||||
super(message);
|
||||
this.toolName = toolName;
|
||||
}
|
||||
|
||||
public ToolRuntimeException(String toolName, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.toolName = toolName;
|
||||
}
|
||||
|
||||
public ToolRuntimeException(Tool tool, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.toolName = tool.name();
|
||||
}
|
||||
|
||||
public ToolRuntimeException(Tool tool, Throwable cause) {
|
||||
super(cause);
|
||||
this.toolName = tool.name();
|
||||
}
|
||||
|
||||
public ToolRuntimeException(String toolName, Throwable cause) {
|
||||
super(cause);
|
||||
this.toolName = toolName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package me.zacharias.chat.plugin.tool;
|
||||
|
||||
import me.zacharias.chat.plugin.Plugin;
|
||||
import me.zacharias.chat.plugin.exceptions.ToolRuntimeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class Tool {
|
||||
|
||||
/**
|
||||
* The parent plugin of this tool, used by {@link Tool#getToolJSON()}.
|
||||
*/
|
||||
protected final Plugin PLUGIN;
|
||||
|
||||
/**
|
||||
* A base contructor, as the {@link Plugin} is used within this class
|
||||
* @param plugin The plugin that owns this tool
|
||||
*/
|
||||
public Tool(Plugin plugin) {
|
||||
this.PLUGIN = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* The core uses this method when generating the list of available functions to the LLM
|
||||
* @return a string formated JSON containing the representation of the tool definitions
|
||||
*/
|
||||
public final String getToolJSON() {
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("type", "function");
|
||||
|
||||
JSONObject function = new JSONObject();
|
||||
function.put("name", String.format("%s_%s_RPCP", name(), PLUGIN.getMetadata().getName()).replaceAll(" ", "_"));
|
||||
if(description() != null) {
|
||||
function.put("description", description());
|
||||
}
|
||||
function.put("parameters", (parameters() == null? new JSONObject() : new JSONObject(parameters().toString())));
|
||||
|
||||
ret.put("function", function);
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Name of the tool.</p>
|
||||
* @apiNote This is a lower snake_case formated string.
|
||||
* <p>Example: {@code "get_clock"}</p>
|
||||
* @return returns the name of this tool
|
||||
*/
|
||||
@NotNull
|
||||
abstract public String name();
|
||||
|
||||
/**
|
||||
* Description for the LLM on what this tool does
|
||||
* @return Short description defining the scope of this tool
|
||||
*/
|
||||
public String description() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameters this tool allows
|
||||
* @apiNote Can return {@link ToolParameters#empty()} if no arguments are needed
|
||||
* @return A {@link ToolParameters} object defining what this tool expects when being called
|
||||
*/
|
||||
@NotNull
|
||||
abstract public ToolParameters parameters();
|
||||
|
||||
/**
|
||||
* This is the main course of the tool. The LLM will call this on request of using your tool
|
||||
* @param arguments A collective of your {@link ToolParameters} from {@link Tool#parameters()}
|
||||
* @return The expected results, or {@link ToolResponse#empty(Tool)} if this is a "void" function
|
||||
* @throws ToolRuntimeException This indicates that an {@link Exception} is not fatal, any other exceptions thrown from this tool will be treated as fatal, and will result in this tool, or it's plugin being disabled
|
||||
*/
|
||||
abstract public ToolResponse callTool(ToolArguments arguments) throws ToolRuntimeException;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package me.zacharias.chat.plugin.tool;
|
||||
|
||||
public class ToolArguments {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package me.zacharias.chat.plugin.tool;
|
||||
|
||||
public class ToolParameters {
|
||||
/**
|
||||
* An empty {@link ToolParameters} for when a tool dosent need any perameters
|
||||
* @return the default {@link ToolParameters}
|
||||
*/
|
||||
public static ToolParameters empty() {
|
||||
return new ToolParameters();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package me.zacharias.chat.plugin.tool;
|
||||
|
||||
public class ToolResponse {
|
||||
public static ToolResponse empty(Tool tool) {
|
||||
return new ToolResponse();
|
||||
}
|
||||
|
||||
public static ToolResponse empty(String toolName)
|
||||
{
|
||||
return new ToolResponse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user