Commit Graph

22 Commits

Author SHA1 Message Date
zhi
54ff78cffe feat: moderator bot for turn handoff messages
Add a dedicated moderator Discord bot that sends handoff messages when
the current speaker says NO_REPLY. This solves the wakeup problem.

Flow:
1. Agent A is current speaker, receives message
2. Agent A responds with NO_REPLY
3. Plugin detects NO_REPLY in message_sent hook, advances turn to Agent B
4. Plugin sends via moderator bot: '轮到(@AgentB)了,如果没有想说的请直接回复NO_REPLY'
5. This real Discord message triggers Agent B's session
6. Turn manager allows Agent B to respond

Implementation:
- moderatorBotToken config field for the moderator bot's Discord token
- userIdFromToken() extracts Discord user ID from bot token (base64)
- resolveDiscordUserId() maps accountId → Discord user ID via account tokens
- sendModeratorMessage() calls Discord REST API directly
- message_received ignores moderator bot messages (transparent to turn state)
- Moderator bot is NOT in the turn order
2026-02-28 12:10:52 +00:00
zhi
476308d0df refactor: auto-managed turn order + dormant state + identity injection
Turn system redesign:
- Turn order auto-populated from config bindings (all bot accounts)
- No manual turnOrder config needed
- Humans (humanList) excluded from turn order automatically
- Dormant state: when all agents NO_REPLY in a cycle, currentSpeaker=null
- Reactivation: any new message wakes the system
  - Human message → start from first in order
  - Bot not in order → start from first
  - Bot in order → next after sender
- Skip already-NO_REPLY'd agents when advancing

Identity injection:
- Group chat prompts now include agent identity
- Format: '你是 {name}(Discord 账号: {accountId})'

Other:
- Remove turnOrder from ChannelPolicy (no longer configurable)
- Add TURN-WAKEUP-PROBLEM.md documenting the NO_REPLY wake-up challenge
- Update message_received to call onNewMessage with proper human detection
- Update message_sent to call onSpeakerDone with NO_REPLY tracking
2026-02-28 12:10:52 +00:00
zhi
1d8881577d feat: turn-based speaking + slash commands + enhanced prompts
1. Rename tool: whispergateway_tools → whispergate_tools

2. Turn-based speaking mechanism:
   - New turn-manager.ts maintains per-channel turn state
   - ChannelPolicy新增turnOrder字段配置发言顺序
   - before_model_resolve hook检查当前agent是否为发言人
   - 非当前发言人直接切换到no-reply模型
   - message_sent hook检测结束符或NO_REPLY时推进turn
   - message_received检测到human消息时重置turn

3. 注入提示词增强:
   - buildEndMarkerInstruction增加isGroupChat参数
   - 群聊时追加规则:与自己无关时主动回复NO_REPLY

4. Slash command支持:
   - /whispergate status - 查看频道策略
   - /whispergate turn-status - 查看轮流状态
   - /whispergate turn-advance - 手动推进轮流
   - /whispergate turn-reset - 重置轮流顺序
2026-02-28 12:10:52 +00:00
zhi
3749de981f fix: use configured endSymbols in injected prompt and exempt gateway keywords
- buildEndMarkerInstruction() replaces hardcoded END_MARKER_INSTRUCTION,
  dynamically using the resolved policy's endSymbols
- Instruction now explicitly exempts gateway keywords (NO_REPLY, HEARTBEAT_OK)
  from requiring end symbols
- Export resolvePolicy from rules.ts for reuse in before_prompt_build hook
2026-02-27 15:16:06 +00:00
zhi
f23d9049a7 fix: bypass DM sessions without metadata and make tool globally visible
1. DM bypass: when neither senderId nor channelId can be extracted from
   the prompt (DM sessions lack untrusted conversation info), skip the
   no-reply gate and allow the message through with end-marker injection.

2. Tool visibility: change whispergateway_tools registration from
   optional=true to optional=false so all agents can see the tool
   without needing explicit tools.allow entries.
2026-02-27 14:14:39 +00:00
a4836097e4 fix: add default values for optional config fields
- Add default values for enableDiscordControlTool, enableWhispergatePolicyTool,
  discordControlApiBaseUrl, enableDebugLogs, debugLogChannelIds
- Merge defaults in both baseConfig and getLivePluginConfig
- Fixes issue where whispergateway_tools tool was not exposed due to missing
  config fields in openclaw.json
2026-02-26 22:16:23 +00:00
4622173787 fix: restore model after no-reply executes (needsRestore flag) 2026-02-26 13:39:43 +00:00
211a94233f chore(debug): log parsed sender/channel fields in hook decision recompute 2026-02-26 11:47:23 +00:00
zhi
f33dc13af4 fix: extract senderId from event.prompt instead of ctx in hooks
Root cause: PluginHookAgentContext in before_model_resolve only has
agentId, sessionKey, sessionId, workspaceDir, messageProvider.
senderId, channelId, input are NOT available in this hook phase.

The plugin was reading ctx.senderId (undefined) -> inHumanList=false
for ALL Discord sessions -> shouldUseNoReply=true -> all silenced.

Fix: use event.prompt which contains the full user message including
the 'Conversation info (untrusted metadata)' JSON block, and extract
sender_id from there. Same fix applied to before_prompt_build.
2026-02-26 08:56:24 +00:00
8eade446b3 fix(hooks): move first-pass decision to before_model_resolve and keep message_received for debug only 2026-02-26 02:33:15 +00:00
51149dd6a0 feat(debug): add whispergate hook diagnostics with channel-scoped debug logs 2026-02-26 01:58:01 +00:00
46ea43b3fe fix(rules): inject end-marker prompt for every non-no-reply discord turn 2026-02-26 01:47:27 +00:00
ca96779159 refactor(tooling): merge discord_control and whispergate_policy into whispergateway_tools 2026-02-26 01:31:31 +00:00
e5999743fe feat(policy-runtime): in-memory policy state with whispergate_policy tool and atomic persist 2026-02-26 00:35:17 +00:00
682d9a336e feat(policy-file): move channel overrides to standalone channelPoliciesFile with hot reload 2026-02-26 00:28:34 +00:00
d6f908b813 feat(policy): add per-channel channelPolicies with hot-reload list mode/lists 2026-02-26 00:23:47 +00:00
6d463a4572 feat(config): add hot-reload config + listMode (human-list/agent-list) 2026-02-26 00:18:05 +00:00
0f526346f4 feat(tool): register optional discord_control tool in whispergate plugin and align defaults 2026-02-25 23:37:15 +00:00
32405fa3e2 feat(plugin): inject 🔚 ending instruction for bypass/end-symbol discord turns 2026-02-25 11:04:01 +00:00
f09972c083 feat(plugin): add sender normalization, TTL, and one-shot decisions 2026-02-25 10:43:11 +00:00
83b9d517ec feat(plugin): extract rule engine and harden channel/session handling 2026-02-25 10:39:47 +00:00
7728892d15 feat(plugin): add WhisperGate rule engine and model override hook 2026-02-25 10:36:59 +00:00