Files
Dirigent/achieve/FEAT.md

159 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 提高可观测性与排障效率。