diff --git a/src/agents/tools/slack-actions.ts b/src/agents/tools/slack-actions.ts index 00d567428..b3a323a1c 100644 --- a/src/agents/tools/slack-actions.ts +++ b/src/agents/tools/slack-actions.ts @@ -5,10 +5,12 @@ import { resolveSlackAccount } from "../../slack/accounts.js"; import { deleteSlackMessage, editSlackMessage, + getSlackChannelInfo, getSlackMemberInfo, listSlackEmojis, listSlackPins, listSlackReactions, + markSlackChannelRead, pinSlackMessage, reactSlackMessage, readSlackMessages, @@ -296,5 +298,30 @@ export async function handleSlackAction( return jsonResult({ ok: true, emojis }); } + if (action === "channelInfo") { + if (!isActionEnabled("channelInfo")) { + throw new Error("Slack channel info is disabled."); + } + const channelId = resolveChannelId(); + const info = readOpts + ? await getSlackChannelInfo(channelId, readOpts) + : await getSlackChannelInfo(channelId); + return jsonResult({ ok: true, ...info }); + } + + if (action === "markRead") { + if (!isActionEnabled("channelInfo")) { + throw new Error("Slack channel info is disabled."); + } + const channelId = resolveChannelId(); + const timestamp = readStringParam(params, "timestamp", { required: true }); + if (writeOpts) { + await markSlackChannelRead(channelId, timestamp, writeOpts); + } else { + await markSlackChannelRead(channelId, timestamp); + } + return jsonResult({ ok: true, markedAt: timestamp }); + } + throw new Error(`Unknown action: ${action}`); } diff --git a/src/channels/plugins/message-action-names.ts b/src/channels/plugins/message-action-names.ts index 1884cacb0..fad27474c 100644 --- a/src/channels/plugins/message-action-names.ts +++ b/src/channels/plugins/message-action-names.ts @@ -34,6 +34,7 @@ export const CHANNEL_MESSAGE_ACTION_NAMES = [ "role-add", "role-remove", "channel-info", + "mark-read", "channel-list", "channel-create", "channel-edit", diff --git a/src/channels/plugins/slack.actions.ts b/src/channels/plugins/slack.actions.ts index ca8aa6fb8..d04b346a4 100644 --- a/src/channels/plugins/slack.actions.ts +++ b/src/channels/plugins/slack.actions.ts @@ -46,6 +46,10 @@ export function createSlackActions(providerId: string): ChannelMessageActionAdap } if (isActionEnabled("memberInfo")) actions.add("member-info"); if (isActionEnabled("emojiList")) actions.add("emoji-list"); + if (isActionEnabled("channelInfo")) { + actions.add("channel-info"); + actions.add("mark-read"); + } return Array.from(actions); }, extractToolSend: ({ args }): ChannelToolSend | null => { @@ -204,6 +208,30 @@ export function createSlackActions(providerId: string): ChannelMessageActionAdap ); } + if (action === "channel-info") { + return await handleSlackAction( + { + action: "channelInfo", + channelId: resolveChannelId(), + accountId: accountId ?? undefined, + }, + cfg, + ); + } + + if (action === "mark-read") { + const timestamp = readStringParam(params, "timestamp", { required: true }); + return await handleSlackAction( + { + action: "markRead", + channelId: resolveChannelId(), + timestamp, + accountId: accountId ?? undefined, + }, + cfg, + ); + } + throw new Error(`Action ${action} is not supported for provider ${providerId}.`); }, }; diff --git a/src/infra/outbound/message-action-spec.ts b/src/infra/outbound/message-action-spec.ts index 639e641d0..3951f0d8a 100644 --- a/src/infra/outbound/message-action-spec.ts +++ b/src/infra/outbound/message-action-spec.ts @@ -39,6 +39,7 @@ export const MESSAGE_ACTION_TARGET_MODE: Record { + const client = await getClient(opts); + const result = await client.conversations.info({ channel: channelId }); + const channel = result.channel as Record | undefined; + return { + id: channel?.id as string | undefined, + name: channel?.name as string | undefined, + lastRead: channel?.last_read as string | undefined, + unreadCount: channel?.unread_count as number | undefined, + unreadCountDisplay: channel?.unread_count_display as number | undefined, + latest: (channel?.latest as Record | undefined)?.ts as string | undefined, + }; +} + +/** + * Mark a channel as read up to a specific timestamp. + * Updates the bot's read cursor for the channel. + */ +export async function markSlackChannelRead( + channelId: string, + timestamp: string, + opts: SlackActionClientOpts = {}, +): Promise { + const client = await getClient(opts); + await client.conversations.mark({ channel: channelId, ts: timestamp }); +}