mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 09:58:38 +00:00
fix(slack): add mention stripPatterns for /new and /reset commands (#9971)
* fix(slack): add mention stripPatterns for /new and /reset commands Fixes #9937 The Slack dock was missing mentions.stripPatterns that Discord has. This caused /new and /reset to fail when sent with a mention (e.g. @bot /reset) because <@USERID> wasn't stripped before matching. * fix(slack): strip mentions for /new and /reset (#9971) (thanks @ironbyte-rgb) --------- Co-authored-by: ironbyte-rgb <amontaboi76@gmail.com> Co-authored-by: George Pickett <gpickett00@gmail.com>
This commit is contained in:
@@ -51,6 +51,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Onboarding: infer auth choice from non-interactive API key flags. (#8484) Thanks @f-trycua.
|
- Onboarding: infer auth choice from non-interactive API key flags. (#8484) Thanks @f-trycua.
|
||||||
- Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.
|
- Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.
|
||||||
- Discord: treat allowlisted senders as owner for system-prompt identity hints while keeping channel topics untrusted.
|
- Discord: treat allowlisted senders as owner for system-prompt identity hints while keeping channel topics untrusted.
|
||||||
|
- Slack: strip `<@...>` mention tokens before command matching so `/new` and `/reset` work when prefixed with a mention. (#9971) Thanks @ironbyte-rgb.
|
||||||
- Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.
|
- Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.
|
||||||
- Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.
|
- Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.
|
||||||
- Security: gate `whatsapp_login` tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.
|
- Security: gate `whatsapp_login` tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.
|
||||||
|
|||||||
@@ -255,6 +255,107 @@ describe("initSessionState reset triggers in WhatsApp groups", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("initSessionState reset triggers in Slack channels", () => {
|
||||||
|
async function createStorePath(prefix: string): Promise<string> {
|
||||||
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
||||||
|
return path.join(root, "sessions.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function seedSessionStore(params: {
|
||||||
|
storePath: string;
|
||||||
|
sessionKey: string;
|
||||||
|
sessionId: string;
|
||||||
|
}): Promise<void> {
|
||||||
|
const { saveSessionStore } = await import("../../config/sessions.js");
|
||||||
|
await saveSessionStore(params.storePath, {
|
||||||
|
[params.sessionKey]: {
|
||||||
|
sessionId: params.sessionId,
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it("Reset trigger /reset works when Slack message has a leading <@...> mention token", async () => {
|
||||||
|
const storePath = await createStorePath("openclaw-slack-channel-reset-");
|
||||||
|
const sessionKey = "agent:main:slack:channel:c1";
|
||||||
|
const existingSessionId = "existing-session-123";
|
||||||
|
await seedSessionStore({
|
||||||
|
storePath,
|
||||||
|
sessionKey,
|
||||||
|
sessionId: existingSessionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const cfg = {
|
||||||
|
session: { store: storePath, idleMinutes: 999 },
|
||||||
|
} as OpenClawConfig;
|
||||||
|
|
||||||
|
const channelMessageCtx = {
|
||||||
|
Body: "<@U123> /reset",
|
||||||
|
RawBody: "<@U123> /reset",
|
||||||
|
CommandBody: "<@U123> /reset",
|
||||||
|
From: "slack:channel:C1",
|
||||||
|
To: "channel:C1",
|
||||||
|
ChatType: "channel",
|
||||||
|
SessionKey: sessionKey,
|
||||||
|
Provider: "slack",
|
||||||
|
Surface: "slack",
|
||||||
|
SenderId: "U123",
|
||||||
|
SenderName: "Owner",
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await initSessionState({
|
||||||
|
ctx: channelMessageCtx,
|
||||||
|
cfg,
|
||||||
|
commandAuthorized: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.isNewSession).toBe(true);
|
||||||
|
expect(result.resetTriggered).toBe(true);
|
||||||
|
expect(result.sessionId).not.toBe(existingSessionId);
|
||||||
|
expect(result.bodyStripped).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Reset trigger /new preserves args when Slack message has a leading <@...> mention token", async () => {
|
||||||
|
const storePath = await createStorePath("openclaw-slack-channel-new-");
|
||||||
|
const sessionKey = "agent:main:slack:channel:c2";
|
||||||
|
const existingSessionId = "existing-session-123";
|
||||||
|
await seedSessionStore({
|
||||||
|
storePath,
|
||||||
|
sessionKey,
|
||||||
|
sessionId: existingSessionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const cfg = {
|
||||||
|
session: { store: storePath, idleMinutes: 999 },
|
||||||
|
} as OpenClawConfig;
|
||||||
|
|
||||||
|
const channelMessageCtx = {
|
||||||
|
Body: "<@U123> /new take notes",
|
||||||
|
RawBody: "<@U123> /new take notes",
|
||||||
|
CommandBody: "<@U123> /new take notes",
|
||||||
|
From: "slack:channel:C2",
|
||||||
|
To: "channel:C2",
|
||||||
|
ChatType: "channel",
|
||||||
|
SessionKey: sessionKey,
|
||||||
|
Provider: "slack",
|
||||||
|
Surface: "slack",
|
||||||
|
SenderId: "U123",
|
||||||
|
SenderName: "Owner",
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await initSessionState({
|
||||||
|
ctx: channelMessageCtx,
|
||||||
|
cfg,
|
||||||
|
commandAuthorized: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.isNewSession).toBe(true);
|
||||||
|
expect(result.resetTriggered).toBe(true);
|
||||||
|
expect(result.sessionId).not.toBe(existingSessionId);
|
||||||
|
expect(result.bodyStripped).toBe("take notes");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("applyResetModelOverride", () => {
|
describe("applyResetModelOverride", () => {
|
||||||
it("selects a model hint and strips it from the body", async () => {
|
it("selects a model hint and strips it from the body", async () => {
|
||||||
const cfg = {} as OpenClawConfig;
|
const cfg = {} as OpenClawConfig;
|
||||||
|
|||||||
@@ -295,6 +295,9 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
|
|||||||
resolveRequireMention: resolveSlackGroupRequireMention,
|
resolveRequireMention: resolveSlackGroupRequireMention,
|
||||||
resolveToolPolicy: resolveSlackGroupToolPolicy,
|
resolveToolPolicy: resolveSlackGroupToolPolicy,
|
||||||
},
|
},
|
||||||
|
mentions: {
|
||||||
|
stripPatterns: () => ["<@[^>]+>"],
|
||||||
|
},
|
||||||
threading: {
|
threading: {
|
||||||
resolveReplyToMode: ({ cfg, accountId, chatType }) =>
|
resolveReplyToMode: ({ cfg, accountId, chatType }) =>
|
||||||
resolveSlackReplyToMode(resolveSlackAccount({ cfg, accountId }), chatType),
|
resolveSlackReplyToMode(resolveSlackAccount({ cfg, accountId }), chatType),
|
||||||
|
|||||||
Reference in New Issue
Block a user