@elizaos/plugin-scheduling 2.0.3-beta.5 → 2.0.3-beta.7

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.
Files changed (57) hide show
  1. package/dist/anchors/anchor-registry.d.ts +33 -0
  2. package/dist/anchors/anchor-registry.d.ts.map +1 -0
  3. package/dist/anchors/anchor-registry.js +129 -0
  4. package/dist/anchors/anchor-registry.js.map +1 -0
  5. package/dist/dispatch-types.d.ts +28 -0
  6. package/dist/dispatch-types.d.ts.map +1 -0
  7. package/dist/dispatch-types.js +1 -0
  8. package/dist/dispatch-types.js.map +1 -0
  9. package/dist/index.d.ts +5 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +18 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/plugin.d.ts +17 -0
  14. package/dist/plugin.d.ts.map +1 -0
  15. package/dist/plugin.js +8 -0
  16. package/dist/plugin.js.map +1 -0
  17. package/dist/scheduled-task/completion-check-registry.d.ts +19 -0
  18. package/dist/scheduled-task/completion-check-registry.d.ts.map +1 -0
  19. package/dist/scheduled-task/completion-check-registry.js +113 -0
  20. package/dist/scheduled-task/completion-check-registry.js.map +1 -0
  21. package/dist/scheduled-task/consolidation-policy.d.ts +51 -0
  22. package/dist/scheduled-task/consolidation-policy.d.ts.map +1 -0
  23. package/dist/scheduled-task/consolidation-policy.js +154 -0
  24. package/dist/scheduled-task/consolidation-policy.js.map +1 -0
  25. package/dist/scheduled-task/due.d.ts +19 -0
  26. package/dist/scheduled-task/due.d.ts.map +1 -0
  27. package/dist/scheduled-task/due.js +349 -0
  28. package/dist/scheduled-task/due.js.map +1 -0
  29. package/dist/scheduled-task/escalation.d.ts +55 -0
  30. package/dist/scheduled-task/escalation.d.ts.map +1 -0
  31. package/dist/scheduled-task/escalation.js +99 -0
  32. package/dist/scheduled-task/escalation.js.map +1 -0
  33. package/dist/scheduled-task/gate-registry.d.ts +18 -0
  34. package/dist/scheduled-task/gate-registry.d.ts.map +1 -0
  35. package/dist/scheduled-task/gate-registry.js +244 -0
  36. package/dist/scheduled-task/gate-registry.js.map +1 -0
  37. package/dist/scheduled-task/index.d.ts +20 -0
  38. package/dist/scheduled-task/index.d.ts.map +1 -0
  39. package/dist/scheduled-task/index.js +83 -0
  40. package/dist/scheduled-task/index.js.map +1 -0
  41. package/dist/scheduled-task/next-fire-at.d.ts +40 -0
  42. package/dist/scheduled-task/next-fire-at.d.ts.map +1 -0
  43. package/dist/scheduled-task/next-fire-at.js +202 -0
  44. package/dist/scheduled-task/next-fire-at.js.map +1 -0
  45. package/dist/scheduled-task/runner.d.ts +263 -0
  46. package/dist/scheduled-task/runner.d.ts.map +1 -0
  47. package/dist/scheduled-task/runner.js +721 -0
  48. package/dist/scheduled-task/runner.js.map +1 -0
  49. package/dist/scheduled-task/state-log.d.ts +56 -0
  50. package/dist/scheduled-task/state-log.d.ts.map +1 -0
  51. package/dist/scheduled-task/state-log.js +87 -0
  52. package/dist/scheduled-task/state-log.js.map +1 -0
  53. package/dist/scheduled-task/types.d.ts +368 -0
  54. package/dist/scheduled-task/types.d.ts.map +1 -0
  55. package/dist/scheduled-task/types.js +14 -0
  56. package/dist/scheduled-task/types.js.map +1 -0
  57. package/package.json +5 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escalation.d.ts","sourceRoot":"","sources":["../../src/scheduled-task/escalation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACxE,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAChD,IAAI,IAAI,gBAAgB,EAAE,CAAC;CAC5B;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAuBzE;AAED,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAC/C,qBAAqB,EACrB,MAAM,CAKP,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAC/C,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAehC,CAAC;AAEH,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,wBAAwB,GAC5B,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,wBAAwB,GACjC,gBAAgB,CAkBlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,GACvB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAc3E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,CAK3E"}
@@ -0,0 +1,99 @@
1
+ function createEscalationLadderRegistry() {
2
+ const map = /* @__PURE__ */ new Map();
3
+ return {
4
+ register(ladder, opts) {
5
+ if (!ladder.ladderKey || typeof ladder.ladderKey !== "string") {
6
+ throw new Error(
7
+ "EscalationLadderRegistry.register: ladderKey required"
8
+ );
9
+ }
10
+ if (map.has(ladder.ladderKey) && !opts?.override) {
11
+ throw new Error(
12
+ `EscalationLadderRegistry.register: duplicate ladderKey "${ladder.ladderKey}"`
13
+ );
14
+ }
15
+ map.set(ladder.ladderKey, ladder);
16
+ },
17
+ get(key) {
18
+ return map.get(key) ?? null;
19
+ },
20
+ list() {
21
+ return Array.from(map.values());
22
+ }
23
+ };
24
+ }
25
+ const PRIORITY_DEFAULT_LADDER_KEYS = {
26
+ low: "priority_low_default",
27
+ medium: "priority_medium_default",
28
+ high: "priority_high_default"
29
+ };
30
+ const DEFAULT_ESCALATION_LADDERS = Object.freeze({
31
+ priority_low_default: { ladderKey: "priority_low_default", steps: [] },
32
+ priority_medium_default: {
33
+ ladderKey: "priority_medium_default",
34
+ steps: [{ delayMinutes: 30, channelKey: "in_app", intensity: "normal" }]
35
+ },
36
+ priority_high_default: {
37
+ ladderKey: "priority_high_default",
38
+ steps: [
39
+ { delayMinutes: 0, channelKey: "in_app", intensity: "soft" },
40
+ { delayMinutes: 15, channelKey: "push", intensity: "normal" },
41
+ { delayMinutes: 45, channelKey: "imessage", intensity: "urgent" }
42
+ ]
43
+ }
44
+ });
45
+ function registerDefaultEscalationLadders(reg) {
46
+ for (const ladder of Object.values(DEFAULT_ESCALATION_LADDERS)) {
47
+ if (!reg.get(ladder.ladderKey)) {
48
+ reg.register(ladder);
49
+ }
50
+ }
51
+ }
52
+ function resolveEffectiveLadder(task, registry) {
53
+ const explicit = task.escalation;
54
+ if (explicit?.steps && explicit.steps.length > 0) {
55
+ return { ladderKey: explicit.ladderKey ?? "inline", steps: explicit.steps };
56
+ }
57
+ if (explicit?.ladderKey) {
58
+ const named = registry.get(explicit.ladderKey);
59
+ if (named) return named;
60
+ }
61
+ const fallbackKey = PRIORITY_DEFAULT_LADDER_KEYS[task.priority];
62
+ const fallback = registry.get(fallbackKey);
63
+ if (fallback) return fallback;
64
+ return DEFAULT_ESCALATION_LADDERS[fallbackKey] ?? {
65
+ ladderKey: fallbackKey,
66
+ steps: []
67
+ };
68
+ }
69
+ function nextEscalationStep(ladder, cursor) {
70
+ const nextIdx = cursor.stepIndex + 1;
71
+ if (nextIdx >= ladder.steps.length) {
72
+ return null;
73
+ }
74
+ const step = ladder.steps[nextIdx];
75
+ if (!step) return null;
76
+ const lastMs = new Date(cursor.lastDispatchedAt).getTime();
77
+ const fireAtMs = lastMs + step.delayMinutes * 6e4;
78
+ return {
79
+ step,
80
+ nextStepIndex: nextIdx,
81
+ fireAtIso: new Date(fireAtMs).toISOString()
82
+ };
83
+ }
84
+ function resetLadderForSnooze(newFireAtIso) {
85
+ return {
86
+ stepIndex: -1,
87
+ lastDispatchedAt: newFireAtIso
88
+ };
89
+ }
90
+ export {
91
+ DEFAULT_ESCALATION_LADDERS,
92
+ PRIORITY_DEFAULT_LADDER_KEYS,
93
+ createEscalationLadderRegistry,
94
+ nextEscalationStep,
95
+ registerDefaultEscalationLadders,
96
+ resetLadderForSnooze,
97
+ resolveEffectiveLadder
98
+ };
99
+ //# sourceMappingURL=escalation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/scheduled-task/escalation.ts"],"sourcesContent":["/**\n * Escalation evaluator.\n *\n * Snooze policy: snooze RESETS the ladder to step 0 at the new fire time.\n * Default ladders by priority (when `escalation` is undefined):\n * - low → no ladder (single attempt)\n * - medium → 1 retry @ 30 min\n * - high → 3-step cross-channel\n *\n * Callers may register additional named ladders that override\n * `priority_<level>_default` keys.\n */\n\nimport type {\n EscalationStep,\n ScheduledTask,\n ScheduledTaskEscalation,\n ScheduledTaskPriority,\n} from \"./types.js\";\n\nexport interface EscalationLadder {\n ladderKey: string;\n steps: EscalationStep[];\n}\n\nexport interface EscalationLadderRegistry {\n register(ladder: EscalationLadder, opts?: { override?: boolean }): void;\n get(ladderKey: string): EscalationLadder | null;\n list(): EscalationLadder[];\n}\n\nexport function createEscalationLadderRegistry(): EscalationLadderRegistry {\n const map = new Map<string, EscalationLadder>();\n return {\n register(ladder, opts) {\n if (!ladder.ladderKey || typeof ladder.ladderKey !== \"string\") {\n throw new Error(\n \"EscalationLadderRegistry.register: ladderKey required\",\n );\n }\n if (map.has(ladder.ladderKey) && !opts?.override) {\n throw new Error(\n `EscalationLadderRegistry.register: duplicate ladderKey \"${ladder.ladderKey}\"`,\n );\n }\n map.set(ladder.ladderKey, ladder);\n },\n get(key) {\n return map.get(key) ?? null;\n },\n list() {\n return Array.from(map.values());\n },\n };\n}\n\nexport const PRIORITY_DEFAULT_LADDER_KEYS: Record<\n ScheduledTaskPriority,\n string\n> = {\n low: \"priority_low_default\",\n medium: \"priority_medium_default\",\n high: \"priority_high_default\",\n};\n\nexport const DEFAULT_ESCALATION_LADDERS: Readonly<\n Record<string, EscalationLadder>\n> = Object.freeze({\n priority_low_default: { ladderKey: \"priority_low_default\", steps: [] },\n priority_medium_default: {\n ladderKey: \"priority_medium_default\",\n steps: [{ delayMinutes: 30, channelKey: \"in_app\", intensity: \"normal\" }],\n },\n priority_high_default: {\n ladderKey: \"priority_high_default\",\n steps: [\n { delayMinutes: 0, channelKey: \"in_app\", intensity: \"soft\" },\n { delayMinutes: 15, channelKey: \"push\", intensity: \"normal\" },\n { delayMinutes: 45, channelKey: \"imessage\", intensity: \"urgent\" },\n ],\n },\n});\n\nexport function registerDefaultEscalationLadders(\n reg: EscalationLadderRegistry,\n): void {\n for (const ladder of Object.values(DEFAULT_ESCALATION_LADDERS)) {\n if (!reg.get(ladder.ladderKey)) {\n reg.register(ladder);\n }\n }\n}\n\n/**\n * Resolve the effective ladder for a task. Inline `escalation.steps` win\n * over `escalation.ladderKey` resolution. If neither is set, the\n * priority-default ladder is returned.\n */\nexport function resolveEffectiveLadder(\n task: ScheduledTask,\n registry: EscalationLadderRegistry,\n): EscalationLadder {\n const explicit: ScheduledTaskEscalation | undefined = task.escalation;\n if (explicit?.steps && explicit.steps.length > 0) {\n return { ladderKey: explicit.ladderKey ?? \"inline\", steps: explicit.steps };\n }\n if (explicit?.ladderKey) {\n const named = registry.get(explicit.ladderKey);\n if (named) return named;\n }\n const fallbackKey = PRIORITY_DEFAULT_LADDER_KEYS[task.priority];\n const fallback = registry.get(fallbackKey);\n if (fallback) return fallback;\n return (\n DEFAULT_ESCALATION_LADDERS[fallbackKey] ?? {\n ladderKey: fallbackKey,\n steps: [],\n }\n );\n}\n\nexport interface EscalationCursor {\n /** Current step index. -1 = escalation has not started. */\n stepIndex: number;\n /** ISO of the most recent dispatch (or task fire for step -1). */\n lastDispatchedAt: string;\n}\n\n/**\n * Compute the next escalation step (returns `null` when ladder exhausted).\n * `lastDispatchedAt` is the anchor for the next delay calculation.\n */\nexport function nextEscalationStep(\n ladder: EscalationLadder,\n cursor: EscalationCursor,\n): { step: EscalationStep; nextStepIndex: number; fireAtIso: string } | null {\n const nextIdx = cursor.stepIndex + 1;\n if (nextIdx >= ladder.steps.length) {\n return null;\n }\n const step = ladder.steps[nextIdx];\n if (!step) return null;\n const lastMs = new Date(cursor.lastDispatchedAt).getTime();\n const fireAtMs = lastMs + step.delayMinutes * 60_000;\n return {\n step,\n nextStepIndex: nextIdx,\n fireAtIso: new Date(fireAtMs).toISOString(),\n };\n}\n\n/**\n * Snooze resets the ladder to step 0 at the new fire time.\n * Returns the cursor the runner should persist post-snooze.\n */\nexport function resetLadderForSnooze(newFireAtIso: string): EscalationCursor {\n return {\n stepIndex: -1,\n lastDispatchedAt: newFireAtIso,\n };\n}\n"],"mappings":"AA+BO,SAAS,iCAA2D;AACzE,QAAM,MAAM,oBAAI,IAA8B;AAC9C,SAAO;AAAA,IACL,SAAS,QAAQ,MAAM;AACrB,UAAI,CAAC,OAAO,aAAa,OAAO,OAAO,cAAc,UAAU;AAC7D,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,UAAI,IAAI,IAAI,OAAO,SAAS,KAAK,CAAC,MAAM,UAAU;AAChD,cAAM,IAAI;AAAA,UACR,2DAA2D,OAAO,SAAS;AAAA,QAC7E;AAAA,MACF;AACA,UAAI,IAAI,OAAO,WAAW,MAAM;AAAA,IAClC;AAAA,IACA,IAAI,KAAK;AACP,aAAO,IAAI,IAAI,GAAG,KAAK;AAAA,IACzB;AAAA,IACA,OAAO;AACL,aAAO,MAAM,KAAK,IAAI,OAAO,CAAC;AAAA,IAChC;AAAA,EACF;AACF;AAEO,MAAM,+BAGT;AAAA,EACF,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AACR;AAEO,MAAM,6BAET,OAAO,OAAO;AAAA,EAChB,sBAAsB,EAAE,WAAW,wBAAwB,OAAO,CAAC,EAAE;AAAA,EACrE,yBAAyB;AAAA,IACvB,WAAW;AAAA,IACX,OAAO,CAAC,EAAE,cAAc,IAAI,YAAY,UAAU,WAAW,SAAS,CAAC;AAAA,EACzE;AAAA,EACA,uBAAuB;AAAA,IACrB,WAAW;AAAA,IACX,OAAO;AAAA,MACL,EAAE,cAAc,GAAG,YAAY,UAAU,WAAW,OAAO;AAAA,MAC3D,EAAE,cAAc,IAAI,YAAY,QAAQ,WAAW,SAAS;AAAA,MAC5D,EAAE,cAAc,IAAI,YAAY,YAAY,WAAW,SAAS;AAAA,IAClE;AAAA,EACF;AACF,CAAC;AAEM,SAAS,iCACd,KACM;AACN,aAAW,UAAU,OAAO,OAAO,0BAA0B,GAAG;AAC9D,QAAI,CAAC,IAAI,IAAI,OAAO,SAAS,GAAG;AAC9B,UAAI,SAAS,MAAM;AAAA,IACrB;AAAA,EACF;AACF;AAOO,SAAS,uBACd,MACA,UACkB;AAClB,QAAM,WAAgD,KAAK;AAC3D,MAAI,UAAU,SAAS,SAAS,MAAM,SAAS,GAAG;AAChD,WAAO,EAAE,WAAW,SAAS,aAAa,UAAU,OAAO,SAAS,MAAM;AAAA,EAC5E;AACA,MAAI,UAAU,WAAW;AACvB,UAAM,QAAQ,SAAS,IAAI,SAAS,SAAS;AAC7C,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,QAAM,cAAc,6BAA6B,KAAK,QAAQ;AAC9D,QAAM,WAAW,SAAS,IAAI,WAAW;AACzC,MAAI,SAAU,QAAO;AACrB,SACE,2BAA2B,WAAW,KAAK;AAAA,IACzC,WAAW;AAAA,IACX,OAAO,CAAC;AAAA,EACV;AAEJ;AAaO,SAAS,mBACd,QACA,QAC2E;AAC3E,QAAM,UAAU,OAAO,YAAY;AACnC,MAAI,WAAW,OAAO,MAAM,QAAQ;AAClC,WAAO;AAAA,EACT;AACA,QAAM,OAAO,OAAO,MAAM,OAAO;AACjC,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,SAAS,IAAI,KAAK,OAAO,gBAAgB,EAAE,QAAQ;AACzD,QAAM,WAAW,SAAS,KAAK,eAAe;AAC9C,SAAO;AAAA,IACL;AAAA,IACA,eAAe;AAAA,IACf,WAAW,IAAI,KAAK,QAAQ,EAAE,YAAY;AAAA,EAC5C;AACF;AAMO,SAAS,qBAAqB,cAAwC;AAC3E,SAAO;AAAA,IACL,WAAW;AAAA,IACX,kBAAkB;AAAA,EACpB;AACF;","names":[]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * TaskGateRegistry. Built-in kinds: `weekend_skip`, `weekend_only`,
3
+ * `weekday_only`, `late_evening_skip`, `quiet_hours`, `during_travel`,
4
+ * `circadian_state_in`, `no_recent_user_message_in`,
5
+ * `personal_baseline_sufficient`.
6
+ *
7
+ * The runner uses these gates in `shouldFire.gates`; composition is
8
+ * the responsibility of the runner (`compose: "all" | "any" | "first_deny"`).
9
+ */
10
+ import type { TaskGateContribution } from "./types.js";
11
+ export interface TaskGateRegistry {
12
+ register(c: TaskGateContribution): void;
13
+ get(kind: string): TaskGateContribution | null;
14
+ list(): TaskGateContribution[];
15
+ }
16
+ export declare function createTaskGateRegistry(): TaskGateRegistry;
17
+ export declare function registerBuiltInGates(reg: TaskGateRegistry): void;
18
+ //# sourceMappingURL=gate-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-registry.d.ts","sourceRoot":"","sources":["../../src/scheduled-task/gate-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAGV,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAiSpB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACxC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAAC;IAC/C,IAAI,IAAI,oBAAoB,EAAE,CAAC;CAChC;AAED,wBAAgB,sBAAsB,IAAI,gBAAgB,CAwBzD;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAUhE"}
@@ -0,0 +1,244 @@
1
+ import { logger } from "@elizaos/core";
2
+ const HHMM_PATTERN = /^([01]\d|2[0-3]):([0-5]\d)$/;
3
+ function parseHHMM(value) {
4
+ if (typeof value !== "string") return null;
5
+ const match = HHMM_PATTERN.exec(value);
6
+ if (!match) return null;
7
+ return {
8
+ hours: Number.parseInt(match[1] ?? "0", 10),
9
+ minutes: Number.parseInt(match[2] ?? "0", 10)
10
+ };
11
+ }
12
+ function intInRange(value, min, max) {
13
+ return Number.isFinite(value) && value >= min && value <= max;
14
+ }
15
+ function localPartsAtTz(iso, tz) {
16
+ const date = new Date(iso);
17
+ if (Number.isNaN(date.getTime())) return null;
18
+ try {
19
+ const formatter = new Intl.DateTimeFormat("en-US", {
20
+ timeZone: tz,
21
+ hour12: false,
22
+ hour: "2-digit",
23
+ minute: "2-digit",
24
+ weekday: "short"
25
+ });
26
+ const parts = formatter.formatToParts(date);
27
+ let hours = 0;
28
+ let minutes = 0;
29
+ let weekday = "Sun";
30
+ for (const part of parts) {
31
+ if (part.type === "hour") hours = Number.parseInt(part.value, 10) % 24;
32
+ else if (part.type === "minute")
33
+ minutes = Number.parseInt(part.value, 10);
34
+ else if (part.type === "weekday") weekday = part.value;
35
+ }
36
+ const map = {
37
+ Sun: 0,
38
+ Mon: 1,
39
+ Tue: 2,
40
+ Wed: 3,
41
+ Thu: 4,
42
+ Fri: 5,
43
+ Sat: 6
44
+ };
45
+ const dayOfWeek = map[weekday] ?? 0;
46
+ if (!intInRange(hours, 0, 23) || !intInRange(minutes, 0, 59)) return null;
47
+ return { hours, minutes, dayOfWeek };
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ function localPartsForContext(context) {
53
+ const tz = context.ownerFacts.timezone ?? "UTC";
54
+ return localPartsAtTz(context.nowIso, tz) ?? localPartsAtTz(context.nowIso, "UTC") ?? {
55
+ hours: 0,
56
+ minutes: 0,
57
+ dayOfWeek: 0
58
+ };
59
+ }
60
+ function isWeekend(dayOfWeek) {
61
+ return dayOfWeek === 0 || dayOfWeek === 6;
62
+ }
63
+ const weekendSkipGate = {
64
+ kind: "weekend_skip",
65
+ evaluate(_task, context) {
66
+ const { dayOfWeek } = localPartsForContext(context);
67
+ if (!isWeekend(dayOfWeek)) {
68
+ return { kind: "allow" };
69
+ }
70
+ return { kind: "deny", reason: "weekend_skip: today is a weekend" };
71
+ }
72
+ };
73
+ const weekendOnlyGate = {
74
+ kind: "weekend_only",
75
+ evaluate(_task, context) {
76
+ const { dayOfWeek } = localPartsForContext(context);
77
+ if (isWeekend(dayOfWeek)) {
78
+ return { kind: "allow" };
79
+ }
80
+ return { kind: "deny", reason: "weekend_only: today is a weekday" };
81
+ }
82
+ };
83
+ const weekdayOnlyGate = {
84
+ kind: "weekday_only",
85
+ evaluate(_task, context) {
86
+ const { dayOfWeek } = localPartsForContext(context);
87
+ if (!isWeekend(dayOfWeek)) {
88
+ return { kind: "allow" };
89
+ }
90
+ return { kind: "deny", reason: "weekday_only: today is a weekend" };
91
+ }
92
+ };
93
+ const lateEveningSkipGate = {
94
+ kind: "late_evening_skip",
95
+ evaluate(_task, context) {
96
+ const params = context.task.shouldFire?.gates.find(
97
+ (g) => g.kind === "late_evening_skip"
98
+ )?.params ?? {};
99
+ const afterHour = intInRange(params.afterHour ?? -1, 0, 23) ? params.afterHour : 21;
100
+ const { hours } = localPartsForContext(context);
101
+ if (hours < afterHour) {
102
+ return { kind: "allow" };
103
+ }
104
+ return {
105
+ kind: "deny",
106
+ reason: `late_evening_skip: hour ${hours} >= ${afterHour}`
107
+ };
108
+ }
109
+ };
110
+ const quietHoursGate = {
111
+ kind: "quiet_hours",
112
+ evaluate(task, context) {
113
+ const params = context.task.shouldFire?.gates.find(
114
+ (g) => g.kind === "quiet_hours"
115
+ )?.params ?? {};
116
+ const highBypass = params.highPriorityBypass !== false;
117
+ if (highBypass && task.priority === "high") {
118
+ return { kind: "allow" };
119
+ }
120
+ const quietHours = context.ownerFacts.quietHours;
121
+ if (!quietHours) {
122
+ return { kind: "allow" };
123
+ }
124
+ const start = parseHHMM(quietHours.start);
125
+ const end = parseHHMM(quietHours.end);
126
+ if (!start || !end) {
127
+ return { kind: "allow" };
128
+ }
129
+ const local = localPartsAtTz(context.nowIso, quietHours.tz) ?? localPartsForContext(context);
130
+ const nowMinutes = local.hours * 60 + local.minutes;
131
+ const startMinutes = start.hours * 60 + start.minutes;
132
+ const endMinutes = end.hours * 60 + end.minutes;
133
+ let inWindow;
134
+ if (startMinutes <= endMinutes) {
135
+ inWindow = nowMinutes >= startMinutes && nowMinutes < endMinutes;
136
+ } else {
137
+ inWindow = nowMinutes >= startMinutes || nowMinutes < endMinutes;
138
+ }
139
+ if (!inWindow) {
140
+ return { kind: "allow" };
141
+ }
142
+ const minutesUntilEnd = startMinutes <= endMinutes ? endMinutes - nowMinutes : nowMinutes >= startMinutes ? 24 * 60 - nowMinutes + endMinutes : endMinutes - nowMinutes;
143
+ return {
144
+ kind: "defer",
145
+ until: { offsetMinutes: Math.max(1, minutesUntilEnd) },
146
+ reason: `quiet_hours: deferring ${minutesUntilEnd}m until ${quietHours.end}`
147
+ };
148
+ }
149
+ };
150
+ const duringTravelGate = {
151
+ kind: "during_travel",
152
+ evaluate(_task, context) {
153
+ if (context.ownerFacts.travelActive === true) {
154
+ return { kind: "allow" };
155
+ }
156
+ return { kind: "deny", reason: "during_travel: no active travel" };
157
+ }
158
+ };
159
+ function makeWarnOnceFallthroughGate(kind, remediation) {
160
+ let warned = false;
161
+ return {
162
+ kind,
163
+ evaluate() {
164
+ if (!warned) {
165
+ warned = true;
166
+ logger.warn(
167
+ { src: "lifeops:scheduled-task:gate-registry", gateKind: kind },
168
+ `Gate "${kind}" has no production reader registered; falling through to allow. ${remediation}`
169
+ );
170
+ }
171
+ return { kind: "allow" };
172
+ }
173
+ };
174
+ }
175
+ const circadianStateInGate = makeWarnOnceFallthroughGate(
176
+ "circadian_state_in",
177
+ "Register a circadian-state-aware contribution via TaskGateRegistry.register before plugin-health default packs load, or remove this gate from those packs."
178
+ );
179
+ const noRecentUserMessageInGate = makeWarnOnceFallthroughGate(
180
+ "no_recent_user_message_in",
181
+ "Register a message-activity-aware contribution via TaskGateRegistry.register, or remove this gate from default packs."
182
+ );
183
+ const personalBaselineSufficientGate = {
184
+ kind: "personal_baseline_sufficient",
185
+ evaluate(_task, context) {
186
+ const params = context.task.shouldFire?.gates.find(
187
+ (g) => g.kind === "personal_baseline_sufficient"
188
+ )?.params ?? {};
189
+ const minSamples = intInRange(params.minSamples ?? 1, 1, 1e4) ? params.minSamples ?? 1 : 1;
190
+ const sampleCount = context.ownerFacts.personalBaseline?.sampleCount;
191
+ if (typeof sampleCount !== "number" || !Number.isFinite(sampleCount)) {
192
+ return {
193
+ kind: "deny",
194
+ reason: "personal_baseline_sufficient: sample count unavailable"
195
+ };
196
+ }
197
+ if (sampleCount >= minSamples) {
198
+ return { kind: "allow" };
199
+ }
200
+ return {
201
+ kind: "deny",
202
+ reason: `personal_baseline_sufficient: sample count ${sampleCount} < ${minSamples}`
203
+ };
204
+ }
205
+ };
206
+ function createTaskGateRegistry() {
207
+ const map = /* @__PURE__ */ new Map();
208
+ const reg = {
209
+ register(c) {
210
+ if (!c.kind || typeof c.kind !== "string") {
211
+ throw new Error("TaskGateRegistry.register: kind required");
212
+ }
213
+ if (map.has(c.kind)) {
214
+ throw new Error(
215
+ `TaskGateRegistry.register: duplicate kind "${c.kind}"`
216
+ );
217
+ }
218
+ map.set(c.kind, c);
219
+ },
220
+ get(kind) {
221
+ return map.get(kind) ?? null;
222
+ },
223
+ list() {
224
+ return Array.from(map.values());
225
+ }
226
+ };
227
+ return reg;
228
+ }
229
+ function registerBuiltInGates(reg) {
230
+ reg.register(weekendSkipGate);
231
+ reg.register(weekendOnlyGate);
232
+ reg.register(weekdayOnlyGate);
233
+ reg.register(lateEveningSkipGate);
234
+ reg.register(quietHoursGate);
235
+ reg.register(duringTravelGate);
236
+ reg.register(circadianStateInGate);
237
+ reg.register(noRecentUserMessageInGate);
238
+ reg.register(personalBaselineSufficientGate);
239
+ }
240
+ export {
241
+ createTaskGateRegistry,
242
+ registerBuiltInGates
243
+ };
244
+ //# sourceMappingURL=gate-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/scheduled-task/gate-registry.ts"],"sourcesContent":["/**\n * TaskGateRegistry. Built-in kinds: `weekend_skip`, `weekend_only`,\n * `weekday_only`, `late_evening_skip`, `quiet_hours`, `during_travel`,\n * `circadian_state_in`, `no_recent_user_message_in`,\n * `personal_baseline_sufficient`.\n *\n * The runner uses these gates in `shouldFire.gates`; composition is\n * the responsibility of the runner (`compose: \"all\" | \"any\" | \"first_deny\"`).\n */\n\nimport { logger } from \"@elizaos/core\";\n\nimport type {\n GateDecision,\n GateEvaluationContext,\n TaskGateContribution,\n} from \"./types.js\";\n\nconst HHMM_PATTERN = /^([01]\\d|2[0-3]):([0-5]\\d)$/;\n\nfunction parseHHMM(value: unknown): { hours: number; minutes: number } | null {\n if (typeof value !== \"string\") return null;\n const match = HHMM_PATTERN.exec(value);\n if (!match) return null;\n return {\n hours: Number.parseInt(match[1] ?? \"0\", 10),\n minutes: Number.parseInt(match[2] ?? \"0\", 10),\n };\n}\n\nfunction intInRange(value: number, min: number, max: number): boolean {\n return Number.isFinite(value) && value >= min && value <= max;\n}\n\n/**\n * Resolve the local hour/minute/dayOfWeek for the given iso instant in the\n * given IANA tz. Returns `null` if the timezone is invalid (caller falls\n * back to UTC reading).\n *\n * `dayOfWeek`: 0 = Sunday, 6 = Saturday.\n */\nfunction localPartsAtTz(\n iso: string,\n tz: string,\n): { hours: number; minutes: number; dayOfWeek: number } | null {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return null;\n try {\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n hour12: false,\n hour: \"2-digit\",\n minute: \"2-digit\",\n weekday: \"short\",\n });\n const parts = formatter.formatToParts(date);\n let hours = 0;\n let minutes = 0;\n let weekday = \"Sun\";\n for (const part of parts) {\n if (part.type === \"hour\") hours = Number.parseInt(part.value, 10) % 24;\n else if (part.type === \"minute\")\n minutes = Number.parseInt(part.value, 10);\n else if (part.type === \"weekday\") weekday = part.value;\n }\n const map: Record<string, number> = {\n Sun: 0,\n Mon: 1,\n Tue: 2,\n Wed: 3,\n Thu: 4,\n Fri: 5,\n Sat: 6,\n };\n const dayOfWeek = map[weekday] ?? 0;\n if (!intInRange(hours, 0, 23) || !intInRange(minutes, 0, 59)) return null;\n return { hours, minutes, dayOfWeek };\n } catch {\n return null;\n }\n}\n\nfunction localPartsForContext(context: GateEvaluationContext): {\n hours: number;\n minutes: number;\n dayOfWeek: number;\n} {\n const tz = context.ownerFacts.timezone ?? \"UTC\";\n return (\n localPartsAtTz(context.nowIso, tz) ??\n localPartsAtTz(context.nowIso, \"UTC\") ?? {\n hours: 0,\n minutes: 0,\n dayOfWeek: 0,\n }\n );\n}\n\nfunction isWeekend(dayOfWeek: number): boolean {\n return dayOfWeek === 0 || dayOfWeek === 6;\n}\n\n// ---------------------------------------------------------------------------\n// Built-in gate kinds\n// ---------------------------------------------------------------------------\n\n// Gates return `deny` to mark \"skipped\" — the runner translates that\n// into `state.status = \"skipped\"`. A `defer` would reschedule; weekend_skip\n// is meant to silently drop the fire.\nconst weekendSkipGate: TaskGateContribution = {\n kind: \"weekend_skip\",\n evaluate(_task, context): GateDecision {\n const { dayOfWeek } = localPartsForContext(context);\n if (!isWeekend(dayOfWeek)) {\n return { kind: \"allow\" };\n }\n return { kind: \"deny\", reason: \"weekend_skip: today is a weekend\" };\n },\n};\n\nconst weekendOnlyGate: TaskGateContribution = {\n kind: \"weekend_only\",\n evaluate(_task, context): GateDecision {\n const { dayOfWeek } = localPartsForContext(context);\n if (isWeekend(dayOfWeek)) {\n return { kind: \"allow\" };\n }\n return { kind: \"deny\", reason: \"weekend_only: today is a weekday\" };\n },\n};\n\nconst weekdayOnlyGate: TaskGateContribution = {\n kind: \"weekday_only\",\n evaluate(_task, context): GateDecision {\n const { dayOfWeek } = localPartsForContext(context);\n if (!isWeekend(dayOfWeek)) {\n return { kind: \"allow\" };\n }\n return { kind: \"deny\", reason: \"weekday_only: today is a weekend\" };\n },\n};\n\ninterface LateEveningSkipParams {\n /** Hour-of-day (0-23) in owner timezone. Default 21 (9pm). */\n afterHour?: number;\n}\n\nconst lateEveningSkipGate: TaskGateContribution = {\n kind: \"late_evening_skip\",\n evaluate(_task, context): GateDecision {\n const params = (context.task.shouldFire?.gates.find(\n (g) => g.kind === \"late_evening_skip\",\n )?.params ?? {}) as LateEveningSkipParams;\n const afterHour = intInRange(params.afterHour ?? -1, 0, 23)\n ? (params.afterHour as number)\n : 21;\n const { hours } = localPartsForContext(context);\n if (hours < afterHour) {\n return { kind: \"allow\" };\n }\n return {\n kind: \"deny\",\n reason: `late_evening_skip: hour ${hours} >= ${afterHour}`,\n };\n },\n};\n\ninterface QuietHoursParams {\n /** When true, `high` priority tasks bypass this gate. Default true. */\n highPriorityBypass?: boolean;\n}\n\nconst quietHoursGate: TaskGateContribution = {\n kind: \"quiet_hours\",\n evaluate(task, context): GateDecision {\n const params = (context.task.shouldFire?.gates.find(\n (g) => g.kind === \"quiet_hours\",\n )?.params ?? {}) as QuietHoursParams;\n const highBypass = params.highPriorityBypass !== false;\n if (highBypass && task.priority === \"high\") {\n return { kind: \"allow\" };\n }\n const quietHours = context.ownerFacts.quietHours;\n if (!quietHours) {\n return { kind: \"allow\" };\n }\n const start = parseHHMM(quietHours.start);\n const end = parseHHMM(quietHours.end);\n if (!start || !end) {\n return { kind: \"allow\" };\n }\n const local =\n localPartsAtTz(context.nowIso, quietHours.tz) ??\n localPartsForContext(context);\n const nowMinutes = local.hours * 60 + local.minutes;\n const startMinutes = start.hours * 60 + start.minutes;\n const endMinutes = end.hours * 60 + end.minutes;\n\n let inWindow: boolean;\n if (startMinutes <= endMinutes) {\n inWindow = nowMinutes >= startMinutes && nowMinutes < endMinutes;\n } else {\n // wraps midnight\n inWindow = nowMinutes >= startMinutes || nowMinutes < endMinutes;\n }\n if (!inWindow) {\n return { kind: \"allow\" };\n }\n // Defer to the next allowed window for low/medium tasks.\n const minutesUntilEnd =\n startMinutes <= endMinutes\n ? endMinutes - nowMinutes\n : nowMinutes >= startMinutes\n ? 24 * 60 - nowMinutes + endMinutes\n : endMinutes - nowMinutes;\n return {\n kind: \"defer\",\n until: { offsetMinutes: Math.max(1, minutesUntilEnd) },\n reason: `quiet_hours: deferring ${minutesUntilEnd}m until ${quietHours.end}`,\n };\n },\n};\n\nconst duringTravelGate: TaskGateContribution = {\n kind: \"during_travel\",\n evaluate(_task, context): GateDecision {\n if (context.ownerFacts.travelActive === true) {\n return { kind: \"allow\" };\n }\n return { kind: \"deny\", reason: \"during_travel: no active travel\" };\n },\n};\n\n/**\n * `circadian_state_in` and `no_recent_user_message_in` are referenced by\n * plugin-health default packs but the concrete data readers (circadian state,\n * recent-user-message lookup) are not wired into the runner today. Until a\n * caller registers a real contribution (overwriting these), the gate falls\n * through to `allow` and logs a warning once per process so the operator can\n * see that the gate isn't doing what its name suggests. Loud > silent.\n */\nfunction makeWarnOnceFallthroughGate(\n kind: string,\n remediation: string,\n): TaskGateContribution {\n let warned = false;\n return {\n kind,\n evaluate(): GateDecision {\n if (!warned) {\n warned = true;\n logger.warn(\n { src: \"lifeops:scheduled-task:gate-registry\", gateKind: kind },\n `Gate \"${kind}\" has no production reader registered; falling through to allow. ${remediation}`,\n );\n }\n return { kind: \"allow\" };\n },\n };\n}\n\nconst circadianStateInGate = makeWarnOnceFallthroughGate(\n \"circadian_state_in\",\n \"Register a circadian-state-aware contribution via TaskGateRegistry.register before plugin-health default packs load, or remove this gate from those packs.\",\n);\n\nconst noRecentUserMessageInGate = makeWarnOnceFallthroughGate(\n \"no_recent_user_message_in\",\n \"Register a message-activity-aware contribution via TaskGateRegistry.register, or remove this gate from default packs.\",\n);\n\ninterface PersonalBaselineSufficientParams {\n minSamples?: number;\n}\n\nconst personalBaselineSufficientGate: TaskGateContribution = {\n kind: \"personal_baseline_sufficient\",\n evaluate(_task, context): GateDecision {\n const params = (context.task.shouldFire?.gates.find(\n (g) => g.kind === \"personal_baseline_sufficient\",\n )?.params ?? {}) as PersonalBaselineSufficientParams;\n const minSamples = intInRange(params.minSamples ?? 1, 1, 10_000)\n ? (params.minSamples ?? 1)\n : 1;\n const sampleCount = context.ownerFacts.personalBaseline?.sampleCount;\n if (typeof sampleCount !== \"number\" || !Number.isFinite(sampleCount)) {\n return {\n kind: \"deny\",\n reason: \"personal_baseline_sufficient: sample count unavailable\",\n };\n }\n if (sampleCount >= minSamples) {\n return { kind: \"allow\" };\n }\n return {\n kind: \"deny\",\n reason: `personal_baseline_sufficient: sample count ${sampleCount} < ${minSamples}`,\n };\n },\n};\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\nexport interface TaskGateRegistry {\n register(c: TaskGateContribution): void;\n get(kind: string): TaskGateContribution | null;\n list(): TaskGateContribution[];\n}\n\nexport function createTaskGateRegistry(): TaskGateRegistry {\n const map = new Map<string, TaskGateContribution>();\n const reg: TaskGateRegistry = {\n register(c) {\n if (!c.kind || typeof c.kind !== \"string\") {\n throw new Error(\"TaskGateRegistry.register: kind required\");\n }\n if (map.has(c.kind)) {\n // Last-writer-wins is intentionally NOT allowed: prevents silent\n // override. Callers should ensure no double-registration.\n throw new Error(\n `TaskGateRegistry.register: duplicate kind \"${c.kind}\"`,\n );\n }\n map.set(c.kind, c);\n },\n get(kind) {\n return map.get(kind) ?? null;\n },\n list() {\n return Array.from(map.values());\n },\n };\n return reg;\n}\n\nexport function registerBuiltInGates(reg: TaskGateRegistry): void {\n reg.register(weekendSkipGate);\n reg.register(weekendOnlyGate);\n reg.register(weekdayOnlyGate);\n reg.register(lateEveningSkipGate);\n reg.register(quietHoursGate);\n reg.register(duringTravelGate);\n reg.register(circadianStateInGate);\n reg.register(noRecentUserMessageInGate);\n reg.register(personalBaselineSufficientGate);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `@elizaos/plugin-scheduling` — ScheduledTask spine.
3
+ *
4
+ * Public exports for cross-module consumers; this barrel re-exports the typed
5
+ * runner surface other plugins build against. The tick driver
6
+ * (`processDueScheduledTasks`) and the runner Service stay in the host
7
+ * (`@elizaos/plugin-personal-assistant`) during the decomposition; they move
8
+ * here in a later slice.
9
+ */
10
+ export { type CompletionCheckRegistry, createCompletionCheckRegistry, registerBuiltInCompletionChecks, } from "./completion-check-registry.js";
11
+ export { __anchorTestUtils, type AnchorRegistry, type ConsolidationRegistry, createAnchorRegistry, createConsolidationRegistry, registerFallbackAnchors, } from "./consolidation-policy.js";
12
+ export { expectedReplyKindForTask, isCompletionTimeoutDue, isRecurringTrigger, isScheduledTaskDue, markWindowFireIfNeeded, pendingPromptRoomIdForTask, type ScheduledTaskDueContext, type ScheduledTaskDueDecision, } from "./due.js";
13
+ export { createEscalationLadderRegistry, DEFAULT_ESCALATION_LADDERS, type EscalationCursor, type EscalationLadder, type EscalationLadderRegistry, nextEscalationStep, PRIORITY_DEFAULT_LADDER_KEYS, registerDefaultEscalationLadders, resetLadderForSnooze, resolveEffectiveLadder, } from "./escalation.js";
14
+ export { createTaskGateRegistry, registerBuiltInGates, type TaskGateRegistry, } from "./gate-registry.js";
15
+ export { computeNextFireAt } from "./next-fire-at.js";
16
+ export { ChannelKeyError, createInMemoryScheduledTaskStore, createScheduledTaskRunner, type ScheduledTaskClaimResult, type ScheduledTaskDispatcher, type ScheduledTaskDispatchRecord, type ScheduledTaskFireResult, type ScheduledTaskRunnerDeps, type ScheduledTaskRunnerExtras, type ScheduledTaskRunnerHandle, type ScheduledTaskStore, type ScheduledTaskUpsertOptions, TestNoopScheduledTaskDispatcher, } from "./runner.js";
17
+ export { createInMemoryScheduledTaskLogStore, createStateLogger, type ScheduledTaskLogStore, STATE_LOG_DEFAULT_RETENTION_DAYS, } from "./state-log.js";
18
+ export type { ActivitySignalBusView, AnchorConsolidationMode, AnchorConsolidationPolicy, AnchorContext, AnchorContribution, CompletionCheckContext, CompletionCheckContribution, CompletionCheckParams, EscalationStep, EventFilter, GateCompose, GateDecision, GateEvaluationContext, GateParams, GlobalPauseView, OwnerFactsView, ScheduledTask, ScheduledTaskCompletionCheck, ScheduledTaskContextRequest, ScheduledTaskEscalation, ScheduledTaskFilter, ScheduledTaskGateRef, ScheduledTaskKind, ScheduledTaskLogEntry, ScheduledTaskLogTransition, ScheduledTaskOutput, ScheduledTaskOutputDestination, ScheduledTaskPipeline, ScheduledTaskPriority, ScheduledTaskRef, ScheduledTaskRunner, ScheduledTaskShouldFire, ScheduledTaskSource, ScheduledTaskState, ScheduledTaskStatus, ScheduledTaskSubject, ScheduledTaskSubjectKind, ScheduledTaskTrigger, ScheduledTaskVerb, SubjectStoreView, TaskExecutionProfile, TaskGateContribution, TerminalState, } from "./types.js";
19
+ export { APPROVAL_DEFAULT_FOLLOWUP_AFTER_MINUTES, DEFAULT_TASK_EXECUTION_PROFILE, TASK_EXECUTION_PROFILES, } from "./types.js";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scheduled-task/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,+BAA+B,GAChC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,GAC9B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,8BAA8B,EAC9B,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,kBAAkB,EAClB,4BAA4B,EAC5B,gCAAgC,EAChC,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,eAAe,EACf,gCAAgC,EAChC,yBAAyB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,+BAA+B,GAChC,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mCAAmC,EACnC,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,gCAAgC,GACjC,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,kBAAkB,EAClB,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,UAAU,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACb,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,8BAA8B,EAC9B,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,uCAAuC,EACvC,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,83 @@
1
+ import {
2
+ createCompletionCheckRegistry,
3
+ registerBuiltInCompletionChecks
4
+ } from "./completion-check-registry.js";
5
+ import {
6
+ __anchorTestUtils,
7
+ createAnchorRegistry,
8
+ createConsolidationRegistry,
9
+ registerFallbackAnchors
10
+ } from "./consolidation-policy.js";
11
+ import {
12
+ expectedReplyKindForTask,
13
+ isCompletionTimeoutDue,
14
+ isRecurringTrigger,
15
+ isScheduledTaskDue,
16
+ markWindowFireIfNeeded,
17
+ pendingPromptRoomIdForTask
18
+ } from "./due.js";
19
+ import {
20
+ createEscalationLadderRegistry,
21
+ DEFAULT_ESCALATION_LADDERS,
22
+ nextEscalationStep,
23
+ PRIORITY_DEFAULT_LADDER_KEYS,
24
+ registerDefaultEscalationLadders,
25
+ resetLadderForSnooze,
26
+ resolveEffectiveLadder
27
+ } from "./escalation.js";
28
+ import {
29
+ createTaskGateRegistry,
30
+ registerBuiltInGates
31
+ } from "./gate-registry.js";
32
+ import { computeNextFireAt } from "./next-fire-at.js";
33
+ import {
34
+ ChannelKeyError,
35
+ createInMemoryScheduledTaskStore,
36
+ createScheduledTaskRunner,
37
+ TestNoopScheduledTaskDispatcher
38
+ } from "./runner.js";
39
+ import {
40
+ createInMemoryScheduledTaskLogStore,
41
+ createStateLogger,
42
+ STATE_LOG_DEFAULT_RETENTION_DAYS
43
+ } from "./state-log.js";
44
+ import {
45
+ APPROVAL_DEFAULT_FOLLOWUP_AFTER_MINUTES,
46
+ DEFAULT_TASK_EXECUTION_PROFILE,
47
+ TASK_EXECUTION_PROFILES
48
+ } from "./types.js";
49
+ export {
50
+ APPROVAL_DEFAULT_FOLLOWUP_AFTER_MINUTES,
51
+ ChannelKeyError,
52
+ DEFAULT_ESCALATION_LADDERS,
53
+ DEFAULT_TASK_EXECUTION_PROFILE,
54
+ PRIORITY_DEFAULT_LADDER_KEYS,
55
+ STATE_LOG_DEFAULT_RETENTION_DAYS,
56
+ TASK_EXECUTION_PROFILES,
57
+ TestNoopScheduledTaskDispatcher,
58
+ __anchorTestUtils,
59
+ computeNextFireAt,
60
+ createAnchorRegistry,
61
+ createCompletionCheckRegistry,
62
+ createConsolidationRegistry,
63
+ createEscalationLadderRegistry,
64
+ createInMemoryScheduledTaskLogStore,
65
+ createInMemoryScheduledTaskStore,
66
+ createScheduledTaskRunner,
67
+ createStateLogger,
68
+ createTaskGateRegistry,
69
+ expectedReplyKindForTask,
70
+ isCompletionTimeoutDue,
71
+ isRecurringTrigger,
72
+ isScheduledTaskDue,
73
+ markWindowFireIfNeeded,
74
+ nextEscalationStep,
75
+ pendingPromptRoomIdForTask,
76
+ registerBuiltInCompletionChecks,
77
+ registerBuiltInGates,
78
+ registerDefaultEscalationLadders,
79
+ registerFallbackAnchors,
80
+ resetLadderForSnooze,
81
+ resolveEffectiveLadder
82
+ };
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/scheduled-task/index.ts"],"sourcesContent":["/**\n * `@elizaos/plugin-scheduling` — ScheduledTask spine.\n *\n * Public exports for cross-module consumers; this barrel re-exports the typed\n * runner surface other plugins build against. The tick driver\n * (`processDueScheduledTasks`) and the runner Service stay in the host\n * (`@elizaos/plugin-personal-assistant`) during the decomposition; they move\n * here in a later slice.\n */\n\nexport {\n type CompletionCheckRegistry,\n createCompletionCheckRegistry,\n registerBuiltInCompletionChecks,\n} from \"./completion-check-registry.js\";\nexport {\n __anchorTestUtils,\n type AnchorRegistry,\n type ConsolidationRegistry,\n createAnchorRegistry,\n createConsolidationRegistry,\n registerFallbackAnchors,\n} from \"./consolidation-policy.js\";\nexport {\n expectedReplyKindForTask,\n isCompletionTimeoutDue,\n isRecurringTrigger,\n isScheduledTaskDue,\n markWindowFireIfNeeded,\n pendingPromptRoomIdForTask,\n type ScheduledTaskDueContext,\n type ScheduledTaskDueDecision,\n} from \"./due.js\";\nexport {\n createEscalationLadderRegistry,\n DEFAULT_ESCALATION_LADDERS,\n type EscalationCursor,\n type EscalationLadder,\n type EscalationLadderRegistry,\n nextEscalationStep,\n PRIORITY_DEFAULT_LADDER_KEYS,\n registerDefaultEscalationLadders,\n resetLadderForSnooze,\n resolveEffectiveLadder,\n} from \"./escalation.js\";\nexport {\n createTaskGateRegistry,\n registerBuiltInGates,\n type TaskGateRegistry,\n} from \"./gate-registry.js\";\nexport { computeNextFireAt } from \"./next-fire-at.js\";\nexport {\n ChannelKeyError,\n createInMemoryScheduledTaskStore,\n createScheduledTaskRunner,\n type ScheduledTaskClaimResult,\n type ScheduledTaskDispatcher,\n type ScheduledTaskDispatchRecord,\n type ScheduledTaskFireResult,\n type ScheduledTaskRunnerDeps,\n type ScheduledTaskRunnerExtras,\n type ScheduledTaskRunnerHandle,\n type ScheduledTaskStore,\n type ScheduledTaskUpsertOptions,\n TestNoopScheduledTaskDispatcher,\n} from \"./runner.js\";\nexport {\n createInMemoryScheduledTaskLogStore,\n createStateLogger,\n type ScheduledTaskLogStore,\n STATE_LOG_DEFAULT_RETENTION_DAYS,\n} from \"./state-log.js\";\nexport type {\n ActivitySignalBusView,\n AnchorConsolidationMode,\n AnchorConsolidationPolicy,\n AnchorContext,\n AnchorContribution,\n CompletionCheckContext,\n CompletionCheckContribution,\n CompletionCheckParams,\n EscalationStep,\n EventFilter,\n GateCompose,\n GateDecision,\n GateEvaluationContext,\n GateParams,\n GlobalPauseView,\n OwnerFactsView,\n ScheduledTask,\n ScheduledTaskCompletionCheck,\n ScheduledTaskContextRequest,\n ScheduledTaskEscalation,\n ScheduledTaskFilter,\n ScheduledTaskGateRef,\n ScheduledTaskKind,\n ScheduledTaskLogEntry,\n ScheduledTaskLogTransition,\n ScheduledTaskOutput,\n ScheduledTaskOutputDestination,\n ScheduledTaskPipeline,\n ScheduledTaskPriority,\n ScheduledTaskRef,\n ScheduledTaskRunner,\n ScheduledTaskShouldFire,\n ScheduledTaskSource,\n ScheduledTaskState,\n ScheduledTaskStatus,\n ScheduledTaskSubject,\n ScheduledTaskSubjectKind,\n ScheduledTaskTrigger,\n ScheduledTaskVerb,\n SubjectStoreView,\n TaskExecutionProfile,\n TaskGateContribution,\n TerminalState,\n} from \"./types.js\";\n// Value constants from types.ts (the type-only re-export block below cannot\n// carry runtime values).\nexport {\n APPROVAL_DEFAULT_FOLLOWUP_AFTER_MINUTES,\n DEFAULT_TASK_EXECUTION_PROFILE,\n TASK_EXECUTION_PROFILES,\n} from \"./types.js\";\n"],"mappings":"AAUA;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAUA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AAgDP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Computes the indexed `next_fire_at` timestamp for a `ScheduledTask`.
3
+ *
4
+ * The scheduler tick (`processDueScheduledTasks`) filters by this column to
5
+ * avoid scanning every row in `life_scheduled_tasks` once per minute. The
6
+ * value is approximate — it is a "next candidate fire time" that the
7
+ * authoritative `isScheduledTaskDue` re-evaluates per task. Triggers that
8
+ * wake on external signals (`event`, `manual`, `after_task`) leave it NULL.
9
+ *
10
+ * Computed for: `once`, `cron`, `interval`, `relative_to_anchor`,
11
+ * `during_window`.
12
+ *
13
+ * Computed by the runner on every state mutation that can change the
14
+ * upcoming fire time: `schedule()`, `apply("snooze")`, `apply("edit")`, and
15
+ * the post-fire/post-skip persistence in `fire()`.
16
+ */
17
+ import type { AnchorRegistry } from "../anchors/anchor-registry.js";
18
+ import type { OwnerFactsView, ScheduledTask } from "./types.js";
19
+ export interface ComputeNextFireAtContext {
20
+ now: Date;
21
+ ownerFacts: OwnerFactsView;
22
+ anchors?: AnchorRegistry | null;
23
+ }
24
+ /**
25
+ * Compute the next-fire-at timestamp for a task. Returns null when the
26
+ * trigger does not have a wall-clock fire time (event/manual/after_task)
27
+ * or when the inputs cannot be resolved (e.g. unknown anchor key).
28
+ *
29
+ * The function is async because anchor resolution may consult the runtime
30
+ * anchor registry (e.g. `wake.confirmed` reads the latest activity signal).
31
+ *
32
+ * Inputs:
33
+ * - `task`: must have its current `trigger` and (post-fire) `state.firedAt`.
34
+ * - `context.now`: clock used for forward-projecting cron/interval/window.
35
+ *
36
+ * Outputs an ISO string, never a Date — the caller writes directly to a
37
+ * Postgres timestamp column.
38
+ */
39
+ export declare function computeNextFireAt(task: Pick<ScheduledTask, "trigger" | "state" | "metadata">, context: ComputeNextFireAtContext): Promise<string | null>;
40
+ //# sourceMappingURL=next-fire-at.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-fire-at.d.ts","sourceRoot":"","sources":["../../src/scheduled-task/next-fire-at.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEd,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,IAAI,CAAC;IACV,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACjC;AAkMD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC,EAC3D,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiDxB"}