Fix Discord autoThread thread-only replies (#807)

Co-authored-by: Shadow <shadow@clawd.bot>
This commit is contained in:
David Guttman
2026-01-12 13:11:48 -10:00
committed by GitHub
parent cf92099d40
commit 2e654e8d63
2 changed files with 20 additions and 11 deletions

View File

@@ -56,6 +56,7 @@
- Auto-reply: elevated/reasoning toggles now enqueue system events so the model sees the mode change immediately.
- Tools: keep `image` available in sandbox and fail over when image models return empty output (fixes “(no text returned)”).
- Discord: add per-channel `autoThread` to auto-create threads for top-level messages. (#800) — thanks @davidguttman.
- Discord: fix autoThread routing so replies stay in the created thread and avoid reply references. (#807) — thanks @davidguttman.
- Onboarding: TUI defaults to `deliver: false` to avoid cross-provider auto-delivery leaks; onboarding spawns the TUI with explicit `deliver: false`. (#791 — thanks @roshanasingh4)
## 2026.1.11

View File

@@ -1179,23 +1179,26 @@ export function createDiscordMessageHandler(params: {
OriginatingChannel: "discord" as const,
OriginatingTo: discordTo,
};
const replyTarget = ctxPayload.To ?? undefined;
let replyTarget = ctxPayload.To ?? undefined;
if (!replyTarget) {
runtime.error?.(danger("discord: missing reply target"));
return;
}
const originalReplyTarget = replyTarget;
let deliverTarget = replyTarget;
if (isGuildMessage && channelConfig?.autoThread && !threadChannel) {
try {
const base = truncateUtf16Safe(
(baseText || combinedBody || "Thread").replace(/\s+/g, " ").trim(),
80,
);
const authorLabel = author.username ?? author.id;
const threadName =
truncateUtf16Safe(`${authorLabel}: ${base}`.trim(), 100) ||
`Thread ${message.id}`;
const rawName = baseText || combinedBody || "Thread";
const cleanedName = rawName
.replace(/<@!?\d+>/g, "") // user mentions
.replace(/<@&\d+>/g, "") // role mentions
.replace(/<#\d+>/g, "") // channel mentions
.replace(/\s+/g, " ")
.trim();
const base = truncateUtf16Safe(cleanedName || "Thread", 80);
const threadName = truncateUtf16Safe(base, 100) || `Thread ${message.id}`;
const created = (await client.rest.post(
`${Routes.channelMessage(message.channelId, message.id)}/threads`,
@@ -1210,6 +1213,8 @@ export function createDiscordMessageHandler(params: {
const createdId = created?.id ? String(created.id) : "";
if (createdId) {
deliverTarget = `channel:${createdId}`;
// When autoThread is enabled, *always* reply in the created thread.
replyTarget = deliverTarget;
}
} catch (err) {
logVerbose(
@@ -1251,12 +1256,15 @@ export function createDiscordMessageHandler(params: {
deliver: async (payload) => {
await deliverDiscordReply({
replies: [payload],
target: deliverTarget,
target: replyTarget,
token,
accountId,
rest: client.rest,
runtime,
replyToMode: deliverTarget !== replyTarget ? "off" : replyToMode,
// The original message is in the parent channel; never try to reply-reference it
// when posting inside the newly-created thread.
replyToMode:
deliverTarget !== originalReplyTarget ? "off" : replyToMode,
textLimit,
maxLinesPerMessage: discordConfig?.maxLinesPerMessage,
});