























@@ -20,6 +20,7 @@ export type SlackRoutingContextDeps = {
2020export type SlackRoutingContext = {
2121route: ReturnType<typeof resolveAgentRoute>;
2222runtimeBinding: RuntimeConversationBindingRouteResult["bindingRecord"];
23+runtimeBoundSessionKey: string | undefined;
2324chatType: "direct" | "group" | "channel";
2425replyToMode: ReturnType<typeof resolveSlackReplyToMode>;
2526threadContext: ReturnType<typeof resolveSlackThreadContext>;
@@ -39,6 +40,25 @@ function resolveSlackBaseConversationId(params: {
3940 : params.message.channel;
4041}
414243+function resolveSlackInitialAgentRoute(params: {
44+ctx: SlackRoutingContextDeps;
45+account: ResolvedSlackAccount;
46+message: SlackMessageEvent;
47+isDirectMessage: boolean;
48+isRoom: boolean;
49+}) {
50+return resolveAgentRoute({
51+cfg: params.ctx.cfg,
52+channel: "slack",
53+accountId: params.account.accountId,
54+teamId: params.ctx.teamId || undefined,
55+peer: {
56+kind: params.isDirectMessage ? "direct" : params.isRoom ? "channel" : "group",
57+id: params.isDirectMessage ? (params.message.user ?? "unknown") : params.message.channel,
58+},
59+});
60+}
61+4262export function resolveSlackRoutingContext(params: {
4363ctx: SlackRoutingContextDeps;
4464account: ResolvedSlackAccount;
@@ -47,17 +67,24 @@ export function resolveSlackRoutingContext(params: {
4767isGroupDm: boolean;
4868isRoom: boolean;
4969isRoomish: boolean;
70+seedTopLevelRoomThread?: boolean;
5071}): SlackRoutingContext {
51-const { ctx, account, message, isDirectMessage, isGroupDm, isRoom, isRoomish } = params;
52-let route = resolveAgentRoute({
53-cfg: ctx.cfg,
54-channel: "slack",
55-accountId: account.accountId,
56-teamId: ctx.teamId || undefined,
57-peer: {
58-kind: isDirectMessage ? "direct" : isRoom ? "channel" : "group",
59-id: isDirectMessage ? (message.user ?? "unknown") : message.channel,
60-},
72+const {
73+ ctx,
74+ account,
75+ message,
76+ isDirectMessage,
77+ isGroupDm,
78+ isRoom,
79+ isRoomish,
80+ seedTopLevelRoomThread,
81+} = params;
82+let route = resolveSlackInitialAgentRoute({
83+ ctx,
84+ account,
85+ message,
86+ isDirectMessage,
87+ isRoom,
6188});
62896390const chatType = isDirectMessage ? "direct" : isGroupDm ? "group" : "channel";
@@ -72,21 +99,32 @@ export function resolveSlackRoutingContext(params: {
7299!isThreadReply && replyToMode === "all" && threadContext.messageTs
73100 ? threadContext.messageTs
74101 : undefined;
75-// Only fork channel/group messages into thread-specific sessions when they are
76-// actual thread replies (thread_ts present, different from message ts).
77-// Top-level channel messages must stay on the per-channel session for continuity.
78-// Before this fix, every channel message used its own ts as threadId, creating
79-// isolated sessions per message (regression from #10686).
102+// Keep ordinary top-level room messages on the per-channel session for
103+// continuity, but preserve Slack thread identity when the event already has
104+// one or when an actionable app mention will seed a reply thread.
105+// This keeps a thread root and its later replies on one parent session
106+// without returning to the old "every channel message is its own thread"
107+// behavior (regression from #10686).
108+const seedCandidateThreadId = threadContext.incomingThreadTs ?? threadContext.messageTs;
109+const seededRoomThreadId =
110+!isThreadReply &&
111+isRoom &&
112+seedTopLevelRoomThread &&
113+replyToMode !== "off" &&
114+seedCandidateThreadId
115+ ? seedCandidateThreadId
116+ : undefined;
80117const roomThreadId = isThreadReply && threadTs ? threadTs : undefined;
81118const canonicalThreadId = isRoomish ? roomThreadId : isThreadReply ? threadTs : autoThreadId;
119+const routedThreadId = canonicalThreadId ?? (isRoomish ? seededRoomThreadId : undefined);
82120const baseConversationId = resolveSlackBaseConversationId({ message, isDirectMessage });
83-const boundThreadRoute = canonicalThreadId
121+const boundThreadRoute = routedThreadId
84122 ? resolveRuntimeConversationBindingRoute({
85123 route,
86124conversation: {
87125channel: "slack",
88126accountId: account.accountId,
89-conversationId: canonicalThreadId,
127+conversationId: routedThreadId,
90128parentConversationId: baseConversationId,
91129},
92130})
@@ -107,9 +145,8 @@ export function resolveSlackRoutingContext(params: {
107145 ? { sessionKey: route.sessionKey, parentSessionKey: undefined }
108146 : resolveThreadSessionKeys({
109147baseSessionKey: route.sessionKey,
110-threadId: canonicalThreadId,
111-parentSessionKey:
112-canonicalThreadId && ctx.threadInheritParent ? route.sessionKey : undefined,
148+threadId: routedThreadId,
149+parentSessionKey: routedThreadId && ctx.threadInheritParent ? route.sessionKey : undefined,
113150});
114151const sessionKey = threadKeys.sessionKey;
115152const historyKey =
@@ -118,6 +155,7 @@ export function resolveSlackRoutingContext(params: {
118155return {
119156 route,
120157runtimeBinding: runtimeRoute.bindingRecord,
158+runtimeBoundSessionKey: runtimeRoute.boundSessionKey,
121159 chatType,
122160 replyToMode,
123161 threadContext,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。