@dexto/orchestration 1.5.8
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/LICENSE +44 -0
- package/dist/agent-controller.cjs +265 -0
- package/dist/agent-controller.d.cts +116 -0
- package/dist/agent-controller.d.ts +116 -0
- package/dist/agent-controller.js +241 -0
- package/dist/condition-engine.cjs +276 -0
- package/dist/condition-engine.d.cts +87 -0
- package/dist/condition-engine.d.ts +87 -0
- package/dist/condition-engine.js +252 -0
- package/dist/index.cjs +57 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +32 -0
- package/dist/signal-bus.cjs +186 -0
- package/dist/signal-bus.d.cts +78 -0
- package/dist/signal-bus.d.ts +78 -0
- package/dist/signal-bus.js +162 -0
- package/dist/task-registry.cjs +345 -0
- package/dist/task-registry.d.cts +124 -0
- package/dist/task-registry.d.ts +124 -0
- package/dist/task-registry.js +321 -0
- package/dist/tools/check-task.cjs +65 -0
- package/dist/tools/check-task.d.cts +56 -0
- package/dist/tools/check-task.d.ts +56 -0
- package/dist/tools/check-task.js +40 -0
- package/dist/tools/index.cjs +51 -0
- package/dist/tools/index.d.cts +10 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +19 -0
- package/dist/tools/list-tasks.cjs +80 -0
- package/dist/tools/list-tasks.d.cts +64 -0
- package/dist/tools/list-tasks.d.ts +64 -0
- package/dist/tools/list-tasks.js +55 -0
- package/dist/tools/start-task.cjs +149 -0
- package/dist/tools/start-task.d.cts +102 -0
- package/dist/tools/start-task.d.ts +102 -0
- package/dist/tools/start-task.js +123 -0
- package/dist/tools/types.cjs +16 -0
- package/dist/tools/types.d.cts +30 -0
- package/dist/tools/types.d.ts +30 -0
- package/dist/tools/types.js +0 -0
- package/dist/tools/wait-for.cjs +116 -0
- package/dist/tools/wait-for.d.cts +74 -0
- package/dist/tools/wait-for.d.ts +74 -0
- package/dist/tools/wait-for.js +91 -0
- package/dist/types.cjs +16 -0
- package/dist/types.d.cts +165 -0
- package/dist/types.d.ts +165 -0
- package/dist/types.js +0 -0
- package/package.json +38 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
class ConditionEngine {
|
|
3
|
+
constructor(taskRegistry, signalBus, logger) {
|
|
4
|
+
this.taskRegistry = taskRegistry;
|
|
5
|
+
this.signalBus = signalBus;
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wait for a condition to be met
|
|
10
|
+
* @param condition Wait condition to evaluate
|
|
11
|
+
* @returns Promise resolving to the signal(s) that satisfied the condition
|
|
12
|
+
*/
|
|
13
|
+
async wait(condition) {
|
|
14
|
+
const immediate = this.check(condition);
|
|
15
|
+
if (immediate) {
|
|
16
|
+
return immediate;
|
|
17
|
+
}
|
|
18
|
+
return this.evaluate(condition);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if a condition is already satisfied (non-blocking)
|
|
22
|
+
* @returns WaitResult if satisfied, null if not
|
|
23
|
+
*/
|
|
24
|
+
check(condition) {
|
|
25
|
+
switch (condition.type) {
|
|
26
|
+
case "task":
|
|
27
|
+
return this.checkTask(condition.taskId);
|
|
28
|
+
case "any":
|
|
29
|
+
return this.checkAny(condition.conditions);
|
|
30
|
+
case "all":
|
|
31
|
+
return this.checkAll(condition.conditions);
|
|
32
|
+
case "timeout":
|
|
33
|
+
return null;
|
|
34
|
+
case "race":
|
|
35
|
+
return this.check(condition.task);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a single task is completed
|
|
40
|
+
*/
|
|
41
|
+
checkTask(taskId) {
|
|
42
|
+
const result = this.taskRegistry.getResult(taskId);
|
|
43
|
+
if (!result) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (result.status === "completed") {
|
|
47
|
+
return {
|
|
48
|
+
signal: {
|
|
49
|
+
type: "task:completed",
|
|
50
|
+
taskId,
|
|
51
|
+
result: result.result
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (result.status === "failed") {
|
|
56
|
+
return {
|
|
57
|
+
signal: {
|
|
58
|
+
type: "task:failed",
|
|
59
|
+
taskId,
|
|
60
|
+
error: result.error ?? "Unknown error"
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (result.status === "cancelled") {
|
|
65
|
+
return {
|
|
66
|
+
signal: {
|
|
67
|
+
type: "task:cancelled",
|
|
68
|
+
taskId
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if any of the conditions is satisfied
|
|
76
|
+
*/
|
|
77
|
+
checkAny(conditions) {
|
|
78
|
+
for (const condition of conditions) {
|
|
79
|
+
const result = this.check(condition);
|
|
80
|
+
if (result) {
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if all conditions are satisfied
|
|
88
|
+
*/
|
|
89
|
+
checkAll(conditions) {
|
|
90
|
+
const signals = [];
|
|
91
|
+
for (const condition of conditions) {
|
|
92
|
+
const result = this.check(condition);
|
|
93
|
+
if (!result) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
signals.push(result.signal);
|
|
97
|
+
}
|
|
98
|
+
const primarySignal = signals[0];
|
|
99
|
+
if (!primarySignal) {
|
|
100
|
+
throw new Error("Internal error: no signals in checkAll result");
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
signal: primarySignal,
|
|
104
|
+
allSignals: signals
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Evaluate a condition asynchronously
|
|
109
|
+
*/
|
|
110
|
+
async evaluate(condition) {
|
|
111
|
+
switch (condition.type) {
|
|
112
|
+
case "task":
|
|
113
|
+
return this.evaluateTask(condition.taskId);
|
|
114
|
+
case "any":
|
|
115
|
+
return this.evaluateAny(condition.conditions);
|
|
116
|
+
case "all":
|
|
117
|
+
return this.evaluateAll(condition.conditions);
|
|
118
|
+
case "timeout":
|
|
119
|
+
return this.evaluateTimeout(condition.ms, condition.conditionId);
|
|
120
|
+
case "race":
|
|
121
|
+
return this.evaluateRace(condition.task, condition.timeout);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Wait for a single task to complete
|
|
126
|
+
*
|
|
127
|
+
* Uses subscribe-then-check pattern to avoid race conditions where
|
|
128
|
+
* the task completes between checking and subscribing.
|
|
129
|
+
*/
|
|
130
|
+
async evaluateTask(taskId) {
|
|
131
|
+
this.logger?.debug(`[ConditionEngine] evaluateTask called for taskId=${taskId}`);
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
let unsubscribe;
|
|
134
|
+
const handler = (signal) => {
|
|
135
|
+
this.logger?.debug(
|
|
136
|
+
`[ConditionEngine] Received signal: type=${signal.type}, taskId=${"taskId" in signal ? signal.taskId : "N/A"}`
|
|
137
|
+
);
|
|
138
|
+
if ((signal.type === "task:completed" || signal.type === "task:failed" || signal.type === "task:cancelled") && signal.taskId === taskId) {
|
|
139
|
+
this.logger?.debug(
|
|
140
|
+
`[ConditionEngine] Signal matches taskId=${taskId}, resolving`
|
|
141
|
+
);
|
|
142
|
+
if (unsubscribe) {
|
|
143
|
+
unsubscribe();
|
|
144
|
+
}
|
|
145
|
+
resolve({ signal });
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
unsubscribe = this.signalBus.onAny(handler);
|
|
149
|
+
this.logger?.debug(`[ConditionEngine] Subscribed to signals for taskId=${taskId}`);
|
|
150
|
+
const immediate = this.checkTask(taskId);
|
|
151
|
+
this.logger?.debug(
|
|
152
|
+
`[ConditionEngine] checkTask(${taskId}) returned: ${immediate ? "found" : "null"}`
|
|
153
|
+
);
|
|
154
|
+
if (immediate) {
|
|
155
|
+
unsubscribe();
|
|
156
|
+
resolve(immediate);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Wait for any of the conditions to be satisfied
|
|
162
|
+
*/
|
|
163
|
+
async evaluateAny(conditions) {
|
|
164
|
+
const immediate = this.checkAny(conditions);
|
|
165
|
+
if (immediate) {
|
|
166
|
+
return immediate;
|
|
167
|
+
}
|
|
168
|
+
const promises = conditions.map((c) => this.evaluate(c));
|
|
169
|
+
const result = await Promise.race(promises);
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Wait for all conditions to be satisfied
|
|
174
|
+
*/
|
|
175
|
+
async evaluateAll(conditions) {
|
|
176
|
+
const immediate = this.checkAll(conditions);
|
|
177
|
+
if (immediate) {
|
|
178
|
+
return immediate;
|
|
179
|
+
}
|
|
180
|
+
const results = await Promise.all(conditions.map((c) => this.evaluate(c)));
|
|
181
|
+
const signals = results.map((r) => r.signal);
|
|
182
|
+
const primarySignal = signals[0];
|
|
183
|
+
if (!primarySignal) {
|
|
184
|
+
throw new Error("Internal error: no signals in evaluateAll result");
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
signal: primarySignal,
|
|
188
|
+
allSignals: signals
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Wait for a timeout
|
|
193
|
+
*/
|
|
194
|
+
async evaluateTimeout(ms, conditionId) {
|
|
195
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
196
|
+
const signal = {
|
|
197
|
+
type: "timeout",
|
|
198
|
+
conditionId
|
|
199
|
+
};
|
|
200
|
+
this.signalBus.emit(signal);
|
|
201
|
+
return { signal };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Race a task condition against a timeout
|
|
205
|
+
*/
|
|
206
|
+
async evaluateRace(taskCondition, timeoutCondition) {
|
|
207
|
+
const immediate = this.check(taskCondition);
|
|
208
|
+
if (immediate) {
|
|
209
|
+
return immediate;
|
|
210
|
+
}
|
|
211
|
+
const result = await Promise.race([
|
|
212
|
+
this.evaluate(taskCondition),
|
|
213
|
+
this.evaluate(timeoutCondition)
|
|
214
|
+
]);
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Helper to create a race condition with timeout
|
|
219
|
+
*/
|
|
220
|
+
static createRaceWithTimeout(taskId, timeoutMs) {
|
|
221
|
+
return {
|
|
222
|
+
type: "race",
|
|
223
|
+
task: { type: "task", taskId },
|
|
224
|
+
timeout: {
|
|
225
|
+
type: "timeout",
|
|
226
|
+
ms: timeoutMs,
|
|
227
|
+
conditionId: `timeout-${randomUUID().slice(0, 8)}`
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Helper to create an 'any' condition from task IDs
|
|
233
|
+
*/
|
|
234
|
+
static createAnyTask(taskIds) {
|
|
235
|
+
return {
|
|
236
|
+
type: "any",
|
|
237
|
+
conditions: taskIds.map((taskId) => ({ type: "task", taskId }))
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Helper to create an 'all' condition from task IDs
|
|
242
|
+
*/
|
|
243
|
+
static createAllTasks(taskIds) {
|
|
244
|
+
return {
|
|
245
|
+
type: "all",
|
|
246
|
+
conditions: taskIds.map((taskId) => ({ type: "task", taskId }))
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export {
|
|
251
|
+
ConditionEngine
|
|
252
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
21
|
+
AgentController: () => import_agent_controller.AgentController,
|
|
22
|
+
CheckTaskInputSchema: () => import_tools2.CheckTaskInputSchema,
|
|
23
|
+
ConditionEngine: () => import_condition_engine.ConditionEngine,
|
|
24
|
+
ListTasksInputSchema: () => import_tools2.ListTasksInputSchema,
|
|
25
|
+
SignalBus: () => import_signal_bus.SignalBus,
|
|
26
|
+
StartTaskInputSchema: () => import_tools2.StartTaskInputSchema,
|
|
27
|
+
TaskRegistry: () => import_task_registry.TaskRegistry,
|
|
28
|
+
WaitForInputSchema: () => import_tools2.WaitForInputSchema,
|
|
29
|
+
createCheckTaskTool: () => import_tools.createCheckTaskTool,
|
|
30
|
+
createGenericTaskStarter: () => import_tools.createGenericTaskStarter,
|
|
31
|
+
createListTasksTool: () => import_tools.createListTasksTool,
|
|
32
|
+
createStartTaskTool: () => import_tools.createStartTaskTool,
|
|
33
|
+
createWaitForTool: () => import_tools.createWaitForTool
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var import_agent_controller = require("./agent-controller.js");
|
|
37
|
+
var import_signal_bus = require("./signal-bus.js");
|
|
38
|
+
var import_task_registry = require("./task-registry.js");
|
|
39
|
+
var import_condition_engine = require("./condition-engine.js");
|
|
40
|
+
var import_tools = require("./tools/index.js");
|
|
41
|
+
var import_tools2 = require("./tools/index.js");
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
AgentController,
|
|
45
|
+
CheckTaskInputSchema,
|
|
46
|
+
ConditionEngine,
|
|
47
|
+
ListTasksInputSchema,
|
|
48
|
+
SignalBus,
|
|
49
|
+
StartTaskInputSchema,
|
|
50
|
+
TaskRegistry,
|
|
51
|
+
WaitForInputSchema,
|
|
52
|
+
createCheckTaskTool,
|
|
53
|
+
createGenericTaskStarter,
|
|
54
|
+
createListTasksTool,
|
|
55
|
+
createStartTaskTool,
|
|
56
|
+
createWaitForTool
|
|
57
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { AgentController, AgentControllerConfig } from './agent-controller.cjs';
|
|
2
|
+
export { SignalBus, SignalHandler, SignalPredicate } from './signal-bus.cjs';
|
|
3
|
+
export { TaskRegistry, TaskRegistryConfig } from './task-registry.cjs';
|
|
4
|
+
export { ConditionEngine } from './condition-engine.cjs';
|
|
5
|
+
export { AgentState, ProcessResult, RegisterTaskOptions, Signal, SignalType, Task, TaskEntry, TaskFilter, TaskInfo, TaskResult, TaskStatus, WaitCondition, WaitResult } from './types.cjs';
|
|
6
|
+
export { StartTaskInput, StartTaskInputSchema, StartTaskOutput, TaskStarter, createGenericTaskStarter, createStartTaskTool } from './tools/start-task.cjs';
|
|
7
|
+
export { WaitForInput, WaitForInputSchema, WaitForOutput, createWaitForTool } from './tools/wait-for.cjs';
|
|
8
|
+
export { CheckTaskInput, CheckTaskInputSchema, CheckTaskOutput, createCheckTaskTool } from './tools/check-task.cjs';
|
|
9
|
+
export { ListTasksInput, ListTasksInputSchema, ListTasksOutput, TaskListItem, createListTasksTool } from './tools/list-tasks.cjs';
|
|
10
|
+
export { OrchestrationTool, OrchestrationToolContext } from './tools/types.cjs';
|
|
11
|
+
import 'zod';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { AgentController, AgentControllerConfig } from './agent-controller.js';
|
|
2
|
+
export { SignalBus, SignalHandler, SignalPredicate } from './signal-bus.js';
|
|
3
|
+
export { TaskRegistry, TaskRegistryConfig } from './task-registry.js';
|
|
4
|
+
export { ConditionEngine } from './condition-engine.js';
|
|
5
|
+
export { AgentState, ProcessResult, RegisterTaskOptions, Signal, SignalType, Task, TaskEntry, TaskFilter, TaskInfo, TaskResult, TaskStatus, WaitCondition, WaitResult } from './types.js';
|
|
6
|
+
export { StartTaskInput, StartTaskInputSchema, StartTaskOutput, TaskStarter, createGenericTaskStarter, createStartTaskTool } from './tools/start-task.js';
|
|
7
|
+
export { WaitForInput, WaitForInputSchema, WaitForOutput, createWaitForTool } from './tools/wait-for.js';
|
|
8
|
+
export { CheckTaskInput, CheckTaskInputSchema, CheckTaskOutput, createCheckTaskTool } from './tools/check-task.js';
|
|
9
|
+
export { ListTasksInput, ListTasksInputSchema, ListTasksOutput, TaskListItem, createListTasksTool } from './tools/list-tasks.js';
|
|
10
|
+
export { OrchestrationTool, OrchestrationToolContext } from './tools/types.js';
|
|
11
|
+
import 'zod';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AgentController } from "./agent-controller.js";
|
|
2
|
+
import { SignalBus } from "./signal-bus.js";
|
|
3
|
+
import { TaskRegistry } from "./task-registry.js";
|
|
4
|
+
import { ConditionEngine } from "./condition-engine.js";
|
|
5
|
+
import {
|
|
6
|
+
createStartTaskTool,
|
|
7
|
+
createWaitForTool,
|
|
8
|
+
createCheckTaskTool,
|
|
9
|
+
createListTasksTool,
|
|
10
|
+
createGenericTaskStarter
|
|
11
|
+
} from "./tools/index.js";
|
|
12
|
+
import {
|
|
13
|
+
StartTaskInputSchema,
|
|
14
|
+
WaitForInputSchema,
|
|
15
|
+
CheckTaskInputSchema,
|
|
16
|
+
ListTasksInputSchema
|
|
17
|
+
} from "./tools/index.js";
|
|
18
|
+
export {
|
|
19
|
+
AgentController,
|
|
20
|
+
CheckTaskInputSchema,
|
|
21
|
+
ConditionEngine,
|
|
22
|
+
ListTasksInputSchema,
|
|
23
|
+
SignalBus,
|
|
24
|
+
StartTaskInputSchema,
|
|
25
|
+
TaskRegistry,
|
|
26
|
+
WaitForInputSchema,
|
|
27
|
+
createCheckTaskTool,
|
|
28
|
+
createGenericTaskStarter,
|
|
29
|
+
createListTasksTool,
|
|
30
|
+
createStartTaskTool,
|
|
31
|
+
createWaitForTool
|
|
32
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var signal_bus_exports = {};
|
|
20
|
+
__export(signal_bus_exports, {
|
|
21
|
+
SignalBus: () => SignalBus
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(signal_bus_exports);
|
|
24
|
+
var import_events = require("events");
|
|
25
|
+
class SignalBus {
|
|
26
|
+
emitter = new import_events.EventEmitter();
|
|
27
|
+
constructor() {
|
|
28
|
+
this.emitter.setMaxListeners(100);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Emit a signal to all subscribers
|
|
32
|
+
*/
|
|
33
|
+
emit(signal) {
|
|
34
|
+
this.emitter.emit(signal.type, signal);
|
|
35
|
+
this.emitter.emit("*", signal);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Subscribe to signals of a specific type
|
|
39
|
+
* @returns Unsubscribe function
|
|
40
|
+
*/
|
|
41
|
+
on(type, handler) {
|
|
42
|
+
this.emitter.on(type, handler);
|
|
43
|
+
return () => this.emitter.off(type, handler);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Subscribe to all signals
|
|
47
|
+
* @returns Unsubscribe function
|
|
48
|
+
*/
|
|
49
|
+
onAny(handler) {
|
|
50
|
+
this.emitter.on("*", handler);
|
|
51
|
+
return () => this.emitter.off("*", handler);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Subscribe to a signal type once
|
|
55
|
+
*/
|
|
56
|
+
once(type, handler) {
|
|
57
|
+
this.emitter.once(type, handler);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Remove a specific handler
|
|
61
|
+
*/
|
|
62
|
+
off(type, handler) {
|
|
63
|
+
this.emitter.off(type, handler);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Wait for a signal matching the predicate
|
|
67
|
+
* @param predicate Function to test signals
|
|
68
|
+
* @param timeout Optional timeout in milliseconds
|
|
69
|
+
* @returns Promise that resolves with the matching signal
|
|
70
|
+
*/
|
|
71
|
+
waitFor(predicate, timeout) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
let timeoutId;
|
|
74
|
+
let unsubscribe;
|
|
75
|
+
const cleanup = () => {
|
|
76
|
+
if (timeoutId) {
|
|
77
|
+
clearTimeout(timeoutId);
|
|
78
|
+
}
|
|
79
|
+
if (unsubscribe) {
|
|
80
|
+
unsubscribe();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const handler = (signal) => {
|
|
84
|
+
if (predicate(signal)) {
|
|
85
|
+
cleanup();
|
|
86
|
+
resolve(signal);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
unsubscribe = this.onAny(handler);
|
|
90
|
+
if (timeout !== void 0 && timeout > 0) {
|
|
91
|
+
timeoutId = setTimeout(() => {
|
|
92
|
+
cleanup();
|
|
93
|
+
reject(new Error(`Signal wait timed out after ${timeout}ms`));
|
|
94
|
+
}, timeout);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Wait for a signal for a specific task
|
|
100
|
+
*/
|
|
101
|
+
waitForTask(taskId, timeout) {
|
|
102
|
+
return this.waitFor(
|
|
103
|
+
(signal) => (signal.type === "task:completed" || signal.type === "task:failed" || signal.type === "task:cancelled") && signal.taskId === taskId,
|
|
104
|
+
timeout
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Wait for any of multiple tasks to complete
|
|
109
|
+
*/
|
|
110
|
+
waitForAnyTask(taskIds, timeout) {
|
|
111
|
+
if (taskIds.length === 0) {
|
|
112
|
+
return Promise.reject(new Error("taskIds must not be empty"));
|
|
113
|
+
}
|
|
114
|
+
const taskIdSet = new Set(taskIds);
|
|
115
|
+
return this.waitFor(
|
|
116
|
+
(signal) => (signal.type === "task:completed" || signal.type === "task:failed" || signal.type === "task:cancelled") && taskIdSet.has(signal.taskId),
|
|
117
|
+
timeout
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Wait for all tasks to complete
|
|
122
|
+
* @returns Promise that resolves with all signals
|
|
123
|
+
*/
|
|
124
|
+
async waitForAllTasks(taskIds, timeout, resolveInitial) {
|
|
125
|
+
if (taskIds.length === 0) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
const remaining = new Set(taskIds);
|
|
129
|
+
const signals = [];
|
|
130
|
+
if (resolveInitial) {
|
|
131
|
+
for (const taskId of taskIds) {
|
|
132
|
+
const signal = resolveInitial(taskId);
|
|
133
|
+
if (signal) {
|
|
134
|
+
remaining.delete(taskId);
|
|
135
|
+
signals.push(signal);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (remaining.size === 0) {
|
|
140
|
+
return signals;
|
|
141
|
+
}
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
let timeoutId;
|
|
144
|
+
let unsubscribe;
|
|
145
|
+
const cleanup = () => {
|
|
146
|
+
if (timeoutId) {
|
|
147
|
+
clearTimeout(timeoutId);
|
|
148
|
+
}
|
|
149
|
+
if (unsubscribe) {
|
|
150
|
+
unsubscribe();
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const handler = (signal) => {
|
|
154
|
+
if ((signal.type === "task:completed" || signal.type === "task:failed" || signal.type === "task:cancelled") && remaining.has(signal.taskId)) {
|
|
155
|
+
remaining.delete(signal.taskId);
|
|
156
|
+
signals.push(signal);
|
|
157
|
+
if (remaining.size === 0) {
|
|
158
|
+
cleanup();
|
|
159
|
+
resolve(signals);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
unsubscribe = this.onAny(handler);
|
|
164
|
+
if (timeout !== void 0 && timeout > 0) {
|
|
165
|
+
timeoutId = setTimeout(() => {
|
|
166
|
+
cleanup();
|
|
167
|
+
reject(
|
|
168
|
+
new Error(
|
|
169
|
+
`Waiting for all tasks timed out after ${timeout}ms. Remaining tasks: ${Array.from(remaining).join(", ")}`
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
}, timeout);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Remove all listeners
|
|
178
|
+
*/
|
|
179
|
+
clear() {
|
|
180
|
+
this.emitter.removeAllListeners();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
184
|
+
0 && (module.exports = {
|
|
185
|
+
SignalBus
|
|
186
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Signal, SignalType } from './types.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SignalBus
|
|
5
|
+
*
|
|
6
|
+
* Event emitter for routing orchestration signals.
|
|
7
|
+
* Supports typed subscriptions and promise-based waiting.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Handler function for signal subscriptions
|
|
12
|
+
*/
|
|
13
|
+
type SignalHandler<T extends Signal = Signal> = (signal: T) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Predicate function for filtering signals
|
|
16
|
+
*/
|
|
17
|
+
type SignalPredicate = (signal: Signal) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* SignalBus - Routes signals between orchestration components
|
|
20
|
+
*/
|
|
21
|
+
declare class SignalBus {
|
|
22
|
+
private emitter;
|
|
23
|
+
constructor();
|
|
24
|
+
/**
|
|
25
|
+
* Emit a signal to all subscribers
|
|
26
|
+
*/
|
|
27
|
+
emit(signal: Signal): void;
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to signals of a specific type
|
|
30
|
+
* @returns Unsubscribe function
|
|
31
|
+
*/
|
|
32
|
+
on<T extends SignalType>(type: T, handler: SignalHandler<Extract<Signal, {
|
|
33
|
+
type: T;
|
|
34
|
+
}>>): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Subscribe to all signals
|
|
37
|
+
* @returns Unsubscribe function
|
|
38
|
+
*/
|
|
39
|
+
onAny(handler: SignalHandler): () => void;
|
|
40
|
+
/**
|
|
41
|
+
* Subscribe to a signal type once
|
|
42
|
+
*/
|
|
43
|
+
once<T extends SignalType>(type: T, handler: SignalHandler<Extract<Signal, {
|
|
44
|
+
type: T;
|
|
45
|
+
}>>): void;
|
|
46
|
+
/**
|
|
47
|
+
* Remove a specific handler
|
|
48
|
+
*/
|
|
49
|
+
off<T extends SignalType>(type: T, handler: SignalHandler<Extract<Signal, {
|
|
50
|
+
type: T;
|
|
51
|
+
}>>): void;
|
|
52
|
+
/**
|
|
53
|
+
* Wait for a signal matching the predicate
|
|
54
|
+
* @param predicate Function to test signals
|
|
55
|
+
* @param timeout Optional timeout in milliseconds
|
|
56
|
+
* @returns Promise that resolves with the matching signal
|
|
57
|
+
*/
|
|
58
|
+
waitFor(predicate: SignalPredicate, timeout?: number): Promise<Signal>;
|
|
59
|
+
/**
|
|
60
|
+
* Wait for a signal for a specific task
|
|
61
|
+
*/
|
|
62
|
+
waitForTask(taskId: string, timeout?: number): Promise<Signal>;
|
|
63
|
+
/**
|
|
64
|
+
* Wait for any of multiple tasks to complete
|
|
65
|
+
*/
|
|
66
|
+
waitForAnyTask(taskIds: string[], timeout?: number): Promise<Signal>;
|
|
67
|
+
/**
|
|
68
|
+
* Wait for all tasks to complete
|
|
69
|
+
* @returns Promise that resolves with all signals
|
|
70
|
+
*/
|
|
71
|
+
waitForAllTasks(taskIds: string[], timeout?: number, resolveInitial?: (taskId: string) => Signal | undefined): Promise<Signal[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Remove all listeners
|
|
74
|
+
*/
|
|
75
|
+
clear(): void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { SignalBus, type SignalHandler, type SignalPredicate };
|