Add tiers, continuation, fetch cooldown, persistent action log, voice read, batch MCP
This commit is contained in:
@@ -34,7 +34,7 @@ async function connectLoop() {
|
||||
puppet = new Puppet(client);
|
||||
|
||||
client.onEvent(event => {
|
||||
puppet!.handleEvent(event).catch(error => console.error("[daemon] event error:", error));
|
||||
void puppet!.enqueueEvent(event);
|
||||
});
|
||||
|
||||
coreConnected = true;
|
||||
@@ -62,6 +62,23 @@ function jsonText(value: unknown) {
|
||||
return { content: [{ type: "text" as const, text: JSON.stringify(value, null, 2) }] };
|
||||
}
|
||||
|
||||
/** Read-only tools that the batch tool can run. Mutating tools stay out. */
|
||||
const READ_ONLY_TOOLS: Record<string, (args: any) => Promise<unknown> | unknown> = {
|
||||
get_state: () => requireCore().getState(),
|
||||
get_voice_state: args => requireCore().voiceGet(args?.userId, args?.guildId),
|
||||
get_context: args =>
|
||||
requirePuppet().getContext(args?.channelId, {
|
||||
maxMessages: args?.maxMessages,
|
||||
maxChars: args?.maxChars,
|
||||
refresh: args?.refresh
|
||||
}),
|
||||
get_message_log: () => requirePuppet().getLog(),
|
||||
get_action_log: args => requirePuppet().readActionLog(args?.limit ?? 100),
|
||||
get_puppet_config: () => requirePuppet().getConfig(),
|
||||
whitelist_list: () => ({ ownerId: requirePuppet().owner, whitelist: requirePuppet().whitelist }),
|
||||
read_messages: args => paced(() => requireCore().readMessages(args?.channelId, args?.limit ?? 20))
|
||||
};
|
||||
|
||||
function buildServer(): McpServer {
|
||||
const server = new McpServer({ name: "veskslop-control", version: "0.0.0" });
|
||||
|
||||
@@ -160,6 +177,8 @@ function buildServer(): McpServer {
|
||||
config: z.object({
|
||||
contextMessages: z.number().int().min(1).max(50).optional(),
|
||||
contextChars: z.number().int().min(200).max(20000).optional(),
|
||||
fetchCooldownSeconds: z.number().int().min(0).max(300).optional(),
|
||||
continuationSeconds: z.number().int().min(0).max(300).optional(),
|
||||
responsePolicy: z
|
||||
.object({
|
||||
defaultMode: z.enum(["channel", "dm"]).optional(),
|
||||
@@ -173,10 +192,70 @@ function buildServer(): McpServer {
|
||||
async ({ config }) => jsonText(requirePuppet().updateConfig(config))
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"get_voice_state",
|
||||
{
|
||||
description: "Which voice channel a user is in and who else is there. Defaults to the logged-in user.",
|
||||
inputSchema: {
|
||||
userId: z.string().optional().describe("User ID. Defaults to the logged-in user."),
|
||||
guildId: z.string().optional().describe("Guild ID. Omit for a DM call.")
|
||||
}
|
||||
},
|
||||
async ({ userId, guildId }) => jsonText(await requireCore().voiceGet(userId, guildId))
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"get_action_log",
|
||||
{
|
||||
description: "Read the persistent action log: triggers, commands, replies, and errors.",
|
||||
inputSchema: {
|
||||
limit: z.number().int().min(1).max(500).default(100).describe("How many entries")
|
||||
}
|
||||
},
|
||||
async ({ limit }) => jsonText(requirePuppet().readActionLog(limit))
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"run_commands",
|
||||
{
|
||||
description: "Run several read-only commands in one call, in order.",
|
||||
inputSchema: {
|
||||
commands: z
|
||||
.array(
|
||||
z.object({
|
||||
tool: z.string().describe("Read-only tool name"),
|
||||
arguments: z.record(z.string(), z.any()).optional()
|
||||
})
|
||||
)
|
||||
.min(1)
|
||||
.max(10)
|
||||
}
|
||||
},
|
||||
async ({ commands }) => {
|
||||
const results: Array<Record<string, unknown>> = [];
|
||||
|
||||
for (const item of commands) {
|
||||
const handler = READ_ONLY_TOOLS[item.tool];
|
||||
if (!handler) {
|
||||
results.push({ tool: item.tool, ok: false, error: "unknown or non-read-only tool" });
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
results.push({ tool: item.tool, ok: true, result: await handler((item.arguments ?? {}) as any) });
|
||||
} catch (error) {
|
||||
results.push({ tool: item.tool, ok: false, error: String((error as Error).message) });
|
||||
}
|
||||
}
|
||||
|
||||
return jsonText({ results });
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"whitelist_list",
|
||||
{
|
||||
description: "List the puppet owner and trusted (whitelisted) user IDs."
|
||||
description: "List the puppet owner and trusted users with their tiers."
|
||||
},
|
||||
async () => jsonText({ ownerId: requirePuppet().owner, whitelist: requirePuppet().whitelist })
|
||||
);
|
||||
@@ -184,12 +263,14 @@ function buildServer(): McpServer {
|
||||
server.registerTool(
|
||||
"whitelist_add",
|
||||
{
|
||||
description: "Add users to the puppet whitelist.",
|
||||
description: "Add users to the puppet whitelist with an optional tier. Defaults to 'user'.",
|
||||
inputSchema: {
|
||||
userIds: z.array(z.string()).min(1).describe("User IDs to trust")
|
||||
userIds: z.array(z.string()).min(1).describe("User IDs to trust"),
|
||||
tier: z.enum(["user", "trusted", "admin"]).optional().describe("Trust tier")
|
||||
}
|
||||
},
|
||||
async ({ userIds }) => jsonText({ whitelist: requirePuppet().addToWhitelist(userIds) })
|
||||
async ({ userIds, tier }) =>
|
||||
jsonText({ whitelist: requirePuppet().addToWhitelist(userIds, tier ?? "user") })
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
|
||||
Reference in New Issue
Block a user