Commit Graph

16 Commits

Author SHA1 Message Date
zhi
d44204fabf feat: wire channel mode runtime config and docs 2026-04-02 04:48:20 +00:00
4d50826f2a refactor(installer): rename to install.mjs, remove record/restore flow, add --no-reply-port and wire config port 2026-03-08 06:38:33 +00:00
zhi
211ad9246f feat: wait for human reply (waitIdentifier 👤)
- Add waitIdentifier config (default: 👤) to DirigentConfig and plugin schema
- Prompt injection: tells agents to end with 👤 when they need a human reply,
  warns to use sparingly (only when human is actively participating)
- Detection in before_message_write and message_sent hooks
- Turn manager: new waitingForHuman state
  - checkTurn() blocks all agents when waiting
  - onNewMessage() clears state on human message
  - Non-human messages ignored while waiting
  - resetTurn() also clears waiting state
- All agents routed to no-reply model during waiting state
- Update docs (FEAT.md, CHANGELOG.md, TASKLIST.md, README.md)
2026-03-07 17:32:28 +00:00
zhi
af33d747d9 feat: complete Dirigent rename + all TASKLIST items
- Task 1: Identity prompt now includes Discord userId
- Task 2: Added configurable schedulingIdentifier (default: ➡️)
- Task 3: Moderator handoff uses <@userId>+identifier instead of semantic messages
- Task 4: All prompts/comments/help text converted to English
- Task 5: Full project rename WhisperGate → Dirigent across all files

Breaking: config key changed from plugins.entries.whispergate to plugins.entries.dirigent
Breaking: channel policies file renamed to dirigent-channel-policies.json
Breaking: tool name changed from whispergate_tools to dirigent_tools
2026-03-03 10:10:27 +00:00
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
75f358001b fix(rules): handle multi-byte emoji in getLastChar via Array.from
getLastChar used t[t.length-1] which only gets the trailing surrogate
of emoji like 🔚 (U+1F51A, a surrogate pair in UTF-16). This meant
end symbol matching ALWAYS failed for emoji symbols, causing every
non-humanList message to hit rule_match_no_end_symbol -> no-reply.

Fix: use Array.from(t) to correctly split by Unicode code points.
2026-02-27 15:20:05 +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
75d659787c fix(rules): strip trailing metadata blocks before checking end symbol
getLastChar was checking the last character of the full event.prompt,
which includes Conversation/Sender metadata blocks appended by OpenClaw
after the actual message. This meant end symbols like 🔚 at the end of
the message body were invisible — the last char was always backtick or
whitespace from the metadata JSON block.

Fix: strip trailing '(untrusted metadata)' blocks before extracting
the last character. This only affects non-humanList senders (humanList
senders bypass end symbol check via human_list_sender reason).
2026-02-27 14:37:59 +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
46ea43b3fe fix(rules): inject end-marker prompt for every non-no-reply discord turn 2026-02-26 01:47:27 +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
83b9d517ec feat(plugin): extract rule engine and harden channel/session handling 2026-02-25 10:39:47 +00:00