ForemanTools¶
Publish tools the AI can call, next to Foreman's own, with your plugin as their provider. They show up in
/foreman tools, in the client's hub and in every chat on the server.
Setup¶
compileOnly on games.qore:foreman-server-api and a soft dependency on Foreman:
Add Foreman to your plugin. Register in onEnable (Foreman enables first). Your tools are removed when your plugin disables, so a reload
registers them again.
A command as a tool¶
The simplest tool runs one of your commands. {argument} placeholders are filled from the call, and the AI gets back
everything the command printed (like server_command).
The last argument runs it as the calling player (who must be online), with their permissions. Otherwise it runs from
the console, and players calling it need foreman.admin, like server_command. Each value is one word, so a call can't
add arguments to the command, except the one whose placeholder ends it (broadcast {message}).
A tool of your own¶
tools.register(this, new ExternalTool(
"npc_list",
"Lists the NPCs of a world with their positions. Use it before moving or editing one.",
"""
{"type": "object", "properties": {"world": {"type": "string", "description": "World name"}}}
""",
false, // modifies: changes are announced to ops with foreman.watch
call -> {
World world = Bukkit.getWorld(call.string("world"));
if (world == null) return ToolReply.error("No such world");
String text = tools.onMainThread(() -> describeNpcs(world));
return ToolReply.ok(text);
}));
tools.register(this, ExternalTool(
"npc_list",
"Lists the NPCs of a world with their positions. Use it before moving or editing one.",
"""{"type": "object", "properties": {"world": {"type": "string", "description": "World name"}}}""",
false, // modifies: changes are announced to ops with foreman.watch
) { call ->
val world = call.string("world")?.let { Bukkit.getWorld(it) }
if (world == null) ToolReply.error("No such world")
else ToolReply.ok(tools.onMainThread { describeNpcs(world) })
})
- Names: lowercase letters, digits and
_. Foreman's own names and other plugins' are refused. - Descriptions: the AI reads them to choose a tool. Say what it does and when to use it.
- Handlers run off the main thread: use
onMainThreadfor the world. - Replies:
ToolReply.ok(text),ToolReply.error(text), ornew ToolReply(text, false, images)with PNG bytes the AI can look at. - Calls:
call.argument(name)(String, Double, Boolean, List, Map or null),call.string,call.number,call.getPlayer()(who asked, when online),call.getArguments()(the JSON).
tools.tools() lists every tool with its provider; unregister(owner, name) removes one.