UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

66 lines (65 loc) • 5.42 kB
/** * design/105 — Scheduler 工具壳(CronCreate / CronDelete / CronList + ScheduleWakeup)。模型可调,把未来意图交给注入的 * daemon backend(`env` 实现 {@link SchedulerCapability})。**core 薄壳**:工具只做 ① cron expr 白名单校验 * ② 组装 `intent`(模型面) + `SchedulerContext`(Runner-held,闭包捕获 principal/scope/sessionId) ③ 调 * `env.schedule/cancel/list`。持久化/触发/起新 task 全在 daemon。 * design/136 §2.2(BREAKING 去超集批):`Sleep` 工具已撤除(CC 无此工具;等待抽象=Monitor/后台通知,定时再醒 * =CronCreate delay/at——纯语法糖零缺口)。旧名调用=通用响亮 roster miss(RB-476-A 墓碑已清);daemon 已排的 `label:"sleep"` * delayed intent 照常触发(daemon 只存 prompt+when,零迁移)。 * * [c209-D2] 同名工具消歧(durable 分层激活批 2026-07-16,防后人混淆):**我方 CronCreate = 持久 daemon 形** * (对标上游产品 /schedule 的云端持久语义);**上游同名工具是会话级易失体**({cron: 5字段串, prompt, * recurring: bool, durable: 死字段}——会话结束即消失);壳仓 vendored 的 ScheduleCronTool 是上游原生实现, * 与本工具无关。两形调用在此汇流:上游生态 skill 平移过来的 CC 形调用(`cron` 字符串,`durable` 缺省 false) * 落 **session 生存期**(会话终结随会话 reap,绝不落成永生任务);我方 `schedule` 对象形保持持久语义零回归, * `durable: true` 显式亦持久。session 生存期需要 backend 能力位(supportsSessionLifetime),缺失时诚实拒绝 * 引导 `durable: true`——绝不静默升级语义。 * * 挂载:prepare-task 在 `hasScheduler(executionEnv)` 时调 {@link createSchedulerTools}(需 Runner-held 上下文,故不在 * `createHandsToolkit` —— 与 present_plan/AskUserQuestion 同:这些工具都在 prepare-task 单独挂,那里有 spec.principal)。 */ import type { AgentTool, ExecutionEnv } from "../internal/harness-types.js"; export declare const SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup"; /** CronCreate-based autonomous-loop 哨兵(CC `Ldt`)。loop runtime(部署侧)在 fire 时解析回 autonomous-loop 指令。 */ export declare const AUTONOMOUS_LOOP_SENTINEL = "<<autonomous-loop>>"; /** ScheduleWakeup(dynamic-pacing)哨兵(CC `ePe`)——ScheduleWakeup 一律用 `-dynamic` 变体。 */ export declare const AUTONOMOUS_LOOP_DYNAMIC_SENTINEL = "<<autonomous-loop-dynamic>>"; /** Runner-held 上下文 + run-stop 出口,工具工厂闭包捕获(模型触不到)。 */ export interface SchedulerToolContext { /** * **会话腿**的越界隔离键(Runner 填 sessionId ?? principal ?? taskId)。durable 腿不用这条链——它的键由 * {@link durableScopeOf} 从 principal 独立铸(ruled 2026-08-03,见该函数注释)。 */ scope: string; principal?: string; sessionId?: string; taskConfig?: unknown; /** `ctx.requestStopAfterTurn`(干净结束本 run 的 runner 原语出口)。design/136 §2.2:Sleep 撤除后本槽位 * 保留(human-suspend saga 等共用同一 runner 原语;prepare-task 仍注入)——当前 scheduler 三件不消费。 */ requestStopAfterTurn?: () => void; } /** * cron 深校验(CC CronCreateTool.validateInput parity):arity(RB-438 D4)+ 数值域(如 `61 * * * *` 分钟越域) * + 永不触发(如 `31 2 30 2 *` 二月 30 日)。返回给模型自纠的错误句;合法返回 null。 * * RB-438 D4 — **只收 5 字段**。带秒的 6 段此前收单成功并回执「Scheduled.」,而兑现腿(常驻 daemon)按标准 * 5 字段解析:6 段记录算不出 next-run,首次 tick 即被当作坏记录丢弃 ⇒ 任务永不触发,且没有任何回执说过它 * 没排上。收单 arity 必须等于开火 arity,差额只能用响亮拒绝补,不能用静默丢弃补。seam 上没有「秒粒度」 * 能力位可判({@link SchedulerCapability} 只有 supported / 上下限 / 两个 session 位),故取保守形:一律拒。 * 将来若真出现支持秒的 backend,加一个 additive 能力位在此开口(缺省仍拒),不要悄悄放行。 * * 永不触发判定:标准 cron OR 语义(CC utils/cron.ts:150-158)—— dom 与 dow **都**受限时任一匹配即触发,而任何受限 * dow 每周都出现 → 必触发。所以唯一永不触发形态 = dom 受限 + dow 通配 + dom 值全部超出所有排程月份的天数上限。 */ export declare function cronScheduleError(expr: string): string | null; /** * cron → 人话(CC utils/cron.ts cronToHuman:218-308 类比,收窄到常见形态):"star/N * * * *"→"every N minutes"、 * "M star/N * * *"→"every N hours"、`M H * * *`→"daily at H:MM"、`M H * * D`→"weekly on <day> at H:MM"、 * `M H * * 1-5`→"weekdays at H:MM";其余原样返回(调用方以 `human !== expr` 判断是否可译)。 * 收 backend 的 `cron <expr>` 显示串(见 {@link cronExprFromSummary});6 段带秒不译(D4 已在收单面拒收)。 */ export declare function cronToHuman(expr: string): string; /** * 构建三个 scheduler 工具(仅当 `env` 暴露 {@link SchedulerCapability} 且 `supported:true`)。否则返回 `[]`(INERT)。 */ export declare function createSchedulerTools(env: ExecutionEnv, ctx: SchedulerToolContext): AgentTool[];