@vellumai/assistant 0.10.3-dev.202606301109.f6f8c0c → 0.10.3-dev.202606301343.ebf8f0b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/__tests__/credential-security-invariants.test.ts +0 -2
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/background-wake/wake-intent-hooks.test.ts +13 -7
- package/src/config/schemas/services.ts +0 -37
- package/src/daemon/lifecycle.ts +2 -93
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/persistence/conversation-row-batch-delete.ts +8 -1
- package/src/schedule/scheduler.ts +129 -65
- package/src/daemon/__tests__/meet-host-supervisor.test.ts +0 -584
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +0 -476
- package/src/daemon/meet-host-supervisor.ts +0 -755
- package/src/daemon/meet-manifest-loader.ts +0 -396
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -340
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
package/package.json
CHANGED
|
@@ -221,13 +221,11 @@ describe("Invariant 2: no generic plaintext secret read API", () => {
|
|
|
221
221
|
"runtime/routes/credential-routes.ts", // CLI credential management routes (CLI-migrated to IPC)
|
|
222
222
|
"runtime/routes/sanity-routes.ts", // Sanity connect/discover routes (reads stored api_token from credential store)
|
|
223
223
|
"runtime/routes/platform-routes.ts", // CLI platform connect/disconnect/status routes (CLI-migrated to IPC)
|
|
224
|
-
"ipc/skill-routes/providers.ts", // host.providers.secureKeys.getProviderKey IPC route (out-of-process SkillHost companion)
|
|
225
224
|
"inbound/platform-callback-registration.ts", // managed credential lookup for platform base URL, assistant ID, and API key
|
|
226
225
|
"tts/providers/elevenlabs-provider.ts", // ElevenLabs TTS API key lookup
|
|
227
226
|
"tts/providers/deepgram-provider.ts", // Deepgram TTS API key lookup
|
|
228
227
|
"tts/providers/xai-provider.ts", // xAI TTS API key lookup
|
|
229
228
|
"credential-health/credential-health-service.ts", // credential health check reads access tokens for liveness pings
|
|
230
|
-
"ipc/skill-routes/providers.ts", // skill IPC route exposes provider key lookup to hosted skills
|
|
231
229
|
"runtime/routes/avatar-routes.ts", // avatar generate route reads platform_base_url from credential store
|
|
232
230
|
"cli/commands/keys.ts", // CLI provider key management
|
|
233
231
|
"cli/commands/oauth/connect.ts", // CLI OAuth connect stored-secret verification
|
|
@@ -43,6 +43,27 @@ mock.module("../runtime/background-job-runner.js", () => ({
|
|
|
43
43
|
},
|
|
44
44
|
}));
|
|
45
45
|
|
|
46
|
+
// The scheduler's conversation-reuse path dispatches through `processMessage`;
|
|
47
|
+
// route it to the same per-test delegate the runner mock uses.
|
|
48
|
+
let processMessageImpl: (
|
|
49
|
+
conversationId: string,
|
|
50
|
+
message: string,
|
|
51
|
+
) => Promise<unknown> = async () => {};
|
|
52
|
+
mock.module("../daemon/process-message.js", () => ({
|
|
53
|
+
processMessage: (conversationId: string, message: string) =>
|
|
54
|
+
processMessageImpl(conversationId, message),
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
// Notify-mode firings dispatch through `emitNotificationSignal`; a per-test
|
|
58
|
+
// delegate lets a scenario make the notification throw to drive failure paths.
|
|
59
|
+
let emitNotificationSignalImpl: (
|
|
60
|
+
payload: unknown,
|
|
61
|
+
) => Promise<unknown> = async () => {};
|
|
62
|
+
mock.module("../notifications/emit-signal.js", () => ({
|
|
63
|
+
emitNotificationSignal: (payload: unknown) =>
|
|
64
|
+
emitNotificationSignalImpl(payload),
|
|
65
|
+
}));
|
|
66
|
+
|
|
46
67
|
import { getDb } from "../persistence/db-connection.js";
|
|
47
68
|
import { initializeDb } from "../persistence/db-init.js";
|
|
48
69
|
import { applyRetryDecision, decideRetry } from "../schedule/retry-policy.js";
|
|
@@ -62,24 +83,23 @@ import { startScheduler as startSchedulerReal } from "../schedule/scheduler.js";
|
|
|
62
83
|
import type { ScheduleMessageProcessor } from "../schedule/scheduler-types.js";
|
|
63
84
|
|
|
64
85
|
/**
|
|
65
|
-
* Wrap `startScheduler` so
|
|
66
|
-
*
|
|
67
|
-
* `
|
|
68
|
-
*
|
|
69
|
-
*
|
|
86
|
+
* Wrap `startScheduler` so a single per-test `processMessage` callback drives
|
|
87
|
+
* both scheduler dispatch paths: the conversation-reuse path (which calls the
|
|
88
|
+
* mocked `daemon/process-message`) and the fresh-bootstrap path (which calls
|
|
89
|
+
* the mocked `runBackgroundJob`). Tests exercise both deterministically through
|
|
90
|
+
* this one callback.
|
|
70
91
|
*/
|
|
71
92
|
function startScheduler(
|
|
72
93
|
processMessage: ScheduleMessageProcessor,
|
|
73
|
-
|
|
74
|
-
|
|
94
|
+
_notifyScheduleOneShot?: unknown,
|
|
95
|
+
_options?: unknown,
|
|
75
96
|
): SchedulerHandle {
|
|
76
|
-
|
|
77
|
-
conversationId: string,
|
|
78
|
-
message: string,
|
|
79
|
-
) => {
|
|
97
|
+
const dispatch = async (conversationId: string, message: string) => {
|
|
80
98
|
await processMessage(conversationId, message, { trustClass: "guardian" });
|
|
81
99
|
};
|
|
82
|
-
|
|
100
|
+
processMessageImpl = dispatch;
|
|
101
|
+
injectedProcessMessageForRunner = dispatch;
|
|
102
|
+
return startSchedulerReal();
|
|
83
103
|
}
|
|
84
104
|
|
|
85
105
|
await initializeDb();
|
|
@@ -102,6 +122,7 @@ function forceScheduleDue(scheduleId: string): void {
|
|
|
102
122
|
|
|
103
123
|
describe("schedule retry store", () => {
|
|
104
124
|
beforeEach(() => {
|
|
125
|
+
emitNotificationSignalImpl = async () => {};
|
|
105
126
|
const db = getDb();
|
|
106
127
|
db.run("DELETE FROM cron_runs");
|
|
107
128
|
db.run("DELETE FROM cron_jobs");
|
|
@@ -203,6 +224,7 @@ describe("scheduler retry integration", () => {
|
|
|
203
224
|
let scheduler: SchedulerHandle;
|
|
204
225
|
|
|
205
226
|
beforeEach(() => {
|
|
227
|
+
emitNotificationSignalImpl = async () => {};
|
|
206
228
|
const db = getDb();
|
|
207
229
|
db.run("DELETE FROM cron_runs");
|
|
208
230
|
db.run("DELETE FROM cron_jobs");
|
|
@@ -389,11 +411,11 @@ describe("scheduler retry integration", () => {
|
|
|
389
411
|
maxRetries: 2,
|
|
390
412
|
});
|
|
391
413
|
|
|
392
|
-
|
|
414
|
+
emitNotificationSignalImpl = async () => {
|
|
393
415
|
throw new Error("notify failed");
|
|
394
416
|
};
|
|
395
417
|
|
|
396
|
-
scheduler = startScheduler(async () => {}
|
|
418
|
+
scheduler = startScheduler(async () => {});
|
|
397
419
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
398
420
|
scheduler.stop();
|
|
399
421
|
|
|
@@ -439,6 +461,7 @@ describe("scheduler retry integration", () => {
|
|
|
439
461
|
|
|
440
462
|
describe("crash recovery", () => {
|
|
441
463
|
beforeEach(() => {
|
|
464
|
+
emitNotificationSignalImpl = async () => {};
|
|
442
465
|
const db = getDb();
|
|
443
466
|
db.run("DELETE FROM cron_runs");
|
|
444
467
|
db.run("DELETE FROM cron_jobs");
|
|
@@ -574,6 +597,7 @@ describe("scheduler-recovery equivalence", () => {
|
|
|
574
597
|
let scheduler: SchedulerHandle;
|
|
575
598
|
|
|
576
599
|
beforeEach(() => {
|
|
600
|
+
emitNotificationSignalImpl = async () => {};
|
|
577
601
|
const db = getDb();
|
|
578
602
|
db.run("DELETE FROM cron_runs");
|
|
579
603
|
db.run("DELETE FROM cron_jobs");
|
|
@@ -89,6 +89,18 @@ mock.module("../daemon/disk-pressure-background-gate.js", () => ({
|
|
|
89
89
|
shouldLogDiskPressureBackgroundSkip: () => true,
|
|
90
90
|
}));
|
|
91
91
|
|
|
92
|
+
const mockProcessMessage = mock((..._args: unknown[]) => Promise.resolve());
|
|
93
|
+
mock.module("../daemon/process-message.js", () => ({
|
|
94
|
+
processMessage: mockProcessMessage,
|
|
95
|
+
}));
|
|
96
|
+
|
|
97
|
+
const mockEmitNotificationSignal = mock((..._args: unknown[]) =>
|
|
98
|
+
Promise.resolve(),
|
|
99
|
+
);
|
|
100
|
+
mock.module("../notifications/emit-signal.js", () => ({
|
|
101
|
+
emitNotificationSignal: mockEmitNotificationSignal,
|
|
102
|
+
}));
|
|
103
|
+
|
|
92
104
|
import { getDb } from "../persistence/db-connection.js";
|
|
93
105
|
import { initializeDb } from "../persistence/db-init.js";
|
|
94
106
|
import { createSchedule } from "../schedule/schedule-store.js";
|
|
@@ -104,6 +116,8 @@ function rawDb(): import("bun:sqlite").Database {
|
|
|
104
116
|
describe("scheduler disk pressure gate", () => {
|
|
105
117
|
beforeEach(() => {
|
|
106
118
|
locked = true;
|
|
119
|
+
mockProcessMessage.mockClear();
|
|
120
|
+
mockEmitNotificationSignal.mockClear();
|
|
107
121
|
const db = getDb();
|
|
108
122
|
db.run("DELETE FROM cron_runs");
|
|
109
123
|
db.run("DELETE FROM cron_jobs");
|
|
@@ -122,14 +136,11 @@ describe("scheduler disk pressure gate", () => {
|
|
|
122
136
|
nextRunAt: dueAt,
|
|
123
137
|
});
|
|
124
138
|
|
|
125
|
-
const
|
|
126
|
-
const notify = mock(() => Promise.resolve());
|
|
127
|
-
|
|
128
|
-
const processed = await runScheduleOnce(processMessage, notify);
|
|
139
|
+
const processed = await runScheduleOnce();
|
|
129
140
|
|
|
130
141
|
expect(processed).toBe(0);
|
|
131
|
-
expect(
|
|
132
|
-
expect(
|
|
142
|
+
expect(mockProcessMessage).not.toHaveBeenCalled();
|
|
143
|
+
expect(mockEmitNotificationSignal).not.toHaveBeenCalled();
|
|
133
144
|
|
|
134
145
|
const row = rawDb()
|
|
135
146
|
.query("SELECT status, next_run_at FROM cron_jobs WHERE id = ?")
|
|
@@ -50,6 +50,25 @@ mock.module("../runtime/background-job-runner.js", () => ({
|
|
|
50
50
|
},
|
|
51
51
|
}));
|
|
52
52
|
|
|
53
|
+
// The scheduler dispatches reuse/task-path messages through `processMessage`;
|
|
54
|
+
// route them to a per-test delegate so tests can capture those calls.
|
|
55
|
+
let processMessageImpl: (
|
|
56
|
+
conversationId: string,
|
|
57
|
+
message: string,
|
|
58
|
+
) => Promise<void> = async () => {};
|
|
59
|
+
mock.module("../daemon/process-message.js", () => ({
|
|
60
|
+
processMessage: (conversationId: string, message: string) =>
|
|
61
|
+
processMessageImpl(conversationId, message),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
// Notify-mode firings go through `emitNotificationSignal`; capture them.
|
|
65
|
+
const notifySignalCalls: Array<Record<string, unknown>> = [];
|
|
66
|
+
mock.module("../notifications/emit-signal.js", () => ({
|
|
67
|
+
emitNotificationSignal: async (payload: Record<string, unknown>) => {
|
|
68
|
+
notifySignalCalls.push(payload);
|
|
69
|
+
},
|
|
70
|
+
}));
|
|
71
|
+
|
|
53
72
|
import { getDb } from "../persistence/db-connection.js";
|
|
54
73
|
import { initializeDb } from "../persistence/db-init.js";
|
|
55
74
|
import {
|
|
@@ -138,6 +157,8 @@ describe("scheduler RRULE execution", () => {
|
|
|
138
157
|
db.run("DELETE FROM conversations");
|
|
139
158
|
onRunBackgroundJobPrompt = null;
|
|
140
159
|
runBackgroundJobShouldFail = false;
|
|
160
|
+
processMessageImpl = async () => {};
|
|
161
|
+
notifySignalCalls.length = 0;
|
|
141
162
|
});
|
|
142
163
|
|
|
143
164
|
test("RRULE schedule fires and creates cron_runs entry", async () => {
|
|
@@ -163,10 +184,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
163
184
|
processedMessages.push({ conversationId, message: prompt });
|
|
164
185
|
};
|
|
165
186
|
|
|
166
|
-
const scheduler = startScheduler(
|
|
167
|
-
async () => {},
|
|
168
|
-
() => {},
|
|
169
|
-
);
|
|
187
|
+
const scheduler = startScheduler();
|
|
170
188
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
171
189
|
scheduler.stop();
|
|
172
190
|
|
|
@@ -201,12 +219,12 @@ describe("scheduler RRULE execution", () => {
|
|
|
201
219
|
const directCalls: { conversationId: string; message: string }[] = [];
|
|
202
220
|
let onMessage: (() => void) | undefined;
|
|
203
221
|
const messageReceived = new Promise<void>((r) => (onMessage = r));
|
|
204
|
-
|
|
222
|
+
processMessageImpl = async (conversationId, message) => {
|
|
205
223
|
directCalls.push({ conversationId, message });
|
|
206
224
|
onMessage?.();
|
|
207
225
|
};
|
|
208
226
|
|
|
209
|
-
const scheduler = startScheduler(
|
|
227
|
+
const scheduler = startScheduler();
|
|
210
228
|
// The run_task path involves a dynamic import which can take >50ms in CI,
|
|
211
229
|
// exceeding the patched setTimeout delay. Await the actual callback instead
|
|
212
230
|
// of relying on a fixed timeout.
|
|
@@ -271,10 +289,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
271
289
|
};
|
|
272
290
|
|
|
273
291
|
// First tick: the expired schedule should fire its final due run
|
|
274
|
-
const scheduler1 = startScheduler(
|
|
275
|
-
async () => {},
|
|
276
|
-
() => {},
|
|
277
|
-
);
|
|
292
|
+
const scheduler1 = startScheduler();
|
|
278
293
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
279
294
|
scheduler1.stop();
|
|
280
295
|
|
|
@@ -294,10 +309,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
294
309
|
|
|
295
310
|
// Second tick: the disabled schedule must NOT fire again
|
|
296
311
|
processedMessages.length = 0;
|
|
297
|
-
const scheduler2 = startScheduler(
|
|
298
|
-
async () => {},
|
|
299
|
-
() => {},
|
|
300
|
-
);
|
|
312
|
+
const scheduler2 = startScheduler();
|
|
301
313
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
302
314
|
scheduler2.stop();
|
|
303
315
|
|
|
@@ -327,10 +339,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
327
339
|
processedMessages.push({ conversationId, message: prompt });
|
|
328
340
|
};
|
|
329
341
|
|
|
330
|
-
const scheduler = startScheduler(
|
|
331
|
-
async () => {},
|
|
332
|
-
() => {},
|
|
333
|
-
);
|
|
342
|
+
const scheduler = startScheduler();
|
|
334
343
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
335
344
|
scheduler.stop();
|
|
336
345
|
|
|
@@ -385,10 +394,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
385
394
|
// Force the schedule to be due
|
|
386
395
|
forceScheduleDue(schedule.id);
|
|
387
396
|
|
|
388
|
-
const scheduler = startScheduler(
|
|
389
|
-
async () => {},
|
|
390
|
-
() => {},
|
|
391
|
-
);
|
|
397
|
+
const scheduler = startScheduler();
|
|
392
398
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
393
399
|
scheduler.stop();
|
|
394
400
|
|
|
@@ -437,10 +443,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
437
443
|
processedMessages.push(prompt);
|
|
438
444
|
};
|
|
439
445
|
|
|
440
|
-
const scheduler = startScheduler(
|
|
441
|
-
async () => {},
|
|
442
|
-
() => {},
|
|
443
|
-
);
|
|
446
|
+
const scheduler = startScheduler();
|
|
444
447
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
445
448
|
scheduler.stop();
|
|
446
449
|
|
|
@@ -516,10 +519,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
516
519
|
processedMessages.push(prompt);
|
|
517
520
|
};
|
|
518
521
|
|
|
519
|
-
const scheduler = startScheduler(
|
|
520
|
-
async () => {},
|
|
521
|
-
() => {},
|
|
522
|
-
);
|
|
522
|
+
const scheduler = startScheduler();
|
|
523
523
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
524
524
|
scheduler.stop();
|
|
525
525
|
|
|
@@ -557,8 +557,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
557
557
|
forceScheduleDue(schedule.id);
|
|
558
558
|
const forcedDueAt = getSchedule(schedule.id)!.nextRunAt;
|
|
559
559
|
|
|
560
|
-
const
|
|
561
|
-
const scheduler = startScheduler(processMessage, () => {});
|
|
560
|
+
const scheduler = startScheduler();
|
|
562
561
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
563
562
|
scheduler.stop();
|
|
564
563
|
|
|
@@ -589,10 +588,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
589
588
|
processedMessages.push({ conversationId, message: prompt });
|
|
590
589
|
};
|
|
591
590
|
|
|
592
|
-
const scheduler = startScheduler(
|
|
593
|
-
async () => {},
|
|
594
|
-
() => {},
|
|
595
|
-
);
|
|
591
|
+
const scheduler = startScheduler();
|
|
596
592
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
597
593
|
scheduler.stop();
|
|
598
594
|
|
|
@@ -623,32 +619,19 @@ describe("scheduler RRULE execution", () => {
|
|
|
623
619
|
|
|
624
620
|
expect(getSchedule(schedule.id)!.status).toBe("active");
|
|
625
621
|
|
|
626
|
-
const
|
|
627
|
-
id: string;
|
|
628
|
-
label: string;
|
|
629
|
-
message: string;
|
|
630
|
-
routingIntent: string;
|
|
631
|
-
routingHints: Record<string, unknown>;
|
|
632
|
-
}> = [];
|
|
633
|
-
const notifyScheduleOneShot = (payload: {
|
|
634
|
-
id: string;
|
|
635
|
-
label: string;
|
|
636
|
-
message: string;
|
|
637
|
-
routingIntent: string;
|
|
638
|
-
routingHints: Record<string, unknown>;
|
|
639
|
-
}) => {
|
|
640
|
-
notifyCalls.push(payload);
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
|
|
622
|
+
const scheduler = startScheduler();
|
|
644
623
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
645
624
|
scheduler.stop();
|
|
646
625
|
|
|
647
|
-
expect(
|
|
648
|
-
expect(
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
626
|
+
expect(notifySignalCalls).toHaveLength(1);
|
|
627
|
+
expect(notifySignalCalls[0]).toMatchObject({
|
|
628
|
+
sourceEventName: "schedule.notify",
|
|
629
|
+
sourceContextId: schedule.id,
|
|
630
|
+
contextPayload: {
|
|
631
|
+
scheduleId: schedule.id,
|
|
632
|
+
label: "One-shot notify",
|
|
633
|
+
message: "Notify about this",
|
|
634
|
+
},
|
|
652
635
|
routingIntent: "multi_channel",
|
|
653
636
|
routingHints: { channel: "slack" },
|
|
654
637
|
});
|
|
@@ -671,10 +654,7 @@ describe("scheduler RRULE execution", () => {
|
|
|
671
654
|
|
|
672
655
|
runBackgroundJobShouldFail = true;
|
|
673
656
|
|
|
674
|
-
const scheduler = startScheduler(
|
|
675
|
-
async () => {},
|
|
676
|
-
() => {},
|
|
677
|
-
);
|
|
657
|
+
const scheduler = startScheduler();
|
|
678
658
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
679
659
|
scheduler.stop();
|
|
680
660
|
|
|
@@ -699,32 +679,19 @@ describe("scheduler RRULE execution", () => {
|
|
|
699
679
|
|
|
700
680
|
forceScheduleDue(schedule.id);
|
|
701
681
|
|
|
702
|
-
const
|
|
703
|
-
id: string;
|
|
704
|
-
label: string;
|
|
705
|
-
message: string;
|
|
706
|
-
routingIntent: string;
|
|
707
|
-
routingHints: Record<string, unknown>;
|
|
708
|
-
}> = [];
|
|
709
|
-
const notifyScheduleOneShot = (payload: {
|
|
710
|
-
id: string;
|
|
711
|
-
label: string;
|
|
712
|
-
message: string;
|
|
713
|
-
routingIntent: string;
|
|
714
|
-
routingHints: Record<string, unknown>;
|
|
715
|
-
}) => {
|
|
716
|
-
notifyCalls.push(payload);
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
|
|
682
|
+
const scheduler = startScheduler();
|
|
720
683
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
721
684
|
scheduler.stop();
|
|
722
685
|
|
|
723
|
-
expect(
|
|
724
|
-
expect(
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
686
|
+
expect(notifySignalCalls).toHaveLength(1);
|
|
687
|
+
expect(notifySignalCalls[0]).toMatchObject({
|
|
688
|
+
sourceEventName: "schedule.notify",
|
|
689
|
+
sourceContextId: schedule.id,
|
|
690
|
+
contextPayload: {
|
|
691
|
+
scheduleId: schedule.id,
|
|
692
|
+
label: "Recurring notify",
|
|
693
|
+
message: "Recurring notification",
|
|
694
|
+
},
|
|
728
695
|
routingIntent: "single_channel",
|
|
729
696
|
routingHints: { preferred: "email" },
|
|
730
697
|
});
|
|
@@ -752,30 +719,13 @@ describe("scheduler RRULE execution", () => {
|
|
|
752
719
|
},
|
|
753
720
|
});
|
|
754
721
|
|
|
755
|
-
const
|
|
756
|
-
id: string;
|
|
757
|
-
label: string;
|
|
758
|
-
message: string;
|
|
759
|
-
routingIntent: string;
|
|
760
|
-
routingHints: Record<string, unknown>;
|
|
761
|
-
}> = [];
|
|
762
|
-
const notifyScheduleOneShot = (payload: {
|
|
763
|
-
id: string;
|
|
764
|
-
label: string;
|
|
765
|
-
message: string;
|
|
766
|
-
routingIntent: string;
|
|
767
|
-
routingHints: Record<string, unknown>;
|
|
768
|
-
}) => {
|
|
769
|
-
notifyCalls.push(payload);
|
|
770
|
-
};
|
|
771
|
-
|
|
772
|
-
const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
|
|
722
|
+
const scheduler = startScheduler();
|
|
773
723
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
774
724
|
scheduler.stop();
|
|
775
725
|
|
|
776
|
-
expect(
|
|
777
|
-
expect(
|
|
778
|
-
expect(
|
|
726
|
+
expect(notifySignalCalls).toHaveLength(1);
|
|
727
|
+
expect(notifySignalCalls[0].routingIntent).toBe("all_channels");
|
|
728
|
+
expect(notifySignalCalls[0].routingHints).toEqual({
|
|
779
729
|
requestedByUser: true,
|
|
780
730
|
channelMentions: ["telegram", "slack"],
|
|
781
731
|
priority: "high",
|