refactor #22

Merged
hzhang merged 33 commits from refactor into main 2026-04-10 07:49:57 +00:00
2 changed files with 40 additions and 6 deletions
Showing only changes of commit 9e61af4a16 - Show all commits

View File

@@ -60,6 +60,12 @@ export function registerBeforeModelResolveHook(deps: Deps): void {
// dead mode: suppress all responses
if (mode === "report" || mode === "dead" as string) return NO_REPLY;
// concluded discussion: suppress all agent responses (auto-reply handled by message_received)
if (mode === "discussion") {
const rec = channelStore.getRecord(channelId);
if (rec.discussion?.concluded) return NO_REPLY;
}
// disabled modes: let agents respond freely
if (mode === "none" || mode === "work") return;

View File

@@ -16,6 +16,18 @@ type Deps = {
interruptTailMatch: InterruptFn;
};
/**
* Process-level dedup for concluded-discussion auto-replies.
* Multiple agent VM contexts all fire message_received for the same incoming message;
* only the first should send the "This discussion is closed" reply.
* Keyed on channelId:messageId; evicted after 500 entries.
*/
const _CONCLUDED_REPLY_DEDUP_KEY = "_dirigentConcludedReplyDedup";
if (!(globalThis as Record<string, unknown>)[_CONCLUDED_REPLY_DEDUP_KEY]) {
(globalThis as Record<string, unknown>)[_CONCLUDED_REPLY_DEDUP_KEY] = new Set<string>();
}
const concludedReplyDedup: Set<string> = (globalThis as Record<string, unknown>)[_CONCLUDED_REPLY_DEDUP_KEY] as Set<string>;
export function registerMessageReceivedHook(deps: Deps): void {
const { api, channelStore, identityRegistry, moderatorBotToken, scheduleIdentifier, interruptTailMatch } = deps;
// Derive the moderator bot's own Discord user ID so we can skip self-messages
@@ -61,15 +73,31 @@ export function registerMessageReceivedHook(deps: Deps): void {
// but we handle archived auto-reply here)
if (mode === "report") return;
// archived: auto-reply via moderator
// archived: auto-reply via moderator (deduped — only one agent instance should reply)
if (mode === "discussion") {
const rec = channelStore.getRecord(channelId);
if (rec.discussion?.concluded && moderatorBotToken) {
const metadata = e.metadata as Record<string, unknown> | undefined;
const convInfo = metadata?.conversation_info as Record<string, unknown> | undefined;
const incomingMsgId = String(
convInfo?.message_id ??
metadata?.message_id ??
metadata?.messageId ??
e.id ?? "",
);
const dedupKey = `${channelId}:${incomingMsgId}`;
if (!concludedReplyDedup.has(dedupKey)) {
concludedReplyDedup.add(dedupKey);
if (concludedReplyDedup.size > 500) {
const oldest = concludedReplyDedup.values().next().value;
if (oldest) concludedReplyDedup.delete(oldest);
}
await sendModeratorMessage(
moderatorBotToken, channelId,
"This discussion is closed and no longer active.",
api.logger,
).catch(() => undefined);
}
return;
}
}