docs: reorganize planning and archive files

This commit is contained in:
nav
2026-03-31 12:46:09 +00:00
parent dbd0fc68c0
commit 0a76dae376
3 changed files with 0 additions and 0 deletions

51
achieve/CHANGELOG.md Normal file
View File

@@ -0,0 +1,51 @@
# Changelog
## 0.3.0
- **Split `dirigent_tools` into 6 individual tools**:
- Discord: `dirigent_discord_channel_create`, `dirigent_discord_channel_update`, `dirigent_discord_member_list`
- Policy: `dirigent_policy_get`, `dirigent_policy_set`, `dirigent_policy_delete`
- Turn management tools removed (internal plugin logic only; use `/dirigent` slash commands)
- **Human @mention override**: When a `humanList` user @mentions specific agents:
- Temporarily overrides the speaking order to only mentioned agents
- Agents cycle in their original turn-order position
- After all mentioned agents have spoken, original order restores and state goes dormant
- Handles edge cases: all NO_REPLY, reset, non-agent mentions
- **Wait for human reply**: New `waitIdentifier` (default: `👤`):
- Agent ends with `👤` to signal it needs a human response
- All agents go silent (routed to no-reply model) until a human speaks
- Prompt injection warns agents to use sparingly (only when human is actively participating)
- **Installer improvements**:
- Dynamic OpenClaw dir resolution (`$OPENCLAW_DIR``openclaw` CLI → `~/.openclaw`)
- Plugin installed to `$(openclaw_dir)/plugins/dirigent`
- New `--update` mode: pulls latest from git `latest` branch and reinstalls
## 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 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
- Added no-touch config rendering and integration docs
- Added installer script with rollback (`scripts/install-dirigent-openclaw.sh`)
- supports `--install` / `--uninstall`
- uninstall restores all recorded changes
- writes install/uninstall records under `~/.openclaw/dirigent-install-records/`
- Added discord-control-api with: (historical; later migrated into plugin internal Discord REST control)
- `channel-private-create` (create private channel for allowlist)
- `channel-private-update` (update allowlist/overwrites for existing channel)
- `member-list` (guild members list with pagination + optional field projection)
- guardrails: action mode validation, id-list limits, response-size limit

158
achieve/FEAT.md Normal file
View File

@@ -0,0 +1,158 @@
# Dirigent — Feature List
All implemented features across all versions.
---
## Core: Rule-Based No-Reply Gate
- Deterministic logic in `before_model_resolve` hook decides whether to route to no-reply model
- **human-list** mode: humanList senders bypass gate; others need end symbol to pass
- **agent-list** mode: agentList senders need end symbol; others bypass
- Non-Discord messages skip entirely
- DM sessions (no metadata) always bypass
- Per-channel policy overrides via JSON file (runtime-updateable)
## Core: End-Symbol Enforcement
- Injects prompt instruction: "Your response MUST end with 🔚"
- Gateway keywords (NO_REPLY, HEARTBEAT_OK) exempt from end symbol
- Group chats get additional rule: "If not relevant, reply NO_REPLY"
- End symbols configurable per-channel via policy
## Core: No-Reply API
- OpenAI-compatible API (`/v1/chat/completions`, `/v1/responses`, `/v1/models`)
- Always returns `NO_REPLY` — used as the override model target
- Optional bearer auth (`AUTH_TOKEN`)
- Auto-started/stopped with gateway lifecycle
## Turn-Based Speaking (Multi-Bot)
- Only the current speaker is allowed to respond; others forced to no-reply model
- Turn order auto-populated from bot accounts seen in each channel
- Turn advances on end-symbol (successful speech) or NO_REPLY
- Successful speech resets NO_REPLY cycle counter
- If all bots NO_REPLY in a cycle → channel goes **dormant**
- Dormant reactivation: human message → first in order; bot message → next after sender
- Turn timeout: auto-advance after 60s of inactivity
- Manual control: `/dirigent turn-status`, `/dirigent turn-advance`, `/dirigent turn-reset`
## Human @Mention Override *(v0.3.0)*
- When a `humanList` user @mentions specific agents (`<@USER_ID>`):
- Extracts mentioned Discord user IDs from message content
- Maps userIds → accountIds via reverse bot token lookup
- Filters to agents in the current turn order
- Orders by their position in the current turn order
- Temporarily replaces speaking order with only those agents
- Cycle: a → b → c → (back to a) → restore original order, go dormant
- Edge cases:
- All override agents NO_REPLY → restore + dormant
- `resetTurn` clears any active override
- Human message without mentions → restores override, normal flow
- Mentioned users not in turn order → ignored
## Agent Identity Injection
- Group chat prompts include: agent name, Discord accountId, Discord userId
- userId resolved from bot token (base64 first segment)
## Wait for Human Reply *(v0.3.0)*
- Configurable wait identifier (default: `👤`)
- Agent ends message with `👤` instead of `🔚` when it needs a human to reply
- Triggers "waiting for human" state:
- All agents routed to no-reply model
- Turn manager goes dormant
- State clears automatically when a human sends a message
- Prompt injection tells agents:
- Use wait identifier only when confident the human is actively participating
- Do NOT use it speculatively
- Works with mention override: wait identifier during override also triggers waiting state
## Scheduling Identifier
- Configurable identifier (default: `➡️`) used for moderator handoff
- Handoff format: `<@TARGET_USER_ID>➡️` (non-semantic scheduling signal)
- Agent prompt explains: identifier is meaningless — check chat history, decide whether to reply
- If nothing to say → NO_REPLY
## Moderator Bot Presence
- Maintains Discord Gateway WebSocket connection for moderator bot
- Shows "online" status with "Moderating" activity
- Handles reconnect, resume, heartbeat, invalid session recovery
- Singleton guard prevents duplicate connections
- Sends handoff messages to trigger next speaker's turn
## Individual Tools *(v0.3.0)*
Six standalone tools (split from former monolithic `dirigent_tools`):
### Discord Control
- **`dirigent_discord_channel_create`** — Create private Discord channel with user/role permissions
- **`dirigent_discord_channel_update`** — Update permissions on existing private channel
- **`dirigent_discord_member_list`** — List guild members with pagination and field projection
### Policy Management
- **`dirigent_policy_get`** — Get all channel policies
- **`dirigent_policy_set`** — Set/update a channel policy (listMode, humanList, agentList, endSymbols)
- **`dirigent_policy_delete`** — Delete a channel policy
### Turn Management (internal only — not exposed as tools)
Turn management is handled entirely by the plugin. Manual control via slash commands:
- `/dirigent turn-status` — Show turn state
- `/dirigent turn-advance` — Manually advance to next speaker
- `/dirigent turn-reset` — Reset turn order (go dormant, clear overrides)
## Slash Command: `/dirigent`
- `status` — Show all channel policies
- `turn-status` — Show turn state for current channel
- `turn-advance` — Manually advance turn
- `turn-reset` — Reset turn order
## Project Rename (WhisperGate → Dirigent) *(v0.2.0)*
- All plugin ids, tool names, config keys, file paths, docs updated
- Legacy `whispergate` config key still supported as fallback
## Installer Script *(updated v0.3.0)*
- `scripts/install-dirigent-openclaw.mjs`
- `--install` / `--uninstall` / `--update` modes
- **Dynamic OpenClaw dir resolution**: `$OPENCLAW_DIR``openclaw config get dataDir``~/.openclaw`
- Builds dist and copies to `$(openclaw_dir)/plugins/dirigent`
- `--update`: pulls latest from git `latest` branch, then reinstalls
- Auto-reinstall (uninstall + install) if already installed
- Backup before changes, rollback on failure
- Records stored in `$(openclaw_dir)/dirigent-install-records/`
## Discord Control API (Sidecar)
- Private channel create/update with permission overwrites
- Member list with pagination + field projection
- Guardrails: action validation, id-list limits, response-size limit
- (Migrated) Discord control now runs in-plugin via direct Discord REST (no companion service)
---
## NEW_FEAT 合并记录(原 NEW_FEAT.md
### 背景与目标
- 解决 turn 初始化依赖被动观察(`recordChannelAccount`)导致 `currentSpeaker` 空值的问题。
- 将 Discord control 从 sidecar 迁移到插件内模块。
- 采用 channel 成员缓存(内存 + 本地持久化),避免轮询。
### 关键实现方向
- 统一 channelId 解析链路,避免 `channel=discord` 错位。
- `before_model_resolve / before_prompt_build` 与消息 hook 使用一致解析策略。
- 清理未使用函数,降低排障噪音。
- 模块化重构:`index.ts` 作为 wiring逻辑拆入 `hooks/core/tools/policy/commands`
### Channel 成员缓存
- 缓存文件:`~/.openclaw/dirigent-channel-members.json`
- 启动加载、运行时原子写盘。
- 记录字段包含 `botAccountIds/updatedAt/source/guildId`
- 首次无缓存时允许 bootstrap 拉取,随后走本地缓存。
### Turn 初始化改造
- `ensureTurnOrder(channelId)` 基于缓存中的 botAccountIds 初始化。
- 不再仅依赖“已见账号”被动记录。
- 提升新频道首条消息场景的稳定性。
### 权限计算(频道可见成员)
- 通过 guild 成员 + roles + channel overwrites 计算 `VIEW_CHANNEL` 可见性。
- 用于内部 turn bootstrap不对外暴露为公共工具。
### 风险与注意
- 权限位计算必须严格按 Discord 规则。
- 缓存读写需原子化,防并发损坏。
- 通过 `updatedAt/source/guildId` 提高可观测性与排障效率。

86
achieve/TASKLIST.md Normal file
View File

@@ -0,0 +1,86 @@
# Dirigent Fixes & Improvements
> Note: Project rename from WhisperGate → Dirigent implies updating all code/docs references (plugin/tool names, strings, files, configs).
## 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: ➡️) ✅
- 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 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 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 ✅
- 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.
---
## 6) Split dirigent_tools into Individual Tools ✅
- **Before**: Single `dirigent_tools` tool with `action` parameter managing 9 sub-actions.
- **After**: 6 individual tools (Discord tools prefixed `dirigent_discord_*`):
- `dirigent_discord_channel_create` — Create private Discord channel
- `dirigent_discord_channel_update` — Update channel permissions
- `dirigent_discord_member_list` — List guild members
- `dirigent_policy_get` — Get all channel policies
- `dirigent_policy_set` — Set/update a channel policy
- `dirigent_policy_delete` — Delete a channel policy
- Turn management (status/advance/reset) NOT exposed as tools — purely internal plugin logic, accessible via `/dirigent` slash commands.
- Shared Discord API helper `executeDiscordAction()` extracted to reduce duplication.
- **Done**: All tools registered individually with specific parameter schemas.
## 7) Human @Mention Override ✅
- When a message from a `humanList` user contains `<@USER_ID>` mentions:
- Extract mentioned Discord user IDs from the message content.
- Map user IDs → accountIds via bot token decoding (reverse of `resolveDiscordUserId`).
- Filter to agents in the current turn order.
- Order by their position in the current turn order.
- Temporarily replace the speaking order with only those agents.
- After the cycle returns to the first agent, restore the original order and go dormant.
- Edge cases handled:
- All override agents NO_REPLY → restore original order, go dormant.
- `resetTurn` clears any active override.
- New human message without mentions → restores override before normal handling.
- Mentioned users not in turn order → ignored, normal flow.
- New functions in `turn-manager.ts`: `setMentionOverride()`, `hasMentionOverride()`.
- New helpers in `index.ts`: `buildUserIdToAccountIdMap()`, `extractMentionedUserIds()`.
- **Done**: Override logic integrated in `message_received` handler.
## 8) Wait for Human Reply ✅
- Added configurable `waitIdentifier` (default: `👤`) to config and config schema.
- Prompt injection in group chats: tells agents to end with `👤` instead of end symbol when they need a human response. Warns to use sparingly — only when human is actively participating.
- Detection in `before_message_write` and `message_sent`: if last char matches wait identifier → `setWaitingForHuman(channelId)`.
- Turn manager `waitingForHuman` state:
- `checkTurn()` blocks all agents (`reason: "waiting_for_human"`) → routed to no-reply model.
- `onNewMessage()` clears `waitingForHuman` on human message → normal flow resumes.
- Non-human messages ignored while waiting.
- `resetTurn()` also clears waiting state.
- **Done**: Full lifecycle implemented across turn-manager, rules, and index.
---
## 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.