Discord: add fetch message action
This commit is contained in:
@@ -12,6 +12,7 @@ Use `discord` to manage messages, reactions, threads, polls, and moderation. You
|
||||
## Inputs to collect
|
||||
|
||||
- For reactions: `channelId`, `messageId`, and an `emoji`.
|
||||
- For fetchMessage: `guildId`, `channelId`, `messageId`, or a `messageLink` like `https://discord.com/channels/<guildId>/<channelId>/<messageId>`.
|
||||
- For stickers/polls/sendMessage: a `to` target (`channel:<id>` or `user:<id>`). Optional `content` text.
|
||||
- Polls also need a `question` plus 2–10 `answers`.
|
||||
- For media: `mediaUrl` with `file:///path` for local files or `https://...` for remote.
|
||||
@@ -21,6 +22,7 @@ Use `discord` to manage messages, reactions, threads, polls, and moderation. You
|
||||
Message context lines include `discord message id` and `channel` fields you can reuse directly.
|
||||
|
||||
**Note:** `sendMessage` uses `to: "channel:<id>"` format, not `channelId`. Other actions like `react`, `readMessages`, `editMessage` use `channelId` directly.
|
||||
**Note:** `fetchMessage` accepts message IDs or full links like `https://discord.com/channels/<guildId>/<channelId>/<messageId>`.
|
||||
|
||||
## Actions
|
||||
|
||||
@@ -144,6 +146,24 @@ Use `discord.actions.*` to disable action groups:
|
||||
}
|
||||
```
|
||||
|
||||
### Fetch a single message
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "fetchMessage",
|
||||
"guildId": "999",
|
||||
"channelId": "123",
|
||||
"messageId": "456"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "fetchMessage",
|
||||
"messageLink": "https://discord.com/channels/999/123/456"
|
||||
}
|
||||
```
|
||||
|
||||
### Send/edit/delete a message
|
||||
|
||||
```json
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
deleteMessageDiscord,
|
||||
editMessageDiscord,
|
||||
fetchChannelPermissionsDiscord,
|
||||
fetchMessageDiscord,
|
||||
fetchReactionsDiscord,
|
||||
listPinsDiscord,
|
||||
listThreadsDiscord,
|
||||
@@ -53,6 +54,23 @@ function formatDiscordTimestamp(ts?: string | null): string | undefined {
|
||||
return `${yyyy}-${mm}-${dd}T${hh}:${min}${sign}${offsetH}:${offsetM}${tzSuffix}`;
|
||||
}
|
||||
|
||||
function parseDiscordMessageLink(link: string) {
|
||||
const normalized = link.trim();
|
||||
const match = normalized.match(
|
||||
/^(?:https?:\/\/)?(?:ptb\.|canary\.)?discord(?:app)?\.com\/channels\/(\d+)\/(\d+)\/(\d+)(?:\/?|\?.*)$/i,
|
||||
);
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
"Invalid Discord message link. Expected https://discord.com/channels/<guildId>/<channelId>/<messageId>.",
|
||||
);
|
||||
}
|
||||
return {
|
||||
guildId: match[1],
|
||||
channelId: match[2],
|
||||
messageId: match[3],
|
||||
};
|
||||
}
|
||||
|
||||
export async function handleDiscordMessagingAction(
|
||||
action: string,
|
||||
params: Record<string, unknown>,
|
||||
@@ -157,6 +175,28 @@ export async function handleDiscordMessagingAction(
|
||||
const permissions = await fetchChannelPermissionsDiscord(channelId);
|
||||
return jsonResult({ ok: true, permissions });
|
||||
}
|
||||
case "fetchMessage": {
|
||||
if (!isActionEnabled("messages")) {
|
||||
throw new Error("Discord message reads are disabled.");
|
||||
}
|
||||
const messageLink = readStringParam(params, "messageLink");
|
||||
let guildId = readStringParam(params, "guildId");
|
||||
let channelId = readStringParam(params, "channelId");
|
||||
let messageId = readStringParam(params, "messageId");
|
||||
if (messageLink) {
|
||||
const parsed = parseDiscordMessageLink(messageLink);
|
||||
guildId = parsed.guildId;
|
||||
channelId = parsed.channelId;
|
||||
messageId = parsed.messageId;
|
||||
}
|
||||
if (!guildId || !channelId || !messageId) {
|
||||
throw new Error(
|
||||
"Discord message fetch requires guildId, channelId, and messageId (or a valid messageLink).",
|
||||
);
|
||||
}
|
||||
const message = await fetchMessageDiscord(channelId, messageId);
|
||||
return jsonResult({ ok: true, message, guildId, channelId, messageId });
|
||||
}
|
||||
case "readMessages": {
|
||||
if (!isActionEnabled("messages")) {
|
||||
throw new Error("Discord message reads are disabled.");
|
||||
|
||||
@@ -11,6 +11,7 @@ const messagingActions = new Set([
|
||||
"sticker",
|
||||
"poll",
|
||||
"permissions",
|
||||
"fetchMessage",
|
||||
"readMessages",
|
||||
"sendMessage",
|
||||
"editMessage",
|
||||
|
||||
@@ -35,6 +35,21 @@ export const DiscordToolSchema = Type.Union([
|
||||
action: Type.Literal("permissions"),
|
||||
channelId: Type.String(),
|
||||
}),
|
||||
Type.Union([
|
||||
Type.Object({
|
||||
action: Type.Literal("fetchMessage"),
|
||||
messageLink: Type.String(),
|
||||
guildId: Type.Optional(Type.String()),
|
||||
channelId: Type.Optional(Type.String()),
|
||||
messageId: Type.Optional(Type.String()),
|
||||
}),
|
||||
Type.Object({
|
||||
action: Type.Literal("fetchMessage"),
|
||||
guildId: Type.String(),
|
||||
channelId: Type.String(),
|
||||
messageId: Type.String(),
|
||||
}),
|
||||
]),
|
||||
Type.Object({
|
||||
action: Type.Literal("readMessages"),
|
||||
channelId: Type.String(),
|
||||
|
||||
@@ -903,6 +903,17 @@ export async function readMessagesDiscord(
|
||||
)) as APIMessage[];
|
||||
}
|
||||
|
||||
export async function fetchMessageDiscord(
|
||||
channelId: string,
|
||||
messageId: string,
|
||||
opts: DiscordReactOpts = {},
|
||||
): Promise<APIMessage> {
|
||||
const rest = resolveDiscordRest(opts);
|
||||
return (await rest.get(
|
||||
Routes.channelMessage(channelId, messageId),
|
||||
)) as APIMessage;
|
||||
}
|
||||
|
||||
export async function editMessageDiscord(
|
||||
channelId: string,
|
||||
messageId: string,
|
||||
|
||||
Reference in New Issue
Block a user