diff --git a/CHANGELOG.md b/CHANGELOG.md index 799fefc..c828e07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,21 @@ # Changelog +## 0.2.0 + +- **Project renamed from WhisperGate to Dirigent** + - All plugin ids, tool names, config keys, file paths, docs updated + - Legacy `whispergate` config key still supported as fallback +- **Identity prompt enhancements**: Discord userId now included in agent identity injection +- **Scheduling identifier**: Added configurable `schedulingIdentifier` (default: `➡️`) + - Moderator handoff now sends `<@USER_ID>➡️` instead of semantic messages + - Agent prompt explains the identifier is meaningless — check chat history and decide +- **All prompts in English**: End-marker instructions, group chat rules, slash command help text + ## 0.1.0-mvp - Added no-reply API service (`/v1/chat/completions`, `/v1/responses`, `/v1/models`) - Added optional bearer auth (`AUTH_TOKEN`) -- Added Dirigent plugin with deterministic rule gate +- Added plugin with deterministic rule gate - Added discord-specific 🔚 prompt injection for bypass/end-symbol paths - Added containerization (`Dockerfile`, `docker-compose.yml`) - Added helper scripts for smoke/dev lifecycle and rule validation diff --git a/README.md b/README.md index 4d9e0a9..0a614f6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Rule-based no-reply gate + turn manager for OpenClaw (Discord). +> Formerly known as WhisperGate. Renamed to Dirigent in v0.2.0. + ## What it does Dirigent adds deterministic logic **before model selection** and **turn-based speaking** for multi-agent Discord channels: @@ -13,8 +15,13 @@ Dirigent adds deterministic logic **before model selection** and **turn-based sp 4. Otherwise → route to no-reply model/provider - **End-symbol enforcement** - - Injects instruction like: `你的这次发言必须以🔚作为结尾…` - - In group chats, also injects: “无关/不需要回应就 NO_REPLY” + - Injects instruction: `Your response MUST end with 🔚…` + - In group chats, also injects: "If not relevant, reply NO_REPLY" + +- **Scheduling identifier (moderator handoff)** + - Configurable identifier (default: `➡️`) used by the moderator bot + - Handoff format: `<@TARGET_USER_ID>➡️` (non-semantic, just a scheduling signal) + - Agent receives instruction explaining the identifier is meaningless — check chat history and decide - **Turn-based speaking (multi-bot)** - Only the current speaker is allowed to respond @@ -22,8 +29,8 @@ Dirigent adds deterministic logic **before model selection** and **turn-based sp - Turn advances on **end-symbol** or **NO_REPLY** - If all bots NO_REPLY, channel becomes **dormant** until a new human message -- **Moderator handoff (optional)** - - When the current speaker NO_REPLYs, a moderator bot can post a handoff message to wake the next speaker +- **Agent identity injection** + - Injects agent name, Discord accountId, and Discord userId into group chat prompts - **Per-channel policy runtime** - Policies stored in a standalone JSON file @@ -39,7 +46,7 @@ Dirigent adds deterministic logic **before model selection** and **turn-based sp - `plugin/` — OpenClaw plugin (gate + turn manager + moderator presence) - `no-reply-api/` — OpenAI-compatible API that always returns `NO_REPLY` -- `discord-control-api/` — Discord 管理扩展 API(私密频道 + 成员列表) +- `discord-control-api/` — Discord admin extension API (private channels + member list) - `docs/` — rollout, integration, run-mode notes, turn-wakeup analysis - `scripts/` — smoke/dev/helper checks - `Makefile` — common dev commands (`make check`, `make check-rules`, `make test-api`, `make smoke-discord-control`, `make up`) @@ -61,7 +68,7 @@ node scripts/render-openclaw-config.mjs ``` See `docs/RUN_MODES.md` for Docker mode. -Discord 扩展能力见:`docs/DISCORD_CONTROL.md`。 +Discord extension capabilities: `docs/DISCORD_CONTROL.md`. --- @@ -92,6 +99,7 @@ Common options (see `docs/INTEGRATION.md`): - `listMode`: `human-list` or `agent-list` - `humanList`, `agentList` - `endSymbols` +- `schedulingIdentifier` (default `➡️`) - `channelPoliciesFile` (per-channel overrides) - `moderatorBotToken` (handoff messages) - `enableDebugLogs`, `debugLogChannelIds` diff --git a/TASKLIST.md b/TASKLIST.md index 9d8b7a7..ed5e557 100644 --- a/TASKLIST.md +++ b/TASKLIST.md @@ -2,48 +2,42 @@ > Note: Project rename from WhisperGate → Dirigent implies updating all code/docs references (plugin/tool names, strings, files, configs). -## 1) Identity Prompt Enhancements -- ✅ Added Discord userId to identity injection via `resolveDiscordUserId()`. -- Identity format now: `You are (Discord account: , Discord userId: ).` +## 1) Identity Prompt Enhancements ✅ +- Current prompt only includes agent-id + discord name. +- **Add Discord userId** to identity injection. +- **Done**: `buildAgentIdentity()` now resolves and includes Discord userId via `resolveDiscordUserId()`. -## 2) Scheduling Identifier (Default: ➡️) -- ✅ Added `schedulingIdentifier` config field (default: `➡️`) to `DirigentConfig` and `openclaw.plugin.json`. -- ✅ Updated `buildEndMarkerInstruction()` to explain scheduling identifier semantics to agents: - - The identifier itself is meaningless. - - When receiving `<@USER_ID>` + identifier, check chat history and decide whether to reply. - - If nothing to say, reply `NO_REPLY`. +## 2) Scheduling Identifier (Default: ➡️) ✅ +- Add a **configurable scheduling identifier** (default: `➡️`). +- Update agent prompt to explain: + - The scheduling identifier itself is meaningless. + - When receiving `<@USER_ID>` + scheduling identifier, the agent should check chat history and decide whether to reply. + - If no reply needed, return `NO_REPLY`. +- **Done**: Added `schedulingIdentifier` config field; `buildSchedulingIdentifierInstruction()` injected for group chats. -## 3) Moderator Handoff Message Format -- ✅ Moderator no longer sends semantic messages. -- Handoff format is now: `<@TARGET_USER_ID>` + scheduling identifier (e.g., `<@123>➡️`). +## 3) Moderator Handoff Message Format ✅ +- Moderator should **no longer send semantic messages** to activate agents. +- Replace with: `<@TARGET_USER_ID>` + scheduling identifier (e.g., `<@123>➡️`). +- **Done**: Both `before_message_write` and `message_sent` handoff messages now use `<@userId>` + scheduling identifier format. -## 4) Prompt Language -- ✅ All prompts converted to English: - - `buildEndMarkerInstruction()` — English with scheduling identifier explanation - - `buildAgentIdentity()` — English format - - Slash command help text — English - - Error messages — English - - Code comments — English +## 4) Prompt Language ✅ +- **All prompts must be in English** (including end-marker instructions and group-chat rules). +- **Done**: `buildEndMarkerInstruction()` and `buildSchedulingIdentifierInstruction()` output English. Slash command help text in English. -## 5) Full Project Rename -- ✅ Plugin id: `whispergate` → `dirigent` -- ✅ Plugin name: `WhisperGate` → `Dirigent` -- ✅ Tool name: `whispergate_tools` → `dirigent_tools` -- ✅ Config type: `WhisperGateConfig` → `DirigentConfig` -- ✅ Config lookup key: `entries.whispergate` → `entries.dirigent` -- ✅ Channel policies file: `whispergate-channel-policies.json` → `dirigent-channel-policies.json` -- ✅ Log prefixes: `whispergate:` → `dirigent:` -- ✅ Slash command: `/whispergate` → `/dirigent` -- ✅ Gateway browser/device identifier: `whispergate` → `dirigent` -- ✅ Scripts renamed: `install-whispergate-*` → `install-dirigent-*` -- ✅ All docs, configs, examples updated -- ✅ dist/ folder: `dist/whispergate/` → `dist/dirigent/` -- ✅ package.json names updated -- ✅ README.md, CHANGELOG.md updated -- ✅ Version bumped to 0.2.0 +## 5) Full Project Rename ✅ +- Project name changed to **Dirigent**. +- Update **all strings** across repo: + - plugin name/id → `dirigent` + - tool name → `dirigent_tools` + - slash command → `/dirigent` + - docs, config, scripts, examples + - any text mentions + - dist output dir → `dist/dirigent` + - docker service → `dirigent-no-reply-api` + - config key fallback: still reads legacy `whispergate` entry if `dirigent` not found +- **Done**: All files updated. --- ## Open Items / Notes - User requested the previous README commit should have been pushed to `main` directly (was pushed to a branch). Address separately if needed. -- **Migration note**: Existing deployments need to update their `openclaw.json` config from `plugins.entries.whispergate` → `plugins.entries.dirigent` and rename the channel policies file. diff --git a/docs/CONFIG.example.json b/docs/CONFIG.example.json index 07af9eb..f719307 100644 --- a/docs/CONFIG.example.json +++ b/docs/CONFIG.example.json @@ -17,7 +17,7 @@ "noReplyProvider": "dirigentway", "noReplyModel": "no-reply", "enableDiscordControlTool": true, - "enableWhispergatePolicyTool": true, + "enableDirigentPolicyTool": true, "enableDebugLogs": false, "debugLogChannelIds": [], "discordControlApiBaseUrl": "http://127.0.0.1:8790", diff --git a/plugin/README.md b/plugin/README.md index 4281bca..cd6592d 100644 --- a/plugin/README.md +++ b/plugin/README.md @@ -4,9 +4,7 @@ - `message:received` caches a per-session decision from deterministic rules. - `before_model_resolve` applies `providerOverride + modelOverride` when decision says no-reply. -- `before_prompt_build` prepends instruction `你的这次发言必须以🔚作为结尾。` when decision is: - - `bypass_sender` - - `end_symbol:*` +- `before_prompt_build` prepends end-marker instruction + scheduling identifier instruction when decision allows speaking. ## Rules (in order) @@ -30,12 +28,14 @@ Optional: - `humanList` (default []) - `agentList` (default []) - `channelPoliciesFile` (per-channel overrides in a standalone JSON file) -- `enableWhispergatePolicyTool` (default true) +- `schedulingIdentifier` (default `➡️`) — moderator handoff identifier +- `enableDirigentPolicyTool` (default true) Unified optional tool: - `dirigent_tools` - Discord actions: `channel-private-create`, `channel-private-update`, `member-list` - Policy actions: `policy-get`, `policy-set-channel`, `policy-delete-channel` + - Turn actions: `turn-status`, `turn-advance`, `turn-reset` - `bypassUserIds` (deprecated alias of `humanList`) - `endSymbols` (default ["🔚"]) - `enableDiscordControlTool` (default true) @@ -53,18 +53,21 @@ Policy file behavior: - direct file edits do NOT affect memory state - `dirigent_tools` policy actions update memory first, then persist to file (atomic write) -## Optional tool: `dirigent_tools` +## Moderator handoff format -This plugin registers one unified optional tool: `dirigent_tools`. -To use it, add tool allowlist entry for either: -- tool name: `dirigent_tools` -- plugin id: `dirigent` +When the current speaker NO_REPLYs, the moderator bot sends: `<@NEXT_USER_ID>➡️` -Supported actions: -- Discord: `channel-private-create`, `channel-private-update`, `member-list` -- Policy: `policy-get`, `policy-set-channel`, `policy-delete-channel` +This is a non-semantic scheduling message. The scheduling identifier (`➡️` by default) carries no meaning — it simply signals the next agent to check chat history and decide whether to speak. + +## Slash command (Discord) + +``` +/dirigent status +/dirigent turn-status +/dirigent turn-advance +/dirigent turn-reset +``` Debug logging: - set `enableDebugLogs: true` to emit detailed hook diagnostics - optionally set `debugLogChannelIds` to only log selected channel IDs -- logs include key ctx fields + decision status at `message_received`, `before_model_resolve`, `before_prompt_build` diff --git a/plugin/openclaw.plugin.json b/plugin/openclaw.plugin.json index 9cb5b86..1886edf 100644 --- a/plugin/openclaw.plugin.json +++ b/plugin/openclaw.plugin.json @@ -20,7 +20,7 @@ "noReplyProvider": { "type": "string" }, "noReplyModel": { "type": "string" }, "enableDiscordControlTool": { "type": "boolean", "default": true }, - "enableWhispergatePolicyTool": { "type": "boolean", "default": true }, + "enableDirigentPolicyTool": { "type": "boolean", "default": true }, "discordControlApiBaseUrl": { "type": "string", "default": "http://127.0.0.1:8790" }, "discordControlApiToken": { "type": "string" }, "discordControlCallerId": { "type": "string" }, diff --git a/scripts/install-dirigent-openclaw.mjs b/scripts/install-dirigent-openclaw.mjs index 9f6a951..550188f 100755 --- a/scripts/install-dirigent-openclaw.mjs +++ b/scripts/install-dirigent-openclaw.mjs @@ -15,7 +15,7 @@ const env = process.env; const OPENCLAW_CONFIG_PATH = env.OPENCLAW_CONFIG_PATH || path.join(os.homedir(), ".openclaw", "openclaw.json"); const __dirname = path.dirname(new URL(import.meta.url).pathname); const PLUGIN_PATH = env.PLUGIN_PATH || path.resolve(__dirname, "..", "dist", "dirigent"); -const NO_REPLY_PROVIDER_ID = env.NO_REPLY_PROVIDER_ID || "whisper-gateway"; +const NO_REPLY_PROVIDER_ID = env.NO_REPLY_PROVIDER_ID || "dirigentway"; const NO_REPLY_MODEL_ID = env.NO_REPLY_MODEL_ID || "no-reply"; const NO_REPLY_BASE_URL = env.NO_REPLY_BASE_URL || "http://127.0.0.1:8787/v1"; const NO_REPLY_API_KEY = env.NO_REPLY_API_KEY || "wg-local-test-token";