# Agent Note: 对话式 Schedule 交付

Status: implemented

[English](2026-08-09-conversational-schedule-delivery.md) | 中文

## 问题

Schedule 已经通过将普通的 agent（智能体）后续轮次排入队列来交付到期提醒。第二条持久 Web 回执通过 Schedule 投影、持久化成功事件、Host 历史记录与 live 伴随数据、客户端同序号升级、通用事件视图 slot 和专用渲染器表示同一次提醒触发。这条路径把一项功能的确认 UI 分散到会话、持久化、Host、客户端运行时、对话 UI 和一个额外包中。

该回执还让「交付」有了第二种含义。即使模型轮次失败，它仍然可见，而对话本身没有成功的提醒答复。用户需要定时对话继续进行；他们不需要一枚单独的持久标记来证明内部 dispatch 已经尝试过。

## 决策

到期提醒会等待 agent 的 idle maintenance phase，再调用 `followup()`。该操作会在稍后开启一个普通轮次，并通过普通对话 transcript（文本记录）显示；Schedule 绝不会调用 `steer()`，也绝不会中断当前轮次。

`schedule/change` 仍是唯一持久 Schedule 状态。其 dispatch 操作记录后续轮次已同步入队，这会在 dispatch 持久化后阻止普通的重启回放。dispatch 不表示模型成功、用户确认或外部通知。入队与持久 dispatch 之间的狭窄崩溃窗口仍保留至少一次语义。

Schedule 不公开呈现投影、Host 伴随数据、浏览器事件节点、按事件键控的 slot 或客户端渲染器。会话持久化保留共享的 `flush()` 约定，且不存在由 Schedule 驱动的成功事件。显式启用的 Web overlay 只加载 `@deepseek-ai/dsh-tool-schedule`。

## 已考虑的替代方案

**保留提交感知回执。** 即使模型失败，它也可以证明 dispatch 已到达持久化，但这是实现结果，而不是用户的提醒。其跨组件协议与后到的同序号合并逻辑，与这点价值不成比例。

**在对话中渲染原始 `schedule/change` 事件。** 这样可以避免领域卡片，但仍会把内部状态转换暴露为面向用户的消息，而且仅为 Schedule 就需要通用的内部事件呈现机制。

**把 dispatch 当作提醒已成功交付。** dispatch 发生在模型请求之前，无法证明 assistant 答复存在或已被读取。将其称为交付会夸大持久事实。

**提醒到期时中途引导当前轮次。** 中途引导会改变进行中的请求路径，并让定时触发中断无关工作。等待完全 idle 后使用 `followup()`，可让每条提醒分别进入一个普通的后续轮次。

## 验证

包生命周期测试固定 idle 等待、maintenance 所有权、后续轮次先于 dispatch 的顺序、同步入队失败、与模型无关的 dispatch 和重启回放。组装后的 Web 场景为产生的 assistant 行生成快照，并断言已持久化的 Schedule dispatch 没有特殊 history view。源码与依赖审计会拒绝残留的已移除呈现符号、事件、sidecar、slot、渲染器包与 overlay 配置项。

## 后果

- Schedule 的实现仅涉及其自身包、常规组合与目录接线；会话、持久化、Host、客户端运行时和对话 UI 不携带 Schedule 专属行为。
- 用户只能通过对话中的普通模型响应看到提醒。失败的模型轮次仍是失败轮次，不会出现与之矛盾的成功回执。
- 需要外部交付或交付确认的消费方必须采用另一条产品边界，并由其拥有自己的通知和确认语义。
