refactor: new design — sidecar services, moderator Gateway client, tool execute API
- Replace standalone no-reply-api Docker service with unified sidecar (services/main.mjs) that routes /no-reply/* and /moderator/* and starts/stops with openclaw-gateway - Add moderator Discord Gateway client (services/moderator/index.mjs) for real-time MESSAGE_CREATE push instead of polling; notifies plugin via HTTP callback - Add plugin HTTP routes (plugin/web/dirigent-api.ts) for moderator → plugin callbacks (wake-from-dormant, interrupt tail-match) - Fix tool registration format: AgentTool requires execute: not handler:; factory form for tools needing ctx - Rename no-reply-process.ts → sidecar-process.ts, startNoReplyApi → startSideCar - Remove dead config fields from openclaw.plugin.json (humanList, agentList, listMode, channelPoliciesFile, endSymbols, waitIdentifier, multiMessage*, bypassUserIds, etc.) - Rename noReplyPort → sideCarPort - Remove docker-compose.yml, dev-up/down scripts, package-plugin.mjs, test-no-reply-api.mjs - Update install.mjs: clean dist before build, copy services/, drop dead config writes - Update README, Makefile, smoke script for new architecture Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
189
README.md
189
README.md
@@ -1,144 +1,117 @@
|
||||
# Dirigent
|
||||
|
||||
Rule-based no-reply gate + turn manager for OpenClaw (Discord).
|
||||
Turn-management and moderation plugin 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:
|
||||
Dirigent adds deterministic routing and **turn-based speaking** for multi-agent Discord channels:
|
||||
|
||||
- **Rule gate (before_model_resolve)**
|
||||
1. Non-Discord → skip
|
||||
2. Sender in bypass list / human list → skip
|
||||
3. Message ends with configured end symbol → skip
|
||||
4. Otherwise → route to no-reply model/provider
|
||||
- **Rule gate (`before_model_resolve`)**
|
||||
- Non-speaker agents → routed to no-reply model (silent turn)
|
||||
- Dormant channels → all agents suppressed until a human message wakes them
|
||||
- Configurable per-channel mode: `chat`, `work`, `discussion`, `report`, `none`
|
||||
|
||||
- **End-symbol enforcement**
|
||||
- Injects instruction: `Your response MUST end with 🔚…`
|
||||
- In group chats, also injects: "If not relevant, reply NO_REPLY"
|
||||
- **Turn management**
|
||||
- Only the current speaker responds; others are silenced
|
||||
- Turn advances when the current speaker ends with a configured symbol or returns `NO_REPLY`
|
||||
- Full round of silence → channel enters **dormant** state
|
||||
- Human message → wakes dormant channel, triggers first speaker
|
||||
|
||||
- **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
|
||||
- **Moderator bot sidecar**
|
||||
- Dedicated Discord Gateway connection (separate bot token) for real-time message push
|
||||
- Sends schedule-trigger messages (`<@USER_ID>➡️`) to signal speaker turns
|
||||
- Notifies the plugin via HTTP callback on new messages (wake/interrupt)
|
||||
|
||||
- **Turn-based speaking (multi-bot)**
|
||||
- Only the current speaker is allowed to respond
|
||||
- Others are forced to no-reply
|
||||
- Turn advances on **end-symbol** or **NO_REPLY**
|
||||
- If all bots NO_REPLY, channel becomes **dormant** until a new human message
|
||||
- **Discussion mode**
|
||||
- Agents can initiate a structured discussion via `create-discussion-channel` tool
|
||||
- Initiator calls `discussion-complete` to conclude; summary is posted to the callback channel
|
||||
|
||||
- **Agent identity injection**
|
||||
- Injects agent name, Discord accountId, and Discord userId into group chat prompts
|
||||
|
||||
- **Human @mention override**
|
||||
- When a `humanList` user @mentions agents, temporarily overrides turn order
|
||||
- Only mentioned agents cycle; original order restores when cycle completes
|
||||
|
||||
- **Per-channel policy runtime**
|
||||
- Policies stored in a standalone JSON file
|
||||
- Update at runtime via `dirigent_policy_set` / `dirigent_policy_delete` tools
|
||||
|
||||
- **Discord control actions (optional)**
|
||||
- Private channel create/update + member list
|
||||
- Via `dirigent_channel_create`, `dirigent_channel_update`, `dirigent_member_list` tools
|
||||
- **Channel management tools**
|
||||
- `create-chat-channel`, `create-work-channel`, `create-report-channel` — create typed channels
|
||||
- `create-discussion-channel`, `discussion-complete` — discussion lifecycle
|
||||
- `dirigent-register` — register an agent identity
|
||||
|
||||
---
|
||||
|
||||
## Repo layout
|
||||
|
||||
- `plugin/` — OpenClaw plugin (gate + turn manager + moderator presence)
|
||||
- `no-reply-api/` — OpenAI-compatible API that always returns `NO_REPLY`
|
||||
- Discord admin actions are now handled in-plugin via direct Discord REST API calls (no sidecar service)
|
||||
- `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`)
|
||||
- `CHANGELOG.md` — milestone summary
|
||||
```
|
||||
plugin/ OpenClaw plugin (hooks, tools, commands, web UI)
|
||||
core/ Channel store, identity registry, moderator REST helpers
|
||||
hooks/ before_model_resolve, agent_end, message_received
|
||||
tools/ Agent-facing tools
|
||||
commands/ Slash commands
|
||||
web/ Control page + Dirigent API (HTTP routes)
|
||||
services/ Sidecar process — spawned automatically by the plugin
|
||||
main.mjs Unified entry point, routes /no-reply/* and /moderator/*
|
||||
no-reply-api/ OpenAI-compatible server that always returns NO_REPLY
|
||||
moderator/ Discord Gateway client + HTTP control endpoints
|
||||
scripts/ Dev helpers
|
||||
docs/ Architecture and integration notes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick start (no Docker)
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
cd no-reply-api
|
||||
node server.mjs
|
||||
node scripts/install.mjs --install
|
||||
```
|
||||
|
||||
Then render config snippet:
|
||||
This copies `plugin/` and `services/` into the OpenClaw plugin directory and registers skills.
|
||||
|
||||
---
|
||||
|
||||
## Sidecar
|
||||
|
||||
The sidecar (`services/main.mjs`) is spawned automatically when openclaw-gateway starts. It exposes:
|
||||
|
||||
| Path prefix | Description |
|
||||
|---|---|
|
||||
| `/no-reply/*` | No-reply model API (`/v1/chat/completions`, `/v1/responses`) |
|
||||
| `/moderator/*` | Moderator bot control (`/send`, `/create-channel`, `/me`, …) |
|
||||
| `/health` | Combined health check |
|
||||
|
||||
Port is configured via `sideCarPort` (default `8787`).
|
||||
|
||||
Smoke-test after gateway start:
|
||||
|
||||
```bash
|
||||
node scripts/render-openclaw-config.mjs
|
||||
```
|
||||
|
||||
See `docs/RUN_MODES.md` for Docker mode.
|
||||
Discord extension capabilities: `docs/DISCORD_CONTROL.md`.
|
||||
|
||||
---
|
||||
|
||||
## Runtime tools & commands
|
||||
|
||||
### Tools (6 individual tools)
|
||||
|
||||
**Discord control:**
|
||||
- `dirigent_discord_channel_create` — Create private channel
|
||||
- `dirigent_discord_channel_update` — Update channel permissions
|
||||
- `dirigent_discord_member_list` — List guild members
|
||||
|
||||
**Policy management:**
|
||||
- `dirigent_policy_get` — Get all policies
|
||||
- `dirigent_policy_set` — Set/update channel policy
|
||||
- `dirigent_policy_delete` — Delete channel policy
|
||||
|
||||
> Turn management is internal to the plugin (not exposed as tools).
|
||||
|
||||
> See `FEAT.md` for full feature documentation.
|
||||
|
||||
### Slash command (Discord)
|
||||
|
||||
```
|
||||
/dirigent status
|
||||
/dirigent turn-status
|
||||
/dirigent turn-advance
|
||||
/dirigent turn-reset
|
||||
/dirigent turn-shuffling
|
||||
/dirigent turn-shuffling on
|
||||
/dirigent turn-shuffling off
|
||||
make smoke
|
||||
# or:
|
||||
./scripts/smoke-no-reply-api.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Config highlights
|
||||
## Plugin config
|
||||
|
||||
Common options (see `docs/INTEGRATION.md`):
|
||||
Key options (in `openclaw.json` under `plugins.entries.dirigent.config`):
|
||||
|
||||
- `listMode`: `human-list` or `agent-list`
|
||||
- `humanList`, `agentList`
|
||||
- `endSymbols`
|
||||
- `schedulingIdentifier` (default `➡️`)
|
||||
- `waitIdentifier` (default `👤`) — agent ends with this to pause all agents until human replies
|
||||
- `channelPoliciesFile` (per-channel overrides)
|
||||
- `moderatorBotToken` (handoff messages)
|
||||
- `multiMessageStartMarker` (default `↗️`)
|
||||
- `multiMessageEndMarker` (default `↙️`)
|
||||
- `multiMessagePromptMarker` (default `⤵️`)
|
||||
- `enableDebugLogs`, `debugLogChannelIds`
|
||||
|
||||
Shuffle mode does not currently have a global config key. It is a per-channel runtime toggle, defaults to off, and is controlled with `/dirigent turn-shuffling ...`.
|
||||
| Key | Default | Description |
|
||||
|---|---|---|
|
||||
| `moderatorBotToken` | — | Discord bot token for the moderator/sidecar bot |
|
||||
| `scheduleIdentifier` | `➡️` | Symbol appended to schedule-trigger mentions |
|
||||
| `listMode` | `human-list` | `human-list` or `agent-list` |
|
||||
| `humanList` | `[]` | Discord user IDs treated as humans (bypass turn gate) |
|
||||
| `agentList` | `[]` | Discord user IDs treated as agents (when `listMode=agent-list`) |
|
||||
| `noReplyProvider` | `dirigent` | Provider ID for the no-reply model |
|
||||
| `noReplyModel` | `no-reply` | Model ID for the no-reply model |
|
||||
| `sideCarPort` | `8787` | Port the sidecar listens on |
|
||||
| `debugMode` | `false` | Enable verbose debug logging |
|
||||
| `debugLogChannelIds` | `[]` | Channel IDs that receive debug log messages |
|
||||
| `channelPoliciesFile` | `~/.openclaw/dirigent-channel-policies.json` | Per-channel policy overrides |
|
||||
|
||||
---
|
||||
|
||||
## Development plan (incremental commits)
|
||||
## Dev commands
|
||||
|
||||
- [x] Task 1: project docs + structure
|
||||
- [x] Task 2: no-reply API MVP
|
||||
- [x] Task 3: plugin MVP with rule chain
|
||||
- [x] Task 4: sample config + quick verification scripts
|
||||
- [x] Task 5: plugin rule extraction + hardening
|
||||
- [x] Task 6: containerization + compose
|
||||
- [x] Task 7: plugin usage notes
|
||||
- [x] Task 8: sender normalization + TTL + one-shot decision
|
||||
- [x] Task 9: auth-aware no-reply API
|
||||
- [x] Task 10: smoke test helpers
|
||||
- [x] Task 11: plugin structure checker
|
||||
- [x] Task 12: rollout checklist
|
||||
```bash
|
||||
make check # TypeScript check (plugin/)
|
||||
make check-rules # Validate rule-case fixtures
|
||||
make check-files # Verify required files exist
|
||||
make smoke # Smoke-test no-reply endpoint (sidecar must be running)
|
||||
make install # Install plugin + sidecar into OpenClaw
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user