diff --git a/docs/subsystems/schedule.i18n.yaml b/docs/subsystems/schedule.i18n.yaml index 17ac53123f..c19e4d3ec6 100644 --- a/docs/subsystems/schedule.i18n.yaml +++ b/docs/subsystems/schedule.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/schedule.md -schedule.md: 4357434fade3b49d6a4704bf8c6b28591e7460c9 -schedule.zh.md: c8291e782068cbff32c9a130a06680506f383c42 +schedule.md: 3a7cbbb46837ff4ea74813eba1f47ed4758457be +schedule.zh.md: 2e24ffbaa6b53d3c5aef4158ecd3783a61b0b1af diff --git a/docs/subsystems/schedule.md b/docs/subsystems/schedule.md index 4357434fad..3a7cbbb468 100644 --- a/docs/subsystems/schedule.md +++ b/docs/subsystems/schedule.md @@ -2,18 +2,18 @@ English | [中文](schedule.zh.md) -Schedule owns durable reminders that return to the original live Session as ordinary later conversation turns. The [durable Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns the persistence and lifecycle decisions, and [conversational delivery](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) owns the no-receipt boundary. This page records the durable and model-facing shapes from [`packages/schedule/tool-schedule/src/types.ts`](../../packages/schedule/tool-schedule/src/types.ts); the [package README](../../packages/schedule/tool-schedule/README.md) owns composition, tool behavior, and the exact reminder framing. +Schedule owns durable reminders that return to the original live Session as ordinary later conversation turns. The [durable Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns the persistence and lifecycle decisions, [conversational delivery](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) owns the no-receipt boundary, and the [explicit time-zone boundary](../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.md) owns browser-local interpretation. This page records the durable and model-facing shapes from [`packages/schedule/tool-schedule/src/types.ts`](../../packages/schedule/tool-schedule/src/types.ts); the [package README](../../packages/schedule/tool-schedule/README.md) owns composition, tool behavior, and the exact reminder framing. ## Durable records -`ScheduleId` is a [branded id](core.md#branded-ids), unique and never reused within one Session. Version 1 initially supports a positive safe-integer `after_seconds` selector. Creation canonicalizes the selected target into a four-digit-year RFC 3339 UTC `scheduledAt`; the submitted delay remains in the record so list results explain the rule that produced it. +`ScheduleId` is a [branded id](core.md#branded-ids), unique and never reused within one Session. Version 1 supports either a positive safe-integer `after_seconds` delay or an explicit absolute `at` target. Creation canonicalizes either selector into a four-digit-year RFC 3339 UTC `scheduledAt`; an `after` record retains its submitted delay, while an `at` record stores only the resulting instant. ```ts type-equiv /** Durable one-shot reminder created from a positive delay. */ interface AfterScheduleRecord { /** Session-local stable identity. */ readonly id: ScheduleId - /** Rule discriminator; v1 supports only delayed one-shot reminders. */ + /** Rule discriminator for a delayed one-shot reminder. */ readonly kind: 'after' /** Trimmed reminder content supplied at creation. */ readonly prompt: string @@ -25,10 +25,49 @@ interface AfterScheduleRecord { ``` ```ts type-equiv -/** The v1 durable reminder record union. */ -type ScheduleRecord = AfterScheduleRecord +/** Durable one-shot reminder created from an absolute instant. */ +interface AtScheduleRecord { + /** Session-local stable identity. */ + readonly id: ScheduleId + /** Rule discriminator for an absolute one-shot reminder. */ + readonly kind: 'at' + /** Trimmed reminder content supplied at creation. */ + readonly prompt: string + /** Four-digit-year RFC 3339 UTC target. */ + readonly scheduledAt: string +} ``` +```ts type-equiv +/** The v1 durable reminder record union. */ +type ScheduleRecord = AfterScheduleRecord | AtScheduleRecord +``` + +## Absolute-time input + +The `at` selector is either a strict offset-bearing RFC 3339 string or an exact local-calendar object. The local form keeps its interpretation explicit at the tool boundary: + +```ts type-equiv +/** Structured local-calendar input accepted by `schedule_create`. */ +interface LocalAtInput { + /** Four-digit ISO calendar date. */ + readonly date: string + /** Local wall-clock time with optional one-to-three digit milliseconds. */ + readonly time: string + /** Explicit UTC or IANA Area/Location zone. */ + readonly time_zone: string +} +``` + +```ts type-equiv +/** Absolute selector accepted by `schedule_create`. */ +type AtInput = string | LocalAtInput +``` + +The official Web overlay samples the browser's IANA zone for every prompt. Time-context tells the model to interpret otherwise-unqualified natural-language dates and times in that request-local zone when the open turn has one unambiguous browser zone; mixed or missing provenance tells the model to ask. That guidance is not a durable Session default: the model must still pass an offset in the string form or `time_zone` in the local form, and Schedule never reads browser, Session, process, or model context. + +Schedule rejects invalid offsets and zones, offset-free strings, non-future targets, and local times inside daylight-saving gaps. A daylight-saving overlap chooses its first, earlier instant. Successful creation stores only canonical UTC `scheduledAt`, so replay never depends on ambient time-zone state. + ## Durable changes and replay The version-1 `schedule/change` Session event is the only durable Schedule authority. Create stores the complete record. Delete and dispatch are terminal id-only transitions for one-shot reminders; dispatch means the follow-up was synchronously queued, not that a model answer succeeded or the user read it. @@ -82,8 +121,8 @@ type ScheduleDeliveryMode = 'session-local' ``` ```ts type-equiv -/** Complete model-facing view of one active after reminder. */ -interface ScheduleView extends AfterScheduleRecord { +/** Complete model-facing view of one active reminder. */ +type ScheduleView = ScheduleRecord & { /** Whether the target remains in the future. */ readonly state: ScheduleState /** Reminder delivery never leaves the owning session. */ @@ -91,7 +130,7 @@ interface ScheduleView extends AfterScheduleRecord { } ``` -The generated [tool catalog](../tool-catalog.md#deepseek-aidsh-tool-schedule) owns the argument and result schemas for `schedule_create`, `schedule_list`, and `schedule_delete`. Management calls serialize with due work in one Agent-scoped queue. Every read or decision first waits for the shared Session persistence barrier; create and an actual delete wait again after appending. A barrier failure reports `persistence_uncertain` instead of guessing whether an eager write committed. The other stable error codes are `invalid_prompt`, `invalid_selector`, `invalid_rule`, `time_out_of_range`, `corrupt_schedule_log`, and `internal_error`. +The generated [tool catalog](../tool-catalog.md#deepseek-aidsh-tool-schedule) owns the argument and result schemas for `schedule_create`, `schedule_list`, and `schedule_delete`. Management calls serialize with due work in one Agent-scoped queue. Every read or decision first waits for the shared Session persistence barrier; create and an actual delete wait again after appending. A barrier failure reports `persistence_uncertain` instead of guessing whether an eager write committed. The other stable error codes are `invalid_prompt`, `invalid_selector`, `invalid_rule`, `invalid_time_zone`, `not_future`, `time_out_of_range`, `corrupt_schedule_log`, and `internal_error`. ## Live delivery diff --git a/docs/subsystems/schedule.zh.md b/docs/subsystems/schedule.zh.md index c8291e7820..2e24ffbaa6 100644 --- a/docs/subsystems/schedule.zh.md +++ b/docs/subsystems/schedule.zh.md @@ -2,18 +2,18 @@ [English](schedule.md) | 中文 -Schedule 拥有持久提醒;这些提醒会作为普通的后续对话轮次返回原 live Session。[持久 Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) 负责持久化与生命周期决策,[对话式交付](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) 负责无回执边界。本页记录 [`packages/schedule/tool-schedule/src/types.ts`](../../packages/schedule/tool-schedule/src/types.ts) 中的持久数据形状和面向模型的数据形状;[包 README](../../packages/schedule/tool-schedule/README.md) 负责组合、工具行为与确切的提醒 framing。 +Schedule 拥有持久提醒;这些提醒会作为普通的后续对话轮次返回原 live Session。[持久 Schedule Agent Note](../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) 负责持久化与生命周期决策,[对话式交付](../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) 负责无回执边界,[显式时区边界](../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.md) 负责浏览器本地解释。本页记录 [`packages/schedule/tool-schedule/src/types.ts`](../../packages/schedule/tool-schedule/src/types.ts) 中的持久数据形状和面向模型的数据形状;[包 README](../../packages/schedule/tool-schedule/README.md) 负责组合、工具行为与确切的提醒 framing。 ## 持久记录 -`ScheduleId` 是[品牌化 id](core.md#branded-ids),在单个 Session 内唯一且绝不复用。版本 1 最初只支持正的安全整数 `after_seconds` 选择器。创建操作会将选定目标规范化为使用四位年份的 RFC 3339 UTC `scheduledAt`;记录仍保留提交的延时,以便 list 结果说明生成该目标所用的规则。 +`ScheduleId` 是[品牌化 id](core.md#branded-ids),在单个 Session 内唯一且绝不复用。版本 1 支持正的安全整数 `after_seconds` 延时或显式的绝对 `at` 目标。创建操作会将任一选择器规范化为使用四位年份的 RFC 3339 UTC `scheduledAt`;`after` 记录会保留提交的延时,`at` 记录则只存储结果时点。 ```ts type-equiv /** Durable one-shot reminder created from a positive delay. */ interface AfterScheduleRecord { /** Session-local stable identity. */ readonly id: ScheduleId - /** Rule discriminator; v1 supports only delayed one-shot reminders. */ + /** Rule discriminator for a delayed one-shot reminder. */ readonly kind: 'after' /** Trimmed reminder content supplied at creation. */ readonly prompt: string @@ -25,10 +25,49 @@ interface AfterScheduleRecord { ``` ```ts type-equiv -/** The v1 durable reminder record union. */ -type ScheduleRecord = AfterScheduleRecord +/** Durable one-shot reminder created from an absolute instant. */ +interface AtScheduleRecord { + /** Session-local stable identity. */ + readonly id: ScheduleId + /** Rule discriminator for an absolute one-shot reminder. */ + readonly kind: 'at' + /** Trimmed reminder content supplied at creation. */ + readonly prompt: string + /** Four-digit-year RFC 3339 UTC target. */ + readonly scheduledAt: string +} ``` +```ts type-equiv +/** The v1 durable reminder record union. */ +type ScheduleRecord = AfterScheduleRecord | AtScheduleRecord +``` + +## 绝对时间输入 + +`at` 选择器可以是严格且带偏移量的 RFC 3339 字符串,也可以是精确的本地日历对象。本地形式让这种解释在工具边界保持显式: + +```ts type-equiv +/** Structured local-calendar input accepted by `schedule_create`. */ +interface LocalAtInput { + /** Four-digit ISO calendar date. */ + readonly date: string + /** Local wall-clock time with optional one-to-three digit milliseconds. */ + readonly time: string + /** Explicit UTC or IANA Area/Location zone. */ + readonly time_zone: string +} +``` + +```ts type-equiv +/** Absolute selector accepted by `schedule_create`. */ +type AtInput = string | LocalAtInput +``` + +官方 Web overlay 会为每条提示词采样浏览器的 IANA 时区。当 open turn 只有一个无歧义的浏览器时区时,Time-context 会告诉模型按该请求本地时区解释未明确限定时区的自然语言日期和时间;provenance 混合或缺失时,则告诉模型询问用户。该指引不是持久 Session 默认值:模型仍必须在字符串形式中传入偏移量,或在本地形式中传入 `time_zone`;Schedule 绝不会读取浏览器、Session、进程或模型上下文。 + +Schedule 会拒绝无效偏移量与时区、不带偏移量的字符串、非未来目标,以及落在夏令时缺口内的本地时间。遇到夏令时重叠时,会选择第一次出现的较早时点。创建成功后只存储规范化后的 UTC `scheduledAt`,因此回放绝不依赖环境时区状态。 + ## 持久变更与回放 版本 1 的 `schedule/change` 会话事件是 Schedule 唯一的持久权威。create 保存完整记录。delete 与 dispatch 是一次性提醒的终结性、仅含 id 的转换;dispatch 表示 follow-up 已同步入队,而不表示模型答复成功或用户已读取答复。 @@ -82,8 +121,8 @@ type ScheduleDeliveryMode = 'session-local' ``` ```ts type-equiv -/** Complete model-facing view of one active after reminder. */ -interface ScheduleView extends AfterScheduleRecord { +/** Complete model-facing view of one active reminder. */ +type ScheduleView = ScheduleRecord & { /** Whether the target remains in the future. */ readonly state: ScheduleState /** Reminder delivery never leaves the owning session. */ @@ -91,7 +130,7 @@ interface ScheduleView extends AfterScheduleRecord { } ``` -生成的[工具目录](../tool-catalog.md#deepseek-aidsh-tool-schedule)负责 `schedule_create`、`schedule_list` 和 `schedule_delete` 的参数与结果 schema。一条 Agent-scoped 队列将管理调用与到期工作串行化。每次读取或判断都会先等待共享的 Session 持久化 barrier;create 与实际执行的 delete 在追加后还会再次等待。barrier 失败会报告 `persistence_uncertain`,而不是猜测 eager write 是否已提交。其他稳定错误代码是 `invalid_prompt`、`invalid_selector`、`invalid_rule`、`time_out_of_range`、`corrupt_schedule_log` 和 `internal_error`。 +生成的[工具目录](../tool-catalog.md#deepseek-aidsh-tool-schedule)负责 `schedule_create`、`schedule_list` 和 `schedule_delete` 的参数与结果 schema。一条 Agent-scoped 队列将管理调用与到期工作串行化。每次读取或判断都会先等待共享的 Session 持久化 barrier;create 与实际执行的 delete 在追加后还会再次等待。barrier 失败会报告 `persistence_uncertain`,而不是猜测 eager write 是否已提交。其他稳定错误代码是 `invalid_prompt`、`invalid_selector`、`invalid_rule`、`invalid_time_zone`、`not_future`、`time_out_of_range`、`corrupt_schedule_log` 和 `internal_error`。 ## Live 交付 diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index 76ea958dfb..04bbd58056 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -226,6 +226,21 @@ "symbol": "AfterScheduleRecord", "source": "packages/schedule/tool-schedule/src/types.ts" }, + { + "doc": "docs/subsystems/schedule.md", + "symbol": "AtScheduleRecord", + "source": "packages/schedule/tool-schedule/src/types.ts" + }, + { + "doc": "docs/subsystems/schedule.md", + "symbol": "LocalAtInput", + "source": "packages/schedule/tool-schedule/src/types.ts" + }, + { + "doc": "docs/subsystems/schedule.md", + "symbol": "AtInput", + "source": "packages/schedule/tool-schedule/src/types.ts" + }, { "doc": "docs/subsystems/schedule.md", "symbol": "ScheduleRecord",