Back to home@EmptyCollin

dsh-peak-valley-queue

Peak/valley pricing task queue for DeepSeek Harness

Stars
0
Language
JavaScript
Created
Aug 27, 2026
Updated
Aug 28, 2026
GitHub repo

Introduction

dsh-peak-valley-queue

输入框左侧一个开关:打开后,聊天消息不再直接发送,而是进入任务队列;在谷段(DeepSeek API 低费率时段)自动按序派发执行。 A composer switch: when on, chat input goes into a task queue instead of being sent directly; tasks auto-dispatch in order during valley windows (DeepSeek off-peak pricing).

DeepSeek Harness 双半区插件(Host + Client):Host 拦截输入入队、按时段调度、精确判定任务完成;Client 提供开关与队列面板(状态行、时段配置、任务列表)。 A DeepSeek Harness plugin (Host + Client halves): the Host intercepts input into a queue, schedules by peak/valley windows and judges completion precisely; the Client provides the switch and the queue panel (status, window config, task list).

功能 / Features

  • 一键开关:输入框左侧「峰谷排队」按钮;开启后输入入队,关闭后消息直发。开关带队列数角标。
  • 谷段自动执行:队列按序(FIFO,可拖拽改序)派发;距下一峰段超过 x 分钟 才自动执行(余量保护)。
  • 峰谷双向倒计时:谷段显示「距下一峰段」,峰段显示「距下一谷段」。
  • 可配置峰段列表:默认 DeepSeek 官方规则(工作日 09:00–12:00 / 14:00–18:00 为峰段,其余为谷段);时段可增删、支持重叠;可设周末是否算峰段、时区(本机 / 固定偏移);清空列表 = 全天谷段。
  • 队列管理:面板直接添加任务;编辑 / 删除 / 拖拽排序 / 合并相邻任务 / 手动「送出」;执行中可「强制完成」兜底。
  • 精确完成判定(4 态):按轮次生命周期区分 已完成后移除 / 被打断(取消、输出截断)/ 失败 / 阻塞;多信号冗余(turn/end + 空闲 + watchdog + 客户端轮询),任一事件漏发都不会卡住队列。
  • 待确认任务(dsh-todo 集成):回复中含 <!-- dsh-todo:start --> 决策清单标记时,任务不判完成,转为「待确认」并暂停队列,等待用户决策(配套安装 dsh-todo-enhancer 提供清单面板);「继续任务」不会自动重跑待确认任务。
  • 失败暂停 + 恢复:失败 / 打断 / 阻塞时队列暂停并提醒(浏览器系统通知 + 可选自定义命令,每 30 分钟重复);点「继续任务」清暂停并按序重排;暂停期间新输入照常入队,绝不静默丢弃。
  • 严格完成校验(可选):派发时注入完成约定,要求回复末尾输出 __TASK_DONE__;未检测到则视为未完成。
  • 多会话独立队列:每个会话(含不同工作区的会话)都有各自的开关与队列,互不干扰、各自持久化(状态文件按会话 id 分文件)。
  • 本地持久化:队列与配置写入 DSH 数据目录 ~/.dsh/peak-valley-queue/$DSH_HOME 优先),绝不写入用户工作区文件(Web 工作区根目录常是桌面);会话归属锁定 owner.json

使用场景 / Use cases

  • 压低 DeepSeek API 成本:把不紧急、可延后的任务(批量改写、批量摘要、巡检清单、报表生成)攒到谷段统一执行,享受低费率。
  • 峰段高峰期自动排队:工作日上午 / 下午高峰时段的输入先入队,谷段一到自动按序执行,无需人工值守。
  • 批量任务保持顺序:多轮任务按队列顺序串行执行,避免并发串扰、保证上下文连贯。
  • 失败可见、可控重试:任务失败自动暂停并通知,人工确认「继续任务」后才重排,不会无限重跑。
  • 长任务安全:没有强制超时 / 强制移除,任务跑多久都可以;空闲兜底只清理「代理已空闲但完成信号未到」的卡死。

不适用场景 / When NOT to use

  • 需要立即回复的实时对话:排队会延迟响应(除非手动「送出」)。
  • 高峰期的紧急任务:会一直等到谷段才自动执行。
  • 强交互式调试:每一步都要立刻看到模型输出再继续的流程,不适合无人值守的队列。
  • 依赖实时人工确认的任务:队列在谷段自动派发,没人盯着也会执行。
  • 需要消息留在聊天区的场景:消息一旦入队即归队列所有,聊天区不会出现该消息(这是拦截设计的预期行为;若希望消息留在聊天区,请关闭开关)。

安装 / Install

本包自带 dsh.bundle 补丁(cordis.patch.yml),一条命令即可安装并自动加入 profile 的 bundle 层:

dsh plugin --profile <profile名> add <本包路径>

例如:dsh plugin --profile web add D:\dsh-plugin\dsh-peak-valley-queue

  • Host 半区:lib/index.js(注册 /pvq/* HTTP 路由);Client 半区:lib/client.bundle.js(由 lib/client.jsnpm run build:client 生成的模块加载器 bundle,产物已提交,安装无需构建)。
  • 安装后重启 dsh 服务(bundle 层在启动时加载),并刷新浏览器页面(重新拉取插件清单)。
  • 代码改动经 link 依赖随重启生效,无需重新 add。
  • 开发期也可用动态方式(cordis_define / cordis_run)加载 lib/dynamic-host-body.txt / lib/dynamic-client-body.txt,无需重启;注意两种方式不要同时启用(会重复拦截)。

快速开始 / Quick start

  1. 安装并重启后,输入框左侧出现「峰谷排队」开关;点击开启(面板自动打开)。
  2. 正常在输入框发消息——消息不会直接发送,而是进入队列。
  3. 谷段(且距下一峰段超过 x 分钟)时队列自动按序执行;峰段则等待。
  4. 面板可随时:查看倒计时 / 手动添加任务 / 编辑、删除、拖拽排序、合并 / 手动「送出」/ 点「继续任务」恢复暂停。

配置说明 / Configuration

面板「时段与配置」区:

配置说明
峰段时段列表增删时段(支持重叠);+ 时段 添加,行尾 删除;清空 = 全天谷段
周末也算峰段关闭(默认):工作日才按时段计算峰谷
本机时区默认按本机时间计算;可改为固定 UTC 偏移
执行余量 x 分钟距下一峰段超过 x 分钟才自动执行,防止任务刚派发就撞上峰段
严格校验开启后要求回复末尾输出 __TASK_DONE__ 才算完成
暂停通知 / 浏览器通知暂停时浏览器系统通知(授权一次),每 30 分钟重复
自定义命令暂停时在沙箱内执行的可选命令(如弹窗提醒),失败只记日志

时段改动若导致「峰段 → 谷段」翻转且队列非空,会弹窗确认(避免误触发批量执行)。

任务状态判定 / Task lifecycle

以轮次生命周期(turn/end reason:completed | aborted | error | max-tokens | blocked + agent/error)精确区分;完成判定为冗余多信号turn/end 精确原因 + agent/status→idle + turn-stopping + 10s watchdog + 客户端 10s 轮询兜底),任一事件漏发都不会让任务卡在「执行中」。

状态含义处理
进行中已派发,turn 未结束队列顶部显示「执行中…」,不派发下一个
已完成有回复 / completed从队列移除(结果在对话里)
打断aborted / max-tokens / blocked插回队列标记「打断」并暂停
失败error 且无任何回复插回队列标记「失败」并暂停

工作原理 / How it works

  • Host:监听 agent/inbox/inserted 拦截用户输入(inbox.remove + 入队),用 agent.followuprpcId: pvq:<taskId> 派发;按消息 id 去重,授权恢复 / 循环重投递的同一条消息只消费、不重复入队。完成信号来自 session/event(turn/end、assistant/message)、agent/statusagent/turn-stopping
  • Client:注册 conversation.input.left(开关)与队列面板(有 sidebar tab 能力则注册页签,否则 shell.overlay 自建浮动侧边板);1s 轮询 get-state 刷新状态;RPC 走 POST /pvq/<method>(动态形式走 host.call)。
  • 面板 / 开关 / 样式全部随插件卸载自动回收。

目录结构 / Structure

cordis.patch.yml      # dsh.bundle 补丁:把本包插入 profile 的 bundle 层
lib/
  index.js            # Host 静态入口(webServer 路由 /pvq/*,导出 { name, inject, apply })
  client.js           # Client 静态入口(import React + fetch RPC)
  client.bundle.js    # Client bundle(__ModuleLoader__ 自注册,由 client.js 生成,产物已提交)
  host-core.js        # Host 核心(纯 JS,动态/静态共用)
  client-core.js      # Client 核心(纯 JS,动态/静态共用)
  dynamic-host.js / dynamic-host-body.txt   # 动态运行器 Host 函数体(cordis_define 用)
  dynamic-client.js / dynamic-client-body.txt # 动态运行器 Client 函数体
scripts/
  build-dynamic.mjs   # 由 host-core/client-core 重新生成动态体
  build-bundle.mjs    # 由 client-core 生成 lib/client.bundle.js
  compact-dynamic.mjs # 生成去注释 compact 体(cordis_define 传输用)
  smoke-host.mjs      # Host 核心回归(mock ctx/agents,78 项)
  smoke-bundle.mjs    # Client bundle 冒烟(槽位注册 / 侧边板迁移)

开发 / Development

npm run check    # 语法检查(全部入口 node --check)
npm run build    # 重新生成动态体 + client bundle + 冒烟
npm run smoke    # 仅跑冒烟(smoke-bundle + smoke-host)

License

MIT