dsh-goal-budget:给 DSH 目标设预算,超了就停

前言

DSH 生态里已经有不少插件能告诉你一个目标花了多少钱、多少 token,但这类插件大多到此为止:只读,只展示。长任务真正缺的是下一步——当预算用尽时把目标停下来,而不是让它继续自动续跑。boom-10 维护的 dsh-goal-budget 补的就是这一步:把会话消耗归因到目标,超限后调用官方策略入口阻断目标。下面介绍它实际做了什么,以及怎么装、怎么用。

这是什么

一句话定位:给 DSH 的长任务目标设一个 token / 费用(以及计算时间)上限,超了就停,不是只报一个数字。

基本信息来自 README 与 package.json:

  • 插件名:dsh-goal-budget
  • 维护者:boom-10
  • 分类:工作流
  • Star:0
  • 版本:0.10.2,license MIT
  • 运行要求:Node ≥ 22,DSH >=0.2.1-rc.5 <0.3.0

这个缺口在 DSH 自带代码里被明确承认过。goal-round-driver 的 README 写着:它的轮次上限不是资源预算,token、货币、时间等策略各自独立,会话事件「不会归因到目标消息」「不会被映射成目标的阻断码」。本插件补上三块:按 goalId + round 做归因,给出树内第三个阻断码 budget-exceeded,并在 0.8.0 加入计算时间预算。

核心功能

目标维度的归因

插件不自己存一份账。它从会话事件日志重建归属关系:agent/inbox/claimed 是唯一把消息和它开启的 turn 配对的事件,assistant/message 携带 turn 和 usage;据此把每个 turn 的消耗累加到对应的 {goalId, round} 上。重启不会重复计费,也不会清零。

阻断而非告警

预算超限时,插件调用 ctx.goals.block(),在一次调用里标记目标 blocked 并解除自动续跑。阻断原因是一个稳定的 code 加一段可读说明,例如 budget-exceeded。可选配置 onExceed: block | warn,warn 模式只记日志不阻断。

展示与判定同源

输入框状态条里多出一个 pill,点开是花费明细。pill 不自己算钱,读的是与阻断判定同一个投影,因此界面上的数和闸门用的数不会分歧。显示分两种状态:未设上限时面板提示怎么设;设了之后标题栏右侧出现使用百分比,pill 上长出进度条,80% 转琥珀,100% 转红。

计算时间预算

除了 token 和费用,还可以设计算时间上限。时长 = 各轮跨度之和(每轮从 turn/start 到最后一个 turn/end),而不是 now - 创建时间,所以目标暂停隔夜不会误爆预算;代价是轮间的空闲不计入。时间只用 SessionEvent.time,不用 Date.now(),重放同一份日志得到同一个数。它是 0.8.0 加入的,pill 上暂时不显示时间。

安装与启用

安装命令来自 README 原文,两条等价,按你的 registry 选:

dsh plugin --profile desktop add dsh-goal-budget                 # npm 源
dsh plugin --profile desktop add github:boom-10/dsh-goal-budget  # GitHub 源

装完重启 DSH(客户端和宿主半边都在启动时加载)。两点注意:

  • 如果本机默认 registry 是公司内网代理且还没同步到这个包,add dsh-goal-budget 会报 ERR_PNPM_NO_VERSIONS,改用 GitHub 源即可。
  • 带版本号的形式在两种源上都不可用,不要写 ...@0.10.0。

在开放插件市场里搜 Goal Budget 也可以装(已收录)。不配任何预算也能装——插件加载后空转,等你用 /budget 设值。

配置与用法

会话内设上限

直接在输入框打命令,不改 YAML、不重启:

/budget            查看当前生效的上限和已用量
/budget $5         本会话费用上限 5 美元
/budget 500k       本会话 token 上限 50 万
/budget $5 500k    两个都设,谁先到算谁
/budget $5 30min   费用和计算时间都设,支持 s / min / h
/budget off        清掉会话覆盖,回到 profile 默认

时间单位用 min 而不是 m,因为 m 已被用来表示百万 token。预算按「会话覆盖 ?? profile 默认」解析:固定额度写在配置里,临时收紧在输入框打一行。

profile 默认

给所有会话一个固定额度的 YAML 配置如下,字段带注释:

- id: dsh-goal-budget
  config:
    budget:
      tokens: 2000000
      costUsd: 5.00
    onExceed: block        # 或 'warn',只记日志不阻断
    warnAtRatio: 0.8
    currency: auto                       # auto:用 DeepSeek 余额接口识别(官方线路);网关线路写 USD 或 CNY
    deepseekCredentialRef: DEEPSEEK_API_KEY   # 凭据服务里的 Key 引用名
    modelAliases: {}                     # 网关给模型改名时映射,例如 cm-ais/deepseek-v5-flash: deepseek-flash
    peakPricing: false                   # 官方线路 true;网关按固定单价计费时 false(否则高峰时段高估一倍)

两层界面的设计理由是:预算是运行时决策,插件配置是启动时读的部署决策;把预算只放在配置里,改一个临时值就得改 YAML 加重启。会话级预算配会话级界面,就是 /budget 存在的原因。

与其他用量插件的区别

生态里报花费的插件已经饱和,且全是只读的,例如 @kenz1117/dsh-ui-usage-billing(账单看板,95 星)、dsh-credits(跟踪余额与套餐)、dsh-composer-balance(显示余额)。它们回答「我花了多少」。本插件回答「该不该继续」,并把这个答案执行下去。

适用场景与注意

适合需要给长任务目标加硬预算、不希望烧穿额度自行停止的用户,尤其是配置了目标自动续跑的场景。README 也列出了已知失败模式,需要按预期理解:一轮里若混入人类消息和目标消息,人类的消费可能被记到目标上导致过早阻断,缓解办法是严格过滤 source.kind === 'goal'。

插件以当前 DSH 进程的权限运行,会在你启动的会话里读取事件、注册命令并调用阻断入口。安装前建议先读源码(许可证为 MIT)确认行为符合预期,尤其是计划把它作为部署默认策略时。

结尾

dsh-goal-budget 的价值在于把「预算超限」从一个数字变成一个动作:让目标停下,而不是继续烧。它复用 DSH 既有的事件与命令机制,不另起账本,界面与判定共用同一份投影。如果需要更细的归因规则或新增预算维度,建议从源码入手。

  • 目录页:https://www.skillhub.cn/plugins/boom-10/dsh-goal-budget
  • 源代码:https://github.com/boom-10/dsh-goal-budget
羽毛球分组比赛记分
小程序二维码

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

小夜