diff --git a/extensions/slack/src/action-runtime.runtime.ts b/extensions/slack/src/action-runtime.runtime.ts new file mode 100644 index 00000000000..836c39ac449 --- /dev/null +++ b/extensions/slack/src/action-runtime.runtime.ts @@ -0,0 +1 @@ +export { handleSlackAction } from "./action-runtime.js"; diff --git a/extensions/slack/src/channel-actions.ts b/extensions/slack/src/channel-actions.ts index 22defb26750..647cbb2e008 100644 --- a/extensions/slack/src/channel-actions.ts +++ b/extensions/slack/src/channel-actions.ts @@ -5,7 +5,6 @@ import { type ChannelMessageToolDiscovery, } from "openclaw/plugin-sdk/channel-contract"; import type { SlackActionContext } from "./action-runtime.js"; -import { handleSlackAction } from "./action-runtime.js"; import { isSlackInteractiveRepliesEnabled } from "./interactive-replies.js"; import { handleSlackMessageAction } from "./message-action-dispatch.js"; import { extractSlackToolSend, listSlackMessageActions } from "./message-actions.js"; @@ -18,6 +17,13 @@ type SlackActionInvoke = ( toolContext: unknown, ) => Promise>; +let slackActionRuntimePromise: Promise | undefined; + +async function loadSlackActionRuntime() { + slackActionRuntimePromise ??= import("./action-runtime.runtime.js"); + return await slackActionRuntimePromise; +} + export function createSlackActions( providerId: string, options?: { invoke?: SlackActionInvoke }, @@ -61,7 +67,7 @@ export function createSlackActions( invoke: async (action, cfg, toolContext) => await (options?.invoke ? options.invoke(action, cfg, toolContext) - : handleSlackAction(action, cfg, { + : (await loadSlackActionRuntime()).handleSlackAction(action, cfg, { ...(toolContext as SlackActionContext | undefined), mediaLocalRoots: ctx.mediaLocalRoots, mediaReadFile: ctx.mediaReadFile, diff --git a/extensions/slack/src/channel.ts b/extensions/slack/src/channel.ts index 466ba55eb18..9e021b8a650 100644 --- a/extensions/slack/src/channel.ts +++ b/extensions/slack/src/channel.ts @@ -36,7 +36,7 @@ import { resolveSlackReplyToMode, type ResolvedSlackAccount, } from "./accounts.js"; -import { handleSlackAction, type SlackActionContext } from "./action-runtime.js"; +import type { SlackActionContext } from "./action-runtime.js"; import { resolveSlackAutoThreadId } from "./action-threading.js"; import { slackApprovalCapability } from "./approval-native.js"; import { createSlackActions } from "./channel-actions.js"; @@ -69,7 +69,6 @@ import { import { getOptionalSlackRuntime, getSlackRuntime } from "./runtime.js"; import { fetchSlackScopes } from "./scopes.js"; import { collectSlackSecurityAuditFindings } from "./security-audit.js"; -import { sendMessageSlack } from "./send.js"; import { slackSetupAdapter } from "./setup-core.js"; import { slackSetupWizard } from "./setup-surface.js"; import { @@ -97,8 +96,11 @@ function resolveSlackProbe() { return probeSlack; } -function resolveSlackHandleAction() { - return getOptionalSlackRuntime()?.channel?.slack?.handleSlackAction ?? handleSlackAction; +async function resolveSlackHandleAction() { + return ( + getOptionalSlackRuntime()?.channel?.slack?.handleSlackAction ?? + (await loadSlackActionRuntime()).handleSlackAction + ); } // Select the appropriate Slack token for read/write operations. @@ -118,16 +120,31 @@ function getTokenForOperation( return botToken ?? userToken; } -type SlackSendFn = typeof sendMessageSlack; +type SlackSendFn = typeof import("./send.runtime.js").sendMessageSlack; -function resolveSlackSendContext(params: { +let slackActionRuntimePromise: Promise | undefined; +let slackSendRuntimePromise: Promise | undefined; + +async function loadSlackActionRuntime() { + slackActionRuntimePromise ??= import("./action-runtime.runtime.js"); + return await slackActionRuntimePromise; +} + +async function loadSlackSendRuntime() { + slackSendRuntimePromise ??= import("./send.runtime.js"); + return await slackSendRuntimePromise; +} + +async function resolveSlackSendContext(params: { cfg: Parameters[0]["cfg"]; accountId?: string; deps?: { [channelId: string]: unknown }; replyToId?: string | number | null; threadId?: string | number | null; }) { - const send = resolveOutboundSendDep(params.deps, "slack") ?? sendMessageSlack; + const send = + resolveOutboundSendDep(params.deps, "slack") ?? + (await loadSlackSendRuntime()).sendMessageSlack; const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId }); const token = getTokenForOperation(account, "write"); const botToken = account.botToken?.trim(); @@ -369,11 +386,9 @@ export const slackPlugin: ChannelPlugin = crea }, actions: createSlackActions(SLACK_CHANNEL, { invoke: async (action, cfg, toolContext) => - await resolveSlackHandleAction()( - action, - cfg as OpenClawConfig, - toolContext as SlackActionContext | undefined, - ), + await ( + await resolveSlackHandleAction() + )(action, cfg as OpenClawConfig, toolContext as SlackActionContext | undefined), }), status: createComputedAccountStatusAdapter({ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID), @@ -476,6 +491,7 @@ export const slackPlugin: ChannelPlugin = crea cfg, accountId: DEFAULT_ACCOUNT_ID, }); + const { sendMessageSlack } = await loadSlackSendRuntime(); const token = getTokenForOperation(account, "write"); const botToken = account.botToken?.trim(); const tokenOverride = token && token !== botToken ? token : undefined; @@ -525,7 +541,7 @@ export const slackPlugin: ChannelPlugin = crea payload, }), sendPayload: async (ctx) => { - const { send, tokenOverride } = resolveSlackSendContext({ + const { send, tokenOverride } = await resolveSlackSendContext({ cfg: ctx.cfg, accountId: ctx.accountId ?? undefined, deps: ctx.deps, @@ -552,7 +568,7 @@ export const slackPlugin: ChannelPlugin = crea attachedResults: { channel: "slack", sendText: async ({ to, text, accountId, deps, replyToId, threadId, cfg }) => { - const { send, threadTsValue, tokenOverride } = resolveSlackSendContext({ + const { send, threadTsValue, tokenOverride } = await resolveSlackSendContext({ cfg, accountId: accountId ?? undefined, deps, @@ -577,7 +593,7 @@ export const slackPlugin: ChannelPlugin = crea threadId, cfg, }) => { - const { send, threadTsValue, tokenOverride } = resolveSlackSendContext({ + const { send, threadTsValue, tokenOverride } = await resolveSlackSendContext({ cfg, accountId: accountId ?? undefined, deps, diff --git a/extensions/slack/src/send.runtime.ts b/extensions/slack/src/send.runtime.ts new file mode 100644 index 00000000000..16eb437da7c --- /dev/null +++ b/extensions/slack/src/send.runtime.ts @@ -0,0 +1 @@ +export { sendMessageSlack } from "./send.js";