@deepseek-ai/dsh-schedule 0.1.1-rc.2 → 0.1.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +138 -22
- package/README.zh.md +154 -38
- package/lib/index.js +130 -29
- package/lib/invariant.js +45 -29
- package/lib/types/client.d.ts +3 -0
- package/lib/types/client.js +2 -0
- package/lib/types/domain.d.ts +11 -0
- package/lib/types/domain.js +695 -0
- package/lib/types/index.js +57 -0
- package/lib/types/invariant.js +48 -0
- package/lib/types/persistence.js +30 -0
- package/lib/types/projection.d.ts +33 -0
- package/lib/types/projection.js +67 -0
- package/lib/types/runtime.js +296 -0
- package/lib/types/tools.js +403 -0
- package/lib/types/transaction.js +22 -0
- package/lib/types/types.d.ts +6 -0
- package/lib/types/types.js +6 -0
- package/package.json +32 -22
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/schedule/schedule/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 871c47309e5ceb544f4e9fc97c69bbdb5b00c0aa
|
|
6
|
+
README.zh.md: 68c66ab22131ea528bd763116b7b343405907912
|
package/README.md
CHANGED
|
@@ -1,56 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Session-local durable reminders: the schedule_create, schedule_list, and schedule_delete tools and live-owner delivery, for users and maintainers choosing, configuring, or debugging the package."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-schedule
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-schedule` gives your session durable reminders: ask the model to remind you later, and the reminder comes back as an ordinary follow-up message in the same conversation. You can schedule a one-time reminder after a delay or at an absolute time, or a repeating reminder on a fixed interval, and you can list what is still pending or cancel a reminder. Reminders survive restarts: an already-live idle agent can deliver due work immediately, while a closed or cold session keeps it overdue until a future live root agent resumes the session. Delivery stays inside the session, with no email, SMS, or push notification. It is an opt-in Web capability; load the Schedule overlay to enable the reminder tools and read-only active-reminder catalog. Ordinary and search sidebar rows also show a non-interactive alarm when their best-effort list projection is known to be non-empty; the alarm does not promise a live runtime.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Use Schedule when you want a reminder to arrive as a message in the same conversation — for example, "remind me in 30 minutes to follow up on the migration" or "check back every hour while this build runs". The agent creates, lists, and cancels reminders through its ordinary tools; you only enable the overlay once.
|
|
29
|
+
|
|
30
|
+
### When to choose it
|
|
31
|
+
|
|
32
|
+
Choose Schedule when you want reminders delivered as messages in the same live conversation. Avoid it when delivery must reach you outside the session — there is no email, SMS, push, or browser notification — or when you need calendar-style rules such as "every weekday at 9": repeating reminders run on a fixed interval only.
|
|
33
|
+
|
|
34
|
+
### Enable Schedule
|
|
35
|
+
|
|
36
|
+
Add the Schedule overlay to a `dsh web` session; the reminder tools then appear in the conversation and the model can use them right away:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
dsh web --patch apps/cli/config/examples/schedule/cordis.yml
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Success looks like this: ask the model "remind me in 10 minutes to review the PR", and it replies with the reminder's id, its target time, and a `scheduled` state. If storage cannot be confirmed at that moment, the tool reports `persistence_uncertain` and suggests re-listing instead of claiming success.
|
|
43
|
+
|
|
44
|
+
Enable the overlay before starting the session you want reminders in: a session that was already running when the overlay loaded does not have the reminder tools.
|
|
45
|
+
|
|
46
|
+
### Schedule a reminder
|
|
47
|
+
|
|
48
|
+
One-time reminders come in two forms: after a delay — for example "in 30 minutes" — or at an absolute time, given either as an instant with an explicit offset such as `2026-09-01T15:00:00+08:00` or as a local date and time with a named zone such as `Europe/Berlin` (the browser's zone applies only when the time-context overlay is present). Repeating reminders run on a fixed interval of at least 5 minutes and stay aligned to the time you first set them. Every reminder needs content to show when it fires.
|
|
49
|
+
|
|
50
|
+
A successful create returns the reminder with its id, target time, state, and delivery mode; `schedule_list` shows all pending reminders in the order you created them; canceling by id removes a pending reminder, and an unknown or already-finished id reports `schedule_not_found` without changing anything.
|
|
51
|
+
|
|
52
|
+
Input that cannot become a reminder — an empty prompt, more than one selector, an invalid time zone, a non-future or out-of-range time, a repeating interval below 5 minutes — returns a stable error code instead of succeeding. The generated [tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-schedule) owns the exact arguments each tool accepts.
|
|
53
|
+
|
|
54
|
+
### When reminders fire
|
|
55
|
+
|
|
56
|
+
Due reminders appear as ordinary follow-up messages after the conversation becomes idle; the agent never interrupts a running turn. An already-live idle agent can claim maintenance and deliver immediately without another resume. One-time reminders fire before any repeating batch, and several repeating reminders due at once arrive together in one message ordered by time. If the session is closed or cold when a reminder comes due, it stays overdue until a future live root agent resumes the session — nothing is sent outside the session. A repeating reminder that missed intervals while the session was away presents only its latest due occurrence, not a backlog. The optional Web catalog shows only active records and is not a delivery receipt; dispatch means the follow-up was queued and recorded, not that the model succeeded or the user read the answer.
|
|
6
57
|
|
|
7
|
-
|
|
58
|
+
-----
|
|
8
59
|
|
|
9
|
-
|
|
60
|
+
<a id="understand-the-implementation"></a>
|
|
61
|
+
## Understand the implementation
|
|
10
62
|
|
|
11
|
-
|
|
63
|
+
<details>
|
|
64
|
+
<summary>Implementation internals — click to expand</summary>
|
|
12
65
|
|
|
13
|
-
|
|
66
|
+
This section explains the design decisions behind the plugin and points at the code that realizes them; the observable behavior is fully covered in [Use this package](#use-this-package).
|
|
14
67
|
|
|
15
|
-
|
|
68
|
+
### Scope and composition
|
|
16
69
|
|
|
17
|
-
The
|
|
70
|
+
The plugin declares `inject = ['agents', 'sessions', 'tools', 'sessionPersistence']`, so a missing persistence service is a composition error. It observes only `agent/created` events published after it loads, installs on those root Agents, and registers all three tools through the exact `agent.ctx`; Agents already live at load time and runtime children never receive Schedule.
|
|
18
71
|
|
|
19
|
-
|
|
72
|
+
Time-context is not a Schedule dependency. The official Web overlay mounts `@deepseek-ai/dsh-time-context` so the model can interpret natural language in the browser's request-local zone, but the model must still pass an explicit offset or `time_zone` to `schedule_create`; Schedule never imports or infers from model context.
|
|
20
73
|
|
|
21
|
-
|
|
74
|
+
Session projection is optional. When `ctx.sessionProjections` exists, the plugin registers the strict `schedule` unit and exposes the complete active `ScheduleRecord[]`; a headless composition without the registry keeps the same tools and runtime. The browser-safe record vocabulary is available from the type-only `@deepseek-ai/dsh-schedule/client` export. The shipped Web bundle resolves `ui-schedule` through a disabled row, and the explicit Schedule overlay enables that row alongside the Host Schedule services.
|
|
22
75
|
|
|
23
|
-
|
|
76
|
+
### Design philosophy
|
|
24
77
|
|
|
25
|
-
|
|
78
|
+
The package rests on one separation and three commitments:
|
|
26
79
|
|
|
27
|
-
|
|
80
|
+
- **The Session log owns the state.** Version-1 `schedule/change` events are the only durable authority; timers, tool values, and follow-ups are disposable projections rebuilt from the fold.
|
|
81
|
+
- **Strict replay.** The decoder rejects unknown versions, extra fields, reused ids, mismatched dispatch shapes, and transitions against inactive records, so a corrupt stream fails loudly instead of deriving wrong views.
|
|
82
|
+
- **Persistence before decision.** Every read or decision awaits the shared Session flush barrier, and create and delete confirm only after a second post-append barrier.
|
|
83
|
+
- **Session-local delivery only.** No external channel, no cold-session scheduler, and no receipt: due work enters the same conversation or stays active.
|
|
28
84
|
|
|
29
|
-
|
|
85
|
+
### Source map
|
|
30
86
|
|
|
31
|
-
|
|
87
|
+
| File | Role |
|
|
88
|
+
|---|---|
|
|
89
|
+
| [`src/index.ts`](src/index.ts) | Plugin entry: `inject`, `agent/created` observation, per-root runtime and tool installation |
|
|
90
|
+
| [`src/tools.ts`](src/tools.ts) | Tool definitions, preflight, serialized transactions, closed error union |
|
|
91
|
+
| [`src/domain.ts`](src/domain.ts) | Strict decoding, fold, time validation, framing, occurrence arithmetic |
|
|
92
|
+
| [`src/runtime.ts`](src/runtime.ts) | Live timer owner: maintenance claim, follow-up, dispatch barrier |
|
|
93
|
+
| [`src/persistence.ts`](src/persistence.ts) | Schedule-owned use of the shared session durability barrier |
|
|
94
|
+
| [`src/projection.ts`](src/projection.ts) | Optional seed-aware Session projection and strict checkpoint schema |
|
|
95
|
+
| [`src/client.ts`](src/client.ts) | Browser-safe type-only `ScheduleRecord` export |
|
|
96
|
+
| [`src/transaction.ts`](src/transaction.ts) | Agent-scoped serialization for reads and durable mutations |
|
|
97
|
+
| [`src/invariant.ts`](src/invariant.ts) | `./invariant` companion applying replay policy to existing logs and candidate events |
|
|
32
98
|
|
|
33
|
-
|
|
99
|
+
### Durable state and replay
|
|
34
100
|
|
|
35
|
-
|
|
101
|
+
A normal Session folds its complete event stream. A fork folds only `session.events.slice(session.header.seedLength ?? 0)`, so a child never inherits its parent's reminders. The Schedule projection derives that boundary from the immutable `SessionHeader` passed to `init(header)` and applies the same transition function to the same owned suffix. Every create record carries a stable Session-local `ScheduleId`, the trimmed prompt, and a four-digit-year RFC 3339 UTC `scheduledAt`; an `after` record also stores `afterSeconds`, an `at` record stores no copy of its submitted offset or local fields, and an `every` record stores `everySeconds` with `scheduledAt` as the earliest creation-anchor-aligned occurrence not yet dispatched. Delete and one-shot dispatch carry only the id; an `every` dispatch adds `acceptedAt`, and replay advances directly to the first anchor-aligned target after that decision time.
|
|
36
102
|
|
|
37
|
-
|
|
103
|
+
### Client projection
|
|
38
104
|
|
|
39
|
-
The
|
|
105
|
+
The optional `schedule` projection checkpoints `{ seedLength, active, seenIds }` as strict plain JSON and publishes only the complete `active` array. Its schema reuses the durable Schedule decoder, rejects duplicate or inconsistent ids, and propagates corrupt durable events through the existing Session read failure instead of publishing a partial catalog. Live lazy build, event-driven build, cold restore, history reads, and detached Subagent reads all use the immutable Session header and the same owned-suffix transition.
|
|
40
106
|
|
|
41
|
-
|
|
107
|
+
The projection carries durable records only. It does not persist or transmit scheduled-versus-overdue status, localized text, relative time, browser-local time, sorting state, popover state, runtime liveness, or delivery receipts. [`dsh-client-ui-schedule`](../../client/ui-schedule/README.md) derives catalog presentation from the complete array and the viewing browser's clock. [`dsh-client-ui-workspace`](../../client/ui-workspace/README.md) derives only whether the list value is a non-empty array, so ordinary and search rows may briefly omit or retain the alarm when the durable projection cache is missing or stale.
|
|
42
108
|
|
|
43
|
-
|
|
109
|
+
### Time validation
|
|
44
110
|
|
|
45
|
-
|
|
111
|
+
Calendar normalization is deterministic. Local times inside a daylight-saving gap are rejected; an overlap chooses its first, earlier instant. Schedule time validation reads no browser, Session-header time-zone field, model time-context, connection, or process time zone, so replay never depends on ambient time-zone state.
|
|
46
112
|
|
|
113
|
+
### Management pipeline
|
|
114
|
+
|
|
115
|
+
One Agent-scoped queue serializes each accepted management transaction with the live owner's due transaction from preflight through any post-append barrier. `schedule_create` checkpoints, allocates a never-reused id, appends the create event, and checkpoints again; a cancelled caller stops before append. Every successful management preflight also asks the live owner to recompute, which recovers a retained create or delete batch after a previous post-append barrier returned `persistence_uncertain`.
|
|
116
|
+
|
|
117
|
+
Every read or decision from the fold first awaits `ctx.sessions.flush(session)`; a missing, rejected, or detached persistence path returns `persistence_uncertain`, and create and an actual delete await a second barrier after append before confirming the mutation. Shape-only failures are validated before the serialized transaction. Input, time, and durability failures return a closed set of stable version-1 error codes; the closed union and each code's conditions live in [`src/tools.ts`](src/tools.ts).
|
|
118
|
+
|
|
119
|
+
### Live owner
|
|
120
|
+
|
|
121
|
+
The owner splits long waits into bounded timer segments and rereads the wall clock after every wake. Due work claims the idle maintenance phase, samples one decision time, builds the complete escaped framing before `followup()`, appends dispatch only after synchronous enqueue returns, releases maintenance, and then awaits durability. Missed fixed-rate intervals are never enumerated: integer arithmetic selects each record's latest due creation-anchor-aligned occurrence and advances it directly to the first future target.
|
|
122
|
+
|
|
123
|
+
An overdue reminder first checkpoints persistence, then claims the Agent's idle maintenance phase through `runMaintenance()`; if a turn or another maintenance task owns the Agent, the claim is rejected, the record stays active, and the owner retries after `whenIdle()`. A successful maintenance task refolds, samples one decision time, builds the fixed framing, synchronously queues `followup()`, and appends the dispatch before releasing the phase. Dispatch means the follow-up was queued and recorded, not that the model succeeded or the user read the answer. Framing or synchronous follow-up failure writes no dispatch; an append failure faults the owner because the message may already be queued; a barrier rejection leaves dispatch pending for a later ordinary preflight. Agent or plugin disposal cancels timers and stops new work without deleting durable records.
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
-----
|
|
128
|
+
|
|
129
|
+
<a id="further-exploration"></a>
|
|
130
|
+
## Further Exploration
|
|
131
|
+
|
|
132
|
+
Read these pages when the package-level contract is not enough. They move from the shared subsystem contracts to the exact tool schemas and the decision evidence behind the delivery design.
|
|
133
|
+
|
|
134
|
+
- [Session-local Schedule subsystem](../../../docs/subsystems/schedule.md) — durable record, transition, view, and delivery contracts with the exact type definitions.
|
|
135
|
+
- [Generated tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-schedule) — the complete `schedule_create`, `schedule_list`, and `schedule_delete` schemas the model receives.
|
|
136
|
+
- [Durable Web Schedule decision](../../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) — persistence and lifecycle decisions behind the package.
|
|
137
|
+
- [Conversational delivery decision](../../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.md) — the no-receipt boundary and follow-up delivery.
|
|
138
|
+
- [Explicit time-zone boundary](../../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.md) — why the model must always pass an explicit zone.
|
|
139
|
+
- [Bounded fixed-rate Schedule](../../../.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.md) — recurrence scope: latest-only catch-up and batch delivery.
|
|
140
|
+
- [Schedule user guide](../../../docs/user/guide/schedule.md) — the official configuration path for mounting this package with time-context.
|
|
141
|
+
|
|
142
|
+
-----
|
|
143
|
+
|
|
144
|
+
<a id="model-experience"></a>
|
|
47
145
|
## Model Experience
|
|
48
146
|
|
|
49
147
|
### Scoped management tools
|
|
50
148
|
|
|
51
149
|
#### What the model sees
|
|
52
150
|
|
|
53
|
-
The model sees the three generated tool schemas only in a live root Agent created after this plugin loads. Tool results contain the canonical JSON values described above.
|
|
151
|
+
The model sees the three generated tool schemas only in a live root Agent created after this plugin loads; the [generated tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-schedule) owns the exact argument and result schemas. Tool results contain the canonical JSON values described above.
|
|
54
152
|
|
|
55
153
|
#### Token effect
|
|
56
154
|
|
|
@@ -108,6 +206,11 @@ The batch appends after existing history and preserves its reusable prefix. Its
|
|
|
108
206
|
|
|
109
207
|
## Known Limitations and Deferred Work
|
|
110
208
|
|
|
209
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
These limits describe when Schedule does not fit your use case or needs special operational care. They are current package constraints, not a general reminder-service comparison or a task backlog.
|
|
213
|
+
|
|
111
214
|
- **Session-local delivery only** — a reminder runs on time only while its original Session is live; a cold Session receives no external notification and processes an overdue record only after resume.
|
|
112
215
|
- **Activity-driven retry** — a rejected due preflight or contained framing/enqueue failure leaves the record active but starts no private retry timer; later Agent activity or a successful Schedule preflight triggers recomputation.
|
|
113
216
|
- **Explicit local zone** — `at` never imports browser context; callers must translate natural language into either an offset-bearing RFC 3339 string or a local object with `time_zone`.
|
|
@@ -115,3 +218,16 @@ The batch appends after existing history and preserves its reusable prefix. Its
|
|
|
115
218
|
- **Latest-only catch-up** — an overdue Every record contributes only its latest due occurrence, so Schedule never replays a missed backlog.
|
|
116
219
|
- **Narrow crash duplicate window** — a crash after synchronous follow-up admission but before the dispatch checkpoint can repeat the reminder; the package does not claim model completion, user acknowledgement, or exactly-once effects.
|
|
117
220
|
- **Load-order boundary** — the plugin does not scan or adopt Agents that were already live when it loaded.
|
|
221
|
+
- **Catalog is read-only current state** — the optional Web surface has no history, mutation, retry, or acknowledgement semantics; terminal records disappear and delivery remains ordinary conversation output.
|
|
222
|
+
|
|
223
|
+
<a id="dev-note"></a>
|
|
224
|
+
### Dev Note
|
|
225
|
+
|
|
226
|
+
<details>
|
|
227
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
228
|
+
|
|
229
|
+
This Dev Note is working context for maintainers: open directions that are not decided. It is explicitly non-authoritative — shipped behavior, limits, and accepted rationale live in the sections above, the package code, and the linked Agent Notes.
|
|
230
|
+
|
|
231
|
+
Calendar-based recurrence remains a future product boundary rather than a dormant compatibility branch; the bounded fixed-rate decision is the shipped scope. An external notification channel for cold Sessions stays explicitly out of scope. Neither direction has a schedule or design owner.
|
|
232
|
+
|
|
233
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,70 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "面向用户与维护者的会话本地持久提醒说明:schedule_create、schedule_list 与 schedule_delete 工具及 live owner 交付,用于选择、配置或排查本包。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-schedule
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-schedule` 为你的会话提供持久的提醒:让模型稍后提醒你,提醒会作为同一会话中的普通 follow-up 消息返回。你可以安排延时后的一次性提醒、绝对时间的一次性提醒,或固定间隔的重复提醒,也可以列出仍待处理的提醒或取消提醒。提醒在重启后依然存在:已经 live 且空闲的 agent 可以立即交付到期工作,而已关闭或 cold 的会话会让提醒保持逾期,直到未来的 live 根 agent 恢复会话。交付只发生在会话内部,没有电子邮件、短信或推送通知。它是可选的 Web 能力;加载 Schedule overlay 即可启用提醒工具与只读活动提醒目录。普通与搜索侧边栏行还会在尽力而为的列表 projection 明确非空时显示不可交互的闹钟;该闹钟不保证 live runtime 存在。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当你希望提醒作为消息出现在同一会话中时使用 Schedule——例如「30 分钟后提醒我跟进迁移」或「构建运行期间每小时检查一次」。agent 会通过它的普通工具为你创建、列出和取消提醒;你只需启用一次 overlay。
|
|
29
|
+
|
|
30
|
+
### 何时选择
|
|
31
|
+
|
|
32
|
+
当你希望提醒以消息形式在同一 live 会话中交付时,选择 Schedule。当交付必须到达会话之外时请避开它——没有电子邮件、短信、推送或浏览器通知——或者当你需要「每个工作日 9 点」这类日历规则时:重复提醒只按固定间隔运行。
|
|
33
|
+
|
|
34
|
+
### 启用 Schedule
|
|
35
|
+
|
|
36
|
+
把 Schedule overlay 添加到 `dsh web` 会话;提醒工具随即出现在会话中,模型可以立即使用它们:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
dsh web --patch apps/cli/config/examples/schedule/cordis.yml
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
成功的样子如下:让模型「10 分钟后提醒我审阅 PR」,它会回复提醒的 id、目标时间与 `scheduled` 状态。如果那一刻存储无法确认,工具会报告 `persistence_uncertain` 并建议重新列出,而不是声称成功。
|
|
43
|
+
|
|
44
|
+
请在你想要提醒的会话开始前启用 overlay:overlay 加载时已在运行的会话没有提醒工具。
|
|
45
|
+
|
|
46
|
+
### 安排提醒
|
|
47
|
+
|
|
48
|
+
一次性提醒有两种形式:延时后——例如「30 分钟后」——或绝对时间,可以给出带显式偏移量的时刻,如 `2026-09-01T15:00:00+08:00`,也可以给出带命名时区(如 `Europe/Berlin`)的本地日期与时间(只有加载 time-context overlay 时才应用浏览器时区)。重复提醒按至少 5 分钟的固定间隔运行,并与你首次设置的时间保持对齐。每条提醒都需要在触发时展示的内容。
|
|
49
|
+
|
|
50
|
+
创建成功会返回带 id、目标时间、状态与交付模式的提醒;`schedule_list` 按创建顺序显示所有待处理提醒;按 id 取消会移除待处理提醒,未知或已结束的 id 会报告 `schedule_not_found` 且不改变任何内容。
|
|
51
|
+
|
|
52
|
+
无法成为提醒的输入——空提示词、多于一个 selector、无效时区、非未来或超出范围的时间、低于 5 分钟的重复间隔——会返回稳定的错误代码而不是成功。生成的[工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-schedule)拥有每个工具接受的精确参数。
|
|
53
|
+
|
|
54
|
+
### 提醒何时触发
|
|
55
|
+
|
|
56
|
+
到期提醒会在会话空闲后作为普通 follow-up 消息出现;agent 绝不会中断正在运行的轮次。已经 live 且空闲的 agent 可以认领 maintenance 并立即交付,无需再次恢复。一次性提醒先于任何重复批次触发;同时到期的多条重复提醒会按时间顺序合并为一条消息。如果会话在提醒到期时已关闭或 cold,提醒会保持逾期,直到未来的 live 根 agent 恢复会话——会话之外不会发送任何内容。错过若干间隔的重复提醒只展示最新一个到期发生时点,不展示积压。可选 Web 目录只显示活动记录,并不充当交付回执;dispatch 表示 follow-up 已入队并被记录,不表示模型成功或用户已读取回答。
|
|
6
57
|
|
|
7
|
-
|
|
58
|
+
-----
|
|
8
59
|
|
|
9
|
-
|
|
60
|
+
<a id="understand-the-implementation"></a>
|
|
61
|
+
## 理解实现
|
|
10
62
|
|
|
11
|
-
|
|
63
|
+
<details>
|
|
64
|
+
<summary>实现细节——点击展开</summary>
|
|
12
65
|
|
|
13
|
-
|
|
66
|
+
本节解释插件背后的设计决策,并指出实现它们的代码位置;可观察行为已在[使用本包](#use-this-package)中完整说明。
|
|
14
67
|
|
|
15
|
-
|
|
68
|
+
### 作用域与组合
|
|
16
69
|
|
|
17
|
-
|
|
70
|
+
插件声明 `inject = ['agents', 'sessions', 'tools', 'sessionPersistence']`,因此缺少持久化服务会直接构成组合错误。它只观察加载后发布的 `agent/created` 事件,在这些根 agent 上安装,并通过完全相同的 `agent.ctx` 注册全部三个工具;加载时已经 live 的 agent 与运行时子 agent 永远不会获得 Schedule。
|
|
18
71
|
|
|
19
|
-
|
|
72
|
+
Time-context 不是 Schedule 的依赖。官方 Web overlay 挂载 `@deepseek-ai/dsh-time-context`,让模型能够按浏览器请求本地时区解释自然语言;但模型仍必须向 `schedule_create` 传入显式偏移量或 `time_zone`;Schedule 绝不会从模型上下文导入或推断该值。
|
|
20
73
|
|
|
21
|
-
|
|
74
|
+
Session projection 是可选能力。`ctx.sessionProjections` 存在时,插件会注册严格的 `schedule` 单元并公开完整的活动 `ScheduleRecord[]`;不带注册表的 headless 组合仍保留相同工具与 runtime。浏览器安全的记录词汇由纯类型出口 `@deepseek-ai/dsh-schedule/client` 提供。随附 Web bundle 通过 disabled row 解析 `ui-schedule`,显式 Schedule overlay 再与 Host Schedule 服务一起启用该 row。
|
|
22
75
|
|
|
23
|
-
|
|
76
|
+
### 设计理念
|
|
24
77
|
|
|
25
|
-
|
|
78
|
+
本包建立在一个分离与三项承诺之上:
|
|
26
79
|
|
|
27
|
-
|
|
80
|
+
- **会话日志拥有状态。** 版本 1 的 `schedule/change` 事件是唯一持久权威;timer、工具值与 follow-up 都是从折叠结果重建的可丢弃投影。
|
|
81
|
+
- **严格回放。** 解码器拒绝未知版本、额外字段、重复使用的 id、形状不匹配的 dispatch 以及针对非活动记录的转换,因此损坏的流会大声失败,而不是派生出错误视图。
|
|
82
|
+
- **先持久化再决策。** 每项读取或决策都等待共享的会话 flush barrier,create 与 delete 只在第二个 post-append barrier 之后才确认。
|
|
83
|
+
- **仅限会话本地交付。** 没有外部渠道、没有 cold 会话调度器、也没有回执:到期工作进入同一会话,否则保持活动。
|
|
28
84
|
|
|
29
|
-
|
|
85
|
+
### 源码地图
|
|
30
86
|
|
|
31
|
-
|
|
87
|
+
| 文件 | 职责 |
|
|
88
|
+
|---|---|
|
|
89
|
+
| [`src/index.ts`](src/index.ts) | 插件入口:`inject`、`agent/created` 观察、按根的 runtime 与工具安装 |
|
|
90
|
+
| [`src/tools.ts`](src/tools.ts) | 工具定义、preflight、序列化事务、封闭错误联合 |
|
|
91
|
+
| [`src/domain.ts`](src/domain.ts) | 严格解码、折叠、时间校验、framing、occurrence 算术 |
|
|
92
|
+
| [`src/runtime.ts`](src/runtime.ts) | live timer owner:maintenance 认领、follow-up、dispatch barrier |
|
|
93
|
+
| [`src/persistence.ts`](src/persistence.ts) | Schedule 对共享会话持久化 barrier 的使用 |
|
|
94
|
+
| [`src/projection.ts`](src/projection.ts) | 可选的 seed-aware Session projection 与严格检查点 schema |
|
|
95
|
+
| [`src/client.ts`](src/client.ts) | 浏览器安全的纯类型 `ScheduleRecord` 出口 |
|
|
96
|
+
| [`src/transaction.ts`](src/transaction.ts) | 读取与持久变更的 agent 范围串行化 |
|
|
97
|
+
| [`src/invariant.ts`](src/invariant.ts) | `./invariant` 配套模块,对现有日志与候选事件应用回放策略 |
|
|
32
98
|
|
|
33
|
-
|
|
99
|
+
### 持久状态与回放
|
|
34
100
|
|
|
35
|
-
|
|
101
|
+
普通会话折叠完整事件流。fork 只折叠 `session.events.slice(session.header.seedLength ?? 0)`,因此子会话永远不会继承父会话的提醒。Schedule projection 从传给 `init(header)` 的不可变 `SessionHeader` 派生该边界,并对同一自有后缀应用同一个 transition 函数。每条 create 记录都携带稳定的会话本地 `ScheduleId`、已 trim 的提示词与四位年份 RFC 3339 UTC `scheduledAt`;`after` 记录还存储 `afterSeconds`,`at` 记录不保留所提交的偏移量或本地字段,`every` 记录存储 `everySeconds`,并把 `scheduledAt` 视为尚未 dispatch 的最早创建锚点对齐发生时点。delete 与一次性 dispatch 只携带 id;`every` dispatch 会附加 `acceptedAt`,回放直接推进到该决策时点之后的第一个锚点对齐目标。
|
|
36
102
|
|
|
37
|
-
|
|
103
|
+
### 客户端 projection
|
|
38
104
|
|
|
39
|
-
live
|
|
105
|
+
可选的 `schedule` projection 将 `{ seedLength, active, seenIds }` 作为严格的纯 JSON 检查点,并且只发布完整的 `active` 数组。其 schema 复用持久 Schedule decoder,拒绝重复或不一致的 id,并让损坏的持久事件通过既有 Session 读取失败传播,而不是发布部分目录。live 惰性构建、事件驱动构建、cold restore、history 读取与 detached Subagent 读取都使用不可变 Session header 与同一套自有后缀 transition。
|
|
40
106
|
|
|
41
|
-
|
|
107
|
+
projection 只携带持久记录。它不持久化或传输 scheduled/overdue 状态、本地化文本、相对时间、浏览器本地时间、排序状态、popover 状态、runtime 存活或交付回执。[`dsh-client-ui-schedule`](../../client/ui-schedule/README.zh.md) 从完整数组与查看方浏览器时钟派生目录呈现。[`dsh-client-ui-workspace`](../../client/ui-workspace/README.zh.md) 只派生列表值是否为非空数组,因此持久 projection cache 缺失或陈旧时,普通行与搜索结果的闹钟可能短暂漏显或残留。
|
|
42
108
|
|
|
43
|
-
|
|
109
|
+
### 时间校验
|
|
44
110
|
|
|
45
|
-
|
|
111
|
+
日历规范化是确定性的。夏令时缺口内的本地时间会被拒绝;重叠时选择第一次出现的较早时刻。Schedule 的时间校验不会读取浏览器、Session header 中的时区字段、模型 time-context、连接或进程时区,因此回放永不依赖环境时区状态。
|
|
46
112
|
|
|
113
|
+
### 管理流水线
|
|
114
|
+
|
|
115
|
+
一条 agent 范围的队列把每项已接纳的管理事务与 live owner 的到期事务从 preflight 到任何 post-append barrier 全程串行化。`schedule_create` 建立检查点、分配永不复用的 id、追加 create 事件,再次建立检查点;被取消的调用方在追加前停止。每次成功的管理 preflight 还会要求 live owner 重新计算,这会在先前的 post-append barrier 返回 `persistence_uncertain` 后恢复所保留的 create 或 delete 批次。
|
|
116
|
+
|
|
117
|
+
每项从折叠结果读取或作出判断的操作都会先等待 `ctx.sessions.flush(session)`;持久化路径缺失、被拒绝或已分离时返回 `persistence_uncertain`,create 与实际 delete 在追加后还会等待第二个 barrier 再确认变更。只依赖输入形状的失败会在序列化事务之前被验证。输入、时间与持久化失败会返回一组封闭的稳定版本 1 错误代码;该封闭联合及各代码的触发条件位于 [`src/tools.ts`](src/tools.ts)。
|
|
118
|
+
|
|
119
|
+
### live owner
|
|
120
|
+
|
|
121
|
+
owner 把长等待拆分为有界的 timer 段,并在每次唤醒后重新读取墙钟。到期工作认领 idle maintenance phase、采样一个决策时点、在 `followup()` 之前构造完整的转义 framing、只在同步入队返回后追加 dispatch、释放 maintenance,然后等待持久化。错过的固定速率间隔永远不会被枚举:整数运算选择每条记录最新一个已到期且与创建锚点对齐的发生时点,并直接推进到第一个未来目标。
|
|
122
|
+
|
|
123
|
+
逾期提醒首先为持久化建立检查点,然后通过 `runMaintenance()` 认领 agent 的 idle maintenance phase;如果某个轮次或另一项 maintenance task 已占用 agent,认领会失败,记录保持活动,owner 在 `whenIdle()` 后重试。获准的 maintenance task 会重新折叠、采样一个决策时点、构造固定 framing、同步将 `followup()` 入队,并在释放 phase 前追加 dispatch。dispatch 表示 follow-up 已入队并被记录,不表示模型成功或用户已读取回答。framing 构造或同步 follow-up 失败不会写入 dispatch;追加失败会使 owner 进入故障状态,因为消息可能已经入队;barrier 拒绝则把 dispatch 留给后续普通 preflight。agent 或插件执行资源释放时取消 timer 并停止新工作,但不删除持久记录。
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
-----
|
|
128
|
+
|
|
129
|
+
<a id="further-exploration"></a>
|
|
130
|
+
## 进一步探索
|
|
131
|
+
|
|
132
|
+
当包级约定不够用时阅读以下页面。它们从共享子系统约定逐步进入精确工具 schema,以及交付设计背后的决策证据。
|
|
133
|
+
|
|
134
|
+
- [仅限会话内的 Schedule 子系统](../../../docs/subsystems/schedule.zh.md)——带精确类型定义的持久记录、转换、视图与交付约定。
|
|
135
|
+
- [生成的工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-schedule)——模型接收的 `schedule_create`、`schedule_list` 与 `schedule_delete` 完整 schema。
|
|
136
|
+
- [持久 Web Schedule 决策](../../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.zh.md)——本包背后的持久化与生命周期决策。
|
|
137
|
+
- [对话式交付决策](../../../.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.zh.md)——无回执边界与 follow-up 交付。
|
|
138
|
+
- [显式时区边界](../../../.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.zh.md)——为什么模型必须始终传入显式时区。
|
|
139
|
+
- [有界固定速率 Schedule](../../../.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.zh.md)——重复调度范围:只追赶最新一次与批次交付。
|
|
140
|
+
- [Schedule 用户指南](../../../docs/user/guide/schedule.zh.md)——挂载本包与 time-context 的官方配置路径。
|
|
141
|
+
|
|
142
|
+
-----
|
|
143
|
+
|
|
144
|
+
<a id="model-experience"></a>
|
|
47
145
|
## 模型体验
|
|
48
146
|
|
|
49
147
|
### 范围限定的管理工具
|
|
50
148
|
|
|
51
|
-
####
|
|
149
|
+
#### 模型看到什么
|
|
52
150
|
|
|
53
|
-
只有在此插件加载后创建的 live 根 agent
|
|
151
|
+
只有在此插件加载后创建的 live 根 agent 中,模型才会看到三个生成的工具 schema;[生成的工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-schedule)拥有精确的参数与结果 schema。工具结果包含上文所述的规范 JSON 值。
|
|
54
152
|
|
|
55
153
|
#### Token 影响
|
|
56
154
|
|
|
57
|
-
安装 Schedule 后,范围限定的 schema 会增加固定的请求前缀。每次执行工具都会经由普通工具结果流水线添加与数据相关的 JSON
|
|
155
|
+
安装 Schedule 后,范围限定的 schema 会增加固定的请求前缀。每次执行工具都会经由普通工具结果流水线添加与数据相关的 JSON 结果;本包不增加私有截断或 token 预算。
|
|
58
156
|
|
|
59
157
|
#### KV Cache 影响
|
|
60
158
|
|
|
61
|
-
|
|
159
|
+
三个 schema 的定义与范围不变时,前缀保持稳定。工具调用和结果会追加到后续历史中,并保留已经可以复用的前缀。
|
|
62
160
|
|
|
63
161
|
### 到期提醒 follow-up
|
|
64
162
|
|
|
65
|
-
####
|
|
163
|
+
#### 模型看到什么
|
|
66
164
|
|
|
67
|
-
|
|
165
|
+
对于每条获得准入且已到期的一次性提醒,本包会将以下稳定的用户角色 framing 入队,并对动态值进行 JSON 转义:
|
|
68
166
|
|
|
69
167
|
##### 提醒 framing
|
|
70
168
|
|
|
@@ -86,9 +184,9 @@ reminder_prompt_json: <JSON.stringify(prompt)>
|
|
|
86
184
|
|
|
87
185
|
### 到期固定速率批次
|
|
88
186
|
|
|
89
|
-
####
|
|
187
|
+
#### 模型看到什么
|
|
90
188
|
|
|
91
|
-
当一条或多条 Every
|
|
189
|
+
当一条或多条 Every 记录逾期时,本包会排入一条稳定的用户角色 framing。`reminders_json` 是一个按目标时间和创建顺序排列的 JSON 数组;每个对象都包含 `schedule_id`、选中的最新 `occurrence_at`,以及创建时提供的 `reminder_prompt`:
|
|
92
190
|
|
|
93
191
|
##### 固定速率批次 framing
|
|
94
192
|
|
|
@@ -100,18 +198,36 @@ reminders_json: <JSON.stringify(reminders)>
|
|
|
100
198
|
|
|
101
199
|
#### Token 影响
|
|
102
200
|
|
|
103
|
-
无论有多少条不同的 Every 记录到期,每个获得准入的固定速率批次只会增加一条与数据相关的用户角色消息。该消息保留在会话历史中,并持续贡献 token
|
|
201
|
+
无论有多少条不同的 Every 记录到期,每个获得准入的固定速率批次只会增加一条与数据相关的用户角色消息。该消息保留在会话历史中,并持续贡献 token,直到普通压缩(compaction)移除或替换这段历史。
|
|
104
202
|
|
|
105
203
|
#### KV Cache 影响
|
|
106
204
|
|
|
107
205
|
该批次会追加到现有历史之后,并保留可复用的前缀。选中的记录、发生时点和提示词只会影响追加的后缀。
|
|
108
206
|
|
|
109
|
-
##
|
|
207
|
+
## 已知限制与延期工作
|
|
208
|
+
|
|
209
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
这些限制说明 Schedule 何时不适合你的使用场景,或何时需要特别的运维注意。它们是当前包约束,不是通用提醒服务对比或任务积压。
|
|
213
|
+
|
|
214
|
+
- **仅限会话本地交付**——提醒只有在原会话 live 时才能准时运行;cold 会话不会收到外部通知,只有恢复后才会处理逾期记录。
|
|
215
|
+
- **活动驱动的重试**——到期 preflight 被拒绝或 framing/入队失败被收容后,记录仍保持活动,但不会启动私有重试 timer;后续 agent 活动或成功的 Schedule preflight 会触发重新计算。
|
|
216
|
+
- **显式本地时区**——`at` 绝不会导入浏览器上下文;调用方必须把自然语言转换为带偏移量的 RFC 3339 字符串,或带 `time_zone` 的本地对象。
|
|
217
|
+
- **固定间隔,而非日历规则**——`every_seconds` 与创建锚点对齐,且运行频率不能高于每 5 分钟一次;协议不包含日历表达式或 Cron 表达式。
|
|
218
|
+
- **只追赶最新一次**——逾期 Every 记录只贡献其最新一个到期发生时点,因此 Schedule 绝不会回放因错过间隔而形成的积压。
|
|
219
|
+
- **存在狭窄的崩溃重复窗口**——同步 follow-up 获得准入后、dispatch 检查点完成前发生崩溃,可能使提醒重复;本包不承诺模型完成、用户确认或副作用恰好执行一次。
|
|
220
|
+
- **加载顺序边界**——插件不会扫描或接管加载时已经 live 的 agent。
|
|
221
|
+
- **目录只是只读当前状态**——可选 Web 界面没有历史、mutation、Retry 或 acknowledgement 语义;终结记录会消失,交付仍然是普通对话输出。
|
|
222
|
+
|
|
223
|
+
<a id="dev-note"></a>
|
|
224
|
+
### 开发备注
|
|
225
|
+
|
|
226
|
+
<details>
|
|
227
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
228
|
+
|
|
229
|
+
本开发备注是维护者的工作上下文:尚未决定的开放方向。它明确不具权威性——已交付的行为、限制与既定理由以上文、包代码和相关 Agent Note 为准。
|
|
230
|
+
|
|
231
|
+
基于日历的重复调度仍是未来的产品边界,而非休眠的兼容分支;有界固定速率决策是已交付的范围。面向 cold 会话的外部通知渠道明确不在范围内。这两个方向都没有进度计划或设计负责人。
|
|
110
232
|
|
|
111
|
-
|
|
112
|
-
- **活动驱动的重试**:到期 preflight 被拒绝或 framing/入队失败被收容后,记录仍保持活动,但不会启动私有重试 timer;后续 Agent 活动或成功的 Schedule preflight 会触发重新计算。
|
|
113
|
-
- **显式本地时区**:`at` 绝不会导入浏览器上下文;调用方必须把自然语言转换为带偏移量的 RFC 3339 字符串,或带 `time_zone` 的本地对象。
|
|
114
|
-
- **固定间隔,而非日历规则**:`every_seconds` 与创建锚点对齐,且运行频率不能高于每 5 分钟一次;协议不包含日历表达式或 Cron 表达式。
|
|
115
|
-
- **只追赶最新一次**:逾期 Every 记录只贡献其最新一个到期发生时点,因此 Schedule 绝不会回放因错过间隔而形成的积压。
|
|
116
|
-
- **存在狭窄的崩溃重复窗口**:同步 follow-up 获得准入后、dispatch 检查点完成前发生崩溃,可能使提醒重复;此包不承诺模型完成、用户确认或副作用恰好执行一次。
|
|
117
|
-
- **加载顺序边界**:插件不会扫描或接管加载时已经 live 的 Agent。
|
|
233
|
+
</details>
|