@defai.digital/agent-parallel 13.4.0
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 +38 -0
- package/dist/context-manager.d.ts +35 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +156 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/dag-analyzer.d.ts +32 -0
- package/dist/dag-analyzer.d.ts.map +1 -0
- package/dist/dag-analyzer.js +237 -0
- package/dist/dag-analyzer.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +27 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +494 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/result-aggregator.d.ts +64 -0
- package/dist/result-aggregator.d.ts.map +1 -0
- package/dist/result-aggregator.js +187 -0
- package/dist/result-aggregator.js.map +1 -0
- package/dist/types.d.ts +207 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +54 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
- package/src/context-manager.ts +194 -0
- package/src/dag-analyzer.ts +285 -0
- package/src/index.ts +70 -0
- package/src/orchestrator.ts +595 -0
- package/src/result-aggregator.ts +238 -0
- package/src/types.ts +320 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages shared immutable context for parallel agent execution.
|
|
5
|
+
* Ensures context is frozen before execution and cannot be modified.
|
|
6
|
+
*
|
|
7
|
+
* Invariants:
|
|
8
|
+
* - INV-APE-003: Shared context immutable during execution
|
|
9
|
+
* - INV-APE-300: Context snapshot timing (frozen before first task)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { SharedContext } from '@defai.digital/contracts';
|
|
13
|
+
import { ParallelExecutionErrorCodes } from '@defai.digital/contracts';
|
|
14
|
+
import type { ContextManager } from './types.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when context mutation is attempted
|
|
18
|
+
*/
|
|
19
|
+
export class ContextMutationError extends Error {
|
|
20
|
+
constructor(message: string) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'ContextMutationError';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static readonly code = ParallelExecutionErrorCodes.CONTEXT_MUTATION;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Deep freeze an object and all nested objects
|
|
30
|
+
* INV-APE-003: Ensures true immutability
|
|
31
|
+
*/
|
|
32
|
+
function deepFreeze<T extends object>(obj: T): T {
|
|
33
|
+
// Get property names
|
|
34
|
+
const propNames = Object.getOwnPropertyNames(obj) as (keyof T)[];
|
|
35
|
+
|
|
36
|
+
// Freeze nested objects first
|
|
37
|
+
for (const name of propNames) {
|
|
38
|
+
const value = obj[name];
|
|
39
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
40
|
+
deepFreeze(value as object);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Freeze self
|
|
45
|
+
return Object.freeze(obj);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates a context manager for shared immutable context
|
|
50
|
+
*/
|
|
51
|
+
export function createContextManager(): ContextManager {
|
|
52
|
+
let context: SharedContext | null = null;
|
|
53
|
+
let frozen = false;
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
/**
|
|
57
|
+
* Create frozen shared context
|
|
58
|
+
* INV-APE-300: Context snapshot timing
|
|
59
|
+
*/
|
|
60
|
+
create(data: Record<string, unknown>): SharedContext {
|
|
61
|
+
// Deep clone to prevent external mutation
|
|
62
|
+
const clonedData = JSON.parse(JSON.stringify(data)) as Record<string, unknown>;
|
|
63
|
+
|
|
64
|
+
// Create context object
|
|
65
|
+
const newContext: SharedContext = {
|
|
66
|
+
data: clonedData,
|
|
67
|
+
createdAt: new Date().toISOString(),
|
|
68
|
+
version: '1',
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Deep freeze the entire context
|
|
72
|
+
// INV-APE-003: Immutable during execution
|
|
73
|
+
context = deepFreeze(newContext);
|
|
74
|
+
frozen = true;
|
|
75
|
+
|
|
76
|
+
return context;
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get read-only view of context
|
|
81
|
+
*/
|
|
82
|
+
get(): SharedContext | null {
|
|
83
|
+
return context;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if context is frozen/immutable
|
|
88
|
+
*/
|
|
89
|
+
isFrozen(): boolean {
|
|
90
|
+
return frozen && context !== null && Object.isFrozen(context);
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Clear context (for cleanup after execution)
|
|
95
|
+
*/
|
|
96
|
+
clear(): void {
|
|
97
|
+
context = null;
|
|
98
|
+
frozen = false;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a proxy that throws on any mutation attempt
|
|
105
|
+
* Alternative approach for stricter runtime enforcement
|
|
106
|
+
*/
|
|
107
|
+
export function createImmutableContextProxy<T extends Record<string, unknown>>(
|
|
108
|
+
data: T
|
|
109
|
+
): Readonly<T> {
|
|
110
|
+
const handler: ProxyHandler<T> = {
|
|
111
|
+
get(target, prop, receiver) {
|
|
112
|
+
const value = Reflect.get(target, prop, receiver);
|
|
113
|
+
// Recursively wrap nested objects
|
|
114
|
+
if (value && typeof value === 'object') {
|
|
115
|
+
return createImmutableContextProxy(value as Record<string, unknown>);
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
set(_target, prop) {
|
|
121
|
+
throw new ContextMutationError(
|
|
122
|
+
`Cannot modify shared context: attempted to set "${String(prop)}". ` +
|
|
123
|
+
'Shared context is immutable during parallel execution (INV-APE-003).'
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
deleteProperty(_target, prop) {
|
|
128
|
+
throw new ContextMutationError(
|
|
129
|
+
`Cannot modify shared context: attempted to delete "${String(prop)}". ` +
|
|
130
|
+
'Shared context is immutable during parallel execution (INV-APE-003).'
|
|
131
|
+
);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
defineProperty(_target, prop) {
|
|
135
|
+
throw new ContextMutationError(
|
|
136
|
+
`Cannot modify shared context: attempted to define "${String(prop)}". ` +
|
|
137
|
+
'Shared context is immutable during parallel execution (INV-APE-003).'
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
setPrototypeOf() {
|
|
142
|
+
throw new ContextMutationError(
|
|
143
|
+
'Cannot modify shared context prototype. ' +
|
|
144
|
+
'Shared context is immutable during parallel execution (INV-APE-003).'
|
|
145
|
+
);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return new Proxy(data, handler) as Readonly<T>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Validates that context data is JSON-serializable
|
|
154
|
+
*/
|
|
155
|
+
export function validateContextData(
|
|
156
|
+
data: unknown
|
|
157
|
+
): { valid: boolean; errors: string[] } {
|
|
158
|
+
const errors: string[] = [];
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Check JSON serializability
|
|
162
|
+
JSON.stringify(data);
|
|
163
|
+
} catch (e) {
|
|
164
|
+
errors.push(
|
|
165
|
+
`Context data is not JSON-serializable: ${e instanceof Error ? e.message : 'Unknown error'}`
|
|
166
|
+
);
|
|
167
|
+
return { valid: false, errors };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Check for functions (not serializable)
|
|
171
|
+
function checkForFunctions(obj: unknown, path: string): void {
|
|
172
|
+
if (typeof obj === 'function') {
|
|
173
|
+
errors.push(`Context contains function at ${path}`);
|
|
174
|
+
} else if (obj && typeof obj === 'object') {
|
|
175
|
+
if (Array.isArray(obj)) {
|
|
176
|
+
obj.forEach((item, index) => checkForFunctions(item, `${path}[${index}]`));
|
|
177
|
+
} else {
|
|
178
|
+
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
|
|
179
|
+
checkForFunctions(value, path ? `${path}.${key}` : key);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
checkForFunctions(data, '');
|
|
186
|
+
|
|
187
|
+
// Check for circular references (JSON.stringify would have failed)
|
|
188
|
+
// Already caught above
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
valid: errors.length === 0,
|
|
192
|
+
errors,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DAG Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Analyzes task dependencies and builds execution layers using topological sort.
|
|
5
|
+
* Detects circular dependencies and validates DAG structure.
|
|
6
|
+
*
|
|
7
|
+
* Invariants:
|
|
8
|
+
* - INV-APE-002: Dependencies honored (DAG ordering)
|
|
9
|
+
* - INV-APE-200: Circular dependencies detected before execution
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { AgentParallelTask } from '@defai.digital/contracts';
|
|
13
|
+
import { ParallelExecutionErrorCodes } from '@defai.digital/contracts';
|
|
14
|
+
import type { DAGAnalyzer, DAGAnalysisResult, TaskLayer } from './types.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when DAG analysis fails
|
|
18
|
+
*/
|
|
19
|
+
export class DAGAnalysisError extends Error {
|
|
20
|
+
constructor(
|
|
21
|
+
public readonly code: string,
|
|
22
|
+
message: string,
|
|
23
|
+
public readonly cycleNodes?: string[]
|
|
24
|
+
) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = 'DAGAnalysisError';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static circularDependency(nodeIds: string[]): DAGAnalysisError {
|
|
30
|
+
return new DAGAnalysisError(
|
|
31
|
+
ParallelExecutionErrorCodes.CIRCULAR_DEPENDENCY,
|
|
32
|
+
`Circular dependency detected: ${nodeIds.join(' -> ')}`,
|
|
33
|
+
nodeIds
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static invalidDependency(taskId: string, depId: string): DAGAnalysisError {
|
|
38
|
+
return new DAGAnalysisError(
|
|
39
|
+
ParallelExecutionErrorCodes.INVALID_PLAN,
|
|
40
|
+
`Task "${taskId}" depends on non-existent task "${depId}"`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a DAG analyzer for parallel task execution
|
|
47
|
+
* Uses Kahn's algorithm for topological sorting
|
|
48
|
+
*/
|
|
49
|
+
export function createDAGAnalyzer(): DAGAnalyzer {
|
|
50
|
+
/**
|
|
51
|
+
* Build execution layers using Kahn's algorithm
|
|
52
|
+
* INV-APE-002: Ensures dependencies honored
|
|
53
|
+
* INV-APE-200: Detects cycles via incomplete processing
|
|
54
|
+
*/
|
|
55
|
+
function buildLayers(tasks: AgentParallelTask[]): DAGAnalysisResult {
|
|
56
|
+
// Handle empty input
|
|
57
|
+
if (tasks.length === 0) {
|
|
58
|
+
return {
|
|
59
|
+
layers: [],
|
|
60
|
+
totalLayers: 0,
|
|
61
|
+
maxParallelism: 0,
|
|
62
|
+
hasCycles: false,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Build task lookup map
|
|
67
|
+
const taskMap = new Map<string, AgentParallelTask>();
|
|
68
|
+
for (const task of tasks) {
|
|
69
|
+
taskMap.set(task.taskId, task);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Validate all dependencies exist
|
|
73
|
+
for (const task of tasks) {
|
|
74
|
+
for (const depId of task.dependencies) {
|
|
75
|
+
if (!taskMap.has(depId)) {
|
|
76
|
+
throw DAGAnalysisError.invalidDependency(task.taskId, depId);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Calculate in-degree for each task
|
|
82
|
+
const inDegree = new Map<string, number>();
|
|
83
|
+
for (const task of tasks) {
|
|
84
|
+
inDegree.set(task.taskId, task.dependencies.length);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Build reverse dependency map (who depends on me)
|
|
88
|
+
const dependents = new Map<string, string[]>();
|
|
89
|
+
for (const task of tasks) {
|
|
90
|
+
dependents.set(task.taskId, []);
|
|
91
|
+
}
|
|
92
|
+
for (const task of tasks) {
|
|
93
|
+
for (const depId of task.dependencies) {
|
|
94
|
+
const depList = dependents.get(depId) ?? [];
|
|
95
|
+
depList.push(task.taskId);
|
|
96
|
+
dependents.set(depId, depList);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Build layers using BFS
|
|
101
|
+
const layers: TaskLayer[] = [];
|
|
102
|
+
let processedCount = 0;
|
|
103
|
+
|
|
104
|
+
// Start with tasks that have no dependencies
|
|
105
|
+
let currentLayerTaskIds = Array.from(inDegree.entries())
|
|
106
|
+
.filter(([_, degree]) => degree === 0)
|
|
107
|
+
.map(([id]) => id);
|
|
108
|
+
|
|
109
|
+
let layerIndex = 0;
|
|
110
|
+
|
|
111
|
+
while (currentLayerTaskIds.length > 0) {
|
|
112
|
+
// Get tasks for current layer, sorted by priority (descending)
|
|
113
|
+
const layerTasks = currentLayerTaskIds
|
|
114
|
+
.map((id) => taskMap.get(id)!)
|
|
115
|
+
.sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));
|
|
116
|
+
|
|
117
|
+
layers.push({
|
|
118
|
+
index: layerIndex,
|
|
119
|
+
tasks: layerTasks,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
processedCount += layerTasks.length;
|
|
123
|
+
|
|
124
|
+
// Find next layer
|
|
125
|
+
const nextLayerTaskIds: string[] = [];
|
|
126
|
+
for (const taskId of currentLayerTaskIds) {
|
|
127
|
+
const deps = dependents.get(taskId) ?? [];
|
|
128
|
+
for (const depId of deps) {
|
|
129
|
+
const degree = (inDegree.get(depId) ?? 0) - 1;
|
|
130
|
+
inDegree.set(depId, degree);
|
|
131
|
+
|
|
132
|
+
if (degree === 0) {
|
|
133
|
+
nextLayerTaskIds.push(depId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
currentLayerTaskIds = nextLayerTaskIds;
|
|
139
|
+
layerIndex++;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check for cycles - if we didn't process all tasks, there's a cycle
|
|
143
|
+
const hasCycles = processedCount !== tasks.length;
|
|
144
|
+
let cycleNodes: string[] | undefined;
|
|
145
|
+
|
|
146
|
+
if (hasCycles) {
|
|
147
|
+
// Find nodes involved in cycle (those not processed)
|
|
148
|
+
cycleNodes = tasks
|
|
149
|
+
.filter((t) => (inDegree.get(t.taskId) ?? 0) > 0)
|
|
150
|
+
.map((t) => t.taskId);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Calculate max parallelism (largest layer)
|
|
154
|
+
const maxParallelism = Math.max(0, ...layers.map((l) => l.tasks.length));
|
|
155
|
+
|
|
156
|
+
const result: DAGAnalysisResult = {
|
|
157
|
+
layers,
|
|
158
|
+
totalLayers: layers.length,
|
|
159
|
+
maxParallelism,
|
|
160
|
+
hasCycles,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Only include cycleNodes if there are cycles
|
|
164
|
+
if (cycleNodes) {
|
|
165
|
+
result.cycleNodes = cycleNodes;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Validate DAG structure
|
|
173
|
+
*/
|
|
174
|
+
function validate(tasks: AgentParallelTask[]): { valid: boolean; errors: string[] } {
|
|
175
|
+
const errors: string[] = [];
|
|
176
|
+
|
|
177
|
+
// Check for duplicate task IDs
|
|
178
|
+
const taskIds = new Set<string>();
|
|
179
|
+
for (const task of tasks) {
|
|
180
|
+
if (taskIds.has(task.taskId)) {
|
|
181
|
+
errors.push(`Duplicate task ID: ${task.taskId}`);
|
|
182
|
+
}
|
|
183
|
+
taskIds.add(task.taskId);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check for self-dependencies
|
|
187
|
+
for (const task of tasks) {
|
|
188
|
+
if (task.dependencies.includes(task.taskId)) {
|
|
189
|
+
errors.push(`Task "${task.taskId}" depends on itself`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Check for missing dependencies
|
|
194
|
+
for (const task of tasks) {
|
|
195
|
+
for (const depId of task.dependencies) {
|
|
196
|
+
if (!taskIds.has(depId)) {
|
|
197
|
+
errors.push(`Task "${task.taskId}" depends on non-existent task "${depId}"`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Check for cycles
|
|
203
|
+
if (errors.length === 0) {
|
|
204
|
+
const result = buildLayers(tasks);
|
|
205
|
+
if (result.hasCycles) {
|
|
206
|
+
errors.push(`Circular dependency detected involving: ${result.cycleNodes?.join(', ')}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
valid: errors.length === 0,
|
|
212
|
+
errors,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
analyze(tasks: AgentParallelTask[]): DAGAnalysisResult {
|
|
218
|
+
const result = buildLayers(tasks);
|
|
219
|
+
|
|
220
|
+
// Throw if cycles detected
|
|
221
|
+
if (result.hasCycles && result.cycleNodes) {
|
|
222
|
+
throw DAGAnalysisError.circularDependency(result.cycleNodes);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return result;
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
validate,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Utility: Find tasks in a cycle using DFS
|
|
234
|
+
*/
|
|
235
|
+
export function findCyclePath(tasks: AgentParallelTask[]): string[] | null {
|
|
236
|
+
const taskMap = new Map<string, AgentParallelTask>();
|
|
237
|
+
for (const task of tasks) {
|
|
238
|
+
taskMap.set(task.taskId, task);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const visited = new Set<string>();
|
|
242
|
+
const recursionStack = new Set<string>();
|
|
243
|
+
const path: string[] = [];
|
|
244
|
+
|
|
245
|
+
function dfs(taskId: string): boolean {
|
|
246
|
+
visited.add(taskId);
|
|
247
|
+
recursionStack.add(taskId);
|
|
248
|
+
path.push(taskId);
|
|
249
|
+
|
|
250
|
+
const task = taskMap.get(taskId);
|
|
251
|
+
if (task) {
|
|
252
|
+
for (const depId of task.dependencies) {
|
|
253
|
+
if (!visited.has(depId)) {
|
|
254
|
+
if (dfs(depId)) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
} else if (recursionStack.has(depId)) {
|
|
258
|
+
// Found cycle
|
|
259
|
+
path.push(depId);
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
recursionStack.delete(taskId);
|
|
266
|
+
path.pop();
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
for (const task of tasks) {
|
|
271
|
+
if (!visited.has(task.taskId)) {
|
|
272
|
+
if (dfs(task.taskId)) {
|
|
273
|
+
// Trim path to only include cycle
|
|
274
|
+
const lastNode = path[path.length - 1];
|
|
275
|
+
if (lastNode) {
|
|
276
|
+
const cycleStart = path.indexOf(lastNode);
|
|
277
|
+
return path.slice(cycleStart);
|
|
278
|
+
}
|
|
279
|
+
return path;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return null;
|
|
285
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @defai.digital/agent-parallel
|
|
3
|
+
*
|
|
4
|
+
* Parallel Agent Execution Domain
|
|
5
|
+
*
|
|
6
|
+
* Provides orchestration for executing multiple agents in parallel
|
|
7
|
+
* with DAG-based dependency management, shared immutable context,
|
|
8
|
+
* and configurable result aggregation.
|
|
9
|
+
*
|
|
10
|
+
* @module @defai.digital/agent-parallel
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// Main Orchestrator
|
|
14
|
+
export {
|
|
15
|
+
createAgentParallelOrchestrator,
|
|
16
|
+
ParallelExecutionError,
|
|
17
|
+
} from './orchestrator.js';
|
|
18
|
+
|
|
19
|
+
// DAG Analyzer
|
|
20
|
+
export {
|
|
21
|
+
createDAGAnalyzer,
|
|
22
|
+
DAGAnalysisError,
|
|
23
|
+
findCyclePath,
|
|
24
|
+
} from './dag-analyzer.js';
|
|
25
|
+
|
|
26
|
+
// Context Manager
|
|
27
|
+
export {
|
|
28
|
+
createContextManager,
|
|
29
|
+
createImmutableContextProxy,
|
|
30
|
+
validateContextData,
|
|
31
|
+
ContextMutationError,
|
|
32
|
+
} from './context-manager.js';
|
|
33
|
+
|
|
34
|
+
// Result Aggregator
|
|
35
|
+
export {
|
|
36
|
+
createResultAggregator,
|
|
37
|
+
AggregationStrategies,
|
|
38
|
+
createKeyedAggregator,
|
|
39
|
+
createTransformAggregator,
|
|
40
|
+
getAggregationStrategy,
|
|
41
|
+
} from './result-aggregator.js';
|
|
42
|
+
|
|
43
|
+
// Types and Interfaces
|
|
44
|
+
export type {
|
|
45
|
+
// Orchestrator types
|
|
46
|
+
AgentParallelOrchestrator,
|
|
47
|
+
AgentParallelOrchestratorOptions,
|
|
48
|
+
// Agent executor port
|
|
49
|
+
AgentExecutorPort,
|
|
50
|
+
AgentExecuteRequest,
|
|
51
|
+
AgentExecuteResult,
|
|
52
|
+
// DAG types
|
|
53
|
+
DAGAnalyzer,
|
|
54
|
+
DAGAnalysisResult,
|
|
55
|
+
TaskLayer,
|
|
56
|
+
// Context types
|
|
57
|
+
ContextManager,
|
|
58
|
+
// Result aggregator types
|
|
59
|
+
ResultAggregator,
|
|
60
|
+
ResultAggregatorOptions,
|
|
61
|
+
AggregationStrategy,
|
|
62
|
+
CustomAggregator,
|
|
63
|
+
// Progress types
|
|
64
|
+
ParallelProgressEvent,
|
|
65
|
+
ParallelProgressEventType,
|
|
66
|
+
ParallelProgressCallback,
|
|
67
|
+
} from './types.js';
|
|
68
|
+
|
|
69
|
+
// Stub implementation for testing
|
|
70
|
+
export { StubAgentExecutor } from './types.js';
|