fix(slack): treat HTTP mode accounts as configured [AI-assisted] (openclaw#30571) thanks @liuxiaopai-ai

Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: liuxiaopai-ai <73659136+liuxiaopai-ai@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Mark L
2026-03-01 23:00:17 +08:00
committed by GitHub
parent e3ba59dc71
commit 4da4cc94c1
3 changed files with 56 additions and 3 deletions

View File

@@ -91,6 +91,7 @@ Docs: https://docs.openclaw.ai
- Cron/Schedule errors: notify users when a job is auto-disabled after repeated schedule computation failures. (#29098) Thanks .
- Cron/Schedule errors: notify users when a job is auto-disabled after repeated schedule computation failures. (#29098) Thanks .
- File tools/tilde paths: expand `~/...` against the user home directory before workspace-root checks in host file read/write/edit paths, while preserving root-boundary enforcement so outside-root targets remain blocked. (#29779) Thanks @Glucksberg.
- Slack/HTTP mode startup: treat Slack HTTP accounts as configured when `botToken` + `signingSecret` are present (without requiring `appToken`) in channel config/runtime status so webhook mode is not silently skipped. (#30567)
- Onboarding/Custom providers: raise default custom-provider model context window to the runtime hard minimum (16k) and auto-heal existing custom model entries below that threshold during reconfiguration, preventing immediate `Model context window too small (4096 tokens)` failures. (#21653) Thanks @r4jiv007.
- Web UI/Assistant text: strip internal `<relevant-memories>...</relevant-memories>` scaffolding from rendered assistant messages (while preserving code-fence literals), preventing memory-context leakage in chat output for models that echo internal blocks. (#29851) Thanks @Valkster70.
- Dashboard/Sessions: allow authenticated Control UI clients to delete and patch sessions while still blocking regular webchat clients from session mutation RPCs, fixing Dashboard session delete failures. (#21264) Thanks @jskoiz.

View File

@@ -1,3 +1,4 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk";
import { describe, expect, it, vi } from "vitest";
const handleSlackActionMock = vi.fn();
@@ -104,3 +105,42 @@ describe("slackPlugin outbound", () => {
expect(result).toEqual({ channel: "slack", messageId: "m-media" });
});
});
describe("slackPlugin config", () => {
it("treats HTTP mode accounts with bot token + signing secret as configured", () => {
const cfg: OpenClawConfig = {
channels: {
slack: {
mode: "http",
botToken: "xoxb-http",
signingSecret: "secret-http",
},
},
};
const account = slackPlugin.config.resolveAccount(cfg, "default");
const configured = slackPlugin.config.isConfigured?.(account, cfg);
const snapshot = slackPlugin.status?.buildAccountSnapshot?.({ account, runtime: undefined });
expect(configured).toBe(true);
expect(snapshot?.configured).toBe(true);
});
it("keeps socket mode requiring app token", () => {
const cfg: OpenClawConfig = {
channels: {
slack: {
mode: "socket",
botToken: "xoxb-socket",
},
},
};
const account = slackPlugin.config.resolveAccount(cfg, "default");
const configured = slackPlugin.config.isConfigured?.(account, cfg);
const snapshot = slackPlugin.status?.buildAccountSnapshot?.({ account, runtime: undefined });
expect(configured).toBe(false);
expect(snapshot?.configured).toBe(false);
});
});

View File

@@ -51,6 +51,18 @@ function getTokenForOperation(
return botToken ?? userToken;
}
function isSlackAccountConfigured(account: ResolvedSlackAccount): boolean {
const mode = account.config.mode ?? "socket";
const hasBotToken = Boolean(account.botToken?.trim());
if (!hasBotToken) {
return false;
}
if (mode === "http") {
return Boolean(account.config.signingSecret?.trim());
}
return Boolean(account.appToken?.trim());
}
export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
id: "slack",
meta: {
@@ -116,12 +128,12 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
accountId,
clearBaseFields: ["botToken", "appToken", "name"],
}),
isConfigured: (account) => Boolean(account.botToken && account.appToken),
isConfigured: (account) => isSlackAccountConfigured(account),
describeAccount: (account) => ({
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: Boolean(account.botToken && account.appToken),
configured: isSlackAccountConfigured(account),
botTokenSource: account.botTokenSource,
appTokenSource: account.appTokenSource,
}),
@@ -382,7 +394,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
return await getSlackRuntime().channel.slack.probeSlack(token, timeoutMs);
},
buildAccountSnapshot: ({ account, runtime, probe }) => {
const configured = Boolean(account.botToken && account.appToken);
const configured = isSlackAccountConfigured(account);
return {
accountId: account.accountId,
name: account.name,