@exaudeus/workrail 3.36.0 → 3.37.1
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/dist/config/config-file.js +2 -0
- package/dist/console-ui/assets/{index-n8cJrS4v.js → index-t8Wi304z.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/daemon/workflow-runner.d.ts +1 -0
- package/dist/daemon/workflow-runner.js +3 -6
- package/dist/infrastructure/session/SessionManager.js +17 -4
- package/dist/manifest.json +25 -17
- package/dist/trigger/notification-service.d.ts +42 -0
- package/dist/trigger/notification-service.js +164 -0
- package/dist/trigger/trigger-listener.js +7 -1
- package/dist/trigger/trigger-router.d.ts +3 -1
- package/dist/trigger/trigger-router.js +4 -1
- package/docs/design/agent-behavior-patterns-discovery.md +312 -0
- package/docs/design/agent-engine-communication-discovery.md +390 -0
- package/docs/design/agent-loop-architecture-alternatives-discovery.md +531 -0
- package/docs/design/agent-loop-error-handling-contract.md +238 -0
- package/docs/design/complete-step-approach-validation-discovery.md +344 -0
- package/docs/design/daemon-stuck-detection-discovery.md +174 -0
- package/docs/design/mcp-server-disconnect-discovery.md +245 -0
- package/docs/design/mcp-server-epipe-crash.md +198 -0
- package/docs/design/notification-design-candidates.md +131 -0
- package/docs/design/notification-design-review.md +84 -0
- package/docs/design/notification-implementation-plan.md +181 -0
- package/docs/design/spawn-agent-failure-modes.md +161 -0
- package/docs/design/spawn-agent-result-handling-implementation-plan.md +186 -0
- package/docs/design/stdio-simplification-design-candidates.md +341 -0
- package/docs/design/stdio-simplification-design-review.md +93 -0
- package/docs/design/stdio-simplification-implementation-plan.md +317 -0
- package/docs/design/structured-output-tools-coexist-findings.md +288 -0
- package/docs/discovery/coordinator-script-design.md +745 -0
- package/docs/discovery/coordinator-ux-discovery.md +471 -0
- package/docs/discovery/spawn-agent-failure-modes.md +309 -0
- package/docs/discovery/workflow-selection-for-discovery-tasks.md +336 -0
- package/docs/discovery/worktrain-status-briefing.md +325 -0
- package/docs/discovery/worktrain-status-design-candidates.md +202 -0
- package/docs/discovery/worktrain-status-design-review-findings.md +86 -0
- package/docs/ideas/backlog.md +608 -0
- package/docs/ideas/daemon-structured-output-vs-tool-calls.md +344 -0
- package/docs/ideas/design-candidates-backlog-consolidation.md +85 -0
- package/docs/ideas/design-review-findings-backlog-consolidation.md +39 -0
- package/docs/ideas/implementation_plan_backlog_consolidation.md +117 -0
- package/docs/plans/authoring-doc-staleness-enforcement-candidates.md +251 -0
- package/docs/plans/authoring-doc-staleness-enforcement-review.md +99 -0
- package/docs/plans/authoring-doc-staleness-enforcement.md +463 -0
- package/package.json +1 -1
package/dist/manifest.json
CHANGED
|
@@ -430,8 +430,8 @@
|
|
|
430
430
|
"bytes": 506
|
|
431
431
|
},
|
|
432
432
|
"config/config-file.js": {
|
|
433
|
-
"sha256": "
|
|
434
|
-
"bytes":
|
|
433
|
+
"sha256": "22006b77ef2c6094c86b97007371b96fbd8792accec652c49bdcccaa40ad327f",
|
|
434
|
+
"bytes": 7277
|
|
435
435
|
},
|
|
436
436
|
"config/feature-flags.d.ts": {
|
|
437
437
|
"sha256": "49cdf81a9c4f31eca560af5257c569143d2138ec996468b949f9807b7ad7802e",
|
|
@@ -445,12 +445,12 @@
|
|
|
445
445
|
"sha256": "cf9d09641f1c31fffe6c7835b30bbbad52572befec1acab7fb9a0c188431af36",
|
|
446
446
|
"bytes": 60355
|
|
447
447
|
},
|
|
448
|
-
"console-ui/assets/index-
|
|
449
|
-
"sha256": "
|
|
448
|
+
"console-ui/assets/index-t8Wi304z.js": {
|
|
449
|
+
"sha256": "d0e010095f9ab0dc8e88d61cd9b8cec4bee7537433854e0f192e73ad4cf2bd5a",
|
|
450
450
|
"bytes": 754955
|
|
451
451
|
},
|
|
452
452
|
"console-ui/index.html": {
|
|
453
|
-
"sha256": "
|
|
453
|
+
"sha256": "e4bd9c7cdc0070c4706e010726ad02d0d26d867e34132e543c2a149211dfd848",
|
|
454
454
|
"bytes": 417
|
|
455
455
|
},
|
|
456
456
|
"console/standalone-console.d.ts": {
|
|
@@ -502,12 +502,12 @@
|
|
|
502
502
|
"bytes": 1009
|
|
503
503
|
},
|
|
504
504
|
"daemon/workflow-runner.d.ts": {
|
|
505
|
-
"sha256": "
|
|
506
|
-
"bytes":
|
|
505
|
+
"sha256": "d62587e9c7da974ff986d2d9cb67f0b30f7f3cb98a469cf98daf1d6fd16fa897",
|
|
506
|
+
"bytes": 4593
|
|
507
507
|
},
|
|
508
508
|
"daemon/workflow-runner.js": {
|
|
509
|
-
"sha256": "
|
|
510
|
-
"bytes":
|
|
509
|
+
"sha256": "e3784aa04ead526de3ac9103d40967b32e3095ae3021ac13237034290be4ba4c",
|
|
510
|
+
"bytes": 63597
|
|
511
511
|
},
|
|
512
512
|
"di/container.d.ts": {
|
|
513
513
|
"sha256": "003bb7fb7478d627524b9b1e76bd0a963a243794a687ff233b96dc0e33a06d9f",
|
|
@@ -690,8 +690,8 @@
|
|
|
690
690
|
"bytes": 2524
|
|
691
691
|
},
|
|
692
692
|
"infrastructure/session/SessionManager.js": {
|
|
693
|
-
"sha256": "
|
|
694
|
-
"bytes":
|
|
693
|
+
"sha256": "b39366c0be96268e6dfeb6d081d68b3b284fea2e709accc9f2c799fb95b5cda8",
|
|
694
|
+
"bytes": 21438
|
|
695
695
|
},
|
|
696
696
|
"infrastructure/session/index.d.ts": {
|
|
697
697
|
"sha256": "52957847da70fcece6a553334bd899efd8ede55cc31f3aa5eb5e3d4bb70e3862",
|
|
@@ -1557,6 +1557,14 @@
|
|
|
1557
1557
|
"sha256": "b8668c607788d560b38cf203750395e84eaa3164fff5711cac8f87f469714592",
|
|
1558
1558
|
"bytes": 1222
|
|
1559
1559
|
},
|
|
1560
|
+
"trigger/notification-service.d.ts": {
|
|
1561
|
+
"sha256": "c78406d3748953548f7879df8ac60cecd5e42f2f3b283f777343168ce2470b8d",
|
|
1562
|
+
"bytes": 1572
|
|
1563
|
+
},
|
|
1564
|
+
"trigger/notification-service.js": {
|
|
1565
|
+
"sha256": "693f617adc30b3a4fcebeca6a78b0da1c58819001660c017a4d0901652d675b8",
|
|
1566
|
+
"bytes": 6373
|
|
1567
|
+
},
|
|
1560
1568
|
"trigger/polled-event-store.d.ts": {
|
|
1561
1569
|
"sha256": "2952a25804177b2389d4273bfc41192477d100bc26100683861dedf28520dec1",
|
|
1562
1570
|
"bytes": 1011
|
|
@@ -1578,16 +1586,16 @@
|
|
|
1578
1586
|
"bytes": 1529
|
|
1579
1587
|
},
|
|
1580
1588
|
"trigger/trigger-listener.js": {
|
|
1581
|
-
"sha256": "
|
|
1582
|
-
"bytes":
|
|
1589
|
+
"sha256": "23f1eed165ae7ec03b2c46ff6d6fdf46f631319d5d58d3a993f710d2732e41f1",
|
|
1590
|
+
"bytes": 10585
|
|
1583
1591
|
},
|
|
1584
1592
|
"trigger/trigger-router.d.ts": {
|
|
1585
|
-
"sha256": "
|
|
1586
|
-
"bytes":
|
|
1593
|
+
"sha256": "5293a744ac4763380716ec7c0b31f16531b9a666d08a3524c6c7993486a728b6",
|
|
1594
|
+
"bytes": 2010
|
|
1587
1595
|
},
|
|
1588
1596
|
"trigger/trigger-router.js": {
|
|
1589
|
-
"sha256": "
|
|
1590
|
-
"bytes":
|
|
1597
|
+
"sha256": "e7b620d2b23a5e74f6fd3b5a39a5299d19d38f745401c545277c399336ef5eaf",
|
|
1598
|
+
"bytes": 15565
|
|
1591
1599
|
},
|
|
1592
1600
|
"trigger/trigger-store.d.ts": {
|
|
1593
1601
|
"sha256": "7afb05127d55bc3757a550dd15d4b797766b3fff29d1bfe76b303764b93322e7",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { WorkflowRunResult } from '../daemon/workflow-runner.js';
|
|
2
|
+
export type ExecFileNotifyFn = (file: string, args: readonly string[], options: {
|
|
3
|
+
timeout: number;
|
|
4
|
+
}, callback: (error: Error | null) => void) => void;
|
|
5
|
+
export type FetchNotifyFn = (url: string, init: {
|
|
6
|
+
method: string;
|
|
7
|
+
headers: Record<string, string>;
|
|
8
|
+
body: string;
|
|
9
|
+
signal: AbortSignal;
|
|
10
|
+
}) => Promise<{
|
|
11
|
+
ok: boolean;
|
|
12
|
+
status: number;
|
|
13
|
+
}>;
|
|
14
|
+
export interface NotificationConfig {
|
|
15
|
+
readonly macOs: boolean;
|
|
16
|
+
readonly webhookUrl?: string;
|
|
17
|
+
readonly execFileFn?: ExecFileNotifyFn;
|
|
18
|
+
readonly fetchFn?: FetchNotifyFn;
|
|
19
|
+
readonly platformFn?: () => NodeJS.Platform;
|
|
20
|
+
}
|
|
21
|
+
export interface NotificationPayload {
|
|
22
|
+
readonly event: 'session_completed';
|
|
23
|
+
readonly workflowId: string;
|
|
24
|
+
readonly outcome: 'success' | 'error' | 'timeout' | 'delivery_failed';
|
|
25
|
+
readonly detail: string;
|
|
26
|
+
readonly goal: string;
|
|
27
|
+
readonly timestamp: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function buildNotificationBody(result: WorkflowRunResult, goal: string): string;
|
|
30
|
+
export declare function buildOutcome(result: WorkflowRunResult): NotificationPayload['outcome'];
|
|
31
|
+
export declare function buildDetail(result: WorkflowRunResult): string;
|
|
32
|
+
export declare class NotificationService {
|
|
33
|
+
private readonly _macOsEnabled;
|
|
34
|
+
private readonly _webhookUrl;
|
|
35
|
+
private readonly _execFileFn;
|
|
36
|
+
private readonly _fetchFn;
|
|
37
|
+
constructor(config: NotificationConfig);
|
|
38
|
+
notify(result: WorkflowRunResult, goal: string): void;
|
|
39
|
+
private _doNotify;
|
|
40
|
+
private _notifyMacOs;
|
|
41
|
+
private _notifyWebhook;
|
|
42
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.NotificationService = void 0;
|
|
37
|
+
exports.buildNotificationBody = buildNotificationBody;
|
|
38
|
+
exports.buildOutcome = buildOutcome;
|
|
39
|
+
exports.buildDetail = buildDetail;
|
|
40
|
+
const childProcess = __importStar(require("node:child_process"));
|
|
41
|
+
const os = __importStar(require("node:os"));
|
|
42
|
+
function buildNotificationBody(result, goal) {
|
|
43
|
+
const truncated = goal.length > 60 ? `${goal.slice(0, 57)}...` : goal;
|
|
44
|
+
switch (result._tag) {
|
|
45
|
+
case 'success':
|
|
46
|
+
return `Session completed: ${truncated}`;
|
|
47
|
+
case 'error':
|
|
48
|
+
return `Session failed: ${truncated}`;
|
|
49
|
+
case 'timeout':
|
|
50
|
+
return `Session timed out: ${truncated}`;
|
|
51
|
+
case 'delivery_failed':
|
|
52
|
+
return `Session completed but result delivery failed: ${truncated}`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function buildOutcome(result) {
|
|
56
|
+
return result._tag;
|
|
57
|
+
}
|
|
58
|
+
function buildDetail(result) {
|
|
59
|
+
switch (result._tag) {
|
|
60
|
+
case 'success':
|
|
61
|
+
return `stopReason: ${result.stopReason}`;
|
|
62
|
+
case 'error':
|
|
63
|
+
return result.message;
|
|
64
|
+
case 'timeout':
|
|
65
|
+
return result.message;
|
|
66
|
+
case 'delivery_failed':
|
|
67
|
+
return `stopReason: ${result.stopReason}; deliveryError: ${result.deliveryError}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
class NotificationService {
|
|
71
|
+
constructor(config) {
|
|
72
|
+
const getPlatform = config.platformFn ?? os.platform.bind(os);
|
|
73
|
+
if (config.macOs && getPlatform() !== 'darwin') {
|
|
74
|
+
console.warn('[NotificationService] WORKTRAIN_NOTIFY_MACOS=true but platform is not darwin ' +
|
|
75
|
+
`(platform: ${getPlatform()}). macOS notifications are disabled.`);
|
|
76
|
+
this._macOsEnabled = false;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this._macOsEnabled = config.macOs;
|
|
80
|
+
}
|
|
81
|
+
if (config.webhookUrl !== undefined && config.webhookUrl !== '') {
|
|
82
|
+
let valid = false;
|
|
83
|
+
try {
|
|
84
|
+
const parsed = new URL(config.webhookUrl);
|
|
85
|
+
valid = parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
valid = false;
|
|
89
|
+
}
|
|
90
|
+
if (!valid) {
|
|
91
|
+
console.warn(`[NotificationService] WORKTRAIN_NOTIFY_WEBHOOK is not a valid http(s) URL ` +
|
|
92
|
+
`("${config.webhookUrl}"). Webhook notifications are disabled.`);
|
|
93
|
+
this._webhookUrl = undefined;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this._webhookUrl = config.webhookUrl;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this._webhookUrl = undefined;
|
|
101
|
+
}
|
|
102
|
+
this._execFileFn = config.execFileFn ?? ((file, args, options, callback) => {
|
|
103
|
+
childProcess.execFile(file, args, options, callback);
|
|
104
|
+
});
|
|
105
|
+
this._fetchFn = config.fetchFn ?? ((url, init) => globalThis.fetch(url, init));
|
|
106
|
+
}
|
|
107
|
+
notify(result, goal) {
|
|
108
|
+
void this._doNotify(result, goal).catch(() => {
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async _doNotify(result, goal) {
|
|
112
|
+
const body = buildNotificationBody(result, goal);
|
|
113
|
+
const deliveries = [];
|
|
114
|
+
if (this._macOsEnabled) {
|
|
115
|
+
deliveries.push(this._notifyMacOs(body, result.workflowId));
|
|
116
|
+
}
|
|
117
|
+
if (this._webhookUrl !== undefined) {
|
|
118
|
+
deliveries.push(this._notifyWebhook(result, goal));
|
|
119
|
+
}
|
|
120
|
+
await Promise.allSettled(deliveries);
|
|
121
|
+
}
|
|
122
|
+
_notifyMacOs(body, workflowId) {
|
|
123
|
+
const script = `display notification ${JSON.stringify(body)} with title "WorkTrain" subtitle ${JSON.stringify(workflowId)}`;
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
this._execFileFn('osascript', ['-e', script], { timeout: 5000 }, (error) => {
|
|
126
|
+
if (error) {
|
|
127
|
+
console.warn(`[NotificationService] macOS notification failed: ${error.message}`);
|
|
128
|
+
}
|
|
129
|
+
resolve();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async _notifyWebhook(result, goal) {
|
|
134
|
+
const url = this._webhookUrl;
|
|
135
|
+
const payload = {
|
|
136
|
+
event: 'session_completed',
|
|
137
|
+
workflowId: result.workflowId,
|
|
138
|
+
outcome: buildOutcome(result),
|
|
139
|
+
detail: buildDetail(result),
|
|
140
|
+
goal,
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
};
|
|
143
|
+
const controller = new AbortController();
|
|
144
|
+
const timer = setTimeout(() => controller.abort(), 30000);
|
|
145
|
+
try {
|
|
146
|
+
const res = await this._fetchFn(url, {
|
|
147
|
+
method: 'POST',
|
|
148
|
+
headers: { 'Content-Type': 'application/json' },
|
|
149
|
+
body: JSON.stringify(payload),
|
|
150
|
+
signal: controller.signal,
|
|
151
|
+
});
|
|
152
|
+
if (!res.ok) {
|
|
153
|
+
console.warn(`[NotificationService] Webhook notification failed: HTTP ${res.status} from ${url}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
console.warn(`[NotificationService] Webhook notification error: ${String(e)}`);
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.NotificationService = NotificationService;
|
|
@@ -44,6 +44,7 @@ const http = __importStar(require("node:http"));
|
|
|
44
44
|
const trigger_store_js_1 = require("./trigger-store.js");
|
|
45
45
|
const trigger_router_js_1 = require("./trigger-router.js");
|
|
46
46
|
const config_file_js_1 = require("../config/config-file.js");
|
|
47
|
+
const notification_service_js_1 = require("./notification-service.js");
|
|
47
48
|
const workflow_runner_js_1 = require("../daemon/workflow-runner.js");
|
|
48
49
|
const types_js_1 = require("./types.js");
|
|
49
50
|
const polling_scheduler_js_1 = require("./polling-scheduler.js");
|
|
@@ -177,8 +178,13 @@ async function startTriggerListener(ctx, options) {
|
|
|
177
178
|
: undefined;
|
|
178
179
|
const parsed = parseInt(maxConcurrencyRaw ?? '', 10);
|
|
179
180
|
const maxConcurrentSessions = !isNaN(parsed) ? parsed : undefined;
|
|
181
|
+
const notifyMacOs = (workrailConfig.kind === 'ok' && workrailConfig.value['WORKTRAIN_NOTIFY_MACOS'] === 'true');
|
|
182
|
+
const notifyWebhook = workrailConfig.kind === 'ok' ? workrailConfig.value['WORKTRAIN_NOTIFY_WEBHOOK'] : undefined;
|
|
183
|
+
const notificationService = (notifyMacOs || (notifyWebhook !== undefined && notifyWebhook !== ''))
|
|
184
|
+
? new notification_service_js_1.NotificationService({ macOs: notifyMacOs, webhookUrl: notifyWebhook })
|
|
185
|
+
: undefined;
|
|
180
186
|
const runWorkflowFn = options.runWorkflowFn ?? workflow_runner_js_1.runWorkflow;
|
|
181
|
-
const router = new trigger_router_js_1.TriggerRouter(triggerIndex, ctx, apiKey, runWorkflowFn, undefined, maxConcurrentSessions, options.emitter);
|
|
187
|
+
const router = new trigger_router_js_1.TriggerRouter(triggerIndex, ctx, apiKey, runWorkflowFn, undefined, maxConcurrentSessions, options.emitter, notificationService);
|
|
182
188
|
const app = createTriggerApp(router);
|
|
183
189
|
const allTriggers = [...triggerIndex.values()];
|
|
184
190
|
const polledEventStore = new polled_event_store_js_1.PolledEventStore(env);
|
|
@@ -3,6 +3,7 @@ import type { V2ToolContext } from '../mcp/types.js';
|
|
|
3
3
|
import type { TriggerDefinition, WebhookEvent } from './types.js';
|
|
4
4
|
import type { ExecFn } from './delivery-action.js';
|
|
5
5
|
import type { DaemonEventEmitter } from '../daemon/daemon-events.js';
|
|
6
|
+
import type { NotificationService } from './notification-service.js';
|
|
6
7
|
export type RouteError = {
|
|
7
8
|
readonly kind: 'not_found';
|
|
8
9
|
readonly triggerId: string;
|
|
@@ -31,7 +32,8 @@ export declare class TriggerRouter {
|
|
|
31
32
|
private readonly semaphore;
|
|
32
33
|
private readonly _maxConcurrentSessions;
|
|
33
34
|
private readonly emitter;
|
|
34
|
-
|
|
35
|
+
private readonly notificationService;
|
|
36
|
+
constructor(index: ReadonlyMap<string, TriggerDefinition>, ctx: V2ToolContext, apiKey: string, runWorkflowFn: RunWorkflowFn, execFn?: ExecFn, maxConcurrentSessions?: number, emitter?: DaemonEventEmitter, notificationService?: NotificationService);
|
|
35
37
|
get activeSessions(): number;
|
|
36
38
|
get maxConcurrentSessions(): number;
|
|
37
39
|
route(event: WebhookEvent): RouteResult;
|
|
@@ -182,7 +182,7 @@ class Semaphore {
|
|
|
182
182
|
}
|
|
183
183
|
const DEFAULT_MAX_CONCURRENT_SESSIONS = 3;
|
|
184
184
|
class TriggerRouter {
|
|
185
|
-
constructor(index, ctx, apiKey, runWorkflowFn, execFn, maxConcurrentSessions, emitter) {
|
|
185
|
+
constructor(index, ctx, apiKey, runWorkflowFn, execFn, maxConcurrentSessions, emitter, notificationService) {
|
|
186
186
|
this.index = index;
|
|
187
187
|
this.ctx = ctx;
|
|
188
188
|
this.apiKey = apiKey;
|
|
@@ -190,6 +190,7 @@ class TriggerRouter {
|
|
|
190
190
|
this.queue = new index_js_1.KeyedAsyncQueue();
|
|
191
191
|
this.execFn = execFn ?? execFileAsync;
|
|
192
192
|
this.emitter = emitter;
|
|
193
|
+
this.notificationService = notificationService;
|
|
193
194
|
const requested = maxConcurrentSessions ?? DEFAULT_MAX_CONCURRENT_SESSIONS;
|
|
194
195
|
const cap = Number.isNaN(requested) ? DEFAULT_MAX_CONCURRENT_SESSIONS : requested;
|
|
195
196
|
if (cap < 1) {
|
|
@@ -301,6 +302,7 @@ class TriggerRouter {
|
|
|
301
302
|
console.log(`[TriggerRouter] Workflow failed: triggerId=${trigger.id} ` +
|
|
302
303
|
`workflowId=${trigger.workflowId} error=${result.message} stopReason=${result.stopReason}`);
|
|
303
304
|
}
|
|
305
|
+
this.notificationService?.notify(result, workflowTrigger.goal);
|
|
304
306
|
await maybeRunDelivery(trigger.id, trigger, originalResult, this.execFn);
|
|
305
307
|
});
|
|
306
308
|
return { _tag: 'enqueued', triggerId: trigger.id };
|
|
@@ -336,6 +338,7 @@ class TriggerRouter {
|
|
|
336
338
|
console.log(`[TriggerRouter] Dispatch failed: workflowId=${workflowTrigger.workflowId} ` +
|
|
337
339
|
`error=${result.message} stopReason=${result.stopReason}`);
|
|
338
340
|
}
|
|
341
|
+
this.notificationService?.notify(result, workflowTrigger.goal);
|
|
339
342
|
});
|
|
340
343
|
return workflowTrigger.workflowId;
|
|
341
344
|
}
|