前言¶
在构建基于 DeepSeek Harness (DSH) 的智能体时,接入外部渠道(如 QQ、Telegram 或邮件)通常需要编写大量协议适配代码,且难以统一管理。dsh-message-hub 作为一个中转插件,提供了一个传输无关的通信中心。它通过统一的“渠道注册表”将入站和出站逻辑解耦:宿主插件负责具体的协议实现(如连接 QQ),而 Hub 负责路由、绑定状态和与 Agent 的交互。
本插件由 FuLuTang 维护,采用 MIT 许可证。
核心功能¶
该插件主要解决多渠道消息的统一接入与路由问题,核心能力包括:
- 渠道注册表:提供入站 和出站 的注册接口,支持 Web API 集成。
- 固定 Agent 工具:提供
message_hub_list_channels、send、bind、status等固定工具,方便 Agent 查询和管理渠道。 - 唤醒模式:支持
steer(插话)和followup(排队)两种模式,控制外部消息如何进入 Agent 上下文。 - 文件适配器:内置
file-spool适配器,支持通过共享目录或 Docker Volume 进行跨进程通信。
安装与启用¶
安装前请确保环境满足 Node.js 版本要求(>=22)。
- 使用官方插件安装器添加插件到 Web profile:
dsh plugin --profile web add github:FuLuTang/dsh-message-hub
- 安装完成后重启 DSH Web 服务,并强制刷新浏览器页面(以加载新的 client bundle)。
配置¶
在 DSH 的 YAML 配置中声明插件实例。channels 仅用于声明元数据和初始开关,实际的运行时实现由受信任的插件代码注册。
- id: dsh-message-hub
config:
storagePath: '' # 默认为 $DSH_HOME/message-hub/state.json
maxLedgerEntries: 2000
wakeupMode: steer # 全局默认唤醒方式:steer=插话 / followup=排队
channels: [] # 声明式渠道元数据
spools: [] # file-spool 配置
outlets: [] # file-spool 出站路由
渠道注册表¶
在 DSH 运行时,通过 Agent 的 ctx 访问 messageHub 进行注册。
注册入站与出站¶
// 注册入站:接收消息
await ctx.messageHub.registerIngress({
id: 'telegram-in',
name: 'Telegram 入站',
description: '接收 Telegram 更新',
template: '来自 {{sender}}:{{text}}',
wakeup: true,
setEnabled: async (enabled) => { /* 启停传输实现 */ }
});
// 注册出站:发送消息
await ctx.messageHub.registerEgress({
id: 'telegram-out',
name: 'Telegram 出站',
description: '发送一条 Telegram 消息',
schema: { type: 'object', required: ['chatId', 'text'] },
setEnabled: async (enabled) => { /* 启停传输实现 */ },
async invoke(args, { deliveryId, sessionId }) {
return { success: true, message: 'sent' }
}
});
状态与开关¶
每个渠道维护两种状态:
* desiredEnabled:用户通过 Web API 或配置要求的开关。
* light:实现报告的运行状态灯(black、yellow、green)。
Agent 工具¶
插件为 Agent 提供了一组固定的工具,用于查询和管理渠道:
| 工具名 | 参数 | 用途 |
|---|---|---|
message_hub_list_channels |
无 | 列出渠道 ID、方向、开关、状态灯和详情。 |
message_hub_describe_channels |
channelIds?: string[] |
查询指定渠道(默认查询所有 egress)的说明和参数 Schema。 |
message_hub_send |
channelId, arguments |
校验参数后调用 egress 发送消息。 |
message_hub_bind / unbind |
channelId, sessionId |
绑定或解除当前对话与旧式 adapter 的关系。 |
message_hub_status |
无 | 查看完整快照(含渠道、绑定、投递记录)。 |
message_hub_read_input |
无 | 读取 file-spool input/ 目录下的 UTF-8 文件(最大 64 KiB)。 |
入站绑定与唤醒模式¶
绑定流程¶
通过 bindIngress(channelId, sessionId, options) 将入站消息绑定到特定的 DSH session。
绑定配置支持:
* template:覆盖默认消息模板。
* wakeup:是否在注入消息后唤醒 Agent(默认开启)。
* wakeupMode:覆盖全局设置。steer 模式下消息作为 next-step 输入插话;followup 模式下消息排队进入下一个独立轮次。
* cwd:替代会话工作目录。
投递语义¶
当 emitIngress(channelId, event) 触发时,Hub 会执行以下步骤:
1. 检查开关和绑定状态。
2. 解析目标 session。若 session 不可用且绑定包含 cwd,Hub 会创建替代会话;否则保留失败结果。
3. 向 Agent 注入两条消息:不可信的外部上下文说明和渲染后的 <external-message> 内容。
4. 根据 wakeupMode 唤醒 Agent(旧版运行时若不支持 steer() 会自动降级为 followup)。
Web API 与客户端¶
启用 Web runtime 时,插件在本地注册前缀 /message-hub/api,仅接受受信任的 localhost 请求。
POST /message-hub/api/snapshot:获取渠道快照(含defaultWakeupMode)。POST /message-hub/api/toggle:修改渠道的desiredEnabled。POST /message-hub/api/bind:绑定 ingress 或 file-spool 到 session。
Web 客户端会自动在设置界面展示“消息渠道”卡片,每 5 秒刷新一次状态,显示渠道方向、轮询灯(绿=轮询中,黄=失败,黑=停止)及绑定信息。
File-spool 适配器¶
对于需要共享目录或跨语言脚本通信的场景,可以使用内置的 file-spool 适配器。它不是 channel registry 的一部分,而是作为独立的输入/输出通道。
配置示例¶
spools:
- id: volume-main
label: 共享目录
root: /mnt/message-device
enabled: true
ackMode: delete # delete | keep
pollMs: 1000
maxBytes: 262144
payloadFile: input/message.json
payloadFormat: json
outlets:
- id: panel-notify
spoolId: volume-main
endpointId: panel
enabled: true
目录布局¶
- root/:根目录。
- input/message.json:入站触发文件。
- output/:出站投递目录。
- .tmp/:临时文件。
- ack/:外部程序写回的确认文件。
- .message-hub/processed/:已处理的触发文件。
- status.json:可选的 endpoint 状态快照。
行为说明¶
- 入站:轮询
root下的触发文件(非特殊目录)。成功排入绑定 session 后,根据ackMode移动或保留文件。 - 出站:写入
output/<deliveryId>.json。外部程序应在output/ack/<deliveryId>.ack.json中确认发送结果。 - 轮询灯:面板上的灯仅反映当前进程的轮询状态,不改变配置文件。
注意事项¶
- 单实例限制:同一个
storagePath下只能运行一个 Hub 实例。 - 协议实现:Hub 本身不实现 QQ、Telegram 等协议,仅注册它们。具体的连接逻辑由宿主插件负责。
- 包格式:必须使用
dsh plugin安装命令,确保包被正确加入 profile 的 bundle 列表,单纯npm install不会生效。 - Node 版本:最低要求 Node.js 22。
总结¶
dsh-message-hub 为 DeepSeek Harness 提供了标准化的通信接口。开发者可以通过注册 Ingress 和 Egress 将任意协议接入 Agent 生态,利用固定的 Agent 工具或 Web API 进行管理。配合 file-spool 适配器,它可以轻松实现与外部脚本或系统的文件交换。