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,441 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { MultiAgentOrchestrator } from "./multi-agent-orchestrator";
|
|
3
|
+
import { WorkflowBuilder, WorkflowTemplates } from "./workflow-builder";
|
|
4
|
+
import { withSpinner } from "../../tui/spinner";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Example: Code review with inline failure handling
|
|
8
|
+
*/
|
|
9
|
+
export async function exampleCodeReviewWorkflow(): Promise<void> {
|
|
10
|
+
console.log(chalk.bold("\nš¤ Code Review Workflow\n"));
|
|
11
|
+
|
|
12
|
+
const workflow = new WorkflowBuilder(
|
|
13
|
+
"review_001",
|
|
14
|
+
"Review the authentication module for security vulnerabilities",
|
|
15
|
+
)
|
|
16
|
+
.addResearcher(
|
|
17
|
+
"security_analyzer",
|
|
18
|
+
"Security Analyzer",
|
|
19
|
+
"Analyzes code for security vulnerabilities and best practices",
|
|
20
|
+
)
|
|
21
|
+
.addImplementer(
|
|
22
|
+
"code_improver",
|
|
23
|
+
"Code Improver",
|
|
24
|
+
"Fixes identified security issues and improves code",
|
|
25
|
+
)
|
|
26
|
+
.addReviewer(
|
|
27
|
+
"qa_validator",
|
|
28
|
+
"QA Validator",
|
|
29
|
+
"Validates that all security fixes are properly implemented",
|
|
30
|
+
)
|
|
31
|
+
.withSequentialStrategy()
|
|
32
|
+
.withRetryOnFailure(1)
|
|
33
|
+
.withExpectedOutput("Security audit report with fixes applied")
|
|
34
|
+
.build();
|
|
35
|
+
|
|
36
|
+
const validation = new WorkflowBuilder(workflow.id, workflow.goal).validate();
|
|
37
|
+
if (!validation.isValid) {
|
|
38
|
+
console.log(chalk.red("ā Validation failed:"));
|
|
39
|
+
validation.errors.forEach((e) => console.log(chalk.red(` ⢠${e}`)));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
44
|
+
|
|
45
|
+
// Listen to events
|
|
46
|
+
const unsubscribe = orchestrator.onEvent((event) => {
|
|
47
|
+
if (event.type === "agent:complete") {
|
|
48
|
+
console.log(chalk.dim(` ā ${event.agentId} completed`));
|
|
49
|
+
} else if (event.type === "agent:failed") {
|
|
50
|
+
console.log(chalk.red(` ā ${event.agentId} failed`));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await withSpinner(
|
|
55
|
+
{
|
|
56
|
+
message: "Orchestrating review workflow...",
|
|
57
|
+
doneMessage: "workflow completed",
|
|
58
|
+
failMessage: "workflow failed",
|
|
59
|
+
},
|
|
60
|
+
() => orchestrator.execute(),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
unsubscribe();
|
|
64
|
+
|
|
65
|
+
const summary = orchestrator.getSummary();
|
|
66
|
+
console.log(chalk.bold("\nš Results\n"));
|
|
67
|
+
console.log(`Status: ${chalk.green(summary.status)}`);
|
|
68
|
+
console.log(`Duration: ${summary.duration}ms`);
|
|
69
|
+
console.log(`Completed: ${summary.completedTasks}`);
|
|
70
|
+
console.log(`Failed: ${summary.failedTasks}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Example: Parallel feature development with multiple models
|
|
75
|
+
*/
|
|
76
|
+
export async function exampleParallelDevelopment(): Promise<void> {
|
|
77
|
+
console.log(chalk.bold("\nā” Parallel Feature Development\n"));
|
|
78
|
+
|
|
79
|
+
const workflow = WorkflowTemplates.featureDevelopmentWorkflow(
|
|
80
|
+
"feature_dev_001",
|
|
81
|
+
"Implement user authentication with OAuth2 support",
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
85
|
+
|
|
86
|
+
await withSpinner(
|
|
87
|
+
{
|
|
88
|
+
message: "Executing parallel feature development...",
|
|
89
|
+
doneMessage: "feature development completed",
|
|
90
|
+
failMessage: "feature development failed",
|
|
91
|
+
},
|
|
92
|
+
() => orchestrator.execute(),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
console.log(chalk.bold("\nā
Feature Development Complete\n"));
|
|
96
|
+
const timeline = orchestrator.getTimeline();
|
|
97
|
+
|
|
98
|
+
for (const result of timeline) {
|
|
99
|
+
if (result.success) {
|
|
100
|
+
console.log(chalk.green(`ā ${result.agentId} (${result.durationMs}ms)`));
|
|
101
|
+
if (result.output) {
|
|
102
|
+
console.log(chalk.dim(` Output: ${result.output.slice(0, 80)}...`));
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
console.log(chalk.red(`ā ${result.agentId}`));
|
|
106
|
+
if (result.error) {
|
|
107
|
+
console.log(chalk.dim(` Error: ${result.error.message}`));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Example: Collaborative bug investigation
|
|
115
|
+
*/
|
|
116
|
+
export async function exampleCollaborativeBugFix(): Promise<void> {
|
|
117
|
+
console.log(chalk.bold("\nš Collaborative Bug Investigation\n"));
|
|
118
|
+
|
|
119
|
+
const workflow = new WorkflowBuilder(
|
|
120
|
+
"bugfix_001",
|
|
121
|
+
"The login endpoint returns 500 errors intermittently",
|
|
122
|
+
)
|
|
123
|
+
.addResearcher(
|
|
124
|
+
"bug_analyzer",
|
|
125
|
+
"Bug Analyzer",
|
|
126
|
+
"Analyzes error logs and traces the source of the issue",
|
|
127
|
+
)
|
|
128
|
+
.addResearcher(
|
|
129
|
+
"test_investigator",
|
|
130
|
+
"Test Investigator",
|
|
131
|
+
"Writes tests to reproduce the bug",
|
|
132
|
+
)
|
|
133
|
+
.addImplementer(
|
|
134
|
+
"bug_fixer",
|
|
135
|
+
"Bug Fixer",
|
|
136
|
+
"Implements the fix based on findings",
|
|
137
|
+
)
|
|
138
|
+
.withCollaborativeStrategy(60_000)
|
|
139
|
+
.withExpectedOutput("Fixed login endpoint with regression tests")
|
|
140
|
+
.build();
|
|
141
|
+
|
|
142
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
143
|
+
|
|
144
|
+
await withSpinner(
|
|
145
|
+
{
|
|
146
|
+
message: "Investigating bug with collaborative agents...",
|
|
147
|
+
doneMessage: "investigation complete",
|
|
148
|
+
failMessage: "investigation failed",
|
|
149
|
+
},
|
|
150
|
+
() => orchestrator.execute(),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const messages = orchestrator.getMessageHistory();
|
|
154
|
+
if (messages.length > 0) {
|
|
155
|
+
console.log(chalk.bold("\nš¬ Agent Communication\n"));
|
|
156
|
+
for (const msg of messages.slice(-5)) {
|
|
157
|
+
console.log(`${chalk.cyan(msg.fromAgentId)} ā ${msg.toAgentId || "all"}: ${msg.type}`);
|
|
158
|
+
console.log(chalk.dim(` ${msg.content.slice(0, 80)}...`));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Example: Advanced DAG workflow with full-stack development
|
|
165
|
+
*/
|
|
166
|
+
export async function exampleAdvancedDAGWorkflow(): Promise<void> {
|
|
167
|
+
console.log(chalk.bold("\nš Full-Stack Development (DAG)\n"));
|
|
168
|
+
|
|
169
|
+
const workflow = WorkflowTemplates.fullStackFeatureWorkflow(
|
|
170
|
+
"fullstack_001",
|
|
171
|
+
"Build a new user profile management feature with database, API, and UI",
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
console.log(chalk.dim("Dependencies:"));
|
|
175
|
+
for (const agent of workflow.agents) {
|
|
176
|
+
const deps = agent.dependsOn?.join(", ") || "(root)";
|
|
177
|
+
console.log(chalk.dim(` ${agent.name} ā ${deps}`));
|
|
178
|
+
}
|
|
179
|
+
console.log();
|
|
180
|
+
|
|
181
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
182
|
+
|
|
183
|
+
// Log events in real-time
|
|
184
|
+
orchestrator.onEvent((event) => {
|
|
185
|
+
if (event.type === "agent:start") {
|
|
186
|
+
console.log(chalk.cyan(`ā ${event.agentId} starting`));
|
|
187
|
+
} else if (event.type === "agent:complete") {
|
|
188
|
+
const duration = event.payload?.duration;
|
|
189
|
+
console.log(chalk.green(`ā ${event.agentId} done${duration ? ` (${duration}ms)` : ""}`));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await withSpinner(
|
|
194
|
+
{
|
|
195
|
+
message: "Executing DAG workflow...",
|
|
196
|
+
doneMessage: "all stages completed",
|
|
197
|
+
failMessage: "workflow encountered errors",
|
|
198
|
+
},
|
|
199
|
+
() => orchestrator.execute(),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const summary = orchestrator.getSummary();
|
|
203
|
+
console.log(chalk.bold("\nš Detailed Report\n"));
|
|
204
|
+
console.log(`Total Duration: ${summary.duration}ms`);
|
|
205
|
+
console.log(`Agents: ${summary.totalAgents}`);
|
|
206
|
+
console.log(`Completed: ${chalk.green(String(summary.completedTasks))}`);
|
|
207
|
+
console.log(`Failed: ${chalk.red(String(summary.failedTasks))}`);
|
|
208
|
+
console.log();
|
|
209
|
+
|
|
210
|
+
for (const result of summary.executionResults) {
|
|
211
|
+
const icon = result.success ? chalk.green("ā") : chalk.red("ā");
|
|
212
|
+
console.log(`${icon} ${chalk.bold(result.agentId)} (${result.role})`);
|
|
213
|
+
console.log(` Duration: ${result.durationMs}ms, Steps: ${result.steps}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Example: Security audit with parallel reviewers
|
|
219
|
+
*/
|
|
220
|
+
export async function exampleSecurityAudit(): Promise<void> {
|
|
221
|
+
console.log(chalk.bold("\nš Security Audit (Parallel)\n"));
|
|
222
|
+
|
|
223
|
+
const workflow = WorkflowTemplates.securityAuditWorkflow(
|
|
224
|
+
"audit_001",
|
|
225
|
+
"Full security audit of the payment processing module",
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
229
|
+
|
|
230
|
+
// Track which agents are running
|
|
231
|
+
const running = new Set<string>();
|
|
232
|
+
orchestrator.onEvent((event) => {
|
|
233
|
+
if (event.type === "agent:start" && event.agentId) {
|
|
234
|
+
running.add(event.agentId);
|
|
235
|
+
console.log(chalk.cyan(`ā [${running.size}] ${event.agentId}`));
|
|
236
|
+
} else if (event.type === "agent:complete" && event.agentId) {
|
|
237
|
+
running.delete(event.agentId);
|
|
238
|
+
console.log(chalk.green(`ā [${running.size}] ${event.agentId}`));
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
await withSpinner(
|
|
243
|
+
{
|
|
244
|
+
message: "Running security audit...",
|
|
245
|
+
doneMessage: "audit completed",
|
|
246
|
+
failMessage: "audit failed",
|
|
247
|
+
},
|
|
248
|
+
() => orchestrator.execute(),
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const summary = orchestrator.getSummary();
|
|
252
|
+
console.log(chalk.bold("\nš Audit Summary\n"));
|
|
253
|
+
console.log(`Status: ${summary.status}`);
|
|
254
|
+
console.log(`Duration: ${summary.duration}ms`);
|
|
255
|
+
|
|
256
|
+
console.log(chalk.bold("\nš Agent Reports\n"));
|
|
257
|
+
const timeline = orchestrator.getTimeline();
|
|
258
|
+
for (const result of timeline) {
|
|
259
|
+
if (result.success) {
|
|
260
|
+
console.log(chalk.green(`ā ${result.agentId}`));
|
|
261
|
+
console.log(chalk.dim(` ${result.output.slice(0, 150)}...`));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Example: Multi-model orchestration ā different models for different agents
|
|
268
|
+
*/
|
|
269
|
+
export async function exampleMultiModelOrchestration(): Promise<void> {
|
|
270
|
+
console.log(chalk.bold("\nš§ Multi-Model Orchestration\n"));
|
|
271
|
+
|
|
272
|
+
const workflow = new WorkflowBuilder(
|
|
273
|
+
"multimodel_001",
|
|
274
|
+
"Refactor API layer to clean architecture",
|
|
275
|
+
)
|
|
276
|
+
.addCoordinator(
|
|
277
|
+
"architect",
|
|
278
|
+
"Software Architect",
|
|
279
|
+
"Designs clean architecture and creates refactoring plan",
|
|
280
|
+
{ model: "anthropic/claude-opus-4" }, // Strongest model
|
|
281
|
+
)
|
|
282
|
+
.addImplementer(
|
|
283
|
+
"refactor_impl",
|
|
284
|
+
"Refactoring Implementer",
|
|
285
|
+
"Executes the refactoring plan",
|
|
286
|
+
{ model: "anthropic/claude-3.5-sonnet" }, // Fast & capable
|
|
287
|
+
)
|
|
288
|
+
.addReviewer(
|
|
289
|
+
"test_validator",
|
|
290
|
+
"Test Validator",
|
|
291
|
+
"Writes and runs tests to verify refactoring",
|
|
292
|
+
) // Uses default
|
|
293
|
+
.withHierarchicalStrategy()
|
|
294
|
+
.withRetryOnFailure(1)
|
|
295
|
+
.build();
|
|
296
|
+
|
|
297
|
+
console.log(chalk.bold("Model Assignments:\n"));
|
|
298
|
+
for (const agent of workflow.agents) {
|
|
299
|
+
const model = agent.model ? chalk.cyan(agent.model) : chalk.dim("(default)");
|
|
300
|
+
console.log(` ${chalk.bold(agent.name)}: ${model}`);
|
|
301
|
+
}
|
|
302
|
+
console.log();
|
|
303
|
+
|
|
304
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
305
|
+
|
|
306
|
+
await withSpinner(
|
|
307
|
+
{
|
|
308
|
+
message: "Running multi-model orchestration...",
|
|
309
|
+
doneMessage: "orchestration complete",
|
|
310
|
+
failMessage: "orchestration failed",
|
|
311
|
+
},
|
|
312
|
+
() => orchestrator.execute(),
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
const summary = orchestrator.getSummary();
|
|
316
|
+
console.log(chalk.bold("\nš Results\n"));
|
|
317
|
+
for (const result of summary.executionResults) {
|
|
318
|
+
const icon = result.success ? chalk.green("ā") : chalk.red("ā");
|
|
319
|
+
const agent = workflow.agents.find((a) => a.id === result.agentId);
|
|
320
|
+
const model = agent?.model ? chalk.cyan(`[${agent.model}]`) : chalk.dim("[default]");
|
|
321
|
+
console.log(`${icon} ${chalk.bold(result.agentId)} ${model}`);
|
|
322
|
+
console.log(` ${result.durationMs}ms, ${result.steps} steps`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Example: Error handling and retry logic
|
|
328
|
+
*/
|
|
329
|
+
export async function exampleErrorHandling(): Promise<void> {
|
|
330
|
+
console.log(chalk.bold("\nā ļø Error Handling & Retry\n"));
|
|
331
|
+
|
|
332
|
+
const workflow = new WorkflowBuilder(
|
|
333
|
+
"error_handling_001",
|
|
334
|
+
"Test error recovery with retries",
|
|
335
|
+
)
|
|
336
|
+
.addImplementer(
|
|
337
|
+
"risky_impl",
|
|
338
|
+
"Risky Implementer",
|
|
339
|
+
"An agent that might fail and will retry",
|
|
340
|
+
)
|
|
341
|
+
.addReviewer(
|
|
342
|
+
"fallback_reviewer",
|
|
343
|
+
"Fallback Reviewer",
|
|
344
|
+
"Reviews if main impl fails",
|
|
345
|
+
)
|
|
346
|
+
.withParallelStrategy(2, 20_000)
|
|
347
|
+
.withRetryOnFailure(3)
|
|
348
|
+
.withFailureMode("continue")
|
|
349
|
+
.build();
|
|
350
|
+
|
|
351
|
+
console.log(chalk.dim("Config:"));
|
|
352
|
+
console.log(chalk.dim(` - Max retries: 3`));
|
|
353
|
+
console.log(chalk.dim(` - Failure mode: continue`));
|
|
354
|
+
console.log(chalk.dim(` - Timeout: 20s per agent\n`));
|
|
355
|
+
|
|
356
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
357
|
+
|
|
358
|
+
orchestrator.onEvent((event) => {
|
|
359
|
+
if (event.type === "agent:retry") {
|
|
360
|
+
const attempt = event.payload?.attempt || 1;
|
|
361
|
+
console.log(chalk.yellow(`ā» ${event.agentId} retry attempt ${attempt}`));
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
await withSpinner(
|
|
366
|
+
{
|
|
367
|
+
message: "Running with error handling...",
|
|
368
|
+
doneMessage: "completed",
|
|
369
|
+
failMessage: "failed",
|
|
370
|
+
},
|
|
371
|
+
() => orchestrator.execute(),
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
const summary = orchestrator.getSummary();
|
|
375
|
+
console.log(chalk.bold("\nš Retry Statistics\n"));
|
|
376
|
+
for (const result of summary.executionResults) {
|
|
377
|
+
console.log(
|
|
378
|
+
`${result.agentId}: attempt ${result.attemptNumber} - ${result.success ? "ā" : "ā"}`,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Example: Event-driven monitoring
|
|
385
|
+
*/
|
|
386
|
+
export async function exampleEventDrivenMonitoring(): Promise<void> {
|
|
387
|
+
console.log(chalk.bold("\nš” Event-Driven Monitoring\n"));
|
|
388
|
+
|
|
389
|
+
const workflow = new WorkflowBuilder("events_001", "Demo event monitoring")
|
|
390
|
+
.addResearcher("researcher", "Researcher", "Gathers info")
|
|
391
|
+
.addImplementer("impl", "Implementer", "Implements", { dependsOn: ["researcher"] })
|
|
392
|
+
.addReviewer("reviewer", "Reviewer", "Reviews", { dependsOn: ["impl"] })
|
|
393
|
+
.withDagStrategy(2, 30_000)
|
|
394
|
+
.build();
|
|
395
|
+
|
|
396
|
+
const orchestrator = new MultiAgentOrchestrator(workflow);
|
|
397
|
+
|
|
398
|
+
const eventCounts = {
|
|
399
|
+
"agent:start": 0,
|
|
400
|
+
"agent:complete": 0,
|
|
401
|
+
"agent:failed": 0,
|
|
402
|
+
"workflow:start": 0,
|
|
403
|
+
"workflow:complete": 0,
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
orchestrator.onEvent((event) => {
|
|
407
|
+
const key = event.type as keyof typeof eventCounts;
|
|
408
|
+
if (key in eventCounts) eventCounts[key]++;
|
|
409
|
+
|
|
410
|
+
const icon =
|
|
411
|
+
event.type.includes("complete") || event.type === "workflow:start"
|
|
412
|
+
? chalk.green("ā")
|
|
413
|
+
: chalk.red("ā");
|
|
414
|
+
console.log(`${icon} ${event.type}`);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
await withSpinner(
|
|
418
|
+
{
|
|
419
|
+
message: "Monitoring events...",
|
|
420
|
+
doneMessage: "completed",
|
|
421
|
+
failMessage: "failed",
|
|
422
|
+
},
|
|
423
|
+
() => orchestrator.execute(),
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
console.log(chalk.bold("\nš Event Summary\n"));
|
|
427
|
+
for (const [type, count] of Object.entries(eventCounts)) {
|
|
428
|
+
console.log(`${type}: ${count}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export default {
|
|
433
|
+
exampleCodeReviewWorkflow,
|
|
434
|
+
exampleParallelDevelopment,
|
|
435
|
+
exampleCollaborativeBugFix,
|
|
436
|
+
exampleAdvancedDAGWorkflow,
|
|
437
|
+
exampleSecurityAudit,
|
|
438
|
+
exampleMultiModelOrchestration,
|
|
439
|
+
exampleErrorHandling,
|
|
440
|
+
exampleEventDrivenMonitoring,
|
|
441
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { AgentMessage, CommunicationChannel } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Implements a publish-subscribe communication channel for agents.
|
|
5
|
+
* Supports directed messages, broadcasts, priority ordering, and replay.
|
|
6
|
+
*/
|
|
7
|
+
export class MessageBroker implements CommunicationChannel {
|
|
8
|
+
messageBuffer: AgentMessage[] = [];
|
|
9
|
+
subscribers: Map<string, (msg: AgentMessage) => void> = new Map();
|
|
10
|
+
private messageId = 0;
|
|
11
|
+
|
|
12
|
+
// āāā Sending āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Broadcast or direct-send a message.
|
|
16
|
+
* High-priority messages are delivered first within the same tick.
|
|
17
|
+
*/
|
|
18
|
+
broadcast(message: Omit<AgentMessage, "id" | "timestamp">): AgentMessage {
|
|
19
|
+
const fullMessage: AgentMessage = {
|
|
20
|
+
id: `msg_${String(++this.messageId).padStart(6, "0")}`,
|
|
21
|
+
timestamp: new Date(),
|
|
22
|
+
priority: "normal",
|
|
23
|
+
...message,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
this.messageBuffer.push(fullMessage);
|
|
27
|
+
|
|
28
|
+
if (message.toAgentId) {
|
|
29
|
+
// Directed message
|
|
30
|
+
const callback = this.subscribers.get(message.toAgentId);
|
|
31
|
+
if (callback) callback(fullMessage);
|
|
32
|
+
} else {
|
|
33
|
+
// Broadcast ā exclude sender, deliver high-priority first
|
|
34
|
+
const recipients = [...this.subscribers.entries()]
|
|
35
|
+
.filter(([agentId]) => agentId !== message.fromAgentId);
|
|
36
|
+
|
|
37
|
+
// Sort so high-priority callbacks fire first
|
|
38
|
+
const ordered =
|
|
39
|
+
fullMessage.priority === "high"
|
|
40
|
+
? recipients
|
|
41
|
+
: recipients; // stable order is fine for normal/low
|
|
42
|
+
|
|
43
|
+
for (const [, callback] of ordered) {
|
|
44
|
+
callback(fullMessage);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return fullMessage;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Convenience wrapper: send a directed message from one agent to another.
|
|
53
|
+
*/
|
|
54
|
+
send(
|
|
55
|
+
fromAgentId: string,
|
|
56
|
+
toAgentId: string,
|
|
57
|
+
content: string,
|
|
58
|
+
type: AgentMessage["type"] = "request",
|
|
59
|
+
extra?: Partial<Omit<AgentMessage, "id" | "timestamp" | "fromAgentId" | "toAgentId" | "content" | "type">>,
|
|
60
|
+
): AgentMessage {
|
|
61
|
+
return this.broadcast({
|
|
62
|
+
fromAgentId,
|
|
63
|
+
toAgentId,
|
|
64
|
+
content,
|
|
65
|
+
type,
|
|
66
|
+
requiresResponse: type === "request",
|
|
67
|
+
...extra,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// āāā Subscribing āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe an agent to receive messages.
|
|
75
|
+
* Returns an unsubscribe function.
|
|
76
|
+
*/
|
|
77
|
+
subscribe(
|
|
78
|
+
agentId: string,
|
|
79
|
+
callback: (msg: AgentMessage) => void,
|
|
80
|
+
): () => void {
|
|
81
|
+
this.subscribers.set(agentId, callback);
|
|
82
|
+
return () => {
|
|
83
|
+
this.subscribers.delete(agentId);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// āāā Querying āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
88
|
+
|
|
89
|
+
/** All messages directed to (or broadcast to) a specific agent */
|
|
90
|
+
getMessagesFor(agentId: string): AgentMessage[] {
|
|
91
|
+
return this.messageBuffer.filter(
|
|
92
|
+
(msg) => !msg.toAgentId || msg.toAgentId === agentId,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** All messages sent FROM a specific agent */
|
|
97
|
+
getMessagesFrom(agentId: string): AgentMessage[] {
|
|
98
|
+
return this.messageBuffer.filter((msg) => msg.fromAgentId === agentId);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Bidirectional conversation between two agents */
|
|
102
|
+
getConversation(agentId1: string, agentId2: string): AgentMessage[] {
|
|
103
|
+
return this.messageBuffer.filter(
|
|
104
|
+
(msg) =>
|
|
105
|
+
(msg.fromAgentId === agentId1 && msg.toAgentId === agentId2) ||
|
|
106
|
+
(msg.fromAgentId === agentId2 && msg.toAgentId === agentId1),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Messages of a specific type */
|
|
111
|
+
getMessagesByType(type: AgentMessage["type"]): AgentMessage[] {
|
|
112
|
+
return this.messageBuffer.filter((msg) => msg.type === type);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Get the reply chain for a given message ID */
|
|
116
|
+
getReplyChain(messageId: string): AgentMessage[] {
|
|
117
|
+
const chain: AgentMessage[] = [];
|
|
118
|
+
let currentId: string | undefined = messageId;
|
|
119
|
+
|
|
120
|
+
while (currentId) {
|
|
121
|
+
const msg = this.messageBuffer.find((m) => m.id === currentId);
|
|
122
|
+
if (!msg) break;
|
|
123
|
+
chain.unshift(msg);
|
|
124
|
+
currentId = msg.replyToId;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return chain;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Total number of messages in the buffer */
|
|
131
|
+
get messageCount(): number {
|
|
132
|
+
return this.messageBuffer.length;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// āāā Buffer Management āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
136
|
+
|
|
137
|
+
clearBuffer(): void {
|
|
138
|
+
this.messageBuffer = [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Trim the buffer to keep only the last `n` messages.
|
|
143
|
+
* Useful for long-running collaborative workflows.
|
|
144
|
+
*/
|
|
145
|
+
trimBuffer(keepLast: number): void {
|
|
146
|
+
if (this.messageBuffer.length > keepLast) {
|
|
147
|
+
this.messageBuffer = this.messageBuffer.slice(-keepLast);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// āāā Replay āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Replay messages for an agent in chronological order.
|
|
155
|
+
*/
|
|
156
|
+
async replayMessages(
|
|
157
|
+
agentId: string,
|
|
158
|
+
callback: (msg: AgentMessage) => Promise<void>,
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
const messages = this.getMessagesFor(agentId);
|
|
161
|
+
for (const msg of messages) {
|
|
162
|
+
await callback(msg);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// āāā Diagnostics āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
167
|
+
|
|
168
|
+
stats() {
|
|
169
|
+
const byType = new Map<string, number>();
|
|
170
|
+
for (const msg of this.messageBuffer) {
|
|
171
|
+
byType.set(msg.type, (byType.get(msg.type) ?? 0) + 1);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
total: this.messageBuffer.length,
|
|
175
|
+
subscribers: this.subscribers.size,
|
|
176
|
+
byType: Object.fromEntries(byType),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|