fix(turn): preserve mention override during membership refresh #17

Merged
hzhang merged 2 commits from debug/mention-override-reset into feat/split-tools-and-mention-override 2026-03-08 08:02:13 +00:00
2 changed files with 42 additions and 2 deletions
Showing only changes of commit a995b7d6bf - Show all commits

View File

@@ -104,14 +104,24 @@ export async function ensureTurnOrder(api: OpenClawPluginApi, channelId: string)
loadCache(api); loadCache(api);
let botAccounts = getChannelBotAccountIds(api, channelId); let botAccounts = getChannelBotAccountIds(api, channelId);
api.logger.info(
`dirigent: turn-debug ensureTurnOrder enter channel=${channelId} cached=${JSON.stringify(botAccounts)} bootstrapTried=${channelBootstrapTried.has(channelId)}`,
);
if (botAccounts.length === 0 && !channelBootstrapTried.has(channelId)) { if (botAccounts.length === 0 && !channelBootstrapTried.has(channelId)) {
channelBootstrapTried.add(channelId); channelBootstrapTried.add(channelId);
const discovered = await fetchVisibleChannelBotAccountIds(api, channelId).catch(() => [] as string[]); const discovered = await fetchVisibleChannelBotAccountIds(api, channelId).catch(() => [] as string[]);
api.logger.info(
`dirigent: turn-debug ensureTurnOrder bootstrap-discovered channel=${channelId} discovered=${JSON.stringify(discovered)}`,
);
for (const aid of discovered) recordChannelAccount(api, channelId, aid); for (const aid of discovered) recordChannelAccount(api, channelId, aid);
botAccounts = getChannelBotAccountIds(api, channelId); botAccounts = getChannelBotAccountIds(api, channelId);
} }
if (botAccounts.length > 0) { if (botAccounts.length > 0) {
api.logger.info(
`dirigent: turn-debug ensureTurnOrder initTurnOrder channel=${channelId} members=${JSON.stringify(botAccounts)}`,
);
initTurnOrder(channelId, botAccounts); initTurnOrder(channelId, botAccounts);
} }
} }

View File

@@ -60,15 +60,30 @@ export function initTurnOrder(channelId: string, botAccountIds: string[]): void
const newSet = new Set(botAccountIds); const newSet = new Set(botAccountIds);
const same = oldSet.size === newSet.size && [...oldSet].every(id => newSet.has(id)); const same = oldSet.size === newSet.size && [...oldSet].every(id => newSet.has(id));
if (same) return; // no change if (same) return; // no change
console.log(
`[dirigent][turn-debug] initTurnOrder membership-changed channel=${channelId} ` +
`oldOrder=${JSON.stringify(existing.turnOrder)} oldCurrent=${existing.currentSpeaker} ` +
`oldOverride=${JSON.stringify(existing.savedTurnOrder || null)} newMembers=${JSON.stringify(botAccountIds)}`,
);
} else {
console.log(
`[dirigent][turn-debug] initTurnOrder first-init channel=${channelId} members=${JSON.stringify(botAccountIds)}`,
);
} }
const nextOrder = shuffleArray(botAccountIds);
channelTurns.set(channelId, { channelTurns.set(channelId, {
turnOrder: shuffleArray(botAccountIds), turnOrder: nextOrder,
currentSpeaker: null, // start dormant currentSpeaker: null, // start dormant
noRepliedThisCycle: new Set(), noRepliedThisCycle: new Set(),
lastChangedAt: Date.now(), lastChangedAt: Date.now(),
waitingForHuman: false, waitingForHuman: false,
}); });
console.log(
`[dirigent][turn-debug] initTurnOrder applied channel=${channelId} newOrder=${JSON.stringify(nextOrder)} newCurrent=null`,
);
} }
/** /**
@@ -190,12 +205,21 @@ export function setMentionOverride(channelId: string, mentionedAccountIds: strin
const state = channelTurns.get(channelId); const state = channelTurns.get(channelId);
if (!state || mentionedAccountIds.length === 0) return false; if (!state || mentionedAccountIds.length === 0) return false;
console.log(
`[dirigent][turn-debug] setMentionOverride start channel=${channelId} ` +
`mentioned=${JSON.stringify(mentionedAccountIds)} current=${state.currentSpeaker} ` +
`order=${JSON.stringify(state.turnOrder)} saved=${JSON.stringify(state.savedTurnOrder || null)}`,
);
// Restore any existing override first // Restore any existing override first
restoreOriginalOrder(state); restoreOriginalOrder(state);
// Filter to agents actually in the turn order // Filter to agents actually in the turn order
const validIds = mentionedAccountIds.filter(id => state.turnOrder.includes(id)); const validIds = mentionedAccountIds.filter(id => state.turnOrder.includes(id));
if (validIds.length === 0) return false; if (validIds.length === 0) {
console.log(`[dirigent][turn-debug] setMentionOverride ignored channel=${channelId} reason=no-valid-mentioned`);
return false;
}
// Order by their position in the current turn order // Order by their position in the current turn order
validIds.sort((a, b) => state.turnOrder.indexOf(a) - state.turnOrder.indexOf(b)); validIds.sort((a, b) => state.turnOrder.indexOf(a) - state.turnOrder.indexOf(b));
@@ -208,6 +232,12 @@ export function setMentionOverride(channelId: string, mentionedAccountIds: strin
state.noRepliedThisCycle = new Set(); state.noRepliedThisCycle = new Set();
state.lastChangedAt = Date.now(); state.lastChangedAt = Date.now();
console.log(
`[dirigent][turn-debug] setMentionOverride applied channel=${channelId} ` +
`overrideOrder=${JSON.stringify(state.turnOrder)} current=${state.currentSpeaker} ` +
`savedOriginal=${JSON.stringify(state.savedTurnOrder || null)}`,
);
return true; return true;
} }