diff --git a/dist/whispergate/index.ts b/dist/whispergate/index.ts index a4b507d..7fc3a6e 100644 --- a/dist/whispergate/index.ts +++ b/dist/whispergate/index.ts @@ -960,6 +960,17 @@ export default { if (!key || !channelId || !accountId) return; + // Only the current speaker should advance the turn. + // Other agents also trigger before_message_write (for incoming messages or forced no-reply), + // but they must not affect turn state. + const currentTurn = getTurnDebugInfo(channelId); + if (currentTurn.currentSpeaker !== accountId) { + api.logger.info( + `whispergate: before_message_write skipping non-current-speaker session=${key} accountId=${accountId} currentSpeaker=${currentTurn.currentSpeaker}`, + ); + return; + } + const live = getLivePluginConfig(api, baseConfig as WhisperGateConfig) as WhisperGateConfig & DebugConfig; ensurePolicyStateLoaded(api, live); const policy = resolvePolicy(live, channelId, policyState.channelPolicies); diff --git a/plugin/index.ts b/plugin/index.ts index a4b507d..7fc3a6e 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -960,6 +960,17 @@ export default { if (!key || !channelId || !accountId) return; + // Only the current speaker should advance the turn. + // Other agents also trigger before_message_write (for incoming messages or forced no-reply), + // but they must not affect turn state. + const currentTurn = getTurnDebugInfo(channelId); + if (currentTurn.currentSpeaker !== accountId) { + api.logger.info( + `whispergate: before_message_write skipping non-current-speaker session=${key} accountId=${accountId} currentSpeaker=${currentTurn.currentSpeaker}`, + ); + return; + } + const live = getLivePluginConfig(api, baseConfig as WhisperGateConfig) as WhisperGateConfig & DebugConfig; ensurePolicyStateLoaded(api, live); const policy = resolvePolicy(live, channelId, policyState.channelPolicies);