Merge branch 'pr-730-merge'
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
- Docs: add gog calendar event color IDs from `gog calendar colors`. (#715) — thanks @mjrussell.
|
||||
- Cron/CLI: trim model overrides on cron edits and document main-session guidance. (#711) — thanks @mjrussell.
|
||||
- Skills: bundle `skill-creator` to guide creating and packaging skills.
|
||||
- Discord: expose channel/category management actions in the message tool. (#730) — thanks @NicholasSpisak
|
||||
|
||||
### Fixes
|
||||
- Doctor: surface plugin diagnostics in the report.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: discord
|
||||
description: Use when you need to control Discord from Clawdbot via the discord tool: send messages, react, post or upload stickers, upload emojis, run polls, manage threads/pins/search, fetch permissions or member/role/channel info, or handle moderation actions in Discord DMs or channels.
|
||||
description: Use when you need to control Discord from Clawdbot via the discord tool: send messages, react, post or upload stickers, upload emojis, run polls, manage threads/pins/search, create/edit/delete channels and categories, fetch permissions or member/role/channel info, or handle moderation actions in Discord DMs or channels.
|
||||
---
|
||||
|
||||
# Discord Actions
|
||||
@@ -135,6 +135,7 @@ Use `discord.actions.*` to disable action groups:
|
||||
- `emojiUploads`, `stickerUploads`
|
||||
- `memberInfo`, `roleInfo`, `channelInfo`, `voiceStatus`, `events`
|
||||
- `roles` (role add/remove, default `false`)
|
||||
- `channels` (channel/category create/edit/delete/move, default `false`)
|
||||
- `moderation` (timeout/kick/ban, default `false`)
|
||||
### Read recent messages
|
||||
|
||||
@@ -314,6 +315,90 @@ Use `discord.actions.*` to disable action groups:
|
||||
}
|
||||
```
|
||||
|
||||
### Channel management (disabled by default)
|
||||
|
||||
Create, edit, delete, and move channels and categories. Enable via `discord.actions.channels: true`.
|
||||
|
||||
**Create a text channel:**
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "channelCreate",
|
||||
"guildId": "999",
|
||||
"name": "general-chat",
|
||||
"type": 0,
|
||||
"parentId": "888",
|
||||
"topic": "General discussion"
|
||||
}
|
||||
```
|
||||
|
||||
- `type`: Discord channel type integer (0 = text, 2 = voice, 4 = category; other values supported)
|
||||
- `parentId`: category ID to nest under (optional)
|
||||
- `topic`, `position`, `nsfw`: optional
|
||||
|
||||
**Create a category:**
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "categoryCreate",
|
||||
"guildId": "999",
|
||||
"name": "Projects"
|
||||
}
|
||||
```
|
||||
|
||||
**Edit a channel:**
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "channelEdit",
|
||||
"channelId": "123",
|
||||
"name": "new-name",
|
||||
"topic": "Updated topic"
|
||||
}
|
||||
```
|
||||
|
||||
- Supports `name`, `topic`, `position`, `parentId` (null to remove from category), `nsfw`, `rateLimitPerUser`
|
||||
|
||||
**Move a channel:**
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "channelMove",
|
||||
"guildId": "999",
|
||||
"channelId": "123",
|
||||
"parentId": "888",
|
||||
"position": 2
|
||||
}
|
||||
```
|
||||
|
||||
- `parentId`: target category (null to move to top level)
|
||||
|
||||
**Delete a channel:**
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "channelDelete",
|
||||
"channelId": "123"
|
||||
}
|
||||
```
|
||||
|
||||
**Edit/delete a category:**
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "categoryEdit",
|
||||
"categoryId": "888",
|
||||
"name": "Renamed Category"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "categoryDelete",
|
||||
"categoryId": "888"
|
||||
}
|
||||
```
|
||||
|
||||
### Voice status
|
||||
|
||||
```json
|
||||
|
||||
@@ -55,6 +55,13 @@ const AllMessageActions = [
|
||||
"role-remove",
|
||||
"channel-info",
|
||||
"channel-list",
|
||||
"channel-create",
|
||||
"channel-edit",
|
||||
"channel-delete",
|
||||
"channel-move",
|
||||
"category-create",
|
||||
"category-edit",
|
||||
"category-delete",
|
||||
"voice-status",
|
||||
"event-list",
|
||||
"event-create",
|
||||
@@ -130,6 +137,14 @@ const MessageToolCommonSchema = {
|
||||
gatewayUrl: Type.Optional(Type.String()),
|
||||
gatewayToken: Type.Optional(Type.String()),
|
||||
timeoutMs: Type.Optional(Type.Number()),
|
||||
name: Type.Optional(Type.String()),
|
||||
type: Type.Optional(Type.Number()),
|
||||
parentId: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
||||
topic: Type.Optional(Type.String()),
|
||||
position: Type.Optional(Type.Number()),
|
||||
nsfw: Type.Optional(Type.Boolean()),
|
||||
rateLimitPerUser: Type.Optional(Type.Number()),
|
||||
categoryId: Type.Optional(Type.String()),
|
||||
};
|
||||
|
||||
function buildMessageToolSchemaFromActions(
|
||||
|
||||
@@ -57,6 +57,15 @@ export const discordMessageActions: ProviderMessageActionAdapter = {
|
||||
actions.add("channel-info");
|
||||
actions.add("channel-list");
|
||||
}
|
||||
if (gate("channels", false)) {
|
||||
actions.add("channel-create");
|
||||
actions.add("channel-edit");
|
||||
actions.add("channel-delete");
|
||||
actions.add("channel-move");
|
||||
actions.add("category-create");
|
||||
actions.add("category-edit");
|
||||
actions.add("category-delete");
|
||||
}
|
||||
if (gate("voiceStatus")) actions.add("voice-status");
|
||||
if (gate("events")) {
|
||||
actions.add("event-list");
|
||||
@@ -449,6 +458,136 @@ export const discordMessageActions: ProviderMessageActionAdapter = {
|
||||
return await handleDiscordAction({ action: "channelList", guildId }, cfg);
|
||||
}
|
||||
|
||||
if (action === "channel-create") {
|
||||
const guildId = readStringParam(params, "guildId", { required: true });
|
||||
const name = readStringParam(params, "name", { required: true });
|
||||
const type = readNumberParam(params, "type", { integer: true });
|
||||
const parentId =
|
||||
params.parentId === null
|
||||
? null
|
||||
: readStringParam(params, "parentId");
|
||||
const topic = readStringParam(params, "topic");
|
||||
const position = readNumberParam(params, "position", { integer: true });
|
||||
const nsfw = typeof params.nsfw === "boolean" ? params.nsfw : undefined;
|
||||
return await handleDiscordAction(
|
||||
{
|
||||
action: "channelCreate",
|
||||
guildId,
|
||||
name,
|
||||
type: type ?? undefined,
|
||||
parentId: parentId ?? undefined,
|
||||
topic: topic ?? undefined,
|
||||
position: position ?? undefined,
|
||||
nsfw,
|
||||
},
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "channel-edit") {
|
||||
const channelId = readStringParam(params, "channelId", {
|
||||
required: true,
|
||||
});
|
||||
const name = readStringParam(params, "name");
|
||||
const topic = readStringParam(params, "topic");
|
||||
const position = readNumberParam(params, "position", { integer: true });
|
||||
const parentId =
|
||||
params.parentId === null
|
||||
? null
|
||||
: readStringParam(params, "parentId");
|
||||
const nsfw = typeof params.nsfw === "boolean" ? params.nsfw : undefined;
|
||||
const rateLimitPerUser = readNumberParam(params, "rateLimitPerUser", {
|
||||
integer: true,
|
||||
});
|
||||
return await handleDiscordAction(
|
||||
{
|
||||
action: "channelEdit",
|
||||
channelId,
|
||||
name: name ?? undefined,
|
||||
topic: topic ?? undefined,
|
||||
position: position ?? undefined,
|
||||
parentId: parentId === undefined ? undefined : parentId,
|
||||
nsfw,
|
||||
rateLimitPerUser: rateLimitPerUser ?? undefined,
|
||||
},
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "channel-delete") {
|
||||
const channelId = readStringParam(params, "channelId", {
|
||||
required: true,
|
||||
});
|
||||
return await handleDiscordAction(
|
||||
{ action: "channelDelete", channelId },
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "channel-move") {
|
||||
const guildId = readStringParam(params, "guildId", { required: true });
|
||||
const channelId = readStringParam(params, "channelId", {
|
||||
required: true,
|
||||
});
|
||||
const parentId =
|
||||
params.parentId === null
|
||||
? null
|
||||
: readStringParam(params, "parentId");
|
||||
const position = readNumberParam(params, "position", { integer: true });
|
||||
return await handleDiscordAction(
|
||||
{
|
||||
action: "channelMove",
|
||||
guildId,
|
||||
channelId,
|
||||
parentId: parentId === undefined ? undefined : parentId,
|
||||
position: position ?? undefined,
|
||||
},
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "category-create") {
|
||||
const guildId = readStringParam(params, "guildId", { required: true });
|
||||
const name = readStringParam(params, "name", { required: true });
|
||||
const position = readNumberParam(params, "position", { integer: true });
|
||||
return await handleDiscordAction(
|
||||
{
|
||||
action: "categoryCreate",
|
||||
guildId,
|
||||
name,
|
||||
position: position ?? undefined,
|
||||
},
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "category-edit") {
|
||||
const categoryId = readStringParam(params, "categoryId", {
|
||||
required: true,
|
||||
});
|
||||
const name = readStringParam(params, "name");
|
||||
const position = readNumberParam(params, "position", { integer: true });
|
||||
return await handleDiscordAction(
|
||||
{
|
||||
action: "categoryEdit",
|
||||
categoryId,
|
||||
name: name ?? undefined,
|
||||
position: position ?? undefined,
|
||||
},
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "category-delete") {
|
||||
const categoryId = readStringParam(params, "categoryId", {
|
||||
required: true,
|
||||
});
|
||||
return await handleDiscordAction(
|
||||
{ action: "categoryDelete", categoryId },
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "voice-status") {
|
||||
const guildId = readStringParam(params, "guildId", {
|
||||
required: true,
|
||||
|
||||
Reference in New Issue
Block a user