dsh-session-clock
Per-session clock injection with durable idle-gap tracking: tells the agent how long it has been since this particular conversation last spoke, which the host's time context (last message only) cannot.
Install
dsh plugin --profile web add dsh-session-clock
Sandbox test
This plugin has not been tested yet. Submit a test →
README
dsh-session-clock
给 DeepSeek Harness 的「会话时钟」插件——按会话授时,并给出跨轮、跨会话的空闲间隔。
定位是宿主内置 @deepseek-ai/dsh-time-context 的补充插件,不是替代品。
[English](README.en.md) | 中文
dsh-hot-reloader — 改完插件源码不用重启
dsh-session-clock — 按会话授时与空闲间隔(本仓库)
dsh-second-opinion — 卡住时把问题交给另一个独立会话,要一份第二意见
dsh-onebot-companion — QQ 通道一体化:出站沉默守卫 / 行为规则 / 对话节奏 / 人设 / 语音
一句话说明
DSH 内置的 time-context 已经很擅长「告诉模型现在几点、距上一条消息过了多久」。
本插件不重复它,只补三件它结构上做不到的事:
能力 · dsh-time-context(内置) · dsh-session-clock(本插件)
当前时间戳 · ✅ 每轮首步 · ➖ 不重复(full 模式下才复刻)
浏览器时区 · ✅ · ➖ 不重复
距上一条模型可见消息多久 · ✅ · ➖ 不重复
只给「指定会话」授时 · ❌ 对所有 agent 一视同仁 · ✅ sessions / exceptSessions 白名单
**/正则/、* 通配匹配会话** · ❌ · ✅
跨会话指针(任何会话上次活跃多久前) · ❌ 不感知会话边界 · ✅
距上一次「用户主动说话」多久 · ❌ 只算模型可见消息 · ✅ 排除定时/主动/工具触发的轮次
重启后间隔依然成立 · ⚠️ 依赖会话内事件 · ✅ 持久化到 $DSH_HOME/session-clock/activity.json
agent 主动查询(session_clock 工具) · ❌ · ✅
HTTP 状态观测面 · ❌ · ✅
为什么需要它
DSH 内置的 @deepseek-ai/dsh-time-context 每个 turn 的首步都会注入一条三行消息:
Time sampled while preparing turn 8, step 1: 2026-10-13T10:14:10+08:00[Asia/Shanghai] Browser time zone for this request: Asia/Shanghai. Interpret otherwise-unqualified dates and times in this zone. Elapsed since the preceding model-visible message: 2h 15m 3s.
第三行在每轮第一步其实已经等于「距上次对话过去多久」——因为 step 1 执行时本轮的
user/message 还没提交,基线落在上一轮最后一条模型可见消息上。这一点本插件承认并且
不去动它(这也是本插件默认 mode: supplement 的原因)。
但它有两个结构性缺口:
1. 它是全局的。 所有 agent、所有会话一视同仁,没法做到「只给这几个会话授时」。
在 QQ 群、定时任务、子代理混跑的场景里,token 花在了不需要的会话上。
2. 它感知不到会话边界。 它知道「距上一条消息」,但不知道「距别的会话上次活跃」,
也不知道「用户上次主动开口是多久前」(定时唤醒、主动搭话也会产生模型可见消息,
把这条基线冲掉)。
本插件就补这两点。注入格式刻意沿用与 time-context 完全一致的时间戳/时长写法
(2026-10-13T10:14:10+08:00[Asia/Shanghai]、1d 2h 3m 4s),两条注入放在一起不打架。
功能详解
1. 按会话授时
sessions: ['onebot-*', 'session-*'] # 白名单,支持 * 通配与 /正则/ exceptSessions: ['/^onebot-group-.*$/'] # 黑名单,优先级高于白名单
'*'(默认)等于全部会话。'onebot-'匹配所有 QQ 通道会话;'/^session-36f4./'走正则。- 非法正则自动退化为字面量匹配,不会让插件崩掉。
2. 跨轮与跨会话间隔
每条注入一行,形如:
Session clock for onebot-group-2000000002-mv40ioj5: previous user message 3d 4h 12m 9s ago; any session last active 12m 3s ago (session-36f403a5-...), turn 42.
previous user message ... ago:距上一次用户主动发言(不含注入消息、不含定时唤醒)。any session last active ... ago:跨会话指针——任何一个被跟踪的会话上次动过是多久前,
括号里是那个会话 id。用来回答「我是不是刚在另一个窗口问过你」。
turn 42:本会话累计轮次数。- 各子句可用
includeUserGap/includeGlobalIdle/includeTurnCount逐个关掉。
3. 持久化
状态写到 $DSH_HOME/session-clock/activity.json(默认 ~/.dsh/session-clock/activity.json)。
DSH 重启后内存里的会话对象是新的,但文件里的间隔基线还在,所以「距上次对话多久」
在重启后依然算得对——这是内置插件做不到的。写盘是延迟合并 + 原子替换
(tmp 文件 → renameSync),不会因为断电留下半个 JSON。
4. agent 可主动查询
注册了一个 session_clock 工具:
action · 作用
now · 本会话(或 session_id 指定)当前时间 + 各类空闲时长
list · 最近活跃的会话及空闲时长(limit 控制条数)
模型可以直接回答「我多久没来了」,而不必依赖注入。
5. HTTP 观测面
只在 loopback(127.x.x.x / localhost / ::1 / *.localhost)可访问,非本机一律 403:
方法 · 路径 · 作用
GET · /session-clock · 当前状态(enabled / mode / 计数 / 上次决策原因)
GET · /session-clock/list · 已跟踪会话及空闲时长
GET · /session-clock/logs · 环形日志缓冲(最近 300 条)
POST · /session-clock/toggle · 开/关注入
POST · /session-clock/flush · 立即落盘
POST · /session-clock/forget · 忘掉某个会话(body {"session": "<id>"})
/session-clock 里的 lastDecision 会告诉你上一次为什么没注入(例如
mode=supplement 只在首步注入)——这个插件每轮只补一条,错过首步就整轮静默,
没有这个字段会很难区分「没轮到」和「坏了」。
环境要求
前置插件
插件 · 版本 · 说明
@deepseek-ai/dsh-time-context · 0.2.0-rc.2 · 宿主内置。必须存在但不要改动它——本插件默认 supplement 模式与它并存(见「与 time-context 共存」)
time-context 由 @deepseek-ai/dsh-base 组合包提供,你不需要单独安装。
本插件不 import 它,只在语义上补它结构上给不出的维度。
注意:dsh-experimental-schedule-bundle也会随包插入同一个dsh-time-context。
profile patch 里请保持单点挂载,插第二份会导致每 turn 首步注入两条逐字相同的消息。
DSH 宿主
项 · 版本
DSH · 0.2.0-rc.2(实测于该版本)
Electron · 44.0.0
Node(宿主内嵌) · 24.18.1
V8 · 15.2
Cordis · 4.0.4
依赖的宿主服务与接口
依赖 · 必需 · 说明
ctx.sessions · ✅ · inject = ['sessions']。取当前会话、读事件流
ctx.sessions.snapshotEvents() · ✅ · 重建「距上次对话多久」的基线
ctx.on('session/event') · ✅ · 追踪每条消息的 time 字段
@deepseek-ai/dsh-llm 的 createUserMessage · ⭕ 可选 · 受控动态 import:try { ... } catch { undefined },拿不到就退回本地 deepFreeze({ id: randomUUID(), role: 'user', ... }) 等价物
webServer · ⭕ 可选 · 没有它插件照常注入,只是看不到 HTTP 观测面
ctx.reflect.provide('sessionClock') · ⭕ 可选 · 已用 try/catch 包裹,宿主没这个服务也不影响
零运行时依赖:只用 node:crypto / node:fs / node:path / node:url,
外加 ./time.js 与 ./store.js 两个自带模块。
状态文件
$DSH_HOME/session-clock/activity.json # 默认;DSH_HOME 缺省时退回 ~/.dsh
- 原子写(tmp +
renameSync),格式{ version: 1, sessions: {...}, global: {...} } MAX_RECORDS = 5000,超出时按lastSeenAt裁剪最旧的- 删掉这个文件 = 清空所有间隔记录(重启后间隔从零开始)
安装
支持的 DSH 版本:>=0.2.0-rc.2 <0.3.0-0(开发与验证所用为 0.2.1-rc.2)。
1. npm / 插件管理器(推荐)
dsh plugin --profile <你的profile> add dsh-session-clock
2. 从源码挂链接
git clone https://github.com/xfgil/dsh-session-clock.git D:\Plugins\dsh-session-clock dsh plugin --profile <你的profile> add link:/绝对路径/dsh-session-clock
link: 方式的好处是改完源码不用重新安装。
3. 下载 Release 附件
在 Releases 页面下载对应版本的
源码压缩包,解压到任意目录,再用上面的 link: 命令挂进 profile。
装好后通常无需重启:宿主内置的 HMR 会监听到 profile 清单变化并自动
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::3,最后更新 2026-11-01