diff --git a/extensions/slack/src/message-action-dispatch.ts b/extensions/slack/src/message-action-dispatch.ts new file mode 100644 index 00000000000..b251d0b80eb --- /dev/null +++ b/extensions/slack/src/message-action-dispatch.ts @@ -0,0 +1,331 @@ +import type { AgentToolResult } from "@mariozechner/pi-agent-core"; +import type { ChannelMessageActionContext } from "openclaw/plugin-sdk"; +import { parseSlackBlocksInput } from "./blocks-input.js"; +import { buildSlackInteractiveBlocks } from "./blocks-render.js"; + +type SlackActionInvoke = ( + action: Record, + cfg: ChannelMessageActionContext["cfg"], + toolContext?: ChannelMessageActionContext["toolContext"], +) => Promise>; + +type InteractiveButtonStyle = "primary" | "secondary" | "success" | "danger"; + +type InteractiveReplyButton = { + label: string; + value: string; + style?: InteractiveButtonStyle; +}; + +type InteractiveReplyOption = { + label: string; + value: string; +}; + +type InteractiveReplyBlock = + | { type: "text"; text: string } + | { type: "buttons"; buttons: InteractiveReplyButton[] } + | { type: "select"; placeholder?: string; options: InteractiveReplyOption[] }; + +type InteractiveReply = { + blocks: InteractiveReplyBlock[]; +}; + +function readTrimmedString(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined; + } + const trimmed = value.trim(); + return trimmed || undefined; +} + +function normalizeButtonStyle(value: unknown): InteractiveButtonStyle | undefined { + const style = readTrimmedString(value)?.toLowerCase(); + return style === "primary" || style === "secondary" || style === "success" || style === "danger" + ? style + : undefined; +} + +function normalizeInteractiveButton(raw: unknown): InteractiveReplyButton | undefined { + if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + return undefined; + } + const record = raw as Record; + const label = readTrimmedString(record.label) ?? readTrimmedString(record.text); + const value = + readTrimmedString(record.value) ?? + readTrimmedString(record.callbackData) ?? + readTrimmedString(record.callback_data); + if (!label || !value) { + return undefined; + } + return { label, value, style: normalizeButtonStyle(record.style) }; +} + +function normalizeInteractiveOption(raw: unknown): InteractiveReplyOption | undefined { + if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + return undefined; + } + const record = raw as Record; + const label = readTrimmedString(record.label) ?? readTrimmedString(record.text); + const value = readTrimmedString(record.value); + return label && value ? { label, value } : undefined; +} + +function normalizeInteractiveReply(raw: unknown): InteractiveReply | undefined { + if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + return undefined; + } + const record = raw as Record; + const blocks = Array.isArray(record.blocks) + ? record.blocks + .map((entry) => { + if (!entry || typeof entry !== "object" || Array.isArray(entry)) { + return undefined; + } + const block = entry as Record; + const type = readTrimmedString(block.type)?.toLowerCase(); + if (type === "text") { + const text = readTrimmedString(block.text); + return text ? ({ type: "text", text } as const) : undefined; + } + if (type === "buttons") { + const buttons = Array.isArray(block.buttons) + ? block.buttons + .map((button) => normalizeInteractiveButton(button)) + .filter((button): button is InteractiveReplyButton => Boolean(button)) + : []; + return buttons.length > 0 ? ({ type: "buttons", buttons } as const) : undefined; + } + if (type === "select") { + const options = Array.isArray(block.options) + ? block.options + .map((option) => normalizeInteractiveOption(option)) + .filter((option): option is InteractiveReplyOption => Boolean(option)) + : []; + return options.length > 0 + ? ({ + type: "select", + placeholder: readTrimmedString(block.placeholder), + options, + } as const) + : undefined; + } + return undefined; + }) + .filter((entry): entry is InteractiveReplyBlock => Boolean(entry)) + : []; + return blocks.length > 0 ? { blocks } : undefined; +} + +function readStringParam( + params: Record, + key: string, + options: { required?: boolean; trim?: boolean; label?: string; allowEmpty?: boolean } = {}, +): string | undefined { + const { required = false, trim = true, label = key, allowEmpty = false } = options; + const raw = params[key]; + if (typeof raw !== "string") { + if (required) { + throw new Error(`${label} required`); + } + return undefined; + } + const value = trim ? raw.trim() : raw; + if (!value && !allowEmpty) { + if (required) { + throw new Error(`${label} required`); + } + return undefined; + } + return value; +} + +function readNumberParam( + params: Record, + key: string, + options: { required?: boolean; label?: string; integer?: boolean; strict?: boolean } = {}, +): number | undefined { + const { required = false, label = key, integer = false, strict = false } = options; + const raw = params[key]; + let value: number | undefined; + if (typeof raw === "number" && Number.isFinite(raw)) { + value = raw; + } else if (typeof raw === "string") { + const trimmed = raw.trim(); + if (trimmed) { + const parsed = strict ? Number(trimmed) : Number.parseFloat(trimmed); + if (Number.isFinite(parsed)) { + value = parsed; + } + } + } + if (value === undefined) { + if (required) { + throw new Error(`${label} required`); + } + return undefined; + } + return integer ? Math.trunc(value) : value; +} + +function readSlackBlocksParam(actionParams: Record) { + return parseSlackBlocksInput(actionParams.blocks) as Record[] | undefined; +} + +export async function handleSlackMessageAction(params: { + providerId: string; + ctx: ChannelMessageActionContext; + invoke: SlackActionInvoke; + normalizeChannelId?: (channelId: string) => string; + includeReadThreadId?: boolean; +}): Promise> { + const { providerId, ctx, invoke, normalizeChannelId, includeReadThreadId = false } = params; + const { action, cfg, params: actionParams } = ctx; + const accountId = ctx.accountId ?? undefined; + const resolveChannelId = () => { + const channelId = + readStringParam(actionParams, "channelId") ?? + readStringParam(actionParams, "to", { required: true }); + return normalizeChannelId ? normalizeChannelId(channelId) : channelId; + }; + + if (action === "send") { + const to = readStringParam(actionParams, "to", { required: true }); + const content = readStringParam(actionParams, "message", { allowEmpty: true }); + const mediaUrl = readStringParam(actionParams, "media", { trim: false }); + const interactive = normalizeInteractiveReply(actionParams.interactive); + const interactiveBlocks = interactive ? buildSlackInteractiveBlocks(interactive) : undefined; + const blocks = readSlackBlocksParam(actionParams) ?? interactiveBlocks; + if (!content && !mediaUrl && !blocks) { + throw new Error("Slack send requires message, blocks, or media."); + } + if (mediaUrl && blocks) { + throw new Error("Slack send does not support blocks with media."); + } + const threadId = readStringParam(actionParams, "threadId"); + const replyTo = readStringParam(actionParams, "replyTo"); + return await invoke( + { + action: "sendMessage", + to, + content: content ?? "", + mediaUrl: mediaUrl ?? undefined, + accountId, + threadTs: threadId ?? replyTo ?? undefined, + ...(blocks ? { blocks } : {}), + }, + cfg, + ctx.toolContext, + ); + } + + if (action === "react") { + const messageId = readStringParam(actionParams, "messageId", { required: true }); + const emoji = readStringParam(actionParams, "emoji", { allowEmpty: true }); + const remove = typeof actionParams.remove === "boolean" ? actionParams.remove : undefined; + return await invoke( + { action: "react", channelId: resolveChannelId(), messageId, emoji, remove, accountId }, + cfg, + ); + } + + if (action === "reactions") { + const messageId = readStringParam(actionParams, "messageId", { required: true }); + const limit = readNumberParam(actionParams, "limit", { integer: true }); + return await invoke( + { action: "reactions", channelId: resolveChannelId(), messageId, limit, accountId }, + cfg, + ); + } + + if (action === "read") { + const limit = readNumberParam(actionParams, "limit", { integer: true }); + const readAction: Record = { + action: "readMessages", + channelId: resolveChannelId(), + limit, + before: readStringParam(actionParams, "before"), + after: readStringParam(actionParams, "after"), + accountId, + }; + if (includeReadThreadId) { + readAction.threadId = readStringParam(actionParams, "threadId"); + } + return await invoke(readAction, cfg); + } + + if (action === "edit") { + const messageId = readStringParam(actionParams, "messageId", { required: true }); + const content = readStringParam(actionParams, "message", { allowEmpty: true }); + const blocks = readSlackBlocksParam(actionParams); + if (!content && !blocks) { + throw new Error("Slack edit requires message or blocks."); + } + return await invoke( + { + action: "editMessage", + channelId: resolveChannelId(), + messageId, + content: content ?? "", + blocks, + accountId, + }, + cfg, + ); + } + + if (action === "delete") { + const messageId = readStringParam(actionParams, "messageId", { required: true }); + return await invoke( + { action: "deleteMessage", channelId: resolveChannelId(), messageId, accountId }, + cfg, + ); + } + + if (action === "pin" || action === "unpin" || action === "list-pins") { + const messageId = + action === "list-pins" + ? undefined + : readStringParam(actionParams, "messageId", { required: true }); + return await invoke( + { + action: action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins", + channelId: resolveChannelId(), + messageId, + accountId, + }, + cfg, + ); + } + + if (action === "member-info") { + const userId = readStringParam(actionParams, "userId", { required: true }); + return await invoke({ action: "memberInfo", userId, accountId }, cfg); + } + + if (action === "emoji-list") { + const limit = readNumberParam(actionParams, "limit", { integer: true }); + return await invoke({ action: "emojiList", limit, accountId }, cfg); + } + + if (action === "download-file") { + const fileId = readStringParam(actionParams, "fileId", { required: true }); + const channelId = + readStringParam(actionParams, "channelId") ?? readStringParam(actionParams, "to"); + const threadId = + readStringParam(actionParams, "threadId") ?? readStringParam(actionParams, "replyTo"); + return await invoke( + { + action: "downloadFile", + fileId, + channelId: channelId ?? undefined, + threadId: threadId ?? undefined, + accountId, + }, + cfg, + ); + } + + throw new Error(`Action ${action} is not supported for provider ${providerId}.`); +} diff --git a/src/plugin-sdk-internal/discord.ts b/src/plugin-sdk-internal/discord.ts new file mode 100644 index 00000000000..9a29900c717 --- /dev/null +++ b/src/plugin-sdk-internal/discord.ts @@ -0,0 +1,116 @@ +export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js"; +export type { OpenClawConfig } from "../config/config.js"; +export type { DiscordAccountConfig, DiscordActionConfig } from "../config/types.js"; +export type { InspectedDiscordAccount } from "../../extensions/discord/src/account-inspect.js"; +export type { ResolvedDiscordAccount } from "../../extensions/discord/src/accounts.js"; +export type { + DiscordSendComponents, + DiscordSendEmbeds, +} from "../../extensions/discord/src/send.shared.js"; +export * from "../plugin-sdk/channel-plugin-common.js"; + +export { + createDiscordActionGate, + listDiscordAccountIds, + resolveDefaultDiscordAccountId, + resolveDiscordAccount, +} from "../../extensions/discord/src/accounts.js"; +export { inspectDiscordAccount } from "../../extensions/discord/src/account-inspect.js"; +export { + projectCredentialSnapshotFields, + resolveConfiguredFromCredentialStatuses, +} from "../channels/account-snapshot-fields.js"; +export { + listDiscordDirectoryGroupsFromConfig, + listDiscordDirectoryPeersFromConfig, +} from "../channels/plugins/directory-config.js"; +export { + looksLikeDiscordTargetId, + normalizeDiscordMessagingTarget, + normalizeDiscordOutboundTarget, +} from "../../extensions/discord/src/normalize.js"; +export { collectDiscordAuditChannelIds } from "../../extensions/discord/src/audit.js"; +export { collectDiscordStatusIssues } from "../../extensions/discord/src/status-issues.js"; +export { + DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, + DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, +} from "../../extensions/discord/src/monitor/timeouts.js"; +export { normalizeExplicitDiscordSessionKey } from "../../extensions/discord/src/session-key-normalization.js"; +export type { DiscordPluralKitConfig } from "../../extensions/discord/src/pluralkit.js"; + +export { + resolveDefaultGroupPolicy, + resolveOpenProviderRuntimeGroupPolicy, +} from "../config/runtime-group-policy.js"; +export { + resolveDiscordGroupRequireMention, + resolveDiscordGroupToolPolicy, +} from "../channels/plugins/group-mentions.js"; +export { discordSetupWizard } from "../../extensions/discord/src/setup-surface.js"; +export { discordSetupAdapter } from "../../extensions/discord/src/setup-core.js"; +export { DiscordConfigSchema } from "../config/zod-schema.providers-core.js"; + +export { + autoBindSpawnedDiscordSubagent, + listThreadBindingsBySessionKey, + unbindThreadBindingsBySessionKey, +} from "../../extensions/discord/src/monitor/thread-bindings.js"; +export { getGateway } from "../../extensions/discord/src/monitor/gateway-registry.js"; +export { getPresence } from "../../extensions/discord/src/monitor/presence-cache.js"; +export { readDiscordComponentSpec } from "../../extensions/discord/src/components.js"; +export { resolveDiscordChannelId } from "../../extensions/discord/src/targets.js"; +export { + addRoleDiscord, + banMemberDiscord, + createChannelDiscord, + createScheduledEventDiscord, + createThreadDiscord, + deleteChannelDiscord, + deleteMessageDiscord, + editChannelDiscord, + editMessageDiscord, + fetchChannelInfoDiscord, + fetchChannelPermissionsDiscord, + fetchMemberInfoDiscord, + fetchMessageDiscord, + fetchReactionsDiscord, + fetchRoleInfoDiscord, + fetchVoiceStatusDiscord, + hasAnyGuildPermissionDiscord, + kickMemberDiscord, + listGuildChannelsDiscord, + listGuildEmojisDiscord, + listPinsDiscord, + listScheduledEventsDiscord, + listThreadsDiscord, + moveChannelDiscord, + pinMessageDiscord, + reactMessageDiscord, + readMessagesDiscord, + removeChannelPermissionDiscord, + removeOwnReactionsDiscord, + removeReactionDiscord, + removeRoleDiscord, + searchMessagesDiscord, + sendDiscordComponentMessage, + sendMessageDiscord, + sendPollDiscord, + sendStickerDiscord, + sendVoiceMessageDiscord, + setChannelPermissionDiscord, + timeoutMemberDiscord, + unpinMessageDiscord, + uploadEmojiDiscord, + uploadStickerDiscord, +} from "../../extensions/discord/src/send.js"; +export { discordMessageActions } from "../../extensions/discord/src/channel-actions.js"; +export type { + ThreadBindingManager, + ThreadBindingRecord, + ThreadBindingTargetKind, +} from "../../extensions/discord/src/monitor/thread-bindings.js"; + +export { + buildComputedAccountStatusSnapshot, + buildTokenChannelStatusSummary, +} from "../plugin-sdk/status-helpers.js"; diff --git a/src/plugin-sdk-internal/imessage.ts b/src/plugin-sdk-internal/imessage.ts new file mode 100644 index 00000000000..170dd7ff188 --- /dev/null +++ b/src/plugin-sdk-internal/imessage.ts @@ -0,0 +1,46 @@ +export type { ResolvedIMessageAccount } from "../../extensions/imessage/src/accounts.js"; +export type { IMessageAccountConfig } from "../config/types.js"; +export * from "../plugin-sdk/channel-plugin-common.js"; +export { + listIMessageAccountIds, + resolveDefaultIMessageAccountId, + resolveIMessageAccount, +} from "../../extensions/imessage/src/accounts.js"; +export { + formatTrimmedAllowFromEntries, + resolveIMessageConfigAllowFrom, + resolveIMessageConfigDefaultTo, +} from "../plugin-sdk/channel-config-helpers.js"; +export { + looksLikeIMessageTargetId, + normalizeIMessageMessagingTarget, +} from "../channels/plugins/normalize/imessage.js"; +export { + createAllowedChatSenderMatcher, + parseChatAllowTargetPrefixes, + parseChatTargetPrefixesOrThrow, + resolveServicePrefixedChatTarget, + resolveServicePrefixedAllowTarget, + resolveServicePrefixedOrChatAllowTarget, + resolveServicePrefixedTarget, +} from "../../extensions/imessage/src/target-parsing-helpers.js"; +export type { + ChatSenderAllowParams, + ParsedChatTarget, +} from "../../extensions/imessage/src/target-parsing-helpers.js"; +export { sendMessageIMessage } from "../../extensions/imessage/src/send.js"; + +export { + resolveAllowlistProviderRuntimeGroupPolicy, + resolveDefaultGroupPolicy, +} from "../config/runtime-group-policy.js"; +export { + resolveIMessageGroupRequireMention, + resolveIMessageGroupToolPolicy, +} from "../channels/plugins/group-mentions.js"; +export { imessageSetupWizard } from "../../extensions/imessage/src/setup-surface.js"; +export { imessageSetupAdapter } from "../../extensions/imessage/src/setup-core.js"; +export { IMessageConfigSchema } from "../config/zod-schema.providers-core.js"; + +export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js"; +export { collectStatusIssuesFromLastError } from "../plugin-sdk/status-helpers.js"; diff --git a/src/plugin-sdk-internal/signal.ts b/src/plugin-sdk-internal/signal.ts new file mode 100644 index 00000000000..4594420af8d --- /dev/null +++ b/src/plugin-sdk-internal/signal.ts @@ -0,0 +1,38 @@ +export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js"; +export type { ResolvedSignalAccount } from "../../extensions/signal/src/accounts.js"; +export type { SignalAccountConfig } from "../config/types.js"; +export * from "../plugin-sdk/channel-plugin-common.js"; +export { + listEnabledSignalAccounts, + listSignalAccountIds, + resolveDefaultSignalAccountId, + resolveSignalAccount, +} from "../../extensions/signal/src/accounts.js"; +export { resolveSignalReactionLevel } from "../../extensions/signal/src/reaction-level.js"; +export { + removeReactionSignal, + sendReactionSignal, +} from "../../extensions/signal/src/send-reactions.js"; +export { sendMessageSignal } from "../../extensions/signal/src/send.js"; +export { + looksLikeSignalTargetId, + normalizeSignalMessagingTarget, +} from "../channels/plugins/normalize/signal.js"; + +export { + resolveAllowlistProviderRuntimeGroupPolicy, + resolveDefaultGroupPolicy, +} from "../config/runtime-group-policy.js"; +export { signalSetupWizard } from "../../extensions/signal/src/setup-surface.js"; +export { signalSetupAdapter } from "../../extensions/signal/src/setup-core.js"; +export { SignalConfigSchema } from "../config/zod-schema.providers-core.js"; + +export { normalizeE164 } from "../utils.js"; +export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js"; + +export { + buildBaseAccountStatusSnapshot, + buildBaseChannelStatusSummary, + collectStatusIssuesFromLastError, + createDefaultChannelRuntimeState, +} from "../plugin-sdk/status-helpers.js"; diff --git a/src/plugin-sdk-internal/slack.ts b/src/plugin-sdk-internal/slack.ts new file mode 100644 index 00000000000..abde5688cdb --- /dev/null +++ b/src/plugin-sdk-internal/slack.ts @@ -0,0 +1,68 @@ +export type { OpenClawConfig } from "../config/config.js"; +export type { SlackAccountConfig } from "../config/types.slack.js"; +export type { InspectedSlackAccount } from "../../extensions/slack/src/account-inspect.js"; +export type { ResolvedSlackAccount } from "../../extensions/slack/src/accounts.js"; +export * from "../plugin-sdk/channel-plugin-common.js"; +export { + listEnabledSlackAccounts, + listSlackAccountIds, + resolveDefaultSlackAccountId, + resolveSlackAccount, + resolveSlackReplyToMode, +} from "../../extensions/slack/src/accounts.js"; +export { isSlackInteractiveRepliesEnabled } from "../../extensions/slack/src/interactive-replies.js"; +export { inspectSlackAccount } from "../../extensions/slack/src/account-inspect.js"; +export { + projectCredentialSnapshotFields, + resolveConfiguredFromCredentialStatuses, + resolveConfiguredFromRequiredCredentialStatuses, +} from "../channels/account-snapshot-fields.js"; +export { + listSlackDirectoryGroupsFromConfig, + listSlackDirectoryPeersFromConfig, +} from "../channels/plugins/directory-config.js"; +export { + looksLikeSlackTargetId, + normalizeSlackMessagingTarget, +} from "../channels/plugins/normalize/slack.js"; +export { parseSlackTarget, resolveSlackChannelId } from "../plugin-sdk/slack-targets.js"; +export { + extractSlackToolSend, + listSlackMessageActions, +} from "../../extensions/slack/src/message-actions.js"; +export { buildSlackThreadingToolContext } from "../../extensions/slack/src/threading-tool-context.js"; +export { parseSlackBlocksInput } from "../../extensions/slack/src/blocks-input.js"; +export { handleSlackHttpRequest } from "../../extensions/slack/src/http/index.js"; +export { sendMessageSlack } from "../../extensions/slack/src/send.js"; +export { + deleteSlackMessage, + downloadSlackFile, + editSlackMessage, + getSlackMemberInfo, + listSlackEmojis, + listSlackPins, + listSlackReactions, + pinSlackMessage, + reactSlackMessage, + readSlackMessages, + removeOwnSlackReactions, + removeSlackReaction, + sendSlackMessage, + unpinSlackMessage, +} from "../../extensions/slack/src/actions.js"; +export { recordSlackThreadParticipation } from "../../extensions/slack/src/sent-thread-cache.js"; +export { buildComputedAccountStatusSnapshot } from "../plugin-sdk/status-helpers.js"; + +export { + resolveDefaultGroupPolicy, + resolveOpenProviderRuntimeGroupPolicy, +} from "../config/runtime-group-policy.js"; +export { + resolveSlackGroupRequireMention, + resolveSlackGroupToolPolicy, +} from "../channels/plugins/group-mentions.js"; +export { slackSetupAdapter } from "../../extensions/slack/src/setup-core.js"; +export { slackSetupWizard } from "../../extensions/slack/src/setup-surface.js"; +export { SlackConfigSchema } from "../config/zod-schema.providers-core.js"; + +export { handleSlackMessageAction } from "../plugin-sdk/slack-message-actions.js"; diff --git a/src/plugin-sdk-internal/telegram.ts b/src/plugin-sdk-internal/telegram.ts new file mode 100644 index 00000000000..bb983d690d1 --- /dev/null +++ b/src/plugin-sdk-internal/telegram.ts @@ -0,0 +1,113 @@ +export type { + ChannelAccountSnapshot, + ChannelGatewayContext, + ChannelMessageActionAdapter, +} from "../channels/plugins/types.js"; +export type { ChannelPlugin } from "../channels/plugins/types.plugin.js"; +export type { OpenClawConfig } from "../config/config.js"; +export type { PluginRuntime } from "../plugins/runtime/types.js"; +export type { OpenClawPluginApi } from "../plugins/types.js"; +export type { TelegramAccountConfig, TelegramActionConfig } from "../config/types.js"; +export type { InspectedTelegramAccount } from "../../extensions/telegram/src/account-inspect.js"; +export type { ResolvedTelegramAccount } from "../../extensions/telegram/src/accounts.js"; +export type { TelegramProbe } from "../../extensions/telegram/src/probe.js"; +export type { + TelegramButtonStyle, + TelegramInlineButtons, +} from "../../extensions/telegram/src/button-types.js"; + +export { emptyPluginConfigSchema } from "../plugins/config-schema.js"; + +export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; + +export { + applyAccountNameToChannelSection, + migrateBaseNameToDefaultAccount, +} from "../channels/plugins/setup-helpers.js"; +export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js"; +export { + deleteAccountFromConfigSection, + clearAccountEntryFields, + setAccountEnabledInConfigSection, +} from "../channels/plugins/config-helpers.js"; +export { formatPairingApproveHint } from "../channels/plugins/helpers.js"; +export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js"; + +export { getChatChannelMeta } from "../channels/registry.js"; + +export { + createTelegramActionGate, + listTelegramAccountIds, + resolveDefaultTelegramAccountId, + resolveTelegramPollActionGateState, + resolveTelegramAccount, +} from "../../extensions/telegram/src/accounts.js"; +export { inspectTelegramAccount } from "../../extensions/telegram/src/account-inspect.js"; +export { + projectCredentialSnapshotFields, + resolveConfiguredFromCredentialStatuses, +} from "../channels/account-snapshot-fields.js"; +export { + listTelegramDirectoryGroupsFromConfig, + listTelegramDirectoryPeersFromConfig, +} from "../channels/plugins/directory-config.js"; +export { + looksLikeTelegramTargetId, + normalizeTelegramMessagingTarget, +} from "../../extensions/telegram/src/normalize.js"; +export { + parseTelegramReplyToMessageId, + parseTelegramThreadId, +} from "../../extensions/telegram/src/outbound-params.js"; +export { + isNumericTelegramUserId, + normalizeTelegramAllowFromEntry, +} from "../../extensions/telegram/src/allow-from.js"; +export { fetchTelegramChatId } from "../../extensions/telegram/src/api-fetch.js"; +export { + resolveTelegramInlineButtonsScope, + resolveTelegramTargetChatType, +} from "../../extensions/telegram/src/inline-buttons.js"; +export { resolveTelegramReactionLevel } from "../../extensions/telegram/src/reaction-level.js"; +export { + createForumTopicTelegram, + deleteMessageTelegram, + editForumTopicTelegram, + editMessageTelegram, + reactMessageTelegram, + sendMessageTelegram, + sendPollTelegram, + sendStickerTelegram, +} from "../../extensions/telegram/src/send.js"; +export { getCacheStats, searchStickers } from "../../extensions/telegram/src/sticker-cache.js"; +export { resolveTelegramToken } from "../../extensions/telegram/src/token.js"; +export { telegramMessageActions } from "../../extensions/telegram/src/channel-actions.js"; +export { collectTelegramStatusIssues } from "../../extensions/telegram/src/status-issues.js"; +export { sendTelegramPayloadMessages } from "../../extensions/telegram/src/outbound-adapter.js"; +export { + buildBrowseProvidersButton, + buildModelsKeyboard, + buildProviderKeyboard, + calculateTotalPages, + getModelsPageSize, + type ProviderInfo, +} from "../../extensions/telegram/src/model-buttons.js"; +export { + isTelegramExecApprovalApprover, + isTelegramExecApprovalClientEnabled, +} from "../../extensions/telegram/src/exec-approvals.js"; +export type { StickerMetadata } from "../../extensions/telegram/src/bot/types.js"; + +export { + resolveAllowlistProviderRuntimeGroupPolicy, + resolveDefaultGroupPolicy, +} from "../config/runtime-group-policy.js"; +export { + resolveTelegramGroupRequireMention, + resolveTelegramGroupToolPolicy, +} from "../channels/plugins/group-mentions.js"; +export { telegramSetupWizard } from "../../extensions/telegram/src/setup-surface.js"; +export { telegramSetupAdapter } from "../../extensions/telegram/src/setup-core.js"; +export { TelegramConfigSchema } from "../config/zod-schema.providers-core.js"; + +export { buildTokenChannelStatusSummary } from "../plugin-sdk/status-helpers.js"; diff --git a/src/plugin-sdk-internal/whatsapp.ts b/src/plugin-sdk-internal/whatsapp.ts new file mode 100644 index 00000000000..a1871198c70 --- /dev/null +++ b/src/plugin-sdk-internal/whatsapp.ts @@ -0,0 +1,108 @@ +export type { ChannelMessageActionName } from "../channels/plugins/types.js"; +export type { ChannelPlugin } from "../channels/plugins/types.plugin.js"; +export type { OpenClawConfig } from "../config/config.js"; +export type { DmPolicy, GroupPolicy, WhatsAppAccountConfig } from "../config/types.js"; +export type { PluginRuntime } from "../plugins/runtime/types.js"; +export type { OpenClawPluginApi } from "../plugins/types.js"; + +export { emptyPluginConfigSchema } from "../plugins/config-schema.js"; + +export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; + +export { + applyAccountNameToChannelSection, + migrateBaseNameToDefaultAccount, +} from "../channels/plugins/setup-helpers.js"; +export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js"; +export { formatPairingApproveHint } from "../channels/plugins/helpers.js"; + +export { getChatChannelMeta } from "../channels/registry.js"; +export { + formatWhatsAppConfigAllowFromEntries, + resolveWhatsAppConfigAllowFrom, + resolveWhatsAppConfigDefaultTo, +} from "../plugin-sdk/channel-config-helpers.js"; +export { + listWhatsAppDirectoryGroupsFromConfig, + listWhatsAppDirectoryPeersFromConfig, +} from "../channels/plugins/directory-config.js"; +export { + hasAnyWhatsAppAuth, + listEnabledWhatsAppAccounts, + resolveWhatsAppAccount, +} from "../../extensions/whatsapp/src/accounts.js"; +export { + WA_WEB_AUTH_DIR, + logWebSelfId, + logoutWeb, + pickWebChannel, + webAuthExists, +} from "../../extensions/whatsapp/src/auth-store.js"; +export { + DEFAULT_WEB_MEDIA_BYTES, + HEARTBEAT_PROMPT, + HEARTBEAT_TOKEN, + monitorWebChannel, + resolveHeartbeatRecipients, + runWebHeartbeatOnce, +} from "../../extensions/whatsapp/src/auto-reply.js"; +export type { + WebChannelStatus, + WebMonitorTuning, +} from "../../extensions/whatsapp/src/auto-reply.js"; +export { + extractMediaPlaceholder, + extractText, + monitorWebInbox, +} from "../../extensions/whatsapp/src/inbound.js"; +export type { + WebInboundMessage, + WebListenerCloseReason, +} from "../../extensions/whatsapp/src/inbound.js"; +export { loginWeb } from "../../extensions/whatsapp/src/login.js"; +export { + getDefaultLocalRoots, + loadWebMedia, + loadWebMediaRaw, + optimizeImageToJpeg, +} from "../../extensions/whatsapp/src/media.js"; +export { + sendMessageWhatsApp, + sendPollWhatsApp, + sendReactionWhatsApp, +} from "../../extensions/whatsapp/src/send.js"; +export { + createWaSocket, + formatError, + getStatusCode, + waitForWaConnection, +} from "../../extensions/whatsapp/src/session.js"; +export { createWhatsAppLoginTool } from "../../extensions/whatsapp/src/agent-tools-login.js"; +export { normalizeWhatsAppAllowFromEntries } from "../channels/plugins/normalize/whatsapp.js"; +export { + collectAllowlistProviderGroupPolicyWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, +} from "../channels/plugins/group-policy-warnings.js"; +export { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js"; +export { resolveWhatsAppOutboundTarget } from "../whatsapp/resolve-outbound-target.js"; + +export { + resolveAllowlistProviderRuntimeGroupPolicy, + resolveDefaultGroupPolicy, +} from "../config/runtime-group-policy.js"; +export { + resolveWhatsAppGroupRequireMention, + resolveWhatsAppGroupToolPolicy, +} from "../channels/plugins/group-mentions.js"; +export { + createWhatsAppOutboundBase, + resolveWhatsAppGroupIntroHint, + resolveWhatsAppMentionStripRegexes, +} from "../channels/plugins/whatsapp-shared.js"; +export { resolveWhatsAppHeartbeatRecipients } from "../channels/plugins/whatsapp-heartbeat.js"; +export { WhatsAppConfigSchema } from "../config/zod-schema.providers-whatsapp.js"; + +export { createActionGate, readStringParam } from "../agents/tools/common.js"; +export { createPluginRuntimeStore } from "../plugin-sdk/runtime-store.js"; + +export { normalizeE164 } from "../utils.js";