dsh-peak-valley-queue
Peak/valley pricing task queue for DeepSeek Harness
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 27, 2026
- Updated
- Aug 28, 2026
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.js经npm run build:client生成的模块加载器 bundle,产物已提交,安装无需构建)。 - 安装后重启 dsh 服务(bundle 层在启动时加载),并刷新浏览器页面(重新拉取插件清单)。
- 代码改动经 link 依赖随重启生效,无需重新 add。
- 开发期也可用动态方式(
cordis_define/cordis_run)加载lib/dynamic-host-body.txt/lib/dynamic-client-body.txt,无需重启;注意两种方式不要同时启用(会重复拦截)。
快速开始 / Quick start
- 安装并重启后,输入框左侧出现「峰谷排队」开关;点击开启(面板自动打开)。
- 正常在输入框发消息——消息不会直接发送,而是进入队列。
- 谷段(且距下一峰段超过 x 分钟)时队列自动按序执行;峰段则等待。
- 面板可随时:查看倒计时 / 手动添加任务 / 编辑、删除、拖拽排序、合并 / 手动「送出」/ 点「继续任务」恢复暂停。
配置说明 / 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.followup以rpcId: pvq:<taskId>派发;按消息 id 去重,授权恢复 / 循环重投递的同一条消息只消费、不重复入队。完成信号来自session/event(turn/end、assistant/message)、agent/status、agent/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