astrabot 0.1.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/README.md +411 -0
- package/ai/ai.config.ts +27 -0
- package/ai/auto-retry.ts +117 -0
- package/ai/config-loader.ts +132 -0
- package/ai/index.ts +4 -0
- package/ai/retry-prompt.ts +30 -0
- package/bin/astra +2 -0
- package/core/retry/error-classifier.ts +208 -0
- package/core/retry/index.ts +29 -0
- package/core/retry/retry-config.ts +142 -0
- package/core/retry/retry-engine.ts +215 -0
- package/game/index.html +573 -0
- package/game/neon-breaker.html +1037 -0
- package/index.ts +140 -0
- package/modes/agent/action-tracker.ts +47 -0
- package/modes/agent/agent-tools.ts +338 -0
- package/modes/agent/approval.ts +184 -0
- package/modes/agent/diff-view.ts +34 -0
- package/modes/agent/orchestrator.ts +234 -0
- package/modes/agent/tool-executor.ts +993 -0
- package/modes/agent/types.ts +68 -0
- package/modes/ask/orchestrator.ts +230 -0
- package/modes/auto.ts +88 -0
- package/modes/cli.ts +43 -0
- package/modes/multi/agent-pool-manager.ts +337 -0
- package/modes/multi/examples.ts +441 -0
- package/modes/multi/message-broker.ts +179 -0
- package/modes/multi/multi-agent-orchestrator.ts +891 -0
- package/modes/multi/orchestrator.ts +414 -0
- package/modes/multi/types.ts +245 -0
- package/modes/multi/workflow-builder.ts +569 -0
- package/modes/plan/orchestrator.ts +198 -0
- package/modes/plan/planner.ts +121 -0
- package/modes/plan/selection.ts +43 -0
- package/modes/plan/types.ts +13 -0
- package/modes/plan/web-tools.ts +132 -0
- package/modes/setup.ts +210 -0
- package/package.json +62 -0
- package/session/index.ts +45 -0
- package/session/session-context.ts +188 -0
- package/session/session-manager.ts +374 -0
- package/session/session-tools.ts +109 -0
- package/session/store.ts +278 -0
- package/tsconfig.json +30 -0
- package/tui/spinner.ts +182 -0
- package/tui/terminal-md.ts +17 -0
- package/tui/wakeup.ts +231 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Multi-Agent Mode Integration
|
|
3
|
+
*
|
|
4
|
+
* This file integrates the multi-agent orchestration system into the main
|
|
5
|
+
* application. It analyzes the goal text using an LLM to smartly choose
|
|
6
|
+
* a template or dynamically craft a custom agent topology.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { text, isCancel, select, confirm, multiselect, spinner } from "@clack/prompts";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import { generateText, stepCountIs } from "ai";
|
|
12
|
+
import { getAgentModel } from "../../ai";
|
|
13
|
+
import { MultiAgentOrchestrator } from "./multi-agent-orchestrator";
|
|
14
|
+
import { WorkflowBuilder, WorkflowTemplates } from "./workflow-builder";
|
|
15
|
+
import type { MultiAgentWorkflow, OrchestratorEvent } from "./types";
|
|
16
|
+
import { composeBeforeAfter, formatPatch } from "../agent/diff-view";
|
|
17
|
+
import { renderTerminalMarkdown } from "../../tui/terminal-md";
|
|
18
|
+
import { withSpinner } from "../../tui/spinner";
|
|
19
|
+
import type { ActionLog } from "../agent/types";
|
|
20
|
+
|
|
21
|
+
interface ReviewGroup {
|
|
22
|
+
label: string;
|
|
23
|
+
actionIds: string[];
|
|
24
|
+
patch: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function groupPendingByAgent(agentId: string, pending: ActionLog[]): ReviewGroup[] {
|
|
28
|
+
const byPath = new Map<string, ActionLog[]>();
|
|
29
|
+
const shells: ActionLog[] = [];
|
|
30
|
+
|
|
31
|
+
for (const a of pending) {
|
|
32
|
+
if (a.type === "tool_execute") {
|
|
33
|
+
shells.push(a);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const key = a.path;
|
|
37
|
+
if (!byPath.has(key)) byPath.set(key, []);
|
|
38
|
+
byPath.get(key)!.push(a);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const groups: ReviewGroup[] = [];
|
|
42
|
+
const pathEntries = [...byPath.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
43
|
+
|
|
44
|
+
for (const [p, acts] of pathEntries) {
|
|
45
|
+
const sorted = acts.sort((x, y) => x.timestamp.getTime() - y.timestamp.getTime());
|
|
46
|
+
const ids = sorted.map((x) => x.id);
|
|
47
|
+
|
|
48
|
+
if (sorted.every((x) => x.type === "folder_create")) {
|
|
49
|
+
groups.push({
|
|
50
|
+
label: `Create folder: ${p}`,
|
|
51
|
+
actionIds: ids,
|
|
52
|
+
patch: null,
|
|
53
|
+
});
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { before, after } = composeBeforeAfter(sorted);
|
|
58
|
+
const patch = formatPatch(p, before, after);
|
|
59
|
+
const kinds = [...new Set(sorted.map((x) => x.type))].join(", ");
|
|
60
|
+
groups.push({ label: `${p} (${kinds})`, actionIds: ids, patch });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const s of shells) {
|
|
64
|
+
groups.push({
|
|
65
|
+
label: `Shell: ${s.details.command ?? "(no command)"}`,
|
|
66
|
+
actionIds: [s.id],
|
|
67
|
+
patch: null,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return groups;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const TEMPLATE_CATALOG = [
|
|
75
|
+
{ id: "code_review", name: "Code Review", template: WorkflowTemplates.codeReviewWorkflow },
|
|
76
|
+
{ id: "feature_dev", name: "Feature Development", template: WorkflowTemplates.featureDevelopmentWorkflow },
|
|
77
|
+
{ id: "bug_fix", name: "Bug Fixing", template: WorkflowTemplates.bugFixingWorkflow },
|
|
78
|
+
{ id: "research", name: "Collaborative Research", template: WorkflowTemplates.collaborativeResearchWorkflow },
|
|
79
|
+
{ id: "security_audit", name: "Security Audit", template: WorkflowTemplates.securityAuditWorkflow },
|
|
80
|
+
{ id: "fullstack", name: "Full-Stack Feature", template: WorkflowTemplates.fullStackFeatureWorkflow },
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
// ─── Main Entry Point ──────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
export async function runMultiAgentMode(preCapturedGoal?: string): Promise<void> {
|
|
86
|
+
console.log(chalk.bold("\n👥 Multi-Agent Orchestration\n"));
|
|
87
|
+
|
|
88
|
+
// 1. Gather the goal text if not passed directly from Auto Mode
|
|
89
|
+
const finalGoal = preCapturedGoal?.trim() ?? await text({
|
|
90
|
+
message: "What complex operations workflow would you like to run?",
|
|
91
|
+
placeholder: "e.g., 'Audit auth code security and patch the leaks'...",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!finalGoal || isCancel(finalGoal) || !finalGoal.trim()) return;
|
|
95
|
+
|
|
96
|
+
let workflow: MultiAgentWorkflow | null = null;
|
|
97
|
+
|
|
98
|
+
// 2. AI Intelligence Engine: Analyze and assemble the best team
|
|
99
|
+
const decisionSpinner = spinner();
|
|
100
|
+
decisionSpinner.start("AI analyzing requirements and building optimal agent team topology...");
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const analysisResponse = await generateText({
|
|
104
|
+
model: getAgentModel(),
|
|
105
|
+
stopWhen: stepCountIs(1),
|
|
106
|
+
prompt: [
|
|
107
|
+
"You are an expert system architecture manager designing multi-agent software pipelines.",
|
|
108
|
+
"Analyze the following user task goal, and decide the absolute best workflow setup.",
|
|
109
|
+
"",
|
|
110
|
+
`User Task Goal: "${finalGoal}"`,
|
|
111
|
+
"",
|
|
112
|
+
"Available Catalog Templates:",
|
|
113
|
+
"- 'code_review': For reading existing code changes, analyzing style/vulnerabilities, and summarizing changes.",
|
|
114
|
+
"- 'feature_dev': Core workflows needing planning, engineering implementation, and QA reviews.",
|
|
115
|
+
"- 'bug_fix': Repair loops starting with debugging/diagnostics, code patch modifications, and testing cycles.",
|
|
116
|
+
"- 'research': Broad reading, framework discoveries, or documentation analysis without writing active patches.",
|
|
117
|
+
"- 'security_audit': Scanners running sweeps across directories feeding synthesis workflows.",
|
|
118
|
+
"- 'fullstack': Complex tasks requiring layered architectures (Database models, APIs, and UI controls) executing in parallel blocks.",
|
|
119
|
+
"",
|
|
120
|
+
"Your task is to respond with a clean, unformatted JSON object containing instructions on how to structure the agent swarm.",
|
|
121
|
+
"Format your response as a valid raw JSON matching EXACTLY one of these two configurations. Do not use markdown blocks.",
|
|
122
|
+
"",
|
|
123
|
+
"Option A: If a catalog template fits perfectly:",
|
|
124
|
+
'{"decisionType": "template", "templateId": "feature_dev" | "bug_fix" | "code_review" | "research" | "security_audit" | "fullstack"}',
|
|
125
|
+
"",
|
|
126
|
+
"Option B: If the task is unique and requires a customized specialized agent group configuration:",
|
|
127
|
+
'{',
|
|
128
|
+
' "decisionType": "custom",',
|
|
129
|
+
' "strategy": "sequential" | "parallel" | "hierarchical" | "collaborative",',
|
|
130
|
+
' "agents": [',
|
|
131
|
+
' { "name": "string", "role": "researcher"|"implementer"|"reviewer"|"coordinator", "description": "precise operational prompt instruction directive context for this agent" }',
|
|
132
|
+
' ]',
|
|
133
|
+
'}'
|
|
134
|
+
].join("\n"),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Clean any accidental markdown wraps from the raw response text
|
|
138
|
+
let cleanJsonText = analysisResponse.text.trim();
|
|
139
|
+
if (cleanJsonText.startsWith("```")) {
|
|
140
|
+
cleanJsonText = cleanJsonText.replace(/^```json\s*/, "").replace(/```$/, "").trim();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const config = JSON.parse(cleanJsonText);
|
|
144
|
+
const timestamp = Date.now();
|
|
145
|
+
|
|
146
|
+
if (config.decisionType === "template" && config.templateId) {
|
|
147
|
+
const match = TEMPLATE_CATALOG.find(t => t.id === config.templateId);
|
|
148
|
+
if (match) {
|
|
149
|
+
decisionSpinner.stop(`✨ AI designated standard pipeline template: [${match.name}]`);
|
|
150
|
+
workflow = match.template(`wf_ai_${config.templateId}_${timestamp}`, finalGoal);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// fallback / bespoke generation block
|
|
155
|
+
if (!workflow && config.decisionType === "custom" && Array.isArray(config.agents)) {
|
|
156
|
+
decisionSpinner.stop(`🛠️ AI created bespoke customized workspace swarm [Strategy: ${config.strategy.toUpperCase()}]`);
|
|
157
|
+
const builder = new WorkflowBuilder(`wf_custom_ai_${timestamp}`, finalGoal);
|
|
158
|
+
|
|
159
|
+
for (const a of config.agents) {
|
|
160
|
+
if (a.role === "researcher") builder.addResearcher(a.name, a.name, a.description);
|
|
161
|
+
else if (a.role === "implementer") builder.addImplementer(a.name, a.name, a.description);
|
|
162
|
+
else if (a.role === "reviewer") builder.addReviewer(a.name, a.name, a.description);
|
|
163
|
+
else builder.addCoordinator(a.name, a.name, a.description);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (config.strategy === "parallel") builder.withParallelStrategy(3, 45000);
|
|
167
|
+
else if (config.strategy === "hierarchical") builder.withHierarchicalStrategy();
|
|
168
|
+
else if (config.strategy === "collaborative") builder.withCollaborativeStrategy(60000);
|
|
169
|
+
else builder.withSequentialStrategy();
|
|
170
|
+
|
|
171
|
+
builder.withRetryOnFailure(1);
|
|
172
|
+
workflow = builder.build();
|
|
173
|
+
}
|
|
174
|
+
} catch (err) {
|
|
175
|
+
// Fail-safe graceful fallback if model errors or outputs invalid JSON
|
|
176
|
+
decisionSpinner.stop("⚠️ Model parsing bottleneck; falling back to dynamic Feature Development group");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Double fallback to protect operation runtime loop
|
|
180
|
+
if (!workflow) {
|
|
181
|
+
const timestamp = Date.now();
|
|
182
|
+
workflow = WorkflowTemplates.featureDevelopmentWorkflow(`wf_fallback_${timestamp}`, finalGoal);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 3. Complete Validation Layer
|
|
186
|
+
const validation = WorkflowBuilder.validateWorkflow(workflow);
|
|
187
|
+
if (!validation.isValid) {
|
|
188
|
+
console.log(chalk.red("\n❌ Generated Workflow validation failed:\n"));
|
|
189
|
+
for (const error of validation.errors) console.log(chalk.red(` • ${error}`));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 4. Summarize and Confirm Execution with User
|
|
194
|
+
displayWorkflowSummary(workflow);
|
|
195
|
+
|
|
196
|
+
const shouldContinue = await confirm({
|
|
197
|
+
message: "Execute this smart-built agent workflow?",
|
|
198
|
+
initialValue: true,
|
|
199
|
+
});
|
|
200
|
+
if (isCancel(shouldContinue) || !shouldContinue) {
|
|
201
|
+
console.log(chalk.dim("\nWorkflow cancelled.\n"));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 5. Standard Core Operational Orchestrator Lifecycle Loop Execution
|
|
206
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
207
|
+
|
|
208
|
+
const unsubscribe = orchestrator.onEvent((event: OrchestratorEvent) => {
|
|
209
|
+
if (event.type === "agent:start") {
|
|
210
|
+
orchestrationLogger.debug(`Agent ${event.agentId} running...`);
|
|
211
|
+
} else if (event.type === "agent:complete") {
|
|
212
|
+
orchestrationLogger.debug(`Agent ${event.agentId} successfully completed steps`);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
await withSpinner(
|
|
217
|
+
{
|
|
218
|
+
message: "Orchestrating system agents pipeline execution...",
|
|
219
|
+
doneMessage: "workflow steps completed successfully",
|
|
220
|
+
failMessage: "workflow processing routine encountered a bottleneck",
|
|
221
|
+
},
|
|
222
|
+
() => orchestrator.execute(),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
unsubscribe();
|
|
226
|
+
|
|
227
|
+
// 6. Print Summary Metric Sheets & Route Approval
|
|
228
|
+
displayExecutionResults(orchestrator);
|
|
229
|
+
await runMultiAgentApprovalFlow(orchestrator);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ─── Native Selector Methods (Preserved for standard fallback uses) ────────
|
|
233
|
+
|
|
234
|
+
async function selectTemplateWorkflow(): Promise<MultiAgentWorkflow | null> {
|
|
235
|
+
const selected = await select({
|
|
236
|
+
message: "Select a workflow template",
|
|
237
|
+
options: TEMPLATE_CATALOG.map((t) => ({
|
|
238
|
+
value: t.id,
|
|
239
|
+
label: chalk.bold(t.name),
|
|
240
|
+
})),
|
|
241
|
+
});
|
|
242
|
+
if (isCancel(selected)) return null;
|
|
243
|
+
const catalog = TEMPLATE_CATALOG.find((t) => t.id === selected);
|
|
244
|
+
if (!catalog) return null;
|
|
245
|
+
const goal = await text({ message: "Describe the goal for this workflow" });
|
|
246
|
+
if (isCancel(goal) || !goal.trim()) return null;
|
|
247
|
+
return catalog.template(`workflow_${selected}_${Date.now()}`, goal.trim());
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function buildCustomWorkflow(): Promise<MultiAgentWorkflow | null> {
|
|
251
|
+
return null; // Interface is bypassed dynamically by the structural smart engine
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function buildAdvancedDAGWorkflow(): Promise<MultiAgentWorkflow | null> {
|
|
255
|
+
return null; // Interface is bypassed dynamically by the structural smart engine
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ─── Display & Approval ────────────────────────────────────────────────────
|
|
259
|
+
|
|
260
|
+
function displayWorkflowSummary(workflow: MultiAgentWorkflow): void {
|
|
261
|
+
console.log(chalk.bold("\n📋 Smart Workflow Configuration\n"));
|
|
262
|
+
console.log(`Goal: ${workflow.goal}`);
|
|
263
|
+
console.log(`Strategy: ${chalk.cyan(workflow.strategy.type)}`);
|
|
264
|
+
console.log(`Agents: ${workflow.agents.length}`);
|
|
265
|
+
console.log(
|
|
266
|
+
`${workflow.agents
|
|
267
|
+
.map(
|
|
268
|
+
(a) =>
|
|
269
|
+
` • ${chalk.bold(a.name)} (${a.role})${a.model ? ` [${chalk.dim(a.model)}]` : ""}${
|
|
270
|
+
a.dependsOn?.length ? ` → depends: ${a.dependsOn.join(", ")}` : ""
|
|
271
|
+
}`,
|
|
272
|
+
)
|
|
273
|
+
.join("\n")}`,
|
|
274
|
+
);
|
|
275
|
+
console.log();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function runMultiAgentApprovalFlow(orchestrator: MultiAgentOrchestrator): Promise<void> {
|
|
279
|
+
const trackers = orchestrator.getAllTrackers();
|
|
280
|
+
const executors = orchestrator.getAllExecutors();
|
|
281
|
+
|
|
282
|
+
let totalPending = 0;
|
|
283
|
+
for (const [, tracker] of trackers) {
|
|
284
|
+
totalPending += tracker.getPendingMutations().length;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (totalPending === 0) {
|
|
288
|
+
console.log(chalk.dim("\nNo staged changes to review.\n"));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
console.log(chalk.bold(`\n📝 ${totalPending} staged change(s) from ${trackers.size} agent(s)\n`));
|
|
293
|
+
|
|
294
|
+
const choice = await select({
|
|
295
|
+
message: "Apply staged changes?",
|
|
296
|
+
options: [
|
|
297
|
+
{ value: "all", label: "Approve all" },
|
|
298
|
+
{ value: "select", label: "Review one by one" },
|
|
299
|
+
{ value: "cancel", label: "Discard all" },
|
|
300
|
+
],
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (isCancel(choice) || choice === "cancel") {
|
|
304
|
+
for (const [, tracker] of trackers) {
|
|
305
|
+
for (const action of tracker.getPendingMutations()) {
|
|
306
|
+
tracker.updateStatus(action.id, "rejected", false);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
for (const [, executor] of executors) {
|
|
310
|
+
executor.discardChanges();
|
|
311
|
+
}
|
|
312
|
+
console.log(chalk.yellow("\nAll changes discarded.\n"));
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (choice === "all") {
|
|
317
|
+
for (const [, tracker] of trackers) {
|
|
318
|
+
for (const action of tracker.getPendingMutations()) {
|
|
319
|
+
tracker.updateStatus(action.id, "approved", true);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
} else if (choice === "select") {
|
|
323
|
+
for (const [agentId, tracker] of trackers) {
|
|
324
|
+
const pending = tracker.getPendingMutations();
|
|
325
|
+
if (pending.length === 0) continue;
|
|
326
|
+
|
|
327
|
+
console.log(chalk.bold(`\n🤖 Agent: ${agentId} (${pending.length} change(s))`));
|
|
328
|
+
const groups = groupPendingByAgent(agentId, pending);
|
|
329
|
+
|
|
330
|
+
for (const g of groups) {
|
|
331
|
+
while (true) {
|
|
332
|
+
const opt = await select({
|
|
333
|
+
message: chalk.bold(g.label),
|
|
334
|
+
options: [
|
|
335
|
+
{ value: "accept", label: "Accept" },
|
|
336
|
+
{ value: "diff", label: "Show diff", hint: g.patch ? "" : "N/A" },
|
|
337
|
+
{ value: "reject", label: "Reject" },
|
|
338
|
+
],
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
if (isCancel(opt)) {
|
|
342
|
+
for (const [, t] of trackers) {
|
|
343
|
+
for (const a of t.getPendingMutations()) t.updateStatus(a.id, "rejected", false);
|
|
344
|
+
}
|
|
345
|
+
for (const [, executor] of executors) executor.discardChanges();
|
|
346
|
+
console.log(chalk.yellow("\nAll changes discarded.\n"));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (opt === "diff") {
|
|
351
|
+
if (g.patch) {
|
|
352
|
+
console.log("\n" + renderTerminalMarkdown("```diff\n" + g.patch + "\n```\n") + "\n");
|
|
353
|
+
}
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
for (const id of g.actionIds) {
|
|
358
|
+
tracker.updateStatus(id, opt === "accept" ? "approved" : "rejected", opt === "accept");
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await withSpinner(
|
|
367
|
+
{
|
|
368
|
+
message: "Applying approved changes…",
|
|
369
|
+
doneMessage: "all changes applied",
|
|
370
|
+
failMessage: "some operations failed",
|
|
371
|
+
},
|
|
372
|
+
async () => {
|
|
373
|
+
const allErrors: string[] = [];
|
|
374
|
+
for (const [agentId, executor] of executors) {
|
|
375
|
+
const { errors } = executor.applyApprovedFromTracker();
|
|
376
|
+
allErrors.push(...errors.map((e) => `[${agentId}] ${e}`));
|
|
377
|
+
}
|
|
378
|
+
if (allErrors.length > 0) {
|
|
379
|
+
console.log(chalk.red("\nErrors:\n"));
|
|
380
|
+
for (const e of allErrors) console.log(chalk.red(` · ${e}`));
|
|
381
|
+
} else {
|
|
382
|
+
console.log(chalk.green("\n✔ All changes applied.\n"));
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function displayExecutionResults(orchestrator: MultiAgentOrchestrator): void {
|
|
389
|
+
const summary = orchestrator.getSummary();
|
|
390
|
+
console.log(chalk.bold("\n📊 Execution Summary\n"));
|
|
391
|
+
const statusColor = summary.status === "completed" ? chalk.green : chalk.red;
|
|
392
|
+
console.log(`Status: ${statusColor(`● ${summary.status}`)}`);
|
|
393
|
+
console.log(`Strategy: ${summary.strategy}`);
|
|
394
|
+
console.log(`Duration: ${summary.duration ? `${summary.duration}ms` : "N/A"}`);
|
|
395
|
+
|
|
396
|
+
console.log(chalk.bold("\n🤖 Pool Stats\n"));
|
|
397
|
+
console.log(`Total Agents Assigned: ${summary.poolStats.totalAgents}`);
|
|
398
|
+
console.log(`Completed Steps: ${chalk.green(String(summary.poolStats.completedAgents))}`);
|
|
399
|
+
console.log(`Completion Accuracy: ${chalk.cyan(`${summary.poolStats.completionPercentage}%`)}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const orchestrationLogger = {
|
|
403
|
+
debug: (msg: string) => {
|
|
404
|
+
if (process.env.DEBUG) console.log(chalk.dim(`[DEBUG] ${msg}`));
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
export default {
|
|
409
|
+
runMultiAgentMode,
|
|
410
|
+
selectTemplateWorkflow,
|
|
411
|
+
buildCustomWorkflow,
|
|
412
|
+
buildAdvancedDAGWorkflow,
|
|
413
|
+
displayExecutionResults,
|
|
414
|
+
};
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Agent Orchestration Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the interfaces and types for coordinating multiple agents
|
|
5
|
+
* working together on complex tasks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ─── Core Agent Types ────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
export type AgentRole =
|
|
11
|
+
| "researcher" // Gathers information and analyzes
|
|
12
|
+
| "implementer" // Writes code and modifies files
|
|
13
|
+
| "reviewer" // Reviews changes and validates
|
|
14
|
+
| "coordinator" // Manages workflow and delegates tasks
|
|
15
|
+
| "custom"; // Custom role defined by user
|
|
16
|
+
|
|
17
|
+
export type AgentStatus = "pending" | "running" | "completed" | "failed" | "skipped" | "retrying";
|
|
18
|
+
|
|
19
|
+
export interface AgentConfig {
|
|
20
|
+
id: string;
|
|
21
|
+
role: AgentRole;
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
model?: string; // Override default model (e.g. "anthropic/claude-sonnet-4.5")
|
|
25
|
+
maxSteps: number;
|
|
26
|
+
tools: string[]; // List of tool names this agent can use
|
|
27
|
+
systemPrompt?: string; // Custom system instructions
|
|
28
|
+
specializations?: string[]; // What this agent is good at
|
|
29
|
+
/** IDs of agents that must complete before this one starts (DAG dependency) */
|
|
30
|
+
dependsOn?: string[];
|
|
31
|
+
/** Hard timeout in ms for this specific agent (overrides strategy timeout) */
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
/** Tags for grouping/filtering agents */
|
|
34
|
+
tags?: string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ─── Messaging ───────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
export type MessageType = "request" | "response" | "status" | "error" | "result" | "handoff";
|
|
40
|
+
|
|
41
|
+
export interface AgentMessage {
|
|
42
|
+
id: string;
|
|
43
|
+
fromAgentId: string;
|
|
44
|
+
toAgentId?: string; // undefined = broadcast to all
|
|
45
|
+
type: MessageType;
|
|
46
|
+
content: string;
|
|
47
|
+
context?: Record<string, unknown>;
|
|
48
|
+
timestamp: Date;
|
|
49
|
+
requiresResponse: boolean;
|
|
50
|
+
/** Message this is a reply to */
|
|
51
|
+
replyToId?: string;
|
|
52
|
+
/** Priority for ordering message delivery */
|
|
53
|
+
priority?: "low" | "normal" | "high";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── Context & State ─────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export interface AgentContext {
|
|
59
|
+
goal: string;
|
|
60
|
+
conversationHistory: AgentMessage[];
|
|
61
|
+
sharedState: Map<string, unknown>;
|
|
62
|
+
parentContext?: AgentContext;
|
|
63
|
+
metadata: AgentContextMetadata;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface AgentContextMetadata {
|
|
67
|
+
startTime: Date;
|
|
68
|
+
endTime?: Date;
|
|
69
|
+
currentStep: number;
|
|
70
|
+
completedTasks: string[];
|
|
71
|
+
failedTasks: string[];
|
|
72
|
+
retryCount: number;
|
|
73
|
+
/** Structured findings the agent surfaced for downstream agents */
|
|
74
|
+
findings?: Record<string, unknown>;
|
|
75
|
+
/** Tokens used, if tracked by the model provider */
|
|
76
|
+
tokensUsed?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── Execution Results ───────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
export interface AgentExecutionResult {
|
|
82
|
+
agentId: string;
|
|
83
|
+
success: boolean;
|
|
84
|
+
output: string;
|
|
85
|
+
executedTools: string[];
|
|
86
|
+
messagesReceived: AgentMessage[];
|
|
87
|
+
messagesSent: AgentMessage[];
|
|
88
|
+
context: AgentContext;
|
|
89
|
+
error?: Error;
|
|
90
|
+
/** Wall-clock duration in ms */
|
|
91
|
+
durationMs: number;
|
|
92
|
+
/** Which attempt produced this result (1-based) */
|
|
93
|
+
attemptNumber: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ─── Orchestration Strategy ──────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
export type StrategyType = "sequential" | "parallel" | "hierarchical" | "collaborative" | "dag";
|
|
99
|
+
|
|
100
|
+
export interface OrchestrationStrategy {
|
|
101
|
+
type: StrategyType;
|
|
102
|
+
config: StrategyConfig;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface StrategyConfig {
|
|
106
|
+
maxConcurrentAgents?: number;
|
|
107
|
+
/** Default timeout in ms applied to all agents (can be overridden per-agent) */
|
|
108
|
+
timeout?: number;
|
|
109
|
+
retryOnFailure?: boolean;
|
|
110
|
+
maxRetries?: number;
|
|
111
|
+
fallbackAgents?: string[];
|
|
112
|
+
/**
|
|
113
|
+
* "fail-fast": abort entire workflow on first agent failure (default for sequential).
|
|
114
|
+
* "continue": skip failed agents and continue.
|
|
115
|
+
* "fail-at-end": complete all agents, then surface errors.
|
|
116
|
+
*/
|
|
117
|
+
failureMode?: "fail-fast" | "continue" | "fail-at-end";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ─── Workflow ─────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
export interface MultiAgentWorkflow {
|
|
123
|
+
id: string;
|
|
124
|
+
goal: string;
|
|
125
|
+
agents: AgentConfig[];
|
|
126
|
+
strategy: OrchestrationStrategy;
|
|
127
|
+
initialPrompt: string;
|
|
128
|
+
expectedOutput?: string;
|
|
129
|
+
createdAt: Date;
|
|
130
|
+
updatedAt: Date;
|
|
131
|
+
/** Optional metadata bag for user-defined fields */
|
|
132
|
+
meta?: Record<string, unknown>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ─── Pool ────────────────────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
export interface AgentPool {
|
|
138
|
+
agents: Map<string, AgentInstance>;
|
|
139
|
+
activeAgents: Set<string>;
|
|
140
|
+
waitingAgents: Set<string>;
|
|
141
|
+
failedAgents: Set<string>;
|
|
142
|
+
completedAgents: Set<string>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface AgentInstance {
|
|
146
|
+
config: AgentConfig;
|
|
147
|
+
context: AgentContext;
|
|
148
|
+
status: AgentStatus;
|
|
149
|
+
/** For backward compat */
|
|
150
|
+
get isActive(): boolean;
|
|
151
|
+
lastMessageTime: Date;
|
|
152
|
+
messageQueue: AgentMessage[];
|
|
153
|
+
completionPercentage: number;
|
|
154
|
+
startedAt?: Date;
|
|
155
|
+
completedAt?: Date;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ─── Orchestrator State ───────────────────────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
export type OrchestratorStatus = "pending" | "running" | "paused" | "completed" | "failed";
|
|
161
|
+
|
|
162
|
+
export interface OrchestratorState {
|
|
163
|
+
workflowId: string;
|
|
164
|
+
status: OrchestratorStatus;
|
|
165
|
+
pool: AgentPool;
|
|
166
|
+
sharedContext: AgentContext;
|
|
167
|
+
timeline: AgentExecutionResult[];
|
|
168
|
+
startTime: Date;
|
|
169
|
+
endTime?: Date;
|
|
170
|
+
currentCoordinator: string;
|
|
171
|
+
/** Emitted events in order */
|
|
172
|
+
events: OrchestratorEvent[];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ─── Events ───────────────────────────────────────────────────────────────────
|
|
176
|
+
|
|
177
|
+
export type OrchestratorEventType =
|
|
178
|
+
| "workflow:start"
|
|
179
|
+
| "workflow:complete"
|
|
180
|
+
| "workflow:failed"
|
|
181
|
+
| "agent:start"
|
|
182
|
+
| "agent:complete"
|
|
183
|
+
| "agent:failed"
|
|
184
|
+
| "agent:retry"
|
|
185
|
+
| "agent:timeout"
|
|
186
|
+
| "strategy:phase"
|
|
187
|
+
| "message:sent";
|
|
188
|
+
|
|
189
|
+
export interface OrchestratorEvent {
|
|
190
|
+
type: OrchestratorEventType;
|
|
191
|
+
timestamp: Date;
|
|
192
|
+
agentId?: string;
|
|
193
|
+
payload?: Record<string, unknown>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export type OrchestratorEventListener = (event: OrchestratorEvent) => void;
|
|
197
|
+
|
|
198
|
+
// ─── Communication ────────────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
export interface CommunicationChannel {
|
|
201
|
+
messageBuffer: AgentMessage[];
|
|
202
|
+
subscribers: Map<string, (msg: AgentMessage) => void>;
|
|
203
|
+
broadcast(message: Omit<AgentMessage, "id" | "timestamp">): AgentMessage;
|
|
204
|
+
subscribe(agentId: string, callback: (msg: AgentMessage) => void): () => void;
|
|
205
|
+
getMessagesFor(agentId: string): AgentMessage[];
|
|
206
|
+
getConversation(agentId1: string, agentId2: string): AgentMessage[];
|
|
207
|
+
clearBuffer(): void;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ─── Summary Types ────────────────────────────────────────────────────────────
|
|
211
|
+
|
|
212
|
+
export interface AgentResultSummary {
|
|
213
|
+
agentId: string;
|
|
214
|
+
success: boolean;
|
|
215
|
+
role: AgentRole | undefined;
|
|
216
|
+
steps: number;
|
|
217
|
+
durationMs: number;
|
|
218
|
+
toolsUsed: string[];
|
|
219
|
+
attemptNumber: number;
|
|
220
|
+
output?: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface PoolStats {
|
|
224
|
+
totalAgents: number;
|
|
225
|
+
activeAgents: number;
|
|
226
|
+
waitingAgents: number;
|
|
227
|
+
failedAgents: number;
|
|
228
|
+
completedAgents: number;
|
|
229
|
+
completionPercentage: number;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface OrchestratorSummary {
|
|
233
|
+
workflowId: string;
|
|
234
|
+
status: OrchestratorStatus;
|
|
235
|
+
goal: string;
|
|
236
|
+
strategy: StrategyType;
|
|
237
|
+
startTime: Date;
|
|
238
|
+
endTime?: Date;
|
|
239
|
+
duration: number | null;
|
|
240
|
+
totalAgents: number;
|
|
241
|
+
completedTasks: number;
|
|
242
|
+
failedTasks: number;
|
|
243
|
+
poolStats: PoolStats;
|
|
244
|
+
executionResults: AgentResultSummary[];
|
|
245
|
+
}
|