dsh-channel-gateway:把 Telegram 与微信收进同一套 DSH 消息契约

前言

在 DeepSeek Harness(DSH)里接 Telegram 或微信,常见做法是各自写一套 webhook、鉴权和消息解析,业务插件再分别订阅不同事件。通道一多,去重、回复路由和「谁可以说话」的边界容易散落在各适配器里。dsh-channel-gateway 把传输层收成一层:适配器把各平台流量规范成同一条入站契约,网关在传输边界做授权并统一抛出 channel/inbound,消费方用入站消息携带的 route 经 ctx.channels.send 回话。下面按资料说明它是什么、怎么装、怎么用,以及启用时要注意的点。

这是什么

dsh-channel-gateway 是社区维护者 wowyuarm 发布的 DSH 插件包,npm 名为 @wowyuarm/dsh-channel-gateway(当前资料中的版本为 0.1.3)。它在 SkillHub 目录分类为 admin-security;GitHub 独立仓库已归档,后续开发在 monorepo wowyuarm/dsh-plugins 的 packages/channel-gateway,已发布的 npm 包路径不变。

插件只负责聊天集成里的「传输半层」:固定消息契约,以及 provider 与 consumer 之间的接缝。消息语义、是否已处理、下一步路由由上层决定。

消息契约与网关 API

公开 API 刻意保持小而稳定,共五类表面(字段细节见仓库 docs/architecture.md):

表面 形态
入站 InboundMessage:channel、providerMessageId、actor、place、visibility、text、可选 attachments、timestamp、可选 replyTo/raw
出站 OutboundMessage:channel、route、text、可选 attachments/replyTo/format
传输 Channel:name、capabilities、start(inbox)、stop()、send(message)、可选 resolveAttachment
网关 ctx.channels.register(channel)、ctx.channels.send(message)、ctx.channels.resolveAttachment、事件 channel/inbound
授权 ChannelAuth { authorize(request) },默认 allowlist

契约里有三块是 consumer 需要、而 provider 原生 payload 往往给不齐的:actor / place / visibility(谁、在哪、对谁可见)、providerMessageId(去重与持久化接受)、以及 place.route(通道 mint 的不透明目的地;回复时原样作为 OutboundMessage.route,上层不必拼 provider 地址)。

核心功能

网关与授权

安装 bundle 后会插入 gateway 服务行。入站消息经网关授权后,以单一类型事件 channel/inbound 通知订阅者;出站统一走 ctx.channels.send。

谁可以说话由 gateway 行 的配置决定,而不是各 adapter 的 token 配置:

- id: channel-gateway
  config:
    allow:
      - telegram:123456789   # 某通道上的单个 actor
      - weixin:*             # 某通道上全部 actor
      # - '*'                # 所有人

allow 为空则谁也不准入。

通道适配器(可选行)

各平台以独立 DSH 行启用,需各自凭证:

适配器 传输 入口包名 说明
Telegram Bot API 长轮询 getUpdates @wowyuarm/dsh-channel-gateway/telegram 文本与媒体;附件可本地 data 或 provider ref/url;resolveAttachment 可下载入站附件字节;format: 'markdown' 按 Telegram HTML 渲染;config.token 缺省时可读环境变量 DSH_TELEGRAM_TOKEN
微信 iLink 长轮询 ilink/bot/getupdates @wowyuarm/dsh-channel-gateway/weixin 文本与媒体;回复需引用入站 context_token(微信约两分钟后过期,适配器会在过期前刷新);format: 'markdown' 为消毒后的微信 Markdown;媒体上下行按参考 iLink 协议实现,资料注明尚未在真实账号上完整验证;QR 登录未实现,需已有 token

两个适配器支持 HTTPS_PROXY / NO_PROXY(Node 自带 fetch 默认不读代理,除非设置 NODE_USE_ENV_PROXY)。

安装与启用

官方安装命令(来自 README):

dsh plugin add @wowyuarm/dsh-channel-gateway --profile <profile>

在 profile 里按需插入 adapter 行,例如:

- insert:
    - id: channel-telegram
      name: '@wowyuarm/dsh-channel-gateway/telegram'
      config: { token: '<bot token>' }
    - id: channel-weixin
      name: '@wowyuarm/dsh-channel-gateway/weixin'
      config: { token: '<iLink bot token>' }

运行环境要求 Node >=22。与 DSH 的耦合仅通过 peer 依赖 @deepseek-ai/cordis(^4.0.1)与 @deepseek-ai/schemastery(^3.18.1);资料中在 DSH 0.1.5-rc.3(latest)与 0.1.7-rc.x(next)上做过 typecheck、测试与构建验证。

典型用法:订阅入站并回复

消费方插件声明 inject: ['channels'],监听 channel/inbound,按 (channel, providerMessageId) 去重并持久化接受后,用入站 place.route 回消息:

import type { Context } from '@deepseek-ai/cordis'
import type {} from '@wowyuarm/dsh-channel-gateway'

export const name = 'my-ingress'
export const inject = ['channels']

export function apply(ctx: Context) {
  ctx.on('channel/inbound', (message) => {
    // Deduplicate on (message.channel, message.providerMessageId), accept it
    // durably, route it.
    void handle(message)
  })
}

async function handle(message: InboundMessage) {
  // ... later, answer it:
  await ctx.channels.send({ channel: message.channel, route: message.place.route, text: 'ok' })
}

适用场景与注意

适合需要在 DSH 内统一接 Telegram Bot 与微信 iLink、且希望授权与入站事件在一处收口的多通道机器人或 ingress 插件。若你只做单一平台且不需要共享契约,可直接用各平台 SDK;若需要网关 allowlist 与 route 抽象,这一包更对口。

启用前请自行阅读源码与 MIT 许可证;插件与 DSH 进程同权限运行,token 与 allow 配置相当于把谁能触发你的 agent 写在 profile 里。微信适配器在资料中明确标注媒体路径与 live 账号验证仍有限制;独立仓库已只读,issue 与 PR 应指向 monorepo。

DSH 生态是「一切皆插件」;SkillHub 等社区目录与 DeepSeek / 幻方无官方从属关系,本文仅基于公开 README 与 package 元数据。

链接

  • 目录页:https://www.skillhub.cn/plugins/wowyuarm/dsh-channel-gateway
  • GitHub(归档):https://github.com/wowyuarm/dsh-channel-gateway
  • 后续开发:https://github.com/wowyuarm/dsh-plugins(packages/channel-gateway)
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye