Bundle
@stars-w/dsh-group-chat
AI 主持人驱动的多角色群聊插件(DSH Host):自动生成主持人 + 3~6 专家团队、动态调度讨论、成员 subagent 深度推理、总结结论并导出 md 到工作区
- Source
- wyStars
- License
- BSD-3-Clause
- Updated
- Updated yesterday
Readme
# @stars-w/dsh-group-chat
基于当前会话的 **AI 主持人驱动多角色群聊**:在主会话输入 `/group-chat <任务/设计方案>` 即呼起群聊 —— 自动生成 **1 位 AI 主持人 + 3~6 位专家**(各有 persona 与职责)并拉入群聊,右侧竖长聊天面板自动展开;**主持人动态调度**(不固定轮数):每步决定点名谁发言、是否串场、何时收尾;被点名的专家可自主判断是否调用 **subagent 深度推理** 再整理为正式发言;**你可以随时插话参与**;讨论结束自动生成结论并导出 Markdown 文档到工作区。
> 适用:**DeepSeek Harness(DSH)** Host 环境(whale-girl 纯 ESM 模式 + Web 浏览器面板)。英文项目名 `group-chat`,常被本地装配为 `dsh-group-chat`。
## 功能
| 能力 | 说明 |
|---|---|
| 指令呼起 | `/group-chat <任务>`(主会话输入框)→ 基于当前会话建团拉群并自动开始讨论,右侧面板自动打开 |
| 主持人制 | 角色生成时 LLM 产出 `{host, roles}`(1 主持人 + 3~6 专家);主持人每步决策 `speak`(点名/串场)、`host_message`(串场)、`summarize`(收尾)——同一专家可被多次点名,不被强制全员发言 |
| 角色实时生成 | 专家可重新生成/增删;**主持人固定展示(不参与增删改)**,更换请「重新生成角色团队」 |
| 右侧竖长聊天框 | `shell.overlay` 右停靠窄面板(无全屏遮罩、不隔离会话),头部紧凑;**按住头部空白区可拖动面板**(位置记忆,拖出停靠区后为浮动模式) |
| 收起态悬浮按钮 | 面板收起后,主会话内容区左上方出现悬浮入口(不遮挡内容主体):**待命**(常规样式)/ **讨论中**(绿色呼吸脉冲 + 三个跳动点动画)/ **出错**(红色描边)——点击即展开面板 |
| **成员深度推理** | 被点名专家先做一次轻量 `direct/deep` 判断;`deep` 时派生一次性 spawn subagent(maxDepth 1、180s 超时、零工具面)深度分析,再把素材流式整理为正式发言;subagent 失败/超时/不可用自动回退 `direct`,不打断讨论 |
| 深度推理开关 | ⚙ 设置区「允许成员深度推理」默认开启,可随时切换(当前发言/推理中的成员不受影响) |
| **用户参与讨论** | 面板底部消息输入框:以主持人身份插话,消息进入共享群聊历史,主持人下一步优先处理(若消息点名了某专家,主持人会调用 TA) |
| **MD 格式显示** | 消息流与结论区按 markdown 渲染(标题/粗斜体/列表/代码块/引用/链接/删除线),**字号显著小于标准 md**(12.5px 基准,适配窄面板展示密度) |
| 讨论干预 | 暂停(不中断 deep)/ 继续 / 跳过(中断当前发言与 deep)/ 停止 / 让某专家重发(↻,主持人优先点名该专家) |
| 结论总结 | 讨论结束自动生成 markdown 结论(结论 / 关键分歧 / 行动建议 / 参考意见)并**自动回注主会话** |
| 导出 MD | 任务 + 主持人 + 团队 + 完整讨论纪要 + 结论 → 写入工作区 `group-chat-<slug>-<时间戳>.md` |
| 自动呼起 | 面板关闭时后台 2s 轻轮询:检测到群聊活动(指令/命令触发)自动打开面板 |
## 安装(DSH 插件命令)
DSH 插件的安装走 **profile 目录的 pnpm**(`dsh plugin` 把剩余参数原样转发给 pnpm),包本身来自 npm 仓库:
> **注意参数顺序**:`--profile <name>` 必须紧跟 `plugin` 子命令(`dsh --profile web plugin …` 会被命令解析器报 `required option '--profile <name>' not specified`)。
```bash
# 安装到 web profile(等价于在 profile 目录执行 pnpm add)
dsh plugin --profile web add @stars-w/dsh-group-chat
# 指定其它 profile(如 tui / headless)
dsh plugin --profile tui add @stars-w/dsh-group-chat
```
> **官方 Electron 桌面版**:桌面版独占 `desktop` profile(`dsh --profile desktop` 被
> 桌面壳接管,CLI 不可启动它),请在**桌面版应用内**的插件管理界面安装,或让桌面版
> 的 pnpm 事务安装到 `desktop` profile。本插件已按桌面版契约打包:`dsh.bundle.patch`
> 指向 `cordis.patch.yml`(装即可装配 host 半)、发布产物不含嵌套 `node_modules`、
> 第一方共享包只出现在 `peerDependencies`(桌面版 `autoInstallPeers: false` +
> `nodeLinker: hoisted`,由宿主 junction 提供)。面板 API 走 DSH 共享 `/api` 通道,
> **不依赖 webServer 服务**,因此桌面版默认不启用 webserver 也能工作。
```bash
# 卸载 / 查看依赖树
dsh plugin --profile web remove @stars-w/dsh-group-chat
dsh plugin --profile web why @stars-w/dsh-group-chat
```
> **PowerShell(Windows 宿主)**:包名建议加引号——`dsh plugin --profile web add "@stars-w/dsh-group-chat"`(避免 `@` 被解释)。
重启 profile 后插件自动装配生效(DSH 会加载已安装依赖中的外部插件;会话头部出现「💬 群聊」、可用 `/group-chat <任务>` 即可确认)。需要显式指定装配顺序/清单时,把包名加入 profile 的 `dsh.profile.bundles` 列表,或在 DSH 插件市场(**设置 → 插件市场**)一键安装。
> **底层等价**:包以标准 npm 包发布(`npm install @stars-w/dsh-group-chat`,`lib/` 为已构建运行产物,无需构建步骤);peer 依赖(`@deepseek-ai/dsh-llm`)由 DSH 宿主提供(桌面版经 profile 内 junction 共享,不重复安装)。client 半所需的 `@deepseek-ai/dsh-client-ui-slots` / `ui-conversation` / `ui-layout` 由 Web 前端模块表提供,写在 `dsh.client.inject` 中而非 peerDependencies。安装在 DSH 宿主进程内(web/tui/desktop),不属于独立 npm 项目依赖。
## 使用步骤
1. **主会话输入框**输入指令:`/group-chat <任务/设计方案>` 回车(如 `/group-chat 设计一款家庭记账 App 的核心产品方案`)
2. 右侧「群聊」面板自动打开:角色团队生成中(拉群中)→ 主持人开始调度讨论
3. 随时在面板**底部输入框**插话(Enter 发送)——主持人会在下一步优先处理;也可 ⚙ 调整任务/深度推理开关/角色,暂停/跳过/停止
4. 讨论结束自动展示**结论** → **📄 导出 MD**(写入工作区并显示路径)
5. 也可点会话顶部「💬 群聊」按钮,或收起后点击左上方悬浮按钮打开面板查看/管理
## 架构
```
浏览器(client bundle) host 进程(lib/index.js + engine.js)
───────────────────────────── ──────────────────────────────────
主会话 composer slash command:/group-chat <任务>
└── 输入 /group-chat <任务> ──────────────▶ commands.register → 建团+自动讨论
conversation.session.header.actions GroupChatEngine 状态机:
└──「💬 群聊」入口按钮 idle → generating-roles → discussing
shell.overlay(右停靠/可拖动面板) → summarizing → done(/ paused / error)
└── 头部(摘要+状态+⚙设置折叠) · llm.stream 驱动:角色生成 {host, roles} /
消息流(主持人/角色/用户气泡) 主持人调度决策 / 成员发言 / 总结
状态提示(调度中/deep 中/输入中) · 主持人步进循环:speak | host_message |
深度推理开关 + 主持人徽标 summarize(隐藏上限 60 步后强制总结)
底部参与输入框(主持人插话) · 成员管线:plan(direct/deep) → 流式发言
│ fetch(打开 500ms / 后台 2s 快照) 或 deep(spawn subagent maxDepth 1, 180s)
└──────────────▶ /api/group-chat · 失败回退:主持 JSON 非法→least-spoken;
GET /state(快照) 子代理失败/超时→direct 发言
POST /command { action: generate-roles | start | pause | resume | skip
| stop | chat | reroll | update-roles | sync-settings | export-md }
```
- **基于会话发起**:命令 handler 取当前 agent 的 session(绑定 sessionId);模型路由优先该会话 agent 的 `options.provider/model`,回退「默认模型选择」(deep subagent 继承同一路由)。
- **上下文共享**:主持人、专家、用户共用同一份 `messages`;主持人决策与成员发言均注入「任务 + 群聊历史(预算 24k 字符,超限保留最近)」。
- **Deep 子代理**:一次性 `spawn`(全新上下文、无父历史),prompt 自包含(角色 persona / 任务 / 相关历史 / 主持人 instruction / 分析作业);`await run.result` 取最终输出,**不向主会话注入任何内部推理通知**;与 skip/stop/reroll/超时共用同一 AbortController。
- **面板交互**:面板可拖动(位置持久化到 `localStorage`);收起态悬浮按钮按讨论状态切换样式;消息/结论按 markdown 小字号渲染。
## 状态机
```
idle ──generateRoles(task)──▶ generating-roles ──成功──▶ idle(角色就绪)
idle ──start()──▶ discussing ──主持人步进循环──▶ summarizing ──▶ done
│ (隐藏上限 60 步 → 强制 summarize)
├─ pause() ──▶ paused(门闩;不中断 deep,动作完成后暂停)
├─ 连续 3 次最终发言失败 / 主持人连续 3 次调度失败 ──▶ error(保留历史)
└─ stop() ──▶ done(保留已有历史,可导出)
```
## 控制语义
| 操作 | 讨论中 | deep 推理中 | 效果 |
|---|---|---|---|
| 暂停 | 有效 | 不中断当前 subagent | 当前动作完成后,在下一步调度前暂停 |
| 继续 | 有效 | — | 释放暂停门闩 |
| 跳过 | 有效 | 有效 | abort 当前发言/subagent;移除半截消息;进入下一轮主持人调度 |
| 停止 | 有效 | 有效 | abort 当前发言 + interrupt subagent;清空后续;`phase=done` |
| 重发(专家) | 有效 | 有效 | 删除该专家最近一条消息;若在推理则 interrupt;主持人下一步优先点名 |
| 重发(主持人) | v1 不支持 | — | 不提供该能力 |
| 用户插话 | 有效 | 有效 | 只追加用户消息,不打断当前动作;下一步主持人优先处理 |
## HTTP API
宿主进程经 `ctx.connection.fetch.register` 在 DSH **共享 `/api` 通道**注册两条精确 Fetch 路由。
web 版由 webserver 把 `/api` 前缀交给同一个 connection handler;官方 Electron 桌面版由
`desktop-host` 直接转发 `/api/*`(桌面版默认禁用 webserver,自建前缀路由在桌面版下不可达,
故本插件不再使用 `webServer.register`)。两种运行方式路径一致,浏览器面板与外部脚本以
**同源 fetch** 调用(请求可携带 `sessionId`,用于模型路由/导出目录解析)。
### GET `/api/group-chat/state` —— 快照轮询
| 字段 | 说明 |
|---|---|
| `phase` | `idle` / `generating-roles` / `discussing` / `summarizing` / `done` / `error` |
| `task` | 本次讨论任务文本 |
| `host` | 主持人 `{id:'host', name, persona, duty}`(未生成时 `null`) |
| `roles` | 专家数组 `{id, name, persona, duty}`(id 固定 `r1..rN`) |
| `messages` | 群聊消息 `{id, roleId, name, text, at, failed}`(`roleId` ∈ `host`/`user`/`r1..rN`) |
| `turn` | 已进行的调度次数(隐藏上限 60 用) |
| `allowDeepReasoning` | 成员深度推理开关 |
| `deepThinkingRoleId` | 正在调用 subagent 深度推理的成员 id(无则 `null`) |
| `moderatorBusy` | 主持人正在调度/决策 |
| `streamingRoleId` | 正在流式发言的角色 id |
| `paused` | 暂停中 |
| `summary` / `error` / `mdPath` / `mdContent` | 结论 / 错误 / 最近导出路径与内容 |
| `version` | 快照版本号(轮询去重用) |
### POST `/api/group-chat/command`
请求体:`{ action, sessionId?, ...该 action 的参数 }`。
| Action | 参数 | 说明 |
|---|---|---|
| `generate-roles` | `{ task }` | 生成 `{host, roles}`;讨论/生成中拒绝 |
| `start` | — | 开始讨论(需角色已生成) |
| `pause` / `resume` | — | 暂停(不中断 deep)/ 继续 |
| `skip` / `stop` | — | 跳过当前动作 / 停止讨论(保留历史) |
| `reroll` | `{ roleId }` | 专家重发(host 拒绝) |
| `chat` | `{ text }` | 用户插话(入历史,不打断当前动作) |
| `update-roles` | `{ roles: [...] }` | 增删改专家(仅非讨论中;主持人不可改) |
| `sync-settings` | `{ allowDeepReasoning }` | 开关深度推理 |
| `export-md` | — | 导出 md(写入会话 cwd,返回 `{path, content, cwd, error}`) |
响应:`{ ok: true, phase, version }`;错误:`{ ok: false, error }`。
## 配置
| 环境变量 | 默认 | 说明 |
|---|---|---|
| `GC_DEEP_TIMEOUT_MS` | `180000` | deep subagent 超时(ms);超时中断并回退 direct |
| `GC_MAX_MODERATOR_TURNS` | `60` | 主持人调度隐藏上限;达到后强制总结 |
引擎常量(`lib/engine.js`):`HISTORY_BUDGET=24000`(历史注入字符预算)、`DEFAULT_MAX_CHARS=900`(单条发言约值)、`MAX_FAILURE_STREAK=3`(连续发言失败中止阈值)。
## 错误处理
| 场景 | 行为 |
|---|---|
| 主持人决策 JSON 非法 | 重试 1 次;再失败回退「发言最少专家」direct 发言 |
| 主持人连续 3 次调度失败 | `phase=error`(保留已有历史) |
| 成员 plan JSON 非法 | 按 direct 回退 |
| subagent 不可用 / 失败 / 超时 | 按 direct 回退,不报错 |
| 最终成员发言失败 | 该条 `failed`,计入连续失败 |
| 连续 ≥3 次最终发言失败 | `phase=error`,保留历史 |
| 隐藏上限 60 次调度 | 强制 summarize |
| 导出失败 | 返回 `error` 字段;`mdContent` 仍可复制 |
## 开发 / 测试 / 发布
```bash
npm test # host 单测(node:test,40 项:角色生成/主持人循环/member-deep/控制语义)
bash scripts/build.sh # 依赖链接 + host 语法/导入链校验 + tsdown 打包 client
npm run build:client # 仅打包 client(tsdown → lib/client.js)
# UI 回归(Playwright;需本地 dsh web 认证 cookie):
python3 test/ui-panel-smoke.py
python3 test/ui-e2e.py
# 面板 API 迁移回归(页面上下文同源 fetch + 面板打开):
DSH_WEB_TOKEN=<dsh web 启动 URL 里的 token> python3 test/api-migration-smoke.py
# 桌面版契约离线校验(npm pack 产物 + 官方校验函数):
npm run check:desktop
# 注入器环境(DSH 开发工作流):
dev_build_plugin . && dev_inject_plugin . && dev_reload_package dsh-group-chat
# 发布:
npm publish --dry-run && npm publish # 需 @stars-w scope 权限(publishConfig.access=public 已声明)
```
- Host:纯 ESM JS(`lib/`,无编译步骤);Client:`src/client/index.js` → tsdown → `lib/client.js`(`ModuleLoader.load` 注册)。
- 注入后刷新 Web 页面,会话头部即出现「💬 群聊」。
## 文件结构
```
lib/index.js host 入口:/api/group-chat 精确 Fetch 路由(connection 共享通道)+ 动作分发 + 模型路由/导出目录解析
lib/engine.js GroupChatEngine:状态机、角色生成 {host,roles}、主持人步进循环、成员 plan/deep、总结、导出
lib/llm.js LLM 封装(llm.stream + BlockAssembler 聚合、JSON 容错提取)
cordis.patch.yml bundle 层:把本包作为 host 半 cordis 插件装配(dsh.bundle.patch 指向它)
src/client/index.js 群聊面板 UI(入口按钮 + overlay 面板 + 轮询 + 悬浮按钮 + md 渲染)
scripts/build.sh 构建脚本
scripts/desktop-compat-check.mjs 桌面版契约离线等价校验(真值调用官方 validateDesktopPluginGraph)
test/ host 单测(node:test)+ Playwright UI 回归脚本
docs/specs/ 设计规格(2026-08-28 初版 / 2026-09-05 主持人制 + 实现注记)
docs/superpowers/plans/ 实现计划(含任务勾选与验证记录)
```
## 常见问题(FAQ)
- **面板显示「已与群聊服务断开」**:插件被卸载/热重载或 DSH 重启。重载后刷新页面即可恢复。
- **讨论显示「出错」**:多为主持人/成员连续调度失败(模型瞬时输出非 JSON)。保留历史可直接导出;点「重新生成」换任务重试。
- **深度推理没触发?**:成员 plan 是轻量判断,简单问题会走 direct。可在 ⚙ 设置区关闭/开启「允许成员深度推理」;当前发言/推理中的成员不受切换影响。
- **导出的 md 在哪?**:会话工作目录(会话 `header.cwd`),面板显示相对路径;讨论完成会自动导出并回注主会话。
- **面板挡住主会话?**:按住面板头部空白区可拖动到任意位置(贴右侧恢复停靠形态);收起时悬浮按钮在内容区左上方且不遮挡内容主体。
## 版本兼容
- DSH 宿主:`>=0.1.5-rc <2`(peer 范围按 semver 预发布元组规则书写:`>=0.0.1-rc <2`
不匹配 `0.1.5-rc.2`,会直接被桌面版 `validateDesktopPluginGraph` 拒绝)。
面板 API 走 `connection` 共享 `/api` 通道的精确 Fetch 路由 + `commands`/`agents`/`subagents`
服务,**不依赖 `webServer`**——web 版与官方 Electron 桌面版(`desktop` profile)通用。
- 桌面版契约自检:`npm run check:desktop`(默认 npm pack 产物 + 官方
`apps/desktop/src/profile-packages.ts` 的真实校验函数,等价于桌面版启动时的插件依赖图校验)。
- 深层依赖(peer):见 `peerDependencies`。Deep 推理需宿主装配 `@deepseek-ai/dsh-subagent` 与 `@deepseek-ai/dsh-subagent-spawn-in-process`(provider `spawn`);缺失时自动回退 direct 发言。
## 非目标(YAGNI)
- 角色不执行通用工具(仅深度推理 subagent 一种内部能力)
- 不做持久化(插件生命周期内状态即存)
- 不做多群聊并行(一次一个群聊会话)
- 不做主持人单独编辑/删除、不做用户手动点名(可通过插话让主持人调度)
## License
[BSD-3-Clause](./LICENSE) © 2026 wy_stars
Install
dsh plugin --profile web add github:wyStars/dsh-group-chat#944ad5b5f1e9cf24f39c16ac870accd19118a6e1
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install stars-w-dsh-group-chat from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.