跳到主要内容
路径文档

定时调度

一句话版@deepseek-ai/dsh-schedule 给 live agent 提供 3 个会话内工具(schedule_create / schedule_list / schedule_delete)管理持久提醒会话事件日志拥有提醒状态,timer 和模型 follow-up 只是日志的可丢弃投影。

让 agent 定时做点事的能力。核心洞察:提醒状态不存"内存定时器",而是存会话事件日志;这样折叠/恢复只认日志,timer 崩了也没关系。

一、三个工具

工具输入行为
schedule_createafter_seconds(正整数)/ at(绝对时间)/ every_seconds(≥5 分钟)创建提醒
schedule_list列出活动提醒(含 scheduled / overdue 状态)
schedule_deleteid删除提醒

schedule_dispatch 不是工具:dispatch 是 schedule/change 事件里的内部 operation。到点投递由运行时做(见下)。

二、状态模型(关键设计)

会话事件日志(唯一真源)
├── schedule/change 事件(create/delete/dispatch 联合,版本 1)
├── timer(可丢弃投影)
└── 模型 follow-up(可丢弃投影)

重要性质:

  • 会话折叠 = 完整日志;fork 只折叠 seedLength 之后:子会话不继承父会话提醒
  • 每次读取前先 ctx.sessions.flush(session);持久化不可用 → persistence_uncertain,绝不把未确认状态当结果
  • 回放拒绝:未知版本、重复 id、形状不匹配的 dispatch、对非活动记录的转换
  • 每次成功 preflight 后、以及真实 barrier 成功后,回调 onDurableChange 驱动 owner 重算

三、时间语义(严格)

at 支持两种:

形式示例
RFC 3339 字符串2026-08-12T10:00:00Z 或带偏移
本地形式{ date, time, time_zone }:必须显式 UTC 或 IANA 时区

拒绝:缺时区、无偏移字符串、DST 缺口内时间(重叠取较早)、非未来目标。创建后只保留规范化 UTC:Schedule 不读浏览器/会话/模型上下文时区。

最小间隔:every_seconds 不能小于 MIN_EVERY_INTERVAL_SECONDS = 300(5 分钟)。

四、运行时投递:提醒怎么变成真实轮次

到点的提醒不是"改个状态",而是被投递成 agent 的一条真实 user message:

每个根 agent 一个 ScheduleRuntime 维护循环
→ 定时器用 whenIdle() + MAX_TIMER_DELAY_MS(2147483647) 等待空闲相位
→ 到点用 agent.runMaintenance(...) 认领空闲相位
→ 构造 user message,agent.followup(message) 注入一次"跟进轮次"
→ 这正是模型实际收到并处理的 next-turn 输入

工具调用还带可取消事务(runCancellableScheduleTransaction / exec.signal),防止重复投递。

五、组合要求

  • 加载顺序:ctx.sessionsctx.agentsctx.toolsctx.sessionPersistence + flush 持久化监听器之后;静态注入失败 = 组合直接失败
  • 只监听后续 agent/created:加载时已存在的 agent 和子 agent 不会获得 Schedule
  • schedule/change 的 durably-commit 投递屏障与 onDurableChange observer 负责在 create/delete 后驱动重算

六、验证

# 会话日志里找 schedule/change 事件(默认 zstd、两级目录)
zstdcat ~/.dsh/sessions/*/*/session.jsonl.zstd | jq -r 'select(.type == "schedule/change")'

# 看投递成什么轮次
zstdcat ~/.dsh/sessions/*/*/session.jsonl.zstd | grep -E "user/message|schedule/" | tail

下一步