Skip to content

Commit 5e572dc

Browse files
LiuwqGitPeter Steinberger
andauthored
fix(slack): prefer current thread session for inherited outbound replies (#97168)
* fix(slack): prefer current thread session for inherited outbound replies to avoid delivery-mirror session sprawl * fix(slack): require explicit replyToIsExplicit===false for current-session precedence * fix(slack): canonicalize inherited thread replies --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent a841c27 commit 5e572dc

2 files changed

Lines changed: 35 additions & 5 deletions

File tree

extensions/slack/src/channel.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,33 @@ describe("slackPlugin outbound", () => {
874874
});
875875
});
876876

877+
it.each([
878+
{
879+
name: "inherited",
880+
replyToIsExplicit: false,
881+
expectedReplyToId: "1712345678.123456",
882+
},
883+
{ name: "explicit", replyToIsExplicit: true, expectedReplyToId: "1712345688.654321" },
884+
{ name: "unknown", replyToIsExplicit: undefined, expectedReplyToId: "1712345688.654321" },
885+
])(
886+
"routes $name child replies to $expectedReplyToId",
887+
({ replyToIsExplicit, expectedReplyToId }) => {
888+
const resolveReplyTransport = slackPlugin.threading?.resolveReplyTransport;
889+
if (!resolveReplyTransport) {
890+
throw new Error("slack threading.resolveReplyTransport unavailable");
891+
}
892+
893+
expect(
894+
resolveReplyTransport({
895+
cfg,
896+
replyToId: "1712345688.654321",
897+
threadId: "1712345678.123456",
898+
replyToIsExplicit,
899+
}),
900+
).toEqual({ replyToId: expectedReplyToId, threadId: null });
901+
},
902+
);
903+
877904
it("ignores explicit reply targets for off-mode final delivery", () => {
878905
const resolveReplyTransport = slackPlugin.threading?.resolveReplyTransport;
879906
if (!resolveReplyTransport) {

extensions/slack/src/channel.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -663,8 +663,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount, SlackProbe> = crea
663663
}
664664
return resolveTargetsWithOptionalToken({
665665
token:
666-
normalizeOptionalString(account.userToken) ??
667-
normalizeOptionalString(account.botToken),
666+
normalizeOptionalString(account.userToken) ?? normalizeOptionalString(account.botToken),
668667
inputs,
669668
missingTokenNote: "missing Slack token",
670669
resolveWithToken: async ({ token, inputs: inputsLocal }) =>
@@ -819,10 +818,14 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount, SlackProbe> = crea
819818
toolContext,
820819
}),
821820
),
822-
resolveReplyTransport: ({ threadId, replyToId, replyDelivery }) => {
821+
resolveReplyTransport: ({ threadId, replyToId, replyToIsExplicit, replyDelivery }) => {
822+
const allowedReplyToId = replyDelivery?.replyToMode === "off" ? undefined : replyToId;
823+
// Slack's thread_ts identifies the root. Only known inherited replies may let
824+
// that root replace a child timestamp; explicit and unknown callers stay reply-first.
825+
const preferThreadId = replyToIsExplicit === false;
823826
const resolvedReplyToId = resolveSlackThreadTsValue({
824-
replyToId: replyDelivery?.replyToMode === "off" ? undefined : replyToId,
825-
threadId,
827+
replyToId: preferThreadId ? threadId : allowedReplyToId,
828+
threadId: preferThreadId ? allowedReplyToId : threadId,
826829
});
827830
return {
828831
replyToId:

0 commit comments

Comments
 (0)