feat: implement multi-message mode and shuffle mode features

- Add multi-message mode with start/end/prompt markers
- Implement turn order shuffling with /turn-shuffling command
- Add channel mode state management
- Update hooks to handle multi-message mode behavior
- Update plugin config with new markers
- Update TASKLIST.md with completed tasks
This commit is contained in:
zhi
2026-04-02 04:36:36 +00:00
parent 684f8f9ee7
commit bfbe40b3c6
8 changed files with 251 additions and 98 deletions

View File

@@ -2,6 +2,7 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import { onNewMessage, setMentionOverride, getTurnDebugInfo } from "../turn-manager.js";
import { extractDiscordChannelId } from "../channel-resolver.js";
import type { DirigentConfig } from "../rules.js";
import { enterMultiMessageMode, exitMultiMessageMode, isMultiMessageMode } from "../core/channel-modes.js";
type DebugConfig = {
enableDebugLogs?: boolean;
@@ -79,21 +80,38 @@ export function registerMessageReceivedHook(deps: MessageReceivedDeps): void {
if (isHuman) {
const messageContent = ((e as Record<string, unknown>).content as string) || ((e as Record<string, unknown>).text as string) || "";
const mentionedUserIds = extractMentionedUserIds(messageContent);
// Handle multi-message mode markers
const startMarker = livePre.multiMessageStartMarker || "↗️";
const endMarker = livePre.multiMessageEndMarker || "↙️";
if (messageContent.includes(startMarker)) {
enterMultiMessageMode(preChannelId);
api.logger.info(`dirigent: entered multi-message mode channel=${preChannelId}`);
} else if (messageContent.includes(endMarker)) {
exitMultiMessageMode(preChannelId);
api.logger.info(`dirigent: exited multi-message mode channel=${preChannelId}`);
// After exiting multi-message mode, activate the turn system
onNewMessage(preChannelId, senderAccountId, isHuman);
} else {
const mentionedUserIds = extractMentionedUserIds(messageContent);
if (mentionedUserIds.length > 0) {
const userIdMap = buildUserIdToAccountIdMap(api);
const mentionedAccountIds = mentionedUserIds.map((uid) => userIdMap.get(uid)).filter((aid): aid is string => !!aid);
if (mentionedUserIds.length > 0) {
const userIdMap = buildUserIdToAccountIdMap(api);
const mentionedAccountIds = mentionedUserIds.map((uid) => userIdMap.get(uid)).filter((aid): aid is string => !!aid);
if (mentionedAccountIds.length > 0) {
await ensureTurnOrder(api, preChannelId);
const overrideSet = setMentionOverride(preChannelId, mentionedAccountIds);
if (overrideSet) {
api.logger.info(
`dirigent: mention override set channel=${preChannelId} mentionedAgents=${JSON.stringify(mentionedAccountIds)}`,
);
if (shouldDebugLog(livePre, preChannelId)) {
api.logger.info(`dirigent: turn state after override: ${JSON.stringify(getTurnDebugInfo(preChannelId))}`);
if (mentionedAccountIds.length > 0) {
await ensureTurnOrder(api, preChannelId);
const overrideSet = setMentionOverride(preChannelId, mentionedAccountIds);
if (overrideSet) {
api.logger.info(
`dirigent: mention override set channel=${preChannelId} mentionedAgents=${JSON.stringify(mentionedAccountIds)}`,
);
if (shouldDebugLog(livePre, preChannelId)) {
api.logger.info(`dirigent: turn state after override: ${JSON.stringify(getTurnDebugInfo(preChannelId))}`);
}
} else {
onNewMessage(preChannelId, senderAccountId, isHuman);
}
} else {
onNewMessage(preChannelId, senderAccountId, isHuman);
@@ -101,8 +119,6 @@ export function registerMessageReceivedHook(deps: MessageReceivedDeps): void {
} else {
onNewMessage(preChannelId, senderAccountId, isHuman);
}
} else {
onNewMessage(preChannelId, senderAccountId, isHuman);
}
} else {
onNewMessage(preChannelId, senderAccountId, isHuman);