mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix(slack): keep top-level dms on stable session
This commit is contained in:
@@ -35,6 +35,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Providers/configure: preserve the existing default model when adding or reauthing a provider whose plugin returns a default-model config patch. Fixes #50268. Thanks @rixcorp-oc.
|
||||
- Slack/message actions: send media before the follow-up Block Kit message when Slack `send` includes a file plus presentation or interactive controls, so file attachments are no longer rejected. Fixes #51458. Thanks @HirokiKobayashi-R.
|
||||
- Slack/DMs: honor `dmHistoryLimit` for fresh 1:1 Slack DM sessions by backfilling recent conversation history before the current reply. Fixes #64427. Thanks @brantley-creator.
|
||||
- Slack/DMs: keep top-level direct messages on the stable DM session even when `replyToMode` targets Slack thread replies, preserving context across DM turns. Fixes #58832. Thanks @daye-jjeong.
|
||||
- Slack/mentions: resolve `<!subteam^...>` user-group mentions through Slack `usergroups.users.list` and treat them as explicit mentions only when the bot user is a member, so mention-gated agent channels wake for real user-group mentions without config-only allowlists. Fixes #73827. Thanks @CG-Intelligence-Agent-Jack.
|
||||
- Slack/message tool: let `read` fetch an exact Slack message timestamp, including a specific thread reply when paired with `threadId`, instead of returning only the parent thread or recent channel history. Fixes #53943. Thanks @zomars.
|
||||
- Web search: point missing-key errors to `web_fetch` for known URLs and the browser tool for interactive pages. Thanks @zhaoyang97.
|
||||
|
||||
@@ -92,9 +92,9 @@ export function resolveSlackRoutingContext(params: {
|
||||
const threadContext = resolveSlackThreadContext({ message, replyToMode });
|
||||
const threadTs = threadContext.incomingThreadTs;
|
||||
const isThreadReply = threadContext.isThreadReply;
|
||||
// Keep true thread replies thread-scoped, but preserve channel-level sessions
|
||||
// for top-level room turns when replyToMode is off.
|
||||
// For DMs, preserve existing auto-thread behavior when replyToMode="all".
|
||||
// Keep true thread replies thread-scoped, while top-level DMs keep their
|
||||
// stable direct-message session even when reply delivery targets a Slack UI
|
||||
// thread.
|
||||
const autoThreadId =
|
||||
!isThreadReply && replyToMode === "all" && threadContext.messageTs
|
||||
? threadContext.messageTs
|
||||
@@ -115,7 +115,15 @@ export function resolveSlackRoutingContext(params: {
|
||||
? seedCandidateThreadId
|
||||
: undefined;
|
||||
const roomThreadId = isThreadReply && threadTs ? threadTs : undefined;
|
||||
const canonicalThreadId = isRoomish ? roomThreadId : isThreadReply ? threadTs : autoThreadId;
|
||||
const canonicalThreadId = isDirectMessage
|
||||
? isThreadReply
|
||||
? threadTs
|
||||
: undefined
|
||||
: isRoomish
|
||||
? roomThreadId
|
||||
: isThreadReply
|
||||
? threadTs
|
||||
: autoThreadId;
|
||||
const routedThreadId = canonicalThreadId ?? (isRoomish ? seededRoomThreadId : undefined);
|
||||
const baseConversationId = resolveSlackBaseConversationId({ message, isDirectMessage });
|
||||
const boundThreadRoute = routedThreadId
|
||||
|
||||
@@ -1073,11 +1073,11 @@ describe("slack prepareSlackMessage inbound contract", () => {
|
||||
expect(prepared!.ctxPayload.Body).not.toContain("parent_user_id");
|
||||
});
|
||||
|
||||
it("creates thread session for top-level DM when replyToMode=all", async () => {
|
||||
it("keeps top-level DM session stable when replyToMode=all", async () => {
|
||||
const { storePath } = storeFixture.makeTmpStorePath();
|
||||
const slackCtx = createInboundSlackCtx({
|
||||
cfg: {
|
||||
session: { store: storePath },
|
||||
session: { store: storePath, dmScope: "per-channel-peer" },
|
||||
channels: { slack: { enabled: true, replyToMode: "all" } },
|
||||
} as OpenClawConfig,
|
||||
replyToMode: "all",
|
||||
@@ -1092,9 +1092,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
|
||||
);
|
||||
|
||||
expect(prepared).toBeTruthy();
|
||||
// Session key should include :thread:500.000 for the auto-threaded message
|
||||
expect(prepared!.ctxPayload.SessionKey).toContain(":thread:500.000");
|
||||
// MessageThreadId should be set for the reply
|
||||
expect(prepared!.ctxPayload.SessionKey).toBe("agent:main:slack:direct:u1");
|
||||
expect(prepared!.ctxPayload.MessageThreadId).toBe("500.000");
|
||||
});
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@ import type { ResolvedSlackAccount } from "../../accounts.js";
|
||||
import type { SlackMessageEvent } from "../../types.js";
|
||||
import { resolveSlackRoutingContext, type SlackRoutingContextDeps } from "./prepare-routing.js";
|
||||
|
||||
function buildCtx(overrides?: { replyToMode?: "all" | "first" | "off" | "batched" }) {
|
||||
function buildCtx(overrides?: {
|
||||
replyToMode?: "all" | "first" | "off" | "batched";
|
||||
dmScope?: "main" | "per-sender" | "per-channel-peer";
|
||||
}) {
|
||||
const replyToMode = overrides?.replyToMode ?? "all";
|
||||
return {
|
||||
cfg: {
|
||||
session: { dmScope: overrides?.dmScope },
|
||||
channels: {
|
||||
slack: { enabled: true, replyToMode },
|
||||
},
|
||||
@@ -321,4 +325,28 @@ describe("thread-level session keys", () => {
|
||||
const sessionKey = routing.sessionKey;
|
||||
expect(sessionKey).not.toContain(":thread:");
|
||||
});
|
||||
|
||||
it("keeps top-level DMs on the direct session when replyToMode=all", () => {
|
||||
const ctx = buildCtx({ replyToMode: "all", dmScope: "per-channel-peer" });
|
||||
const account = buildAccount("all");
|
||||
|
||||
const routing = resolveSlackRoutingContext({
|
||||
ctx,
|
||||
account,
|
||||
message: {
|
||||
channel: "D456",
|
||||
channel_type: "im",
|
||||
user: "U3",
|
||||
text: "dm message",
|
||||
ts: "1770408530.000000",
|
||||
} as SlackMessageEvent,
|
||||
isDirectMessage: true,
|
||||
isGroupDm: false,
|
||||
isRoom: false,
|
||||
isRoomish: false,
|
||||
});
|
||||
|
||||
expect(routing.sessionKey).toBe("agent:main:slack:direct:u3");
|
||||
expect(routing.threadContext.messageThreadId).toBe("1770408530.000000");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user