Commit Graph

176 Commits

Author SHA1 Message Date
0c06aeb36c refactor(plugin): extract common utils and moderator discord helpers 2026-03-08 05:31:08 +00:00
f9ac401877 refactor(plugin): extract turn bootstrap/cache helpers into core module 2026-03-08 05:25:53 +00:00
05b902c0b2 refactor(plugin): extract identity and mention helpers into core modules 2026-03-08 05:19:40 +00:00
e258e99ed2 refactor(plugin): extract live config and policy store modules 2026-03-07 22:38:11 +00:00
d021b0c06c refactor(plugin): extract discord/policy tool registration module 2026-03-07 22:33:28 +00:00
3a8b85eb7b refactor(plugin): extract dirigent slash command and fix recursive prepare copy 2026-03-07 22:27:03 +00:00
b63c1dfe94 refactor(plugin): extract message_received hook and slim index imports 2026-03-07 22:24:48 +00:00
5c4340d5a9 refactor(plugin): extract before_prompt_build and before_message_write hooks 2026-03-07 22:21:16 +00:00
c15ea0d471 refactor(plugin): extract before_model_resolve and message_sent hooks 2026-03-07 22:18:09 +00:00
96a1f18d1b refactor(plugin): extract channel/decision parsing modules and unify channelId resolution 2026-03-07 22:12:27 +00:00
b7381395fe Merge pull request 'fix: align no-reply-api install path with plugin runtime expectation' (#15) from fix/no-reply-api-install-path into feat/split-tools-and-mention-override
Reviewed-on: #15
2026-03-07 19:24:26 +00:00
e8de773ee4 fix(installer): install no-reply API at expected plugins/no-reply-api path 2026-03-07 19:22:11 +00:00
zhi
fc2cdf0eee refactor: simplify openclaw dir resolution priority
Priority: --openclaw-profile-path arg >  env > ~/.openclaw
Remove openclaw CLI command attempts, simplify to 3 clear sources
2026-03-07 18:39:55 +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
e4454bfc1a refactor: remove turn tools, rename discord tools, rewrite installer
- Remove turn management tools (turn-status/advance/reset) — internal only,
  accessible via /dirigent slash commands
- Rename discord tools: dirigent_discord_channel_create,
  dirigent_discord_channel_update, dirigent_discord_member_list
- Rewrite install script:
  - Dynamic OpenClaw dir resolution (OPENCLAW_DIR env → openclaw CLI → ~/.openclaw)
  - Plugin installed to $(openclaw_dir)/plugins/dirigent
  - New --update mode: git pull from latest branch + reinstall
  - Cleaner uninstall: removes installed plugin files
- Update docs (FEAT.md, README.md, CHANGELOG.md, TASKLIST.md)
2026-03-07 17:24:36 +00:00
zhi
7b93db3ed9 docs: replace NEW_FEAT.md with comprehensive FEAT.md, update README
- Delete NEW_FEAT.md
- Create FEAT.md with complete feature documentation across all versions
- Update README.md to reflect individual tool names and add @mention override
2026-03-07 17:04:42 +00:00
zhi
0729e83b38 feat: split dirigent_tools into individual tools + human @mention override
Feature 1: Split dirigent_tools
- Replace monolithic dirigent_tools (9 actions) with 9 individual tools
- Discord: dirigent_channel_create, dirigent_channel_update, dirigent_member_list
- Policy: dirigent_policy_get, dirigent_policy_set, dirigent_policy_delete
- Turn: dirigent_turn_status, dirigent_turn_advance, dirigent_turn_reset
- Extract shared executeDiscordAction() helper

Feature 2: Human @mention override
- When humanList user @mentions agents, temporarily override turn order
- Only mentioned agents cycle, ordered by their turn order position
- Original order restores when cycle returns to first agent or all NO_REPLY
- New: setMentionOverride(), hasMentionOverride(), extractMentionedUserIds()
- New: buildUserIdToAccountIdMap() for reverse userId→accountId resolution

Bump version to 0.3.0
2026-03-07 16:55:01 +00:00
nav
bbd18cd90c docs: add new feature notes 2026-03-07 16:46:33 +00:00
nav
d55eac8dc1 docs: add human mention override requirement 2026-03-05 11:34:07 +00:00
ac65d7e036 Merge pull request 'fix: resolve pluginDir correctly and ensure no-reply-api is copied during install' (#13) from no-reply-api-fix into main
Reviewed-on: #13
2026-03-03 20:25:21 +00:00
zhi
5c9c979f26 fix: resolve pluginDir correctly and ensure no-reply-api is copied during install
- Use import.meta.url instead of api.resolvePath('.') to get script directory
- Add debug logging for no-reply-api and moderator bot startup
- Copy no-reply-api to dist during installation
2026-03-03 20:23:29 +00:00
3d91d7ed95 Merge pull request 'dev/fix-issues' (#12) from dev/fix-issues into main
Reviewed-on: #12
2026-03-03 18:41:27 +00:00
zhi
92799176bf fix(install): fix uninstall order to satisfy config validation
- Remove from plugins.allow BEFORE deleting plugins.entries.dirigent
- OpenClaw validates that allow[] entries must exist in entries{}
- New order: allow → entry → paths → provider
2026-03-03 18:28:44 +00:00
zhi
cd0ce6a910 fix(install): use unsetPath for plugin entry removal
- Use openclaw config unset instead of get-modify-set
- Avoids triggering full plugins config validation
- Handles both added and replaced entries uniformly
2026-03-03 18:23:01 +00:00
zhi
a177150554 fix(install): uninstall always deletes plugin entry
- For uninstall, always delete plugins.entries.dirigent
- Don't try to restore old config (which may fail validation due to missing required fields)
- Provider restoration still works (replaced providers are restored)
2026-03-03 18:20:48 +00:00
zhi
b79cc1eb84 fix: use api.resolvePath for plugin directory
- Replace import.meta.url with api.resolvePath('.') for reliable path resolution
- Fixes no-reply API not starting due to incorrect pluginDir calculation
2026-03-03 18:16:47 +00:00
zhi
ed5ffd6c53 fix(install): clone function handle undefined
- clone(undefined) now returns undefined instead of throwing JSON.parse error
- This fixes install when plugins.entries.dirigent doesn't exist yet
2026-03-03 18:06:14 +00:00
zhi
be8fe835d0 fix(install): handle 'undefined' string from openclaw config get
- getJson now treats 'undefined' string as missing value
- Add try-catch to JSON.parse for robustness
2026-03-03 17:57:34 +00:00
zhi
91cd402627 fix(install): remove duplicate function definition
- Remove empty duplicate runOpenclaw function that caused syntax error
2026-03-03 17:02:08 +00:00
84b0363d59 Merge pull request 'dev/dirigent-tasks' (#11) from dev/dirigent-tasks into main
Reviewed-on: #11
2026-03-03 16:54:44 +00:00
zhi
83c03b6934 feat(install): idempotent install/uninstall
- Repeat install = reinstall: auto-detect existing install, uninstall first, then install
- Repeat uninstall = no-op: if no install record found, exit 0 with message
- Uses spawnSync to re-exec uninstall phase during reinstall
2026-03-03 16:39:40 +00:00
zhi
6423dbcdfa fix(install): handle plugins.allow in install/uninstall
- Install: add 'dirigent' to plugins.allow if not present, record in delta
- Uninstall: remove 'dirigent' from plugins.allow if it was added by us
- Delta tracking preserves other allowlist entries
2026-03-03 16:36:33 +00:00
zhi
d378e27be9 fix(install): delta-tracking uninstall + remove sh script
- Rewrite install/uninstall to use delta-tracking (added/replaced/removed)
- Install records only what the plugin changed:
  * added: plugin新增的配置(卸载时删除)
  * replaced: plugin覆盖的旧配置(卸载时恢复)
- Uninstall only affects plugin-managed keys, preserving user changes elsewhere
- Remove install-dirigent-openclaw.sh to avoid confusion
2026-03-03 16:34:50 +00:00
zhi
2ea4f59a1e build: support both registry publish and git clone install
- Add root package.json with files[] for registry publishing
- Add prepare script to sync dist/ from plugin/
- Add postinstall to auto-run install script
- Modify install script: auto-create dist/ if missing (git clone case)
- Plugin works in both scenarios:
  * npm install @hangman-lab/dirigent -> uses bundled dist/
  * git clone + node scripts/install-dirigent-openclaw.mjs -> auto-creates dist/
2026-03-03 16:24:05 +00:00
zhi
8e26744162 feat: lifecycle management - no-reply API + moderator bot follow gateway start/stop
- Added gateway_start hook: spawns no-reply API as child process, then starts moderator bot
- Added gateway_stop hook: kills no-reply API process, stops moderator bot
- No-reply API server.mjs is located relative to plugin dir via import.meta.url
- Moderator presence moved from register() to gateway_start for proper lifecycle
2026-03-03 16:01:34 +00:00
zhi
cb58e3d951 docs: add schedulingIdentifier to CONFIG.example.json 2026-03-03 14:23:52 +00:00
zhi
fd1bf449a4 refine: cleanup remaining whispergate refs, improve docs and TASKLIST formatting
- Fix enableWhispergatePolicyTool → enableDirigentPolicyTool in config schema and example
- Fix whisper-gateway → dirigentway in install script
- Add v0.2.0 changelog entry
- Improve README with scheduling identifier docs and English text
- Clean up plugin README with moderator handoff format docs
- Reformat TASKLIST with cleaner done markers
2026-03-03 10:13:39 +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
2afb982c04 docs: add tasklist for upcoming fixes 2026-03-03 09:59:19 +00:00
zhi
a18168749b docs: update README for turn-based features 2026-03-03 09:59:12 +00:00
329f6ed490 Merge pull request 'fix: advance turn in before_message_write to prevent race condition' (#10) from fix/turn-advance-race-condition into main
Reviewed-on: nav/WhisperGate#10
2026-03-03 03:47:35 +00:00
zhi
cf9be60145 fix: advance turn in before_message_write to prevent race condition
When a speaker finishes with an end symbol, the turn was only advanced
in the message_sent hook. But by that time, the message had already been
broadcast to other agents, whose before_model_resolve ran with the old
turn state, causing them to be blocked by the turn gate (forced no-reply).

Fix:
- Move turn advance for both NO_REPLY and end-symbol cases to
  before_message_write, which fires before the message is broadcast.
- Guard 1: Only the current speaker can advance the turn (accountId check).
- Guard 2: Only process assistant messages (role check). before_message_write
  fires for incoming user messages too, which contain end symbols from other
  agents and would cause cascading turn advances.
- Use sessionTurnHandled set to prevent double-advancing in message_sent.
2026-03-02 11:34:40 +00:00
zhi
6d17e6a911 fix: advance turn in before_message_write to prevent race condition
When a speaker finishes with an end symbol, the turn was only advanced
in the message_sent hook. But by that time, the message had already been
broadcast to other agents, whose before_model_resolve ran with the old
turn state, causing them to be blocked by the turn gate (forced no-reply).

Fix: Move turn advance for both NO_REPLY and end-symbol cases to
before_message_write, which fires before the message is broadcast.
Use sessionTurnHandled set to prevent double-advancing in message_sent.
2026-03-02 11:04:41 +00:00
aeecb534b7 Merge pull request 'fix: channelId extraction, sender identification, and per-channel turn order' (#9) from fix/turn-gate-and-handoff into main
Reviewed-on: orion/WhisperGate#9
2026-03-01 11:12:17 +00:00
zhi
d90083317b fix: channelId extraction, sender identification, and per-channel turn order
- Fix channelId extraction: ctx.channelId is platform name ('discord'), not
  the Discord channel snowflake. Now extracts from conversation_label field
  ('channel id:123456') and sessionKey fallback (':channel:123456').

- Fix extractDiscordChannelId: support 'discord:channel:xxx' format in
  addition to 'channel:xxx' for conversationId/event.to fields.

- Fix sender identification in message_received: event.from returns channel
  target, not sender ID. Now uses event.metadata.senderId for humanList
  matching so human messages correctly reset turn order.

- Fix per-channel turn order: was using all server-wide bot accounts from
  bindings, causing deadlock when turn landed on bots not in the channel.
  Now dynamically tracks which bot accounts are seen per channel via
  message_received and only includes those in turn order.

- Always save sessionChannelId/sessionAccountId mappings in before_model_resolve
  regardless of turn check result, so downstream hooks can use them.

- Add comprehensive debug logging to message_sent hook.
2026-03-01 11:08:41 +00:00
zhi
a4bc9990db fix: add sessionAccountId mapping and use in before_message_write
- Add sessionAccountId Map to track sessionKey -> accountId
- Save accountId in before_model_resolve when resolving accountId
- Use sessionChannelId/sessionAccountId fallback in before_message_write
2026-03-01 09:16:55 +00:00
zhi
435a7712b8 fix: add sessionChannelId mapping for message_sent
- Add sessionChannelId Map to track sessionKey -> channelId
- Save channelId in before_model_resolve when we have derived.channelId
- Fix message_sent to use sessionChannelId fallback when ctx.channelId is undefined
- Add debug logging to message_sent
2026-03-01 09:13:03 +00:00
zhi
9e754d32cf fix: make before_message_write synchronous
- Remove async/await from before_message_write hook
- Use fire-and-forget for sendModeratorMessage (void ... .catch())
- OpenClaw's before_message_write is synchronous, not async
2026-03-01 04:59:45 +00:00
zhi
692111eeda fix: implement turn gate and handoff improvements
1. Fix channelId priority: use ctx.channelId > conv.chat_id > conv.channel_id
2. Add sessionAllowed state: track if session was allowed (true) or forced no-reply (false)
3. Add sessionInjected Set: implement one-time prependContext injection
4. Add before_message_write hook: detect NO_REPLY and handle turn advancement
   - forced no-reply: don't advance turn
   - allowed + NO_REPLY: advance turn + handoff
   - dormant state: don't trigger handoff
5. message_sent: continues to handle real messages with end symbols
2026-02-28 21:44:53 +00:00
zhi
80439b0912 Revert "Merge pull request 'fix: use systemPrompt instead of prependContext for end marker instruction' (#5) from fix/moderator-and-system-prompt into feat/turn-based-speaking"
This reverts commit 6a81f75fd0, reversing
changes made to 86fdc63802.
2026-02-28 19:34:37 +00:00