dsh-session-guard
August 30, 2026 · View on GitHub
高峰自动会话门:周末模式 + 高峰自动暂停 + 会话级冻结 + 后端自动重试
dsh-session-guard
- English README
- 中文 README
- 日本語 README
- 한국어 README
- Installation guide
- 中文安装指南
- 日本語インストールガイド
- 한국어 설치 안내
- Changelog
- 日本語 changelog
- 한국어 changelog
兼容性说明: v0.1.1 已包含日语(
ja)和韩语(ko)字典,但当前官方 DSH 只通过LocaleRuntime提供zh和en。在原版 DSH 中选择ja或ko会失败,并提示locale "<id>" is not registered。需要等待官方 DSH 增加对应 locale ID 后才能正常使用。高级用户可以维护 DSH fork 进行扩展。
高峰时段自动暂停运行中的会话、低峰/周末自动续跑;配合 input-traffic 的冻结按钮做到会话级锁定;后端自动重试在冻结/门控期间让路。核心基于自研会话门(
agent.cancel keepInbox + goals.pause + session/event 安全边界 + followup 续跑),不再依赖 dsh-task-control。
无需修改 dsh 源码、无需提 PR:dsh plugin 命令组装 + bundle patch 装配的 cordis 插件。
💡 为什么推荐:DeepSeek 已于 2026-08-17 实行峰谷计费——高峰时段(北京时间 9:00-12:00、14:00-18:00)单价为闲时(含午间、夜间、周末与节假日)的 2 倍。本插件在高峰自动停住运行会话、退峰自动续跑,错峰长跑最多可省 50%;手动冻结(配 input-traffic 按钮)可进一步按会话精确控停。
功能一览
- 周末模式:识别周末(基于配置时区
Intl.DateTimeFormat,不踩裸getUTCDay()的北京边界 8 小时 bug)→ 周末无视峰谷、畅快跑。 - 高峰自动暂停(全局):进入高峰(且非周末)时,对所有 running root session 自动暂停;退峰自动恢复全部——全局开关,无需手动。
- 会话级冻结 / 恢复:
sessionGuard冗余端口 +POST /session-guard/rpc,input-traffic 冻结按钮逐会话透传接入;也提供/pause /resume /cancel手动命令。 - 后端自动重试(D9):turn/end 瞬时失败(error/429/max-tokens)自适应退避自动续跑;永久失败停止;冻结/门控期间让路,绝不绕过会话门。
- fail-open:自研会话门不可用、session-guard 未装、设置服务缺失——均静默降级,绝不因依赖而崩。
界面预览
实际运行截屏(Windows,dsh web)——周末模式激活状态:
安装
dsh plugin --profile web add github:<owner>/dsh-session-guard
装后重启 dsh web 并刷新页面。
设置(设置 → 插件 → session-guard,简单开关)
| 开关 | 默认 | 说明 |
|---|---|---|
enabled | on | 高峰自动暂停冻结会话:高峰时段自动暂停运行会话 |
offPeakAutoResume | on | 低谷自动恢复:低峰时段自动恢复被暂停的会话;关掉则退峰不自动恢复(需手动) |
weekendMode | on | 周末模式:识别周末 → 周末不自动暂停(周末本无高峰,畅快跑) |
queueFallback | on | 自研会话门不可用时回退锁等待队列(fail-open) |
retryEnabled | off | 自动重试(后端):瞬时失败自动续跑(默认关,保守) |
附属配置:
timezone(默认 Asia/Shanghai)——周末判定和徽标显示用的时区;不影响峰谷判定(峰谷固定按北京时间);peakWindows(默认 09:00–12:00 / 14:00–18:00)——按北京时间(UTC+8)的峰谷窗口,与 DeepSeek 官方计费一致;pauseMode(safe/force)、pauseReason(wait/stop)——暂停推进方式;- 重试参数:
retryText、retryGraceMs、retryCooldownMs、retryBackoffFactor、retryBackoffMaxMs、retryMaxConsecutive。
行为
高峰自动门(全局)
- 入峰(且非周末):对所有 running root session 调
gate.stopNextTurn——自研会话门真暂停(不打断推理,推理完成/工具派发前落在安全边界暂停),或按queueFallback回退锁等待队列; - 退峰 / 周末:
gate.resume全部会话(自动续跑,无需手动)——受offPeakAutoResume开关控制,关掉则退峰不自动恢复; - 峰谷时区:固定使用北京时间(
Asia/Shanghai),与 DeepSeek 官方计费基准一致,不受timezone配置影响; - 状态机:单实例
NORMAL ↔ PAUSED_PEAK(scheduler.js),由单一 30s tick 驱动。
会话锁定(冻结)
- 冗余端口:
ctx.provide('sessionGuard', service)——stopNextTurn(sessionId)/resume(sessionId)/lockQueue(sessionId)/unlockQueue(sessionId)/state(sessionId); - RPC 桥:
POST /session-guard/rpc { action, sessionId }——input-traffic 冻结按钮按sessionId逐会话调用stopNextTurn/resume;本插件未装则静默跳过(D8 fail-open); - 手动命令:
/pause [force|safe] [stop|wait]、/resume [confirm] [rerun|skip]、/cancel——作用于调用它的会话(取invocation.agent.id)。
后端自动重试(D9)
监听 turn/end,将失败分类:
- 瞬时失败(error/429/max-tokens 等)→ 自适应退避自动
followup(retryText)续跑; - 永久失败(鉴权/余额/模型/上下文超限)→ 停止;
- 冻结/门控期间让路:
isFrozen(sessionId)为真(queueLocked / paused / taskControl paused)时不重试; - 用户介入或成功回合重置连续失败计数。
状态徽标(前端展示)
输入区右侧显示一个纯展示状态徽标,实时反映当前所处阶段:
| 阶段 | 徽标文案 | CSS 类 | 含义 |
|---|---|---|---|
peak | 高峰 | sg-peak | 工作日高峰时段,会话已被自动暂停 |
off-peak | 谷时 | sg-off | 非高峰时段,会话正常运行 |
weekend | 周末 | sg-weekend | 周末(周末模式开启时),无视峰谷畅快跑 |
- 轮询:每 15 秒请求
GET /session-guard/status,获取全局phase; - fail-open:路由不可达、网络错误、或
enabled关闭时→ 徽标静默隐藏,不影响任何会话; - 独立于 input-traffic:徽标由 session-guard 客户端独立渲染,不需要安装 input-traffic 插件即可显示。input-traffic 只负责冻结按钮,与徽标无依赖关系;
- tooltip:悬停显示
阶段 · 时区 · 周末模式(如周末 · Asia/Shanghai · 周末模式)。
时区处理与校验
- 时区判定基于 IANA 时区名(如
Asia/Shanghai、Asia/Tokyo、Asia/Seoul),通过Intl.DateTimeFormat投影为配置时区的墙钟,不依赖裸getUTCDay()——避免北京时区 UTC+8 边界错 8 小时的经典 bug(周六 00:30 北京时间,UTC 还是周五); Intl.DateTimeFormat本身即为校验层:传入无效时区名(如Foo/Bar)会抛RangeError,被外层 try-catch 静默降级为默认时区Asia/Shanghai(fail-open);- 峰谷窗口为左闭右开
[start, end),支持跨午夜窗口(如22:00–06:00); timezone配置项对所有语言(中/英/日/韩)通用——Intl.DateTimeFormat的 IANA 时区名不依赖 locale,日文/韩文界面下时区行为与中文完全一致。
与 input-traffic 协作
- input-traffic 的冻结按钮触发时经
sessionGuard.stopNextTurn(RPC,会话级)透传服务端; - input-traffic 只做冻结增强(队列冻结/解冻 + composer block),重试归本插件后端;
- 两者共享「会话隔离」语义:input-traffic 冻结队列按 sessionId 隔离,session-guard RPC 同样按 sessionId 锁。
冗余端口 sessionGuard
{
stopNextTurn(sessionId, opts), // 停掉 session 下一回合(自研会话门 / 回退锁队列)
resume(sessionId, opts), // 恢复(confirm + choice: rerun|skip)
lockQueue(sessionId, reason), // 显式锁队列
unlockQueue(sessionId), // 显式解锁
state(sessionId), // { queueLocked, lockReason, paused, taskControlAvailable, taskControl }
}
HTTP 路由
GET /session-guard/state?session=<id>— 会话状态GET /session-guard/settings— 设置 + taskControl 可用性GET /session-guard/status— 全局当前阶段(状态徽标轮询)GET /session-guard/diag— 运行时诊断POST /session-guard/rpc—{ action: stopNextTurn|resume|lockQueue|unlockQueue|state, sessionId }
状态存储
每会话 JSON:$DSH_HOME/.dsh/session-guard/<sessionId>.json(原子写;DSH_SESSION_GUARD_STATE_DIR 可覆盖)。
测试
npm test # node --test tests/*.test.mjs(时区/周末/状态机/会话门/桥接/重试)
模块
| 文件 | 职责 |
|---|---|
src/time.js | 高峰/周末判定(时区正确) |
src/scheduler.js | 纯状态机 NORMAL ↔ PAUSED_PEAK |
src/pause-gate.js | 自研会话门引擎(agent.cancel keepInbox + goals.pause + 安全边界 + followup 续跑) |
src/pause-store.js | 自研暂停状态持久化 |
src/gate.js | 会话门驱动(自研真暂停 / 回退锁队列,fail-open) |
src/bridge.js | sessionGuard 冗余端口 |
src/retry.js | 后端自动重试(失败分类/退避/冻结让路) |
src/detect.js | 自动检测(host taskControl / client input-traffic 桥) |
src/store.js | 每会话持久化状态 |
src/settings.js | 设置子板块(schemastery schema + fail-open 注册) |
src/index.js | host apply(设置/路由/tick/提供服务/重试接线) |
src/client/ | 浏览器 half(状态徽标 + 设置卡片) |
License
MIT — 见 LICENSE。