fix: prevent idle reminder from re-waking dormant discussion channel
The moderator bot's own idle reminder message triggered message_received, which saw senderId != currentSpeaker and called wakeFromDormant, immediately undoing the dormant state just entered. Fix: derive the moderator bot's Discord user ID from the token and skip wake-from-dormant when the sender is the moderator bot itself. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|||||||
|
|
||||||
type Logger = { info: (m: string) => void; warn: (m: string) => void };
|
type Logger = { info: (m: string) => void; warn: (m: string) => void };
|
||||||
|
|
||||||
function userIdFromToken(token: string): string | undefined {
|
export function userIdFromBotToken(token: string): string | undefined {
|
||||||
try {
|
try {
|
||||||
const segment = token.split(".")[0];
|
const segment = token.split(".")[0];
|
||||||
const padded = segment + "=".repeat((4 - (segment.length % 4)) % 4);
|
const padded = segment + "=".repeat((4 - (segment.length % 4)) % 4);
|
||||||
@@ -19,7 +19,7 @@ export function resolveDiscordUserId(api: OpenClawPluginApi, accountId: string):
|
|||||||
const accounts = (discord.accounts as Record<string, Record<string, unknown>>) || {};
|
const accounts = (discord.accounts as Record<string, Record<string, unknown>>) || {};
|
||||||
const acct = accounts[accountId];
|
const acct = accounts[accountId];
|
||||||
if (!acct?.token || typeof acct.token !== "string") return undefined;
|
if (!acct?.token || typeof acct.token !== "string") return undefined;
|
||||||
return userIdFromToken(acct.token);
|
return userIdFromBotToken(acct.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModeratorMessageResult =
|
export type ModeratorMessageResult =
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { ChannelStore } from "../core/channel-store.js";
|
|||||||
import type { IdentityRegistry } from "../core/identity-registry.js";
|
import type { IdentityRegistry } from "../core/identity-registry.js";
|
||||||
import { parseDiscordChannelId } from "./before-model-resolve.js";
|
import { parseDiscordChannelId } from "./before-model-resolve.js";
|
||||||
import { isDormant, wakeFromDormant, isCurrentSpeaker, hasSpeakers, setSpeakerList, getInitializingChannels, type SpeakerEntry } from "../turn-manager.js";
|
import { isDormant, wakeFromDormant, isCurrentSpeaker, hasSpeakers, setSpeakerList, getInitializingChannels, type SpeakerEntry } from "../turn-manager.js";
|
||||||
import { sendAndDelete, sendModeratorMessage } from "../core/moderator-discord.js";
|
import { sendAndDelete, sendModeratorMessage, userIdFromBotToken } from "../core/moderator-discord.js";
|
||||||
import { fetchVisibleChannelBotAccountIds } from "../core/channel-members.js";
|
import { fetchVisibleChannelBotAccountIds } from "../core/channel-members.js";
|
||||||
import type { InterruptFn } from "./agent-end.js";
|
import type { InterruptFn } from "./agent-end.js";
|
||||||
|
|
||||||
@@ -18,6 +18,9 @@ type Deps = {
|
|||||||
|
|
||||||
export function registerMessageReceivedHook(deps: Deps): void {
|
export function registerMessageReceivedHook(deps: Deps): void {
|
||||||
const { api, channelStore, identityRegistry, moderatorBotToken, scheduleIdentifier, interruptTailMatch } = deps;
|
const { api, channelStore, identityRegistry, moderatorBotToken, scheduleIdentifier, interruptTailMatch } = deps;
|
||||||
|
// Derive the moderator bot's own Discord user ID so we can skip self-messages
|
||||||
|
// from waking dormant channels (idle reminders must not re-trigger the cycle).
|
||||||
|
const moderatorBotUserId = moderatorBotToken ? userIdFromBotToken(moderatorBotToken) : undefined;
|
||||||
|
|
||||||
api.on("message_received", async (event, ctx) => {
|
api.on("message_received", async (event, ctx) => {
|
||||||
try {
|
try {
|
||||||
@@ -125,8 +128,9 @@ export function registerMessageReceivedHook(deps: Deps): void {
|
|||||||
interruptTailMatch(channelId);
|
interruptTailMatch(channelId);
|
||||||
api.logger.info(`dirigent: message_received interrupt tail-match channel=${channelId} senderId=${senderId}`);
|
api.logger.info(`dirigent: message_received interrupt tail-match channel=${channelId} senderId=${senderId}`);
|
||||||
|
|
||||||
// Wake from dormant if needed
|
// Wake from dormant if needed — but ignore the moderator bot's own messages
|
||||||
if (isDormant(channelId) && moderatorBotToken) {
|
// (e.g. idle reminder) to prevent it from immediately re-waking the channel.
|
||||||
|
if (isDormant(channelId) && moderatorBotToken && senderId !== moderatorBotUserId) {
|
||||||
const first = wakeFromDormant(channelId);
|
const first = wakeFromDormant(channelId);
|
||||||
if (first) {
|
if (first) {
|
||||||
const msg = `<@${first.discordUserId}>${scheduleIdentifier}`;
|
const msg = `<@${first.discordUserId}>${scheduleIdentifier}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user