feat: add announce delivery mode for automation runs
This commit is contained in:
@@ -98,6 +98,22 @@ describe('CronScheduler', () => {
|
||||
expect(messages[0].metadata?.deliveryMode).toBe('isolated_job');
|
||||
});
|
||||
|
||||
it('uses announce sender IDs and metadata when delivery mode is announce', async () => {
|
||||
const jobs = [makeCronJob()];
|
||||
scheduler = new CronScheduler(jobs, asCronChannelRegistry(mockChannelRegistry), 'announce');
|
||||
|
||||
const messages: InboundMessage[] = [];
|
||||
scheduler.onMessage((msg: InboundMessage) => messages.push(msg));
|
||||
await scheduler.connect();
|
||||
scheduler.triggerJob('test-job');
|
||||
|
||||
expect(messages).toHaveLength(1);
|
||||
expect(messages[0].senderId).toMatch(/^test-job:announce:run-/);
|
||||
expect(messages[0].metadata?.replyPeerId).toBe('test-job');
|
||||
expect(messages[0].metadata?.deliveryMode).toBe('announce');
|
||||
expect(messages[0].metadata?.announce).toBe(true);
|
||||
});
|
||||
|
||||
it('forwards response to output channel on send()', async () => {
|
||||
const mockOutputAdapter = {
|
||||
send: vi.fn().mockResolvedValue(undefined),
|
||||
|
||||
@@ -9,7 +9,7 @@ interface ChannelLookup {
|
||||
get(name: string): { send(peerId: string, message: OutboundMessage): Promise<void> } | undefined;
|
||||
}
|
||||
|
||||
type DeliveryMode = 'shared_session' | 'isolated_job';
|
||||
type DeliveryMode = 'shared_session' | 'isolated_job' | 'announce';
|
||||
|
||||
export class CronScheduler implements ChannelAdapter {
|
||||
readonly name = 'cron';
|
||||
@@ -99,7 +99,11 @@ export class CronScheduler implements ChannelAdapter {
|
||||
this.lastTriggeredLocalDateByJob.set(jobName, dayKey);
|
||||
}
|
||||
const runId = `run-${randomUUID()}`;
|
||||
const senderId = this.deliveryMode === 'isolated_job' ? `${jobName}:${runId}` : jobName;
|
||||
const senderId = this.deliveryMode === 'shared_session'
|
||||
? jobName
|
||||
: this.deliveryMode === 'announce'
|
||||
? `${jobName}:announce:${runId}`
|
||||
: `${jobName}:${runId}`;
|
||||
|
||||
const msg: InboundMessage = {
|
||||
id: `cron-${jobName}-${Date.now()}`,
|
||||
@@ -113,6 +117,7 @@ export class CronScheduler implements ChannelAdapter {
|
||||
scheduled: true,
|
||||
modelTier: job.model_tier,
|
||||
deliveryMode: this.deliveryMode,
|
||||
announce: this.deliveryMode === 'announce',
|
||||
runId,
|
||||
replyPeerId: jobName,
|
||||
},
|
||||
|
||||
@@ -137,6 +137,26 @@ describe('WebhookHandler', () => {
|
||||
expect(messages[0].metadata?.deliveryMode).toBe('isolated_job');
|
||||
});
|
||||
|
||||
it('handleRequest uses announce sender IDs and metadata when delivery mode is announce', async () => {
|
||||
const webhooks = [makeWebhook()];
|
||||
handler = new WebhookHandler(webhooks, asWebhookChannelLookup(mockChannelRegistry), 'announce');
|
||||
|
||||
const messages: InboundMessage[] = [];
|
||||
handler.onMessage((msg: InboundMessage) => messages.push(msg));
|
||||
await handler.connect();
|
||||
|
||||
const req = mockRequest('hello world');
|
||||
const res = mockResponse();
|
||||
const result = await handler.handleRequest('test-hook', req, res);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(messages).toHaveLength(1);
|
||||
expect(messages[0].senderId).toMatch(/^test-hook:announce:run-/);
|
||||
expect(messages[0].metadata?.replyPeerId).toBe('test-hook');
|
||||
expect(messages[0].metadata?.deliveryMode).toBe('announce');
|
||||
expect(messages[0].metadata?.announce).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for unknown webhook', async () => {
|
||||
handler = new WebhookHandler([], asWebhookChannelLookup(mockChannelRegistry));
|
||||
await handler.connect();
|
||||
|
||||
@@ -10,7 +10,7 @@ interface ChannelLookup {
|
||||
get(name: string): { send(peerId: string, message: OutboundMessage): Promise<void> } | undefined;
|
||||
}
|
||||
|
||||
type DeliveryMode = 'shared_session' | 'isolated_job';
|
||||
type DeliveryMode = 'shared_session' | 'isolated_job' | 'announce';
|
||||
|
||||
/** Verify HMAC-SHA256 signature from the X-Webhook-Signature header. */
|
||||
function verifyHmac(body: string, secret: string, signature: string): boolean {
|
||||
@@ -162,7 +162,11 @@ export class WebhookHandler implements ChannelAdapter {
|
||||
// Render message template
|
||||
const text = renderTemplate(webhook.message, body);
|
||||
const runId = `run-${randomUUID()}`;
|
||||
const senderId = this.deliveryMode === 'isolated_job' ? `${webhookName}:${runId}` : webhookName;
|
||||
const senderId = this.deliveryMode === 'shared_session'
|
||||
? webhookName
|
||||
: this.deliveryMode === 'announce'
|
||||
? `${webhookName}:announce:${runId}`
|
||||
: `${webhookName}:${runId}`;
|
||||
|
||||
const msg: InboundMessage = {
|
||||
id: `webhook-${webhookName}-${Date.now()}`,
|
||||
@@ -175,6 +179,7 @@ export class WebhookHandler implements ChannelAdapter {
|
||||
webhookName,
|
||||
body,
|
||||
deliveryMode: this.deliveryMode,
|
||||
announce: this.deliveryMode === 'announce',
|
||||
runId,
|
||||
replyPeerId: webhookName,
|
||||
},
|
||||
|
||||
@@ -1059,6 +1059,16 @@ describe('configSchema automation', () => {
|
||||
expect(result.automation.delivery_mode).toBe('isolated_job');
|
||||
});
|
||||
|
||||
it('accepts announce automation delivery mode', () => {
|
||||
const result = configSchema.parse({
|
||||
...baseConfig,
|
||||
automation: {
|
||||
delivery_mode: 'announce',
|
||||
},
|
||||
});
|
||||
expect(result.automation.delivery_mode).toBe('announce');
|
||||
});
|
||||
|
||||
it('accepts config with cron jobs', () => {
|
||||
const result = configSchema.parse({
|
||||
...baseConfig,
|
||||
|
||||
@@ -417,7 +417,7 @@ const minioSyncAutomationSchema = z.object({
|
||||
notify_on_success: z.boolean().default(false),
|
||||
}).default({});
|
||||
|
||||
const automationDeliveryModeSchema = z.enum(['shared_session', 'isolated_job']);
|
||||
const automationDeliveryModeSchema = z.enum(['shared_session', 'isolated_job', 'announce']);
|
||||
|
||||
const automationSchema = z.object({
|
||||
/** Session strategy for automation-triggered runs (cron/webhooks/gmail). */
|
||||
|
||||
Reference in New Issue
Block a user