dsh-qq-email:在 DSH 里用已授权的 agently-cli 发 QQ 邮件

前言

在 DeepSeek Harness(DSH)里做智能体时,常见需求是「对话里说一句,帮某人发一封邮件」。若自己对接 QQ 邮箱 OAuth、再拼发送逻辑,工作量大,且确认与安全边界容易不一致。本插件 dsh-qq-email(维护者 altmanWang,分类:联网工具)把发送逻辑集中在 Cordis 服务层,复用本机已授权的 agently-cli,同时提供 Agent 工具 send_qq_email 与 ctx.qqEmail 供其他插件调用;插件本身不保存 OAuth 凭据。

这是什么

一句话:dsh-qq-email 用已授权的 agently-cli 发 QQ 邮件,一个 npm 包两种入口——服务 ctx.qqEmail(service.js)给其他插件 inject: ['qqEmail'] 使用;工具 send_qq_email(tool.js)供对话里直接说「给 xxx 发封邮件」。发送逻辑只在服务层实现一次,工具只做参数翻译;两行插件可在 cordis.patch.yml 里独立开关。

当前版本(资料来源 package.json):0.1.0,许可证 MIT,DSH 引擎要求 0.2.x(见 engines.dsh)。

核心功能

  • 对话发信:模型调用 send_qq_email 后,DSH 弹出确认卡(发件人 / 收件人 / 抄送 / 密送 / 主题 / 正文预览),用户点「批准」后才发送。
  • 插件内发信:ctx.qqEmail.send(...);也可自管确认 UX:prepare() 只拿确认令牌、不会发信,用户许可后再 commit()。
  • 默认 fail-closed:没有批准、没有确认入口、没有 confirmedByCaller 都不会发送。
  • 账号与额度:ctx.qqEmail.account() 可查当前授权账号与额度(默认缓存 60 秒)。
  • 能力边界:只发送,不读信、不回复、不转发、不带附件;需要更多能力请直接用 agently-cli。

前置条件

  1. Node.js ≥ 22.19(DSH 运行环境自带)。
  2. DSH 0.2.x。
  3. 本机安装并授权 agently-cli:
npm install -g @tencent-qqmail/agently-cli
agently-cli auth login
agently-cli +me        # 能打印出邮箱地址即授权成功

令牌由 agently-cli 自行管理(Windows 上为 DPAPI),插件以当前进程身份调用 CLI。

安装与启用

发布到 npm 后:

dsh plugin --profile web add dsh-qq-email

从 GitHub 安装(纯 JS,无构建步骤,不需要 allowBuilds):

dsh plugin --profile web add github:altmanWang/dsh-qq-email

本地开发目录:

dsh plugin --profile web add /绝对路径/plugin/dsh-qq-email

装完重启 dsh web(或刷新页面);Web UI 插件页应能看到服务与工具两行。

典型用法

在对话里

直接说明收件人、主题、正文与抄送,例如:

帮我给 alice@qq.com 发一封邮件,主题「项目进度同步」,正文「本周已完成 X,下周计划 Y」;抄送 bob@qq.com。

模型调用 send_qq_email 后出现确认卡,仅「批准」后发送。

在其他插件里

// 你的插件入口
export const inject = ['qqEmail']

export function apply(ctx) {
  // 1) 最常用:完整流程。传 agent 上下文时,服务会弹出确认提示,用户批准后才发送。
  const sent = await ctx.qqEmail.send(
    { to: 'alice@example.com', subject: '周报', body: '见附件' },
    { agent, callId, signal },
  )

  // 2) 自己管确认 UX(例如在 IM 频道里问):先预检,用户点头后再提交。
  const pending = await ctx.qqEmail.prepare({ to: 'a@qq.com', subject: 'Hi', body: '你好' })
  // …向用户展示 pending.summary / pending.request,拿到许可…
  const sent2 = await ctx.qqEmail.commit(pending, { signal })

  // 3) 查当前授权账号与额度(默认缓存 60 秒)
  const { email, scopes, rateLimits } = await ctx.qqEmail.account()
}

agent 须为完整 DSH Agent 对象(如工具里的 exec.agent);prepare() + commit() 时确认责任在调用方。

TypeScript 可在插件内自行增强 Context(types.d.ts 不引用 @deepseek-ai/*):

import type { Context } from '@deepseek-ai/cordis'
import type { QqEmailService } from 'dsh-qq-email/types'

declare module '@deepseek-ai/cordis' {
  interface Context { qqEmail: QqEmailService }
}

配置

CLI 入口按顺序解析,第一个存在的生效:

  1. 环境变量 DSH_QQ_EMAIL_CLI(指向 .../agently-cli/scripts/run.js 的绝对路径)
  2. 插件 config 的 cliEntry(在 profile patch 里给该行加 config:)
  3. 各平台 npm 全局前缀推导(Windows / POSIX 常见路径,见 README)

示例(profile 的 cordis.patch.yml):

# profile 的 cordis.patch.yml
- id: qq-email-service
  name: dsh-qq-email
  config:
    cliEntry: C:\Users\me\AppData\Roaming\npm\node_modules\@tencent-qqmail\agently-cli\scripts\run.js

确认与安全

  • 两道确认:CLI 的 prepare(ctk_* 令牌)+ commit 发送,以及 DSH 的 approval;工具路径必须在界面点「批准」。
  • 确认前不可变:prepare() 返回的 request 被深度冻结,确认卡与实际发送同源数据。
  • 正文经 argv 传给 CLI,可能出现在本机进程命令行(同用户可读);Windows 命令行长度有限,超长会报 QQ_EMAIL_ARGS。
  • 发送阶段被取消或超时,结果未知,错误信息会提示先查「已发送」,勿直接重试;确认令牌默认 5 分钟,批准过久时 send() 会用同一请求重新预检再发。

错误处理请按 error.code 分支:QQ_EMAIL_ARGS、QQ_EMAIL_CLI_MISSING、QQ_EMAIL_CLI_FAILED、QQ_EMAIL_NOT_CONFIRMED、QQ_EMAIL_UNEXPECTED。

限制与适用注意

  • 主题 UTF-8 约 4 KB;正文最多 20000 字符;收件人(to+cc+bcc)最多 50 个;同一地址不能同时在 cc 与 bcc。
  • 工具路径必须由用户在 DSH 里确认;无头/自动化请用带 confirmedByCaller: true 的插件调用路径,并自行负责确认。
  • 插件以当前 dsh 进程权限运行,安装前建议阅读仓库源码与 MIT 许可证;社区目录 SkillHub 插件页 为独立站点,与 DeepSeek / 幻方无官方从属关系。

结尾

dsh-qq-email 把 QQ 发信接到 DSH 的确认模型与 Cordis 生态里:对话用工具、编排用服务,凭据留在 agently-cli。进一步了解与 issue 见 GitHub:altmanWang/dsh-qq-email,目录页见 SkillHub。

羽毛球分组比赛记分
小程序二维码

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

Xiaoye