@vellumai/assistant 0.10.8-dev.202607130516.157ae8a → 0.10.8-dev.202607131107.073396f

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 (41) hide show
  1. package/openapi.yaml +7 -63
  2. package/package.json +1 -1
  3. package/src/__tests__/memory-jobs-worker-backoff.test.ts +4 -6
  4. package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -1
  5. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
  6. package/src/__tests__/{scheduler-worker-standdown.test.ts → run-due-schedules.test.ts} +5 -55
  7. package/src/__tests__/schedule-retry.test.ts +22 -15
  8. package/src/__tests__/scheduler-recurrence.test.ts +15 -23
  9. package/src/__tests__/scheduler-reuse-conversation.test.ts +19 -27
  10. package/src/__tests__/scheduler-wake.test.ts +8 -16
  11. package/src/background-wake/background-wake-routes.test.ts +2 -3
  12. package/src/cli/commands/memory/__tests__/worker.test.ts +8 -5
  13. package/src/cli/commands/memory/index.help.ts +7 -10
  14. package/src/cli/commands/memory/worker.ts +29 -39
  15. package/src/cli/commands/schedules-worker.ts +10 -43
  16. package/src/cli/commands/schedules.help.ts +8 -13
  17. package/src/config/schema.ts +0 -2
  18. package/src/config/schemas/memory-lifecycle.ts +0 -12
  19. package/src/config/schemas/memory.ts +0 -4
  20. package/src/daemon/shutdown-handlers.ts +3 -16
  21. package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +8 -7
  22. package/src/{persistence → plugins/defaults/memory}/__tests__/worker-control.test.ts +8 -10
  23. package/src/plugins/defaults/memory/hooks/shutdown.ts +8 -11
  24. package/src/plugins/defaults/memory/jobs-worker.ts +28 -101
  25. package/src/plugins/defaults/memory/paths.ts +3 -2
  26. package/src/plugins/defaults/memory/routes/__tests__/memory-worker-routes.test.ts +201 -0
  27. package/src/plugins/defaults/memory/routes/memory-worker-routes.ts +162 -0
  28. package/src/plugins/defaults/memory/startup.ts +6 -7
  29. package/src/{persistence → plugins/defaults/memory}/worker-control.ts +12 -21
  30. package/src/plugins/defaults/memory/worker.ts +2 -2
  31. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +16 -66
  32. package/src/runtime/routes/background-wake-routes.ts +0 -1
  33. package/src/runtime/routes/index.ts +1 -1
  34. package/src/runtime/routes/schedule-worker-routes.ts +16 -84
  35. package/src/schedule/__tests__/worker-control.test.ts +3 -3
  36. package/src/schedule/scheduler.ts +21 -66
  37. package/src/schedule/worker-control.ts +11 -21
  38. package/src/schedule/worker.ts +3 -4
  39. package/src/config/schemas/schedules.ts +0 -35
  40. package/src/runtime/routes/__tests__/memory-worker-routes.test.ts +0 -318
  41. package/src/runtime/routes/memory-worker-routes.ts +0 -227
package/openapi.yaml CHANGED
@@ -17607,7 +17607,7 @@ paths:
17607
17607
  post:
17608
17608
  operationId: memory_worker_start_post
17609
17609
  summary: Start the memory worker
17610
- description: Spawns (or reuses) the memory worker process as a child of the daemon and enables memory.worker.enabled.
17610
+ description: Spawns (or reuses) the memory worker process as a child of the daemon.
17611
17611
  tags:
17612
17612
  - system
17613
17613
  responses:
@@ -17622,15 +17622,11 @@ paths:
17622
17622
  type: number
17623
17623
  alreadyRunning:
17624
17624
  type: boolean
17625
- workerEnabled:
17626
- type: boolean
17627
- const: true
17628
17625
  pidPath:
17629
17626
  type: string
17630
17627
  required:
17631
17628
  - pid
17632
17629
  - alreadyRunning
17633
- - workerEnabled
17634
17630
  - pidPath
17635
17631
  additionalProperties: false
17636
17632
  /v1/memory/worker/status:
@@ -17638,8 +17634,8 @@ paths:
17638
17634
  operationId: memory_worker_status_get
17639
17635
  summary: Memory worker status
17640
17636
  description:
17641
- Reports the memory worker process state, memory.worker.enabled, the synchronous in-process runner, and the
17642
- embedding-backend status (including a degraded flag and reason when no backend resolves).
17637
+ Reports the memory worker process liveness and the embedding-backend status (including a degraded flag and
17638
+ reason when no backend resolves).
17643
17639
  tags:
17644
17640
  - system
17645
17641
  responses:
@@ -17657,21 +17653,6 @@ paths:
17657
17653
  - not_running
17658
17654
  pid:
17659
17655
  type: number
17660
- workerEnabled:
17661
- type: boolean
17662
- syncRunner:
17663
- type: object
17664
- properties:
17665
- status:
17666
- type: string
17667
- enum:
17668
- - running
17669
- - not_running
17670
- pid:
17671
- type: number
17672
- required:
17673
- - status
17674
- additionalProperties: false
17675
17656
  embedding:
17676
17657
  type: object
17677
17658
  properties:
@@ -17705,15 +17686,13 @@ paths:
17705
17686
  additionalProperties: false
17706
17687
  required:
17707
17688
  - status
17708
- - workerEnabled
17709
- - syncRunner
17710
17689
  - embedding
17711
17690
  additionalProperties: false
17712
17691
  /v1/memory/worker/stop:
17713
17692
  post:
17714
17693
  operationId: memory_worker_stop_post
17715
17694
  summary: Stop the memory worker
17716
- description: Disables memory.worker.enabled and SIGTERMs the memory worker process if it is running.
17695
+ description: SIGTERMs the memory worker process if it is running.
17717
17696
  tags:
17718
17697
  - system
17719
17698
  responses:
@@ -17728,12 +17707,8 @@ paths:
17728
17707
  type: boolean
17729
17708
  pid:
17730
17709
  type: number
17731
- workerEnabled:
17732
- type: boolean
17733
- const: false
17734
17710
  required:
17735
17711
  - workerWasRunning
17736
- - workerEnabled
17737
17712
  additionalProperties: false
17738
17713
  /v1/messages:
17739
17714
  get:
@@ -25522,9 +25497,7 @@ paths:
25522
25497
  post:
25523
25498
  operationId: schedules_worker_start_post
25524
25499
  summary: Start the schedule worker
25525
- description:
25526
- Spawns (or reuses) the schedule worker process as a child of the daemon and enables
25527
- schedules.worker.enabled, so scheduled jobs run out of process.
25500
+ description: Spawns (or reuses) the schedule worker process as a child of the daemon.
25528
25501
  tags:
25529
25502
  - system
25530
25503
  responses:
@@ -25539,24 +25512,18 @@ paths:
25539
25512
  type: number
25540
25513
  alreadyRunning:
25541
25514
  type: boolean
25542
- workerEnabled:
25543
- type: boolean
25544
- const: true
25545
25515
  pidPath:
25546
25516
  type: string
25547
25517
  required:
25548
25518
  - pid
25549
25519
  - alreadyRunning
25550
- - workerEnabled
25551
25520
  - pidPath
25552
25521
  additionalProperties: false
25553
25522
  /v1/schedules/worker/status:
25554
25523
  get:
25555
25524
  operationId: schedules_worker_status_get
25556
25525
  summary: Schedule worker status
25557
- description:
25558
- Reports the schedule worker process state, schedules.worker.enabled, and whether the daemon's in-process
25559
- scheduler is currently executing schedules.
25526
+ description: Reports the schedule worker process liveness.
25560
25527
  tags:
25561
25528
  - system
25562
25529
  responses:
@@ -25574,33 +25541,14 @@ paths:
25574
25541
  - not_running
25575
25542
  pid:
25576
25543
  type: number
25577
- workerEnabled:
25578
- type: boolean
25579
- inProcessScheduler:
25580
- type: object
25581
- properties:
25582
- status:
25583
- type: string
25584
- enum:
25585
- - running
25586
- - not_running
25587
- pid:
25588
- type: number
25589
- required:
25590
- - status
25591
- additionalProperties: false
25592
25544
  required:
25593
25545
  - status
25594
- - workerEnabled
25595
- - inProcessScheduler
25596
25546
  additionalProperties: false
25597
25547
  /v1/schedules/worker/stop:
25598
25548
  post:
25599
25549
  operationId: schedules_worker_stop_post
25600
25550
  summary: Stop the schedule worker
25601
- description:
25602
- Disables schedules.worker.enabled (handing schedule execution back to the in-process scheduler) and
25603
- SIGTERMs the schedule worker process if it is running.
25551
+ description: SIGTERMs the schedule worker process if it is running.
25604
25552
  tags:
25605
25553
  - system
25606
25554
  responses:
@@ -25615,12 +25563,8 @@ paths:
25615
25563
  type: boolean
25616
25564
  pid:
25617
25565
  type: number
25618
- workerEnabled:
25619
- type: boolean
25620
- const: false
25621
25566
  required:
25622
25567
  - workerWasRunning
25623
- - workerEnabled
25624
25568
  additionalProperties: false
25625
25569
  /v1/search:
25626
25570
  get:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.10.8-dev.202607130516.157ae8a",
3
+ "version": "0.10.8-dev.202607131107.073396f",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -31,14 +31,12 @@ mock.module("../persistence/checkpoints.js", () => ({
31
31
  import {
32
32
  POLL_INTERVAL_MAX_MS,
33
33
  POLL_INTERVAL_MIN_MS,
34
- startMemoryJobsWorker,
34
+ startMemoryJobsWorkerLoop,
35
35
  } from "../plugins/defaults/memory/jobs-worker.js";
36
36
  import { setConfig } from "./helpers/set-config.js";
37
37
 
38
- // Memory disabled so each idle tick stays on the mocked-store fast path, and
39
- // the worker flag off so the supervisor neither spawns the out-of-process
40
- // worker nor stands the in-process runner down at the slow-poll cap.
41
- setConfig("memory", { enabled: false, worker: { enabled: false } });
38
+ // Memory disabled so each idle tick stays on the mocked-store fast path.
39
+ setConfig("memory", { enabled: false });
42
40
 
43
41
  describe("memory jobs worker adaptive poll interval", () => {
44
42
  test("exports expected poll interval constants", () => {
@@ -86,7 +84,7 @@ describe("memory jobs worker adaptive poll interval", () => {
86
84
  globalThis.clearTimeout = (() => {}) as typeof clearTimeout;
87
85
 
88
86
  try {
89
- const worker = startMemoryJobsWorker();
87
+ const worker = startMemoryJobsWorkerLoop();
90
88
 
91
89
  // Wait for the initial tick() promise to settle
92
90
  await new Promise((resolve) => originalSetTimeout(resolve, 20));
@@ -135,6 +135,8 @@ const BASELINE: Record<string, readonly string[]> = {
135
135
  "../../../../skills/catalog-cache.js",
136
136
  "../../../../telemetry/watchdog-events-store.js",
137
137
  "../../../../tools/skills/delete-managed.js",
138
+ "../../../../util/logger.js",
139
+ "../../../../util/platform.js",
138
140
  "../../../channels/types.js",
139
141
  "../../../config/loader.js",
140
142
  "../../../config/memory-v3-gate.js",
@@ -180,7 +182,6 @@ const BASELINE: Record<string, readonly string[]> = {
180
182
  "../../../persistence/jobs-store.js",
181
183
  "../../../persistence/raw-query.js",
182
184
  "../../../persistence/schema/index.js",
183
- "../../../persistence/worker-control.js",
184
185
  "../../../prompts/persona-resolver.js",
185
186
  "../../../prompts/system-prompt.js",
186
187
  "../../../prompts/template-detection.js",
@@ -205,6 +206,7 @@ const BASELINE: Record<string, readonly string[]> = {
205
206
  "../../../util/strip-comment-lines.js",
206
207
  "../../../util/truncate.js",
207
208
  "../../../util/worker-memory.js",
209
+ "../../../util/worker-process.js",
208
210
  "../../types.js",
209
211
  "../injection-presence.js",
210
212
  "../injector-order.js",
@@ -102,7 +102,6 @@ const BASELINE: Record<string, readonly string[]> = {
102
102
  "src/permissions/checker.ts",
103
103
  "src/persistence/conversation-crud.ts",
104
104
  "src/persistence/steps.ts",
105
- "src/persistence/worker-control.ts",
106
105
  "src/prompts/system-prompt.ts",
107
106
  "src/runtime/routes/consolidation-routes.ts",
108
107
  "src/runtime/routes/conversation-query-routes.ts",
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Scheduler ↔ schedule-worker ownership: while `schedules.worker.enabled` is
3
- * set, the daemon's in-process scheduler must leave every due schedule
4
- * unclaimed (the worker process owns schedule execution), while
5
- * `runDueSchedulesOnce` — the worker's tick — claims and executes them.
2
+ * `runDueSchedulesOnce` — the schedule worker's tick — claims and executes
3
+ * every due schedule across modes. Schedule execution is owned by the schedule
4
+ * worker process; the daemon's own scheduler tick runs only watchers and
5
+ * sequences.
6
6
  */
7
7
 
8
8
  import { beforeEach, describe, expect, mock, test } from "bun:test";
@@ -44,16 +44,7 @@ mock.module("../notifications/emit-signal.js", () => ({
44
44
  import { getDb } from "../persistence/db-connection.js";
45
45
  import { initializeDb } from "../persistence/db-init.js";
46
46
  import { createSchedule } from "../schedule/schedule-store.js";
47
- import {
48
- runDueSchedulesOnce,
49
- runScheduleDueWorkOnce,
50
- } from "../schedule/scheduler.js";
51
- import { setConfig } from "./helpers/set-config.js";
52
-
53
- /** Seed `schedules.worker.enabled` for real; the scheduler re-reads it per tick. */
54
- function setWorkerEnabled(enabled: boolean): void {
55
- setConfig("schedules", { worker: { enabled } });
56
- }
47
+ import { runDueSchedulesOnce } from "../schedule/scheduler.js";
57
48
 
58
49
  await initializeDb();
59
50
 
@@ -63,7 +54,6 @@ function rawDb(): import("bun:sqlite").Database {
63
54
  }
64
55
 
65
56
  beforeEach(() => {
66
- setWorkerEnabled(false);
67
57
  mockEmitNotificationSignal.mockClear();
68
58
  const db = getDb();
69
59
  db.run("DELETE FROM cron_runs");
@@ -95,48 +85,8 @@ function runsFor(jobId: string): Array<{ status: string }> {
95
85
  .all(jobId) as Array<{ status: string }>;
96
86
  }
97
87
 
98
- describe("scheduler stand-down for the schedule worker", () => {
99
- test("flag on: leaves every due schedule unclaimed and reports none pending", async () => {
100
- setWorkerEnabled(true);
101
- const { script } = await createDueScriptAndNotifyJobs();
102
- const dueBefore = rawDb()
103
- .query("SELECT id, next_run_at FROM cron_jobs")
104
- .all() as Array<{ id: string; next_run_at: number }>;
105
-
106
- const result = await runScheduleDueWorkOnce({
107
- includeStillPending: true,
108
- });
109
-
110
- expect(result.claimed).toBe(0);
111
- expect(result.stillPending).toBe(0);
112
- expect(mockEmitNotificationSignal).not.toHaveBeenCalled();
113
- expect(runsFor(script.id)).toHaveLength(0);
114
- // Nothing advanced — every schedule stays due for the worker to claim.
115
- const dueAfter = rawDb()
116
- .query("SELECT id, next_run_at FROM cron_jobs")
117
- .all() as Array<{ id: string; next_run_at: number }>;
118
- expect(dueAfter).toEqual(dueBefore);
119
- });
120
-
121
- test("flag off: the in-process scheduler claims and runs due schedules itself", async () => {
122
- setWorkerEnabled(false);
123
- const { script } = await createDueScriptAndNotifyJobs();
124
-
125
- const result = await runScheduleDueWorkOnce();
126
-
127
- expect(result.claimed).toBe(2);
128
- const scriptRuns = runsFor(script.id);
129
- expect(scriptRuns).toHaveLength(1);
130
- expect(scriptRuns[0].status).toBe("ok");
131
- expect(mockEmitNotificationSignal).toHaveBeenCalled();
132
- });
133
- });
134
-
135
88
  describe("runDueSchedulesOnce (the schedule worker's tick)", () => {
136
89
  test("claims and executes due schedules across modes", async () => {
137
- // The worker runs with the flag on; runDueSchedulesOnce itself does not
138
- // consult the flag — its caller owns schedule execution.
139
- setWorkerEnabled(true);
140
90
  const { script } = await createDueScriptAndNotifyJobs();
141
91
 
142
92
  const result = await runDueSchedulesOnce();
@@ -56,7 +56,6 @@ mock.module("../notifications/emit-signal.js", () => ({
56
56
  emitNotificationSignalImpl(payload),
57
57
  }));
58
58
 
59
- import { loadRawConfig, saveRawConfig } from "../config/loader.js";
60
59
  import { getDb } from "../persistence/db-connection.js";
61
60
  import { initializeDb } from "../persistence/db-init.js";
62
61
  import { applyRetryDecision, decideRetry } from "../schedule/retry-policy.js";
@@ -72,15 +71,19 @@ import {
72
71
  scheduleRetry,
73
72
  } from "../schedule/schedule-store.js";
74
73
  import type { SchedulerHandle } from "../schedule/scheduler.js";
75
- import { startScheduler as startSchedulerReal } from "../schedule/scheduler.js";
74
+ import {
75
+ runDueSchedulesOnce,
76
+ runScheduleDueWorkOnce,
77
+ } from "../schedule/scheduler.js";
76
78
  import type { ScheduleMessageProcessor } from "../schedule/scheduler-types.js";
77
79
 
78
80
  /**
79
- * Wrap `startScheduler` so a single per-test `processMessage` callback drives
80
- * both scheduler dispatch paths: the conversation-reuse path (which calls the
81
- * mocked `daemon/process-message`) and the fresh-bootstrap path (which calls
82
- * the mocked `runBackgroundJob`). Tests exercise both deterministically through
83
- * this one callback.
81
+ * Wire a single per-test `processMessage` callback into both schedule dispatch
82
+ * paths — the conversation-reuse path (mocked `daemon/process-message`) and the
83
+ * fresh-bootstrap path (mocked `runBackgroundJob`) — and return a handle that
84
+ * drives schedule execution directly via `runDueSchedulesOnce` (the schedule
85
+ * worker's path). Avoids spawning the real worker process in tests while
86
+ * exercising the exact execution + retry logic.
84
87
  */
85
88
  function startScheduler(
86
89
  processMessage: ScheduleMessageProcessor,
@@ -92,18 +95,22 @@ function startScheduler(
92
95
  };
93
96
  processMessageImpl = dispatch;
94
97
  injectedProcessMessageForRunner = dispatch;
95
- return startSchedulerReal();
98
+ // Mimic the real scheduler's immediate startup tick that fires due
99
+ // schedules once; tests await a short delay for it to settle before
100
+ // asserting or driving further runs via `runOnce`.
101
+ void runDueSchedulesOnce();
102
+ return {
103
+ async runOnce(): Promise<number> {
104
+ const r = await runDueSchedulesOnce();
105
+ return r.completed + r.failed + r.skipped;
106
+ },
107
+ runDueWorkOnce: (options) => runScheduleDueWorkOnce(options),
108
+ stop(): void {},
109
+ };
96
110
  }
97
111
 
98
112
  await initializeDb();
99
113
 
100
- // The schedule worker is on by default, which stands the daemon's in-process
101
- // scheduler down. These tests exercise that in-process execution path directly,
102
- // so pin the worker flag off for this test process.
103
- const rawConfig = loadRawConfig();
104
- rawConfig.schedules = { worker: { enabled: false } };
105
- saveRawConfig(rawConfig);
106
-
107
114
  /** Access the underlying bun:sqlite Database for raw parameterized queries. */
108
115
  function getRawDb(): import("bun:sqlite").Database {
109
116
  return (getDb() as unknown as { $client: import("bun:sqlite").Database })
@@ -53,7 +53,6 @@ mock.module("../notifications/emit-signal.js", () => ({
53
53
  },
54
54
  }));
55
55
 
56
- import { loadRawConfig, saveRawConfig } from "../config/loader.js";
57
56
  import { getDb } from "../persistence/db-connection.js";
58
57
  import { initializeDb } from "../persistence/db-init.js";
59
58
  import {
@@ -61,17 +60,10 @@ import {
61
60
  getSchedule,
62
61
  getScheduleRuns,
63
62
  } from "../schedule/schedule-store.js";
64
- import { runScheduleDueWorkOnce } from "../schedule/scheduler.js";
63
+ import { runDueSchedulesOnce } from "../schedule/scheduler.js";
65
64
 
66
65
  await initializeDb();
67
66
 
68
- // The schedule worker is on by default, which stands the daemon's in-process
69
- // scheduler down. These tests exercise that in-process execution path directly,
70
- // so pin the worker flag off for this test process.
71
- const rawConfig = loadRawConfig();
72
- rawConfig.schedules = { worker: { enabled: false } };
73
- saveRawConfig(rawConfig);
74
-
75
67
  /** Access the underlying bun:sqlite Database for raw parameterized queries. */
76
68
  function getRawDb(): import("bun:sqlite").Database {
77
69
  return (getDb() as unknown as { $client: import("bun:sqlite").Database })
@@ -150,7 +142,7 @@ describe("scheduler RRULE execution", () => {
150
142
  processedMessages.push({ conversationId, message: prompt });
151
143
  };
152
144
 
153
- await runScheduleDueWorkOnce();
145
+ await runDueSchedulesOnce();
154
146
 
155
147
  // The runner should have been invoked with the RRULE message
156
148
  expect(
@@ -198,7 +190,7 @@ describe("scheduler RRULE execution", () => {
198
190
  };
199
191
 
200
192
  // First tick: the expired schedule should fire its final due run
201
- await runScheduleDueWorkOnce();
193
+ await runDueSchedulesOnce();
202
194
 
203
195
  // The message IS delivered once
204
196
  expect(processedMessages).toContain("Final expired run");
@@ -216,7 +208,7 @@ describe("scheduler RRULE execution", () => {
216
208
 
217
209
  // Second tick: the disabled schedule must NOT fire again
218
210
  processedMessages.length = 0;
219
- await runScheduleDueWorkOnce();
211
+ await runDueSchedulesOnce();
220
212
 
221
213
  expect(processedMessages).not.toContain("Final expired run");
222
214
  // No additional runs
@@ -244,7 +236,7 @@ describe("scheduler RRULE execution", () => {
244
236
  processedMessages.push({ conversationId, message: prompt });
245
237
  };
246
238
 
247
- await runScheduleDueWorkOnce();
239
+ await runDueSchedulesOnce();
248
240
 
249
241
  // The runner should have been invoked with the cron message
250
242
  expect(processedMessages.some((m) => m.message === "Cron message")).toBe(
@@ -275,7 +267,7 @@ describe("scheduler RRULE execution", () => {
275
267
  dispatched.push(message);
276
268
  };
277
269
 
278
- await runScheduleDueWorkOnce();
270
+ await runDueSchedulesOnce();
279
271
 
280
272
  // The raw `run_task:<id>` string must never reach the agent.
281
273
  expect(dispatched).toHaveLength(0);
@@ -326,7 +318,7 @@ describe("scheduler RRULE execution", () => {
326
318
  // Force the schedule to be due
327
319
  forceScheduleDue(schedule.id);
328
320
 
329
- await runScheduleDueWorkOnce();
321
+ await runDueSchedulesOnce();
330
322
 
331
323
  // The schedule should have been claimed and nextRunAt advanced
332
324
  const after = getSchedule(schedule.id);
@@ -373,7 +365,7 @@ describe("scheduler RRULE execution", () => {
373
365
  processedMessages.push(prompt);
374
366
  };
375
367
 
376
- await runScheduleDueWorkOnce();
368
+ await runDueSchedulesOnce();
377
369
 
378
370
  expect(processedMessages).toContain("Set fire test");
379
371
 
@@ -447,7 +439,7 @@ describe("scheduler RRULE execution", () => {
447
439
  processedMessages.push(prompt);
448
440
  };
449
441
 
450
- await runScheduleDueWorkOnce();
442
+ await runDueSchedulesOnce();
451
443
 
452
444
  // The schedule should have fired
453
445
  expect(processedMessages).toContain("EXRULE scheduler fire");
@@ -483,7 +475,7 @@ describe("scheduler RRULE execution", () => {
483
475
  forceScheduleDue(schedule.id);
484
476
  const forcedDueAt = getSchedule(schedule.id)!.nextRunAt;
485
477
 
486
- await runScheduleDueWorkOnce();
478
+ await runDueSchedulesOnce();
487
479
 
488
480
  const after = getSchedule(schedule.id);
489
481
  expect(after).not.toBeNull();
@@ -512,7 +504,7 @@ describe("scheduler RRULE execution", () => {
512
504
  processedMessages.push({ conversationId, message: prompt });
513
505
  };
514
506
 
515
- await runScheduleDueWorkOnce();
507
+ await runDueSchedulesOnce();
516
508
 
517
509
  expect(
518
510
  processedMessages.some((m) => m.message === "Execute this once"),
@@ -541,7 +533,7 @@ describe("scheduler RRULE execution", () => {
541
533
 
542
534
  expect(getSchedule(schedule.id)!.status).toBe("active");
543
535
 
544
- await runScheduleDueWorkOnce();
536
+ await runDueSchedulesOnce();
545
537
 
546
538
  expect(notifySignalCalls).toHaveLength(1);
547
539
  expect(notifySignalCalls[0]).toMatchObject({
@@ -574,7 +566,7 @@ describe("scheduler RRULE execution", () => {
574
566
 
575
567
  runBackgroundJobShouldFail = true;
576
568
 
577
- await runScheduleDueWorkOnce();
569
+ await runDueSchedulesOnce();
578
570
 
579
571
  const after = getSchedule(schedule.id);
580
572
  expect(after).not.toBeNull();
@@ -597,7 +589,7 @@ describe("scheduler RRULE execution", () => {
597
589
 
598
590
  forceScheduleDue(schedule.id);
599
591
 
600
- await runScheduleDueWorkOnce();
592
+ await runDueSchedulesOnce();
601
593
 
602
594
  expect(notifySignalCalls).toHaveLength(1);
603
595
  expect(notifySignalCalls[0]).toMatchObject({
@@ -635,7 +627,7 @@ describe("scheduler RRULE execution", () => {
635
627
  },
636
628
  });
637
629
 
638
- await runScheduleDueWorkOnce();
630
+ await runDueSchedulesOnce();
639
631
 
640
632
  expect(notifySignalCalls).toHaveLength(1);
641
633
  expect(notifySignalCalls[0].routingIntent).toBe("all_channels");