feat(plugin): scaffold RPCP plugin loading core
build / build (push) Has been cancelled

- Add JarFile-based plugin.json manifest reading and validation
- Implement reflection-based plugin class instantiation (Data or no-arg constructor)
- Wrap Tool objects into OllamaFunctionTool with basic parameter/response handling
- Implement ToolArguments storage and ToolResponse record
- Extract RPCP_SOURCE constant; add plugin name validation
- Update Data interface: getLoadedPlugins() returns LoadedPlugin[]
- Fix launcher package references (me.zacharias.chat → me.neurodock)

TODO: Extract FileSystem from JAR, populate PluginMetadata, complete
OllamaFunctionArgument↔ToolArguments wrapping, invoke plugin lifecycle hooks

Signed-off-by: zacharias <alienfromdia@proton.me>
This commit is contained in:
2026-06-15 22:09:55 +02:00
parent d016ad9a48
commit b74c5e9e97
12 changed files with 244 additions and 51 deletions
@@ -4,6 +4,6 @@ import java.io.File;
public abstract class Data {
public abstract File getDataDictionary();
public abstract LoadedPlugins getLoadedPlugins();
public abstract LoadedPlugin[] getLoadedPlugins();
public abstract File getCacheDirectory();
}
@@ -0,0 +1,9 @@
package me.neurodock.plugin;
public record LoadedPlugin(
Plugin plugin,
ClassLoader loader,
PluginMetadata metaData
) {
}
@@ -1,5 +0,0 @@
package me.neurodock.plugin;
public class LoadedPlugins {
// TODO: Implement
}
@@ -9,6 +9,10 @@ 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 is a magic constant plugin name used for when a plugin's name cant be loaded
*/
public static final String UNKNOWN_PLUGIN = "UNKNOWN PLUGIN";
/**
* This shuld be used if {@link PluginEntryPoint#requireData()} is false (default)
@@ -29,12 +33,12 @@ public abstract class Plugin {
public void onInit(){}
/**
* This will be called if the core gets a "fetal" exception or fails to fetch certain info
* This will be called if the core gets a "fetal" exception or fails to fetch certain info AND the plugin was able to be loaded.
*/
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
* This will be called after all plugins have been initialized; here it is safe to perform potential stuff where you load data from optional dependencies, or similar things
*/
public void onEnable(){}
@@ -9,5 +9,10 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface PluginEntryPoint {
boolean requireData() default true;
/**
* NOT YET IMPLEMENTED!
* @return An array of plugins this plugin depends on
*/
String[] dependencies() default {};
}
@@ -4,4 +4,9 @@ public class PluginLoadingException extends RuntimeException {
public PluginLoadingException(String message, String pluginName) {
super("Plugin: \""+pluginName+"\"> "+message);
}
public PluginLoadingException(String message, Throwable cause, String pluginName)
{
super("Plugin: \""+pluginName+"\"> "+message, cause);
}
}
@@ -6,6 +6,11 @@ import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
public abstract class Tool {
/**
* Magic constant for RPCP sources.<br>
* This is solely here to replace the case of a magic string being used in the code
*/
public static final String RPCP_SOURCE = "RPCP";
/**
* The parent plugin of this tool, used by {@link Tool#getToolJSON()}.
@@ -29,7 +34,7 @@ public abstract class Tool {
ret.put("type", "function");
JSONObject function = new JSONObject();
function.put("name", String.format("%s_%s_RPCP", name(), PLUGIN.getMetadata().getName()).replaceAll(" ", "_"));
function.put("name", String.format("%s_%s_%s", name(), PLUGIN.getMetadata().getName(), RPCP_SOURCE).replaceAll(" ", "_"));
if(description() != null) {
function.put("description", description());
}
@@ -1,4 +1,30 @@
package me.neurodock.plugin.tool;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
public class ToolArguments {
Map<String, Object> arguments = new HashMap<>();
public void addArguments(Map<String, Object> args)
{
arguments.putAll(args);
}
public void addArgument(String name, Object value)
{
arguments.put(name, value);
}
public Object getArgument(String name)
{
if(!arguments.containsKey(name)) throw new NoSuchElementException("Trying to access missing argument");
return arguments.get(name);
}
public boolean hasArgument(String name)
{
return arguments.containsKey(name);
}
}
@@ -1,12 +1,14 @@
package me.neurodock.plugin.tool;
public class ToolResponse {
public record ToolResponse(String name, String response) {
public static ToolResponse empty(Tool tool) {
return new ToolResponse();
return new ToolResponse(tool.name(), "");
}
public static ToolResponse empty(String toolName)
{
return new ToolResponse();
return new ToolResponse(toolName, "");
}
}