@qilin-agent/schedule 3.1.7 → 3.1.9

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.
@@ -1,14 +1,25 @@
1
1
  import z from '@qilin-agent/schemastery';
2
2
  import { Context, Service } from '@qilin-agent/kylin';
3
+ import type { Agent } from '@qilin-agent/agent';
3
4
  import { TypertRemoteService } from '@qilin-agent/typert-protocol';
4
- import type { SessionId } from '@qilin-agent/session';
5
- import type { ScheduleCatalogEntry, ScheduleCreateRequest, ScheduleDeleteRequest, ScheduleDeleteResult, ScheduleDeliveryHistoryRequest, ScheduleDeliveryHistoryResult, ScheduleListRequest, ScheduleRecord, ScheduleUpdateRequest, ScheduleUpdateResult } from './types.ts';
6
- export type * from './types.ts';
5
+ import { type SessionId } from '@qilin-agent/session';
6
+ import type { ScheduleCatalogEntry, ScheduleCreateRequest, ScheduleDeleteInactiveResult, ScheduleDeliveryHistoryRequest, ScheduleDeliveryHistoryResult, ScheduleEditRequest, ScheduleEditResult, ScheduleListRequest, ScheduleListResult, ScheduleRunRequest, ScheduleRunResult, ScheduleViewRequest, ScheduleViewResult } from './types.ts';
7
+ export type * from './client.ts';
7
8
  export { scheduleDomain } from './storage.ts';
8
9
  export type { ScheduleTask } from './storage.ts';
9
10
  export type { RecurringOccurrence } from './domain.ts';
10
- export { SCHEDULE_CHANGE_VERSION, MIN_EVERY_INTERVAL_SECONDS, MAX_TITLE_LENGTH, REQUIRED_TITLE_MESSAGE, ScheduleId, ScheduleInputError, ScheduleLogError, canonicalizeCronExpression, createAfterScheduleRecord, createAtScheduleRecord, createEveryScheduleRecord, createDailyScheduleRecord, createWeeklyScheduleRecord, createCronScheduleRecord, decodeScheduleChange, decodeScheduleRecord, foldScheduleEvents, isRecurringScheduleRecord, normalizeWeekdays, parseCronInput, parseWeeklyInput, renderReminderFraming, renderRecurringReminderBatchFraming, resolveEveryOccurrence, resolveDailyOccurrence, resolveWeeklyOccurrence, resolveCronOccurrence, resolveRecurringOccurrence, scheduleTitle, scheduleView, weeklyTime, } from './domain.ts';
11
+ export { formatScheduleLocalTime } from './domain.ts';
12
+ export { MIN_EVERY_INTERVAL_SECONDS, MAX_TITLE_LENGTH, REQUIRED_TITLE_MESSAGE, ScheduleId, ScheduleInputError, ScheduleLogError, canonicalizeCronExpression, createAfterScheduleRecord, createAtScheduleRecord, createEveryScheduleRecord, createDailyScheduleRecord, createWeeklyScheduleRecord, createCronScheduleRecord, createRRuleScheduleRecord, decodeScheduleRecord, isRecurringScheduleRecord, normalizeWeekdays, parseCronInput, parseWeeklyInput, renderReminderFraming, renderRecurringReminderBatchFraming, resolveEveryOccurrence, resolveDailyOccurrence, resolveWeeklyOccurrence, resolveCronOccurrence, resolveRecurringOccurrence, scheduleTitle, weeklyTime, } from './domain.ts';
11
13
  declare module '@qilin-agent/kylin' {
14
+ interface Events {
15
+ /**
16
+ * Restore a reminder's Session through its embedding's owning controller.
17
+ * Call next() to use the Web Session controller.
18
+ * @param sessionId - Original Session receiving the reminder.
19
+ * @mode waterfall
20
+ */
21
+ 'schedule/resolve-agent'(sessionId: SessionId, next: () => Promise<Agent>): Promise<Agent>;
22
+ }
12
23
  interface Context {
13
24
  /** Durable Host-wide reminder management. */
14
25
  schedule: ScheduleService;
@@ -26,95 +37,143 @@ export interface Config {
26
37
  * cap and the window wins, and the newest records survive.
27
38
  */
28
39
  deliveryHistoryRecords?: number;
40
+ /**
41
+ * Shortest spacing, in seconds, from the occurrence of one delivery to the next delivery of one task whose target
42
+ * creates a Session at every delivery; omission defaults to 60. Timed and manual deliveries both wait for it.
43
+ */
44
+ newSessionIntervalSeconds?: number;
29
45
  }
46
+ /** Page size of a task list request that states none. */
47
+ export declare const DEFAULT_LIST_LIMIT = 100;
48
+ /** Largest page size of one task list request. */
49
+ export declare const MAX_LIST_LIMIT = 500;
30
50
  /**
31
- * Shared management service; reads, deletion, and timing edits never activate a Session.
51
+ * Shared management service; reads and management writes never activate a Session, and only delivery creates or
52
+ * resumes one.
32
53
  *
33
- * `sessionPersistence` is a load-order requirement rather than a directly called
34
- * service: a delivery commits only when `ctx.sessions.flush()` reports that a
35
- * `session/flush` listener participated, and the persistence backend providing this
36
- * service is the plugin that registers that listener.
54
+ * `sessionPersistence` supplies header-only target validation and the `session/flush`
55
+ * listener that acknowledges durable inbox delivery through `ctx.sessions.flush()`.
37
56
  */
38
57
  export declare class ScheduleService extends TypertRemoteService {
39
58
  static inject: string[];
40
59
  static Config: z<Config>;
41
- /** Resolved retention bounds shared with the runtime that appends acknowledgments. */
42
- private readonly retention;
60
+ /** Resolved retention and admission limits shared with the runtime that appends acknowledgments. */
61
+ private readonly limits;
43
62
  private readonly ready;
44
63
  private readonly initialized;
45
64
  private chain;
65
+ private notifications;
46
66
  private runtime;
67
+ private resolveWebAgent;
47
68
  private stopping;
48
69
  /**
49
70
  * @param ctx - Host services owning storage, dispatch, and Session restoration.
50
- * @param config - Validated retention configuration for delivery history.
71
+ * @param config - Validated delivery-history retention and new-Session admission configuration.
51
72
  */
52
73
  constructor(ctx: Context, config: Config);
53
74
  [Service.init](): Promise<void>;
75
+ /** Read effective delivery limits without loading or activating a task.
76
+ * @returns The configured minimum spacing between deliveries that each create a Session, in seconds.
77
+ */
78
+ deliveryLimits(): {
79
+ readonly newSessionIntervalSeconds: number;
80
+ };
54
81
  /**
55
- * Create a reminder bound to the caller-selected Session without activating it.
82
+ * Create one task with a Host-generated identity for a human Remote caller.
83
+ * @param request - Title, prompt, recurrence, and delivery destination.
84
+ * @param signal - Cancellation checked before the durable write begins, including after FIFO waits.
85
+ * @returns The stored task. Cancellation does not roll back an in-flight write.
86
+ */
87
+ remoteCreate(request: ScheduleCreateRequest, signal?: AbortSignal): Promise<ScheduleCatalogEntry>;
88
+ /**
89
+ * Create one task and record the acting Agent's Session as involved; the Remote form omits that Session.
56
90
  *
57
- * The request must supply a title; a missing, blank-after-trim, or over-long
58
- * title rejects with `invalid_prompt` instead of deriving one from the prompt.
59
- * A Session a delegated child owns rejects with `subagent_session`, because delivery
60
- * can never reach it: the child is one whose delegation depth is above zero.
61
- * The record is built from the clock reading taken before the request joins the
62
- * serialized queue, so a create that waits behind a longer operation keeps its
63
- * request-time anchor and may already be due when the queue reaches it.
64
- * @param sessionId - Original Session receiving the reminder.
65
- * @param request - Validated tool selector, required title, and reminder content.
66
- * @param signal - Optional cancellation checked before persistence begins, including after FIFO waits.
67
- * @returns The durably stored schedule. Cancellation does not roll back an in-flight write.
68
- */
69
- create(sessionId: SessionId, request: ScheduleCreateRequest, signal?: AbortSignal): Promise<ScheduleRecord>;
70
- /**
71
- * Read the selected Session's active tasks without resuming its Agent.
72
- * @param request - Session whose task list is requested.
73
- * @returns Persisted reminders in storage order.
74
- */
75
- list(request: ScheduleListRequest): Promise<ScheduleRecord[]>;
76
- /**
77
- * Read all active and inactive Host reminders with their original Session bindings.
78
- * A deleted reminder has no row, so it is absent here.
79
- * Does not activate Sessions or read Session history.
80
- * @returns Reminders ordered by scheduledAt ascending, then lexicographically by id.
91
+ * The record is built from the clock reading taken before the request joins the serialized queue. A `session`
92
+ * target must exist and must not belong to a delegated child; a `new_once` target reserves its Session identity.
93
+ * @param request - Title, prompt, recurrence, and delivery destination.
94
+ * @param actorSessionId - Session of the acting Agent, or undefined for a human caller.
95
+ * @param signal - Cancellation checked before the durable write begins, including after FIFO waits.
96
+ * @returns The stored task. Cancellation does not roll back an in-flight write.
97
+ */
98
+ create(request: ScheduleCreateRequest, actorSessionId?: SessionId, signal?: AbortSignal): Promise<ScheduleCatalogEntry>;
99
+ /**
100
+ * Read one page of Host tasks without activating target Sessions.
101
+ * @param request - Optional activity filter, page size, and offset.
102
+ * @returns The requested page and total matching task count.
103
+ */
104
+ list(request?: ScheduleListRequest): Promise<ScheduleListResult>;
105
+ /**
106
+ * Remote form of the shared Host-wide list.
107
+ * @param request - Optional activity filter, page size, and offset.
108
+ * @returns The requested page and total matching task count.
109
+ */
110
+ remoteList(request: ScheduleListRequest): Promise<ScheduleListResult>;
111
+ /**
112
+ * Read every Host task without a page bound or Session activation.
113
+ * @returns All tasks, active first, with target and execution metadata.
81
114
  */
82
115
  catalog(): Promise<ScheduleCatalogEntry[]>;
83
116
  /**
84
- * Read saved inbox deliveries without activating or reading the original Session.
85
- * The task's own row supplies its binding, so its records stay readable through this lookup.
86
- * @param request - Session binding, task identity, explicit limit, and optional exclusive message cursor.
87
- * @returns Newest-first deliveries in append order, or a task/cursor lookup failure.
88
- * @throws ScheduleInputError when limit is not a safe integer from 1 through 100.
117
+ * Read one task without activating its target Sessions.
118
+ * @param request - Task identity.
119
+ * @returns The task, or a non-mutating miss.
120
+ */
121
+ view(request: ScheduleViewRequest): Promise<ScheduleViewResult>;
122
+ /**
123
+ * Read one page of saved deliveries without activating or reading a target Session.
124
+ * @param request - Task identity, explicit page size, and optional exclusive cursor.
125
+ * @returns Newest-first saved deliveries, or a task/cursor lookup failure.
89
126
  */
90
127
  history(request: ScheduleDeliveryHistoryRequest): Promise<ScheduleDeliveryHistoryResult>;
91
128
  /**
92
- * Delete one task belonging to the selected Session, leaving queued messages intact.
129
+ * Remote form of the target-based {@link ScheduleService.history}; an invalid limit rejects with
130
+ * `schedule/input-invalid`.
131
+ * @param request - Task identity, explicit limit, and optional exclusive message cursor.
132
+ * @returns Newest-first deliveries in append order, or a task/cursor lookup failure.
133
+ */
134
+ remoteHistory(request: ScheduleDeliveryHistoryRequest): Promise<ScheduleDeliveryHistoryResult>;
135
+ /**
136
+ * Deliver one task now without consuming or moving its scheduled occurrence; an archived destination Session rejects
137
+ * with `schedule/target-archived`.
138
+ * @param request - Task identity.
139
+ * @param signal - Cancellation checked after entering the delivery transaction and before delivery.
140
+ * @returns Task state after Session persistence acknowledged the delivery, `schedule_execution_pending` while
141
+ * another execution of the task is queued, running, or inside its delivery floor, or a non-mutating miss.
142
+ */
143
+ run(request: ScheduleRunRequest, signal?: AbortSignal): Promise<ScheduleRunResult>;
144
+ /**
145
+ * Delete every ended Host task, leaving active tasks armed.
93
146
  *
94
- * The row is removed: the task no longer schedules, leaves `list` and `catalog`, and its
95
- * saved delivery records go with it. A task bound to a Session a delegated child owns
96
- * stays deletable even though creation and timing edits refuse that binding, so a task
97
- * stored before that rule existed remains removable.
98
- * @param request - Session and exact task identity.
99
- * @param signal - Optional cancellation checked before persistence begins, including after FIFO waits.
100
- * @returns Whether that Session owned a deleted task. Cancellation does not roll back an in-flight write.
101
- */
102
- delete(request: ScheduleDeleteRequest, signal?: AbortSignal): Promise<ScheduleDeleteResult>;
103
- /**
104
- * Update the name, instruction, and timing of an active task within the original Session
105
- * binding without activating the Session or changing saved deliveries.
147
+ * Ended tasks never schedule another delivery, so the removal changes no pending
148
+ * target and no timer is recomputed. Rows are enumerated and removed in one FIFO
149
+ * slot, so a delivery ordered behind this call ends its task after the
150
+ * enumeration rather than during it. Each row is one durable write: a failure
151
+ * rejects with the rows removed so far gone and the remaining rows still
152
+ * stored.
153
+ * A successful nonempty removal emits `schedule/changed` without Agent notices.
154
+ * A rejected removal announces `schedule/changed` because it does not establish
155
+ * which rows landed, and clients then re-read the catalog.
156
+ * @returns Count of removed rows; zero when the Host held no ended task.
157
+ */
158
+ deleteInactive(): Promise<ScheduleDeleteInactiveResult>;
159
+ /**
160
+ * Update or delete one task for a human Remote caller; an invalid patch rejects with `schedule/input-invalid`.
161
+ * @param request - Task identity and one update or delete operation.
162
+ * @param signal - Cancellation checked before the durable write begins, including after FIFO waits.
163
+ * @returns The updated task, the deletion outcome, or a non-mutating miss or conflict.
164
+ */
165
+ remoteEdit(request: ScheduleEditRequest, signal?: AbortSignal): Promise<ScheduleEditResult>;
166
+ /**
167
+ * Update or delete one task and record the acting Agent's Session as involved; the Remote form omits that Session.
106
168
  *
107
- * Each supplied field replaces its stored value; an omitted field keeps it. A name or
108
- * instruction change alone does not reset the committed target. A Session a delegated
109
- * child owns returns the non-mutating `subagent_session` result, so an edit cannot
110
- * re-arm a task bound to a Session delivery can never reach, and the Web editor can
111
- * explain the refusal through the ordinary result it already renders.
112
- * @param request - Task binding, complete observed record, and any combination of timing, name, and instruction.
113
- * @param signal - Cancellation checked after domain readiness and FIFO waits, before persistence begins.
114
- * @returns The committed record, unchanged record for a no-op, or a non-mutating input/lookup/conflict/refusal result.
115
- * Storage and lifecycle failures reject; cancellation after a write starts does not roll it back.
116
- */
117
- update(request: ScheduleUpdateRequest, signal?: AbortSignal): Promise<ScheduleUpdateResult>;
169
+ * An update applies every patch field in one write and recomputes the next occurrence when the rule changes or
170
+ * the task resumes. A supplied `expectedUpdatedAt` that differs from the stored value returns `schedule_conflict`.
171
+ * @param request - Task identity and one update or delete operation.
172
+ * @param actorSessionId - Session of the acting Agent, or undefined for a human caller.
173
+ * @param signal - Cancellation checked before the durable write begins, including after FIFO waits.
174
+ * @returns The updated task, the deletion outcome, or a non-mutating miss or conflict.
175
+ */
176
+ edit(request: ScheduleEditRequest, actorSessionId?: SessionId, signal?: AbortSignal): Promise<ScheduleEditResult>;
118
177
  /**
119
178
  * Dispatch one post-commit `schedule/changed` notification, containing
120
179
  * synchronous listener failures: every call site emits only after its durable
@@ -124,30 +183,59 @@ export declare class ScheduleService extends TypertRemoteService {
124
183
  private emitChanged;
125
184
  private getDomain;
126
185
  /**
127
- * Refuse a Session no delivery can reach because a delegated child owns it.
186
+ * Resolve a requested destination without activating a Session.
128
187
  *
129
- * Delivery resolves the bound Session through `ctx.sessionController.resolveAgent`,
130
- * which rejects the live Agent of a delegated child; a stored task for such a Session
131
- * would stay permanently overdue and retry on every drive. Both operations that can
132
- * arm a delivery read that same fact here instead of restating it: a delegated child
133
- * is one whose {@link delegationDepthOf} is above zero, the accounting the delegation
134
- * cap itself enforces, which survives a cold resume through the persisted header.
135
- * @param sessionId - Session the task would be bound to.
136
- * @returns The stable refusal for a delegated child's Session, or undefined when the Session is eligible.
137
- */
138
- private reminderTargetRefusal;
139
- /**
140
- * Remove every active task stored for one Session, inside the queue the tools
188
+ * A `session` target must exist and must not belong to a delegated child: a live Agent answers through
189
+ * {@link delegationDepthOf}, and a stored Session answers through the delegation depth in its saved header.
190
+ * @param request - Requested destination.
191
+ * @param signal - Cancellation of the stored Session header read.
192
+ * @returns Stored destination; a `new_once` target reserves its Session identity here.
193
+ */
194
+ private resolveTarget;
195
+ /** Check arming prerequisites without activating a Session; repeated inside the mutation FIFO. */
196
+ private validateTarget;
197
+ /** New destinations require a provider before a task can be armed. */
198
+ private requireSessionCreation;
199
+ /** Every stored task as a catalog entry, in {@link compareEntries} order. */
200
+ private entries;
201
+ private entry;
202
+ /**
203
+ * Tell each involved Session's live Agent about one committed change, except the acting Session.
204
+ * A stored Session stays inactive; it reads the current task state when it next lists its tasks.
205
+ */
206
+ private notify;
207
+ /**
208
+ * Queue one change notice behind earlier notices without adding Session I/O to the management operation.
209
+ * Callers queue inside the serialized operation, so teardown, which drains that queue first, cannot overtake it.
210
+ */
211
+ private queueNotification;
212
+ /**
213
+ * Remove every active task that delivers to one Session, inside the queue the tools
141
214
  * use.
142
215
  *
143
216
  * Enumerating and deleting in one queue slot is what makes an archive stop
144
217
  * ordered behind a create whose write is still in flight: a stop that read the
145
218
  * table outside the queue could miss a row the create was about to commit and
146
- * leave an armed reminder behind. Re-entering the public `delete()` from here
219
+ * leave an armed reminder behind. Re-entering the public `edit()` from here
147
220
  * would deadlock on this queue, so the rows are removed directly.
148
221
  * @param sessionId - Session whose active Host tasks must stop.
149
222
  */
150
223
  private stopSessionTasks;
224
+ /**
225
+ * Remove rows one durable write each inside the current queue slot.
226
+ *
227
+ * This storage domain has no batch delete primitive, so a rejection part-way
228
+ * through leaves the earlier rows removed and the rest stored; the rejection
229
+ * still announces `schedule/changed` so observers re-read instead of trusting
230
+ * a stale catalog. Enumerating and deleting in one queue slot is what keeps a
231
+ * removal ordered behind a write that is still in flight. A rejection reason
232
+ * that carries no Error is wrapped with the operation label.
233
+ * @param ids - rows to remove.
234
+ * @param label - failure message prefix naming the operation that owned them.
235
+ * @param rearm - whether the rows were armed, so the pending timer must be recomputed.
236
+ * @returns the number of rows this call removed.
237
+ */
238
+ private removeRows;
151
239
  private serialize;
152
240
  }
153
241
  export default ScheduleService;